|
@@ -1,32 +1,72 @@
|
|
|
|
+pub mod contlines;
|
|
|
|
+
|
|
|
|
+use contlines::ContinuationLines;
|
|
|
|
+
|
|
|
|
+
|
|
struct ParsingContext {
|
|
struct ParsingContext {
|
|
- continuation_line: bool,
|
|
|
|
current_record_type: Option<String>,
|
|
current_record_type: Option<String>,
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+
|
|
#[derive(Eq, PartialEq, Debug)]
|
|
#[derive(Eq, PartialEq, Debug)]
|
|
pub struct Record {
|
|
pub struct Record {
|
|
pub rec_type: Option<String>,
|
|
pub rec_type: Option<String>,
|
|
pub fields: Vec<(String, String)>,
|
|
pub fields: Vec<(String, String)>,
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+impl Record {
|
|
|
|
+ pub fn write<W>(&self, w: &mut W) -> std::io::Result<()>
|
|
|
|
+ where W: std::io::Write
|
|
|
|
+ {
|
|
|
|
+ for &(ref name, ref value) in self.fields.iter() {
|
|
|
|
+ write!(w, "{}: {}\n", name, value)?;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ write!(w, "\n")
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pub fn size(&self) -> usize {
|
|
|
|
+ self.fields.len()
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
#[derive(Eq, PartialEq, Debug)]
|
|
#[derive(Eq, PartialEq, Debug)]
|
|
pub struct Recfile {
|
|
pub struct Recfile {
|
|
pub records: Vec<Record>,
|
|
pub records: Vec<Record>,
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+impl Recfile {
|
|
|
|
+ pub fn write<W>(&self, w: &mut W) -> std::io::Result<()>
|
|
|
|
+ where W: std::io::Write
|
|
|
|
+ {
|
|
|
|
+ for r in self.records.iter() {
|
|
|
|
+ r.write(w)?;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ Ok(())
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pub fn filter_by_type(&mut self, type_name: &str) {
|
|
|
|
+ self.records.retain(|r| match r.rec_type {
|
|
|
|
+ Some(ref t) => t == type_name,
|
|
|
|
+ None => false,
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
|
|
impl Recfile {
|
|
impl Recfile {
|
|
pub fn parse<I>(i: I) -> Result<Recfile, String>
|
|
pub fn parse<I>(i: I) -> Result<Recfile, String>
|
|
where I: std::io::BufRead
|
|
where I: std::io::BufRead
|
|
{
|
|
{
|
|
- let mut iter = i.lines();
|
|
|
|
|
|
+ let mut iter = ContinuationLines::new(i.lines());
|
|
let mut current = Record {
|
|
let mut current = Record {
|
|
fields: vec![],
|
|
fields: vec![],
|
|
rec_type: None,
|
|
rec_type: None,
|
|
};
|
|
};
|
|
let mut buf = vec![];
|
|
let mut buf = vec![];
|
|
let mut ctx = ParsingContext {
|
|
let mut ctx = ParsingContext {
|
|
- continuation_line: false,
|
|
|
|
current_record_type: None,
|
|
current_record_type: None,
|
|
};
|
|
};
|
|
|
|
|
|
@@ -76,6 +116,7 @@ impl Recfile {
|
|
|
|
|
|
Ok(Recfile { records: buf })
|
|
Ok(Recfile { records: buf })
|
|
}
|
|
}
|
|
|
|
+
|
|
}
|
|
}
|
|
|
|
|
|
#[cfg(test)]
|
|
#[cfg(test)]
|
|
@@ -86,6 +127,7 @@ mod tests {
|
|
let file = Recfile {
|
|
let file = Recfile {
|
|
records: expected.iter().map( |v| {
|
|
records: expected.iter().map( |v| {
|
|
Record {
|
|
Record {
|
|
|
|
+ rec_type: None,
|
|
fields: v.iter().map( |&(k, v)| {
|
|
fields: v.iter().map( |&(k, v)| {
|
|
(k.to_owned(), v.to_owned())
|
|
(k.to_owned(), v.to_owned())
|
|
}).collect(),
|
|
}).collect(),
|