},
}
+/// Format [Type] categories.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum Category {
- // Numeric formats.
+ /// F, COMMA, DOT, DOLLAR, PCT, and E.
Basic,
+
+ /// CCx.
Custom,
+
+ /// N and Z.
Legacy,
+
+ /// P, PK, IB, PIB, and RB.
Binary,
+
+ /// PIBHEX and RBHEX.
Hex,
+
+ /// DATE, ADATE, EDATE, JDATE, SDATE, QYR, MOYR, WKYR, DATETIME, and YMDHMS.
Date,
+
+ /// MTIME, TIME, and DTIME.
Time,
+
+ /// WKDAY and MONTH.
DateComponent,
- // String formats.
+ // A and AHEX.
String,
}
//! <https://cldr.unicode.org/index/downloads>, rename it as
//! `cldr-json-full.zip` in the same directory as `build.rs`,
//! and touch `build.rs` to force a rebuild.
-use std::{collections::HashMap, sync::LazyLock};
use crate::format::Decimal;
+use std::{collections::HashMap, sync::LazyLock};
/// Map from language to decimal point.
pub static LANG_TO_DECIMAL: LazyLock<HashMap<&'static str, Decimal>> = LazyLock::new(|| {
}
}
for label in footnote_labels {
- for (index, text) in label.text().iter().enumerate() {
- if let Some(uses_reference) = text.uses_reference {
- let entry = footnote_builder
- .entry(uses_reference.get() - 1)
- .or_default();
- if index % 2 == 1 {
- entry.content = text.text.strip_suffix('\n').unwrap_or(&text.text).into();
+ for (i, text) in label.text().iter().enumerate() {
+ if let DecodedText::FootnoteDefinition { index, text } = text.decode() {
+ let entry = footnote_builder.entry(index).or_default();
+ if i % 2 == 1 {
+ entry.content = text.strip_suffix('\n').unwrap_or(text).into();
} else {
- entry.marker = Some(
- text.text
- .trim_end()
- .strip_suffix('.')
- .unwrap_or(&text.text)
- .into(),
- );
+ entry.marker =
+ Some(text.trim_end().strip_suffix('.').unwrap_or(text).into());
}
}
}
#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
struct Text {
+ /// If this is present, then `text` defines the content or the marker for a
+ /// footnote.
#[serde(rename = "@usesReference")]
uses_reference: Option<NonZeroUsize>,
+ /// If this is present, then
#[serde(rename = "@definesReference")]
defines_reference: Option<NonZeroUsize>,
text: String,
}
+enum DecodedText<'a> {
+ /// Defines footnote `index` content or marker as `text`.
+ FootnoteDefinition { index: usize, text: &'a str },
+
+ /// Adds a reference to footnote `index`.
+ FootnoteReference { index: usize },
+
+ /// Text content.
+ Text { text: &'a str },
+}
+
+impl Text {
+ fn decode(&self) -> DecodedText<'_> {
+ if let Some(uses_reference) = self.uses_reference {
+ DecodedText::FootnoteDefinition {
+ index: uses_reference.get() - 1,
+ text: &self.text,
+ }
+ } else if let Some(defines_reference) = self.defines_reference {
+ DecodedText::FootnoteReference {
+ index: defines_reference.get() - 1,
+ }
+ } else {
+ DecodedText::Text { text: &self.text }
+ }
+ }
+}
+
#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
struct LabelFrame {
if !labels.is_empty() {
let mut s = String::new();
let mut f = Vec::new();
- for t in labels {
- if let LabelChild::Text(text) = &t.child {
- for t in text {
- if t.uses_reference.is_none() {
- if let Some(defines_reference) = t.defines_reference
- && let Some(footnote) = footnotes.get(defines_reference.get() - 1)
- {
- f.push(footnote);
- } else {
- s += &t.text;
+ for label in labels {
+ for text in label.text() {
+ match text.decode() {
+ DecodedText::FootnoteReference { index } => {
+ if let Some(footnote) = footnotes.get(index) {
+ f.push(footnote)
}
}
+ DecodedText::Text { text } => s += text,
+ _ => (),
}
}
}
- let mut value = Value::new_user_text(s);
- for footnote in f {
- value = value.with_footnote(footnote);
- }
- Some(value)
+ Some(Value::new_user_text(s).with_footnotes(f))
} else {
None
}