Skip to content

Commit

Permalink
Cripple the decoder to work with FnOnce.
Browse files Browse the repository at this point in the history
  • Loading branch information
BurntSushi committed Dec 17, 2014
1 parent 841fb82 commit b7cb50d
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 58 deletions.
2 changes: 1 addition & 1 deletion examples/stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use std::time::Duration;

fn main() {
let (send, recv) = channel();
spawn(proc() {
spawn(move || {
let w = io::ChanWriter::new(send);
let mut enc = csv::Writer::from_writer(w);
for x in range(1u, 6) {
Expand Down
46 changes: 7 additions & 39 deletions src/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,43 +106,14 @@ impl serialize::Decoder<Error> for Decoded {
}
fn read_enum_variant<T, F>(&mut self, names: &[&str], f: F)
-> CsvResult<T>
where F: FnMut(&mut Decoded, uint) -> CsvResult<T> {
where F: FnOnce(&mut Decoded, uint) -> CsvResult<T> {
let variant = to_lower(try!(self.pop_string()).as_slice());

// This is subtly broken. Supporting both zero-parameter and
// one-parameter enum variants, I think, is impossible right now.
// The issue is, we don't know how many parameters each variant
// takes, so we can't detect all possible failures.
// match names.iter().position(|&name| to_lower(name) == variant) {
// Some(idx) => return f(self, idx),
// None => {}
// }

// At this point, we couldn't find a verbatim Enum variant, so let's
// assume we're trying to load enum variants of one argument.
// We don't know which one to pick, so we try each of them until we
// get a hit.
//
// If we fail, it's tough to know what error to report. Probably the
// right way to do this is to maintain a stack of errors. Ug.
self.push_string(variant); // push what we popped earlier
for i in range(0, names.len()) {
// Copy the top of the stack now. We'll push it back on if
// decoding into this variant fails.
let cur = try!(self.pop_string());
let copy = cur.clone();
self.push_string(cur);

match f(self, i) {
Ok(v) => return Ok(v), // loaded a value successfully; bail!
Err(_) => {
// Put what we popped back on the stack so we can retry.
self.push_string(copy);
}
}
match names.iter().position(|&name| to_lower(name) == variant) {
Some(idx) => f(self, idx),
None => self.err(format!(
"Could not match '{}' with any of the variants: {}",
variant, names)),
}
return self.err(format!(
"Could not load value into any variant in {}", names))
}
fn read_enum_variant_arg<T, F>(&mut self, _: uint, f: F) -> CsvResult<T>
where F: FnOnce(&mut Decoded) -> CsvResult<T> {
Expand Down Expand Up @@ -199,10 +170,7 @@ impl serialize::Decoder<Error> for Decoded {
f(self, false)
} else {
self.push_string(s);
match f(self, true) {
Ok(v) => Ok(v),
Err(_) => f(self, false),
}
f(self, true)
}
}
fn read_seq<T, F>(&mut self, f: F) -> CsvResult<T>
Expand Down
11 changes: 7 additions & 4 deletions src/reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,9 +185,7 @@ impl<R: io::Reader> Reader<R> {
/// cannot be decoded into the type requested, an error is returned.
///
/// Enums are also supported in a limited way. Namely, its variants must
/// have exactly `0` or `1` parameters. Variants with `0` parameters decode
/// based on a case-insensitive string match. Variants with `1` decode
/// based on its constituent type. Examples follow.
/// have no parameters and can match CSV fields by name (case insensitive).
///
/// ### Examples
///
Expand Down Expand Up @@ -230,12 +228,15 @@ impl<R: io::Reader> Reader<R> {
/// #[deriving(Decodable, PartialEq, Show)]
/// struct MyUint(uint);
///
/// #[deriving(Decodable, PartialEq, Show)]
/// enum Color { Red, Green, Blue }
///
/// #[deriving(Decodable)]
/// struct Pair {
/// name1: String,
/// name2: String,
/// dist: Option<MyUint>,
/// color: String,
/// color: Color,
/// }
///
/// let mut rdr = csv::Reader::from_string("foo,bar,1,red\nfoo,baz,,green")
Expand All @@ -246,6 +247,8 @@ impl<R: io::Reader> Reader<R> {
///
/// assert_eq!(rows[0].dist, Some(MyUint(1)));
/// assert_eq!(rows[1].dist, None);
/// assert_eq!(rows[0].color, Color::Red);
/// assert_eq!(rows[1].color, Color::Green);
/// # }
/// ```
///
Expand Down
24 changes: 10 additions & 14 deletions src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,25 +235,22 @@ fail_parses_to!(nonflexible, "a\nx,y", vec![])
fail_parses_to!(nonflexible2, "a,b\nx", vec![])

#[deriving(Decodable, Encodable, Show, PartialEq, Eq)]
enum Val {
Unsigned(uint),
Signed(int),
Bool(bool),
}
enum Color { Red, Blue, Green }

decodes_to!(decode_int, "1", (uint,), vec![(1u,)])
decodes_to!(decode_many_int, "1,2", (uint, i16), vec![(1u,2i16)])
decodes_to!(decode_float, "1,1.0,1.5", (f64, f64, f64), vec![(1f64, 1.0, 1.5)])
decodes_to!(decode_char, "a", (char,), vec![('a',)])
decodes_to!(decode_str, "abc", (String,), vec![("abc".into_string(),)])

decodes_to!(decode_opt_int, "a", (Option<uint>,), vec![(None,)])
decodes_to!(decode_opt_float, "a", (Option<f64>,), vec![(None,)])
decodes_to!(decode_opt_char, "ab", (Option<char>,), vec![(None,)])
decodes_to!(decode_opt_int, "\"\"", (Option<uint>,), vec![(None,)])
decodes_to!(decode_opt_float, "\"\"", (Option<f64>,), vec![(None,)])
decodes_to!(decode_opt_char, "\"\"", (Option<char>,), vec![(None,)])
decodes_to!(decode_opt_empty, "\"\"", (Option<String>,), vec![(None,)])

decodes_to!(decode_val, "false,-5,5", (Val, Val, Val),
vec![(Val::Bool(false), Val::Signed(-5), Val::Unsigned(5))])
decodes_to!(decode_opt_val, "1.0", (Option<Val>,), vec![(None,)])
decodes_to!(decode_color, "red,Blue,GrEeN", (Color, Color, Color),
vec![(Color::Red, Color::Blue, Color::Green)])
decodes_to!(decode_opt_color, "\"\"", (Option<Color>,), vec![(None,)])

decodes_to!(decode_tail, "abc,1,2,3,4", (String, Vec<uint>),
vec![("abc".into_string(), vec![1u, 2, 3, 4])])
Expand Down Expand Up @@ -319,9 +316,8 @@ encodes_as!(encode_float, vec![(1f64, 1.0f64, 1.5f64)], "1,1,1.5\n")
encodes_as!(encode_char, vec![('a',)], "a\n")
encodes_as!(encode_none, vec![(None::<bool>,)], "\"\"\n")
encodes_as!(encode_some, vec![(Some(true),)], "true\n")
encodes_as!(encode_val,
vec![(Val::Bool(false), Val::Signed(-5), Val::Unsigned(5))],
"false,-5,5\n")
encodes_as!(encode_color, vec![(Color::Red, Color::Blue, Color::Green)],
"Red,Blue,Green\n")

#[test]
fn no_headers_no_skip_one_record() {
Expand Down

0 comments on commit b7cb50d

Please sign in to comment.