app
AI Flow: JLCPCB
Public Made by Adomby adom
The whole JLCPCB order, from gerbers to assembled boards in hand: proven part swaps, design rules, rotation checks, quote and order.
main
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
//! A small RFC 4180 CSV reader and writer (quoted fields, doubled quotes, commas and newlines in quotes).
pub fn parse(text: &str) -> Vec<Vec<String>> {
let mut rows = Vec::new();
let mut row = Vec::new();
let mut field = String::new();
let mut quoted = false;
let mut chars = text.chars().peekable();
let mut any = false;
while let Some(c) = chars.next() {
any = true;
if quoted {
if c == '"' {
if chars.peek() == Some(&'"') { field.push('"'); chars.next(); } else { quoted = false; }
} else { field.push(c); }
continue;
}
match c {
'"' => quoted = true,
',' => row.push(std::mem::take(&mut field)),
'\r' => {}
'\n' => { row.push(std::mem::take(&mut field)); rows.push(std::mem::take(&mut row)); any = false; }
_ => field.push(c),
}
}
if any { row.push(field); rows.push(row); }
rows
}
/// Header and rows as maps, like Python's csv.DictReader (missing cells read as "").
pub struct Table { pub head: Vec<String>, pub rows: Vec<Vec<String>> }
impl Table {
pub fn read(path: &std::path::Path) -> std::io::Result<Table> {
let t = std::fs::read_to_string(path)?;
let t = t.strip_prefix('\u{feff}').unwrap_or(&t);
let mut all = parse(t);
if all.is_empty() { return Ok(Table { head: vec![], rows: vec![] }); }
let head = all.remove(0).into_iter().map(|h| h.trim().to_string()).collect();
Ok(Table { head, rows: all.into_iter().filter(|r| !(r.len() == 1 && r[0].is_empty())).collect() })
}
pub fn col(&self, name: &str) -> Option<usize> { self.head.iter().position(|h| h == name) }
pub fn get<'a>(&self, row: &'a [String], name: &str) -> &'a str {
self.col(name).and_then(|i| row.get(i)).map(|s| s.as_str()).unwrap_or("")
}
}
fn quote(f: &str) -> String {
if f.contains([',', '"', '\n', '\r']) { format!("\"{}\"", f.replace('"', "\"\"")) } else { f.to_string() }
}
/// Rows joined with `eol` ("\r\n" matches Python's csv module default, which JLCPCB's files were made with).
pub fn write(rows: &[Vec<String>], eol: &str) -> String {
rows.iter().map(|r| r.iter().map(|f| quote(f)).collect::<Vec<_>>().join(",") + eol).collect()
}
#[cfg(test)]
mod tests {
#[test]
fn quoted_fields_round_trip() {
let rows = super::parse("a,\"b, c\",\"d \"\"e\"\"\"\r\n1,2,3\n");
assert_eq!(rows, vec![vec!["a", "b, c", "d \"e\""], vec!["1", "2", "3"]]);
assert_eq!(super::write(&rows, "\n"), "a,\"b, c\",\"d \"\"e\"\"\"\n1,2,3\n");
}
}