///|
fn csv_field(text : String) -> String {
let out = StringBuilder()
out.write_char('"')
for c in text.iter() {
if c == '"' {
out.write_char('"')
}
out.write_char(c)
}
out.write_char('"')
out.to_string()
}
///|
/// CSV with quoted mnemonic/unit header, CRLF records and empty missing cells.
/// Intended for numerical pipelines, not spreadsheet formulas or LAS roundtrips.
pub fn write_csv(
log : Log,
include_units? : Bool = true,
) -> String raise WellError {
validate(log)
let out = StringBuilder()
for i in 0.. 0 {
out.write_string(",")
}
let c = log.curves[i]
out.write_string(
csv_field(c.name + (if include_units { " [" + c.unit + "]" } else { "" })),
)
}
out.write_string("\r\n")
for row in log.rows {
for i in 0.. 0 {
out.write_string(",")
}
if row[i] is Some(value) {
out.write_string(value.to_string())
}
}
out.write_string("\r\n")
}
out.to_string()
}
///|
/// Long-form provenance CSV; null cells omitted and synthetic depth has no run owner.
pub fn provenance_csv(assembly : Assembly) -> String raise WellError {
validate_assembly(assembly)
let out = StringBuilder()
out.write_string("depth,curve,run,interpolated,value\r\n")
for i in 0.. Unit raise WellError {
validate(assembly.log)
if assembly.sources.length() != assembly.log.rows.length() {
fail("source row count mismatch")
}
for i in 0..
if source.run < 0 || source.run >= assembly.run_names.length() {
fail("invalid source run index")
}
(None, None) => ()
_ => fail("source and sample presence differ")
}
}
}
for conflict in assembly.conflicts {
if conflict.row < 0 ||
conflict.row >= assembly.log.rows.length() ||
conflict.kept_run < 0 ||
conflict.kept_run >= assembly.run_names.length() ||
conflict.incoming_run < 0 ||
conflict.incoming_run >= assembly.run_names.length() ||
!finite(conflict.depth) ||
!finite(conflict.kept_value) ||
!finite(conflict.incoming_value) {
fail("invalid conflict record")
}
}
}