///|
enum CellValueType {
String
Number
Bool
Error
} derive(Eq, Debug)
///|
pub type CellType = CellValueType
///|
pub(all) enum CellValue {
String(String)
Numeric(Double)
Bool(Bool)
Error(String)
} derive(Debug)
///|
fn cell_value_type(value : CellValue) -> CellValueType {
match value {
String(_) => String
// NaN and infinities cannot be stored in a numeric cell; Excelize
// writes them as string cells instead.
Numeric(value) =>
if value.is_nan() || value.is_inf() {
String
} else {
Number
}
Bool(_) => Bool
Error(_) => Error
}
}
///|
/// Renders a non-finite double the way Go's fmt.Sprint does, which is the
/// text Excelize stores for NaN/Inf cell values.
fn non_finite_to_string(value : Double) -> String {
if value.is_nan() {
"NaN"
} else if value.is_pos_inf() {
"+Inf"
} else {
"-Inf"
}
}
///|
fn cell_value_raw_string(value : CellValue) -> String {
match value {
String(text) => text
Numeric(value) =>
if value.is_nan() || value.is_inf() {
non_finite_to_string(value)
} else {
value.to_string()
}
Bool(value) => if value { "1" } else { "0" }
Error(text) => text
}
}
///|
fn parse_cell_bool(value : StringView) -> Bool {
match value.to_lower() {
"1" | "true" | "yes" => true
_ => false
}
}
///|
fn cell_value_from_raw(
value_type : CellValueType,
raw : String,
) -> CellValue raise XlsxError {
match value_type {
String => String(raw)
Number =>
Numeric(
@string.parse_double(raw) catch {
_ => raise InvalidXml(msg="cell number invalid")
},
)
Bool => Bool(parse_cell_bool(raw))
Error => Error(raw)
}
}
///|
test "cell value wb: parse yes bool literal" {
inspect(parse_cell_bool("yes"), content="true")
}
///|
test "cell value wb: invalid numeric raw parse raises InvalidXml" {
let result : Result[CellValue, Error] = Ok(
cell_value_from_raw(Number, "not-a-number"),
) catch {
e => Err(e)
}
inspect(result is Err(XlsxError::InvalidXml(_)), content="true")
}