From fb3df5d4b96392425a5f7f670b5284a59f3631e1 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 17 Oct 2014 14:55:11 -0700 Subject: [PATCH] Allow generic decoding of usage into a type When writing a generic decode function over any types, one is tempted to write something along the lines of: extern crate serialize; extern crate docopt; use serialize::Decodable; fn foo<'a, T>(usage: &str) -> T where T: Decodable, docopt::Error> { let map = docopt::docopt(usage).unwrap_or_else(|e| e.exit()); map.decode().unwrap_or_else(|e| e.exit()) } Currently there are two problems with this approach. 1. The `docopt::Decoder` structure is private, so it cannot be referenced in a function signature. 2. The lifetime parameter on `Decoder` prevents usage of the local variable `map`. The `decode` function requires `&'a self`, which requires callers of this function to provide a lifetime variable `'a` which is the lifetime of the stack frame of `foo` itself. Sadly this cannot currently be done (higher ranked trait lifetimes maybe?). To work around these two problems, I've made the `Decoder` structure public and changed the `decode` method on `ValueMap` to consume the map, removing the lifetime parameter on `Decoder`. There may be some more generic wizardry to get around this problem, but this at least seems to work for now! --- src/lib.rs | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 7ad925a..8307d90 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -481,15 +481,15 @@ impl ValueMap { /// /// In this example, only the `bool` type was used, but any type satisfying /// the `Decodable` trait is valid. - pub fn decode<'a, T: Decodable, Error>> - (&'a self) -> Result { + pub fn decode> + (self) -> Result { Decodable::decode(&mut Decoder { vals: self, stack: vec!() }) } /// The same as `decode`, except if there is an error, it is logged to /// `stderr` and the current program will *unsafely* exit with an error /// code of `1`. - pub fn decode_must<'a, T: Decodable, Error>>(&'a self) -> T { + pub fn decode_must>(self) -> T { match self.decode() { Ok(v) => v, Err(err) => err.exit(), @@ -617,8 +617,8 @@ impl fmt::Show for ValueMap { } } -struct Decoder<'a> { - vals: &'a ValueMap, +pub struct Decoder { + vals: ValueMap, stack: Vec, } @@ -633,7 +633,7 @@ macro_rules! derr( ($($arg:tt)*) => (return Err(Decode(format!($($arg)*)))) ) -impl<'a> Decoder<'a> { +impl Decoder { fn push(&mut self, struct_field: &str) { let key = ValueMap::struct_field_to_key(struct_field); self.stack.push(DecoderItem { @@ -680,7 +680,7 @@ impl<'a> Decoder<'a> { } } -impl<'a> serialize::Decoder for Decoder<'a> { +impl serialize::Decoder for Decoder { fn error(&mut self, err: &str) -> Error { Decode(err.to_string()) } @@ -739,12 +739,12 @@ impl<'a> serialize::Decoder for Decoder<'a> { self.pop_val().map(|v| v.as_str().to_string()) } fn read_enum(&mut self, name: &str, - f: |&mut Decoder<'a>| -> Result) + f: |&mut Decoder| -> Result) -> Result { f(self) } fn read_enum_variant(&mut self, names: &[&str], - f: |&mut Decoder<'a>, uint| -> Result) + f: |&mut Decoder, uint| -> Result) -> Result { let v = try!(self.pop_val()); let vstr = to_lower(v.as_str()); @@ -760,52 +760,52 @@ impl<'a> serialize::Decoder for Decoder<'a> { } fn read_enum_variant_arg( &mut self, a_idx: uint, - f: |&mut Decoder<'a>| -> Result) -> Result { + f: |&mut Decoder| -> Result) -> Result { unimplemented!() } fn read_enum_struct_variant( &mut self, names: &[&str], - f: |&mut Decoder<'a>, uint| -> Result) -> Result { + f: |&mut Decoder, uint| -> Result) -> Result { unimplemented!() } fn read_enum_struct_variant_field( &mut self, f_name: &str, f_idx: uint, - f: |&mut Decoder<'a>| -> Result) -> Result { + f: |&mut Decoder| -> Result) -> Result { unimplemented!() } fn read_struct(&mut self, s_name: &str, len: uint, - f: |&mut Decoder<'a>| -> Result) + f: |&mut Decoder| -> Result) -> Result { f(self) } fn read_struct_field(&mut self, f_name: &str, f_idx: uint, - f: |&mut Decoder<'a>| -> Result) + f: |&mut Decoder| -> Result) -> Result { self.push(f_name); f(self) } fn read_tuple(&mut self, - f: |&mut Decoder<'a>, uint| -> Result) + f: |&mut Decoder, uint| -> Result) -> Result { unimplemented!() } fn read_tuple_arg(&mut self, a_idx: uint, - f: |&mut Decoder<'a>| -> Result) + f: |&mut Decoder| -> Result) -> Result { unimplemented!() } fn read_tuple_struct(&mut self, s_name: &str, - f: |&mut Decoder<'a>, uint| -> Result) + f: |&mut Decoder, uint| -> Result) -> Result { unimplemented!() } fn read_tuple_struct_arg(&mut self, a_idx: uint, - f: |&mut Decoder<'a>| -> Result) + f: |&mut Decoder| -> Result) -> Result { unimplemented!() } fn read_option(&mut self, - f: |&mut Decoder<'a>, bool| -> Result) + f: |&mut Decoder, bool| -> Result) -> Result { let option = match self.stack.last() { @@ -817,7 +817,7 @@ impl<'a> serialize::Decoder for Decoder<'a> { f(self, option) } fn read_seq(&mut self, - f: |&mut Decoder<'a>, uint| -> Result) + f: |&mut Decoder, uint| -> Result) -> Result { let it = try!(self.pop()); let list = it.val.unwrap_or(List(vec!())); @@ -832,22 +832,22 @@ impl<'a> serialize::Decoder for Decoder<'a> { f(self, vals.len()) } fn read_seq_elt(&mut self, idx: uint, - f: |&mut Decoder<'a>| -> Result) + f: |&mut Decoder| -> Result) -> Result { f(self) } fn read_map(&mut self, - f: |&mut Decoder<'a>, uint| -> Result) + f: |&mut Decoder, uint| -> Result) -> Result { unimplemented!() } fn read_map_elt_key(&mut self, idx: uint, - f: |&mut Decoder<'a>| -> Result) + f: |&mut Decoder| -> Result) -> Result { unimplemented!() } fn read_map_elt_val(&mut self, idx: uint, - f: |&mut Decoder<'a>| -> Result) + f: |&mut Decoder| -> Result) -> Result { unimplemented!() }