<commit_before>/*!
Functionality for declaring Objective-C classes.

Classes can be declared using the `ClassDecl` struct. Instance variables and
methods can then be added before the class is ultimately registered.

# Example

The following example demonstrates declaring a class named `MyNumber` that has
one ivar, a `u32` named `_number` and a `number` method that returns it:

```
# #[macro_use] extern crate objc;
# use objc::declare::ClassDecl;
# use objc::runtime::{Class, Object, Sel};
# fn main() {
let superclass = Class::get("NSObject").unwrap();
let mut decl = ClassDecl::new(superclass, "MyNumber").unwrap();

// Add an instance variable
decl.add_ivar::<u32>("_number");

// Add an ObjC method for getting the number
extern fn my_number_get(this: &Object, _cmd: Sel) -> u32 {
    unsafe { *this.get_ivar("_number") }
}
unsafe {
    decl.add_method(sel!(number),
        my_number_get as extern fn(&Object, Sel) -> u32);
}

decl.register();
# }
```
*/

use std::error::Error;
use std::ffi::CString;
use std::fmt;
use std::mem;

use {Encode, Encoding, Message};
use runtime::{Class, Imp, NO, Object, Sel, self};

/// An error returned from `MethodImplementation::imp_for` to indicate that a
/// selector and function accept unequal numbers of arguments.
#[derive(Clone, PartialEq, Debug)]
pub struct UnequalArgsError {
    sel_args: usize,
    fn_args: usize,
}

impl fmt::Display for UnequalArgsError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Selector accepts {} arguments, but function accepts {}",
            self.sel_args, self.fn_args)
    }
}

impl Error for UnequalArgsError {
    fn description(&self) -> &str {
        "Selector and function accept unequal numbers of arguments"
    }
}

/// Types that can be used as the implementation of an Objective-C method.
pub trait MethodImplementation {
    /// The callee type of the method.
    type Callee: Message;
    /// The return type of the method.
    type Ret: Encode;

    /// Returns the type encodings of Self's arguments.
    fn argument_encodings() -> Box<[Encoding]>;

    /// Returns self as an `Imp` of a method for the given selector.
    ///
    /// Returns an error if self and the selector do not accept the same number
    /// of arguments.
    fn imp_for(self, sel: Sel) -> Result<Imp, UnequalArgsError>;
}

macro_rules! count_idents {
    () => (0);
    ($a:ident) => (1);
    ($a:ident, $($b:ident),+) => (1 + count_idents!($($b),*));
}

macro_rules! method_decl_impl {
    (-$s:ident, $r:ident, $f:ty, $($t:ident),*) => (
        impl<$s, $r $(, $t)*> MethodImplementation for $f
                where $s: Message, $r: Encode $(, $t: Encode)* {
            type Callee = $s;
            type Ret = $r;

            fn argument_encodings() -> Box<[Encoding]> {
                Box::new([
                    <*mut Object>::encode(),
                    Sel::encode(),
                    $($t::encode()),*
                ])
            }

            fn imp_for(self, sel: Sel) -> Result<Imp, UnequalArgsError> {
                // Add 2 to the arguments for self and _cmd
                let fn_args = 2 + count_idents!($($t),*);
                let sel_args = 2 + sel.name().chars().filter(|&c| c == ':').count();
                if sel_args == fn_args {
                    unsafe { Ok(mem::transmute(self)) }
                } else {
                    Err(UnequalArgsError { sel_args: sel_args, fn_args: fn_args })
                }
            }
        }
    );
    ($($t:ident),*) => (
        method_decl_impl!(-T, R, extern fn(&T, Sel $(, $t)*) -> R, $($t),*);
        method_decl_impl!(-T, R, extern fn(&mut T, Sel $(, $t)*) -> R, $($t),*);
    );
}

method_decl_impl!();
method_decl_impl!(A);
method_decl_impl!(A, B);
method_decl_impl!(A, B, C);
method_decl_impl!(A, B, C, D);
method_decl_impl!(A, B, C, D, E);
method_decl_impl!(A, B, C, D, E, F);
method_decl_impl!(A, B, C, D, E, F, G);
method_decl_impl!(A, B, C, D, E, F, G, H);
method_decl_impl!(A, B, C, D, E, F, G, H, I);
method_decl_impl!(A, B, C, D, E, F, G, H, I, J);
method_decl_impl!(A, B, C, D, E, F, G, H, I, J, K);
method_decl_impl!(A, B, C, D, E, F, G, H, I, J, K, L);

fn method_type_encoding<F>() -> CString where F: MethodImplementation {
    let mut types = F::Ret::encode().as_str().to_owned();
    types.extend(F::argument_encodings().iter().map(|e| e.as_str()));
    CString::new(types).unwrap()
}

/// A type for declaring a new class and adding new methods and ivars to it
/// before registering it.
pub struct ClassDecl {
    cls: *mut Class,
}

impl ClassDecl {
    /// Constructs a `ClassDecl` with the given superclass and name.
    /// Returns `None` if the class couldn't be allocated.
    pub fn new(superclass: &Class, name: &str) -> Option<ClassDecl> {
        let name = CString::new(name).unwrap();
        let cls = unsafe {
            runtime::objc_allocateClassPair(superclass, name.as_ptr(), 0)
        };
        if cls.is_null() {
            None
        } else {
            Some(ClassDecl { cls: cls })
        }
    }

    /// Adds a method with the given name and implementation to self.
    /// Panics if the method wasn't sucessfully added
    /// or if the selector and function take different numbers of arguments.
    /// Unsafe because the caller must ensure that the types match those that
    /// are expected when the method is invoked from Objective-C.
    pub unsafe fn add_method<F>(&mut self, sel: Sel, func: F)
            where F: MethodImplementation<Callee=Object> {
        let types = method_type_encoding::<F>();
        let imp = match func.imp_for(sel) {
            Ok(imp) => imp,
            Err(err) => panic!("{}", err),
        };

        let success = runtime::class_addMethod(self.cls, sel, imp,
            types.as_ptr());
        assert!(success != NO, "Failed to add method {:?}", sel);
    }

    /// Adds a class method with the given name and implementation to self.
    /// Panics if the method wasn't sucessfully added
    /// or if the selector and function take different numbers of arguments.
    /// Unsafe because the caller must ensure that the types match those that
    /// are expected when the method is invoked from Objective-C.
    pub unsafe fn add_class_method<F>(&mut self, sel: Sel, func: F)
            where F: MethodImplementation<Callee=Class> {
        let types = method_type_encoding::<F>();
        let imp = match func.imp_for(sel) {
            Ok(imp) => imp,
            Err(err) => panic!("{}", err),
        };

        let cls_obj = self.cls as *const Object;
        let metaclass = runtime::object_getClass(cls_obj) as *mut Class;
        let success = runtime::class_addMethod(metaclass, sel, imp,
            types.as_ptr());
        assert!(success != NO, "Failed to add class method {:?}", sel);
    }

    /// Adds an ivar with type `T` and the provided name to self.
    /// Panics if the ivar wasn't successfully added.
    pub fn add_ivar<T>(&mut self, name: &str) where T: Encode {
        let c_name = CString::new(name).unwrap();
        let encoding = CString::new(T::encode().as_str()).unwrap();
        let size = mem::size_of::<T>();
        let align = mem::align_of::<T>() as u8;
        let success = unsafe {
            runtime::class_addIvar(self.cls, c_name.as_ptr(), size, align,
                encoding.as_ptr())
        };
        assert!(success != NO, "Failed to add ivar {}", name);
    }

    /// Registers self, consuming it and returning a reference to the
    /// newly registered `Class`.
    pub fn register(self) -> &'static Class {
        unsafe {
            let cls = self.cls;
            runtime::objc_registerClassPair(cls);
            // Forget self otherwise the class will be disposed in drop
            mem::forget(self);
            &*cls
        }
    }
}

impl Drop for ClassDecl {
    fn drop(&mut self) {
        unsafe {
            runtime::objc_disposeClassPair(self.cls);
        }
    }
}

#[cfg(test)]
mod tests {
    use runtime::{Object, Sel};
    use test_utils;
    use super::MethodImplementation;

    #[test]
    fn test_custom_class() {
        // Registering the custom class is in test_utils
        let obj = test_utils::custom_object();
        unsafe {
            let _: () = msg_send![obj, setFoo:13u32];
            let result: u32 = msg_send![obj, foo];
            assert!(result == 13);
        }
    }

    #[test]
    fn test_class_method() {
        let cls = test_utils::custom_class();
        unsafe {
            let result: u32 = msg_send![cls, classFoo];
            assert!(result == 7);
        }
    }

    #[test]
    fn test_mismatched_args() {
        extern fn wrong_num_args_method(_obj: &Object, _cmd: Sel, _a: i32) { }

        let sel = sel!(doSomethingWithFoo:bar:);
        let f: extern fn(&Object, Sel, i32) = wrong_num_args_method;
        let imp = f.imp_for(sel);
        assert!(imp.is_err());
    }
}
<commit_msg>Use EncodeArguments for method declarations.<commit_after>/*!
Functionality for declaring Objective-C classes.

Classes can be declared using the `ClassDecl` struct. Instance variables and
methods can then be added before the class is ultimately registered.

# Example

The following example demonstrates declaring a class named `MyNumber` that has
one ivar, a `u32` named `_number` and a `number` method that returns it:

```
# #[macro_use] extern crate objc;
# use objc::declare::ClassDecl;
# use objc::runtime::{Class, Object, Sel};
# fn main() {
let superclass = Class::get("NSObject").unwrap();
let mut decl = ClassDecl::new(superclass, "MyNumber").unwrap();

// Add an instance variable
decl.add_ivar::<u32>("_number");

// Add an ObjC method for getting the number
extern fn my_number_get(this: &Object, _cmd: Sel) -> u32 {
    unsafe { *this.get_ivar("_number") }
}
unsafe {
    decl.add_method(sel!(number),
        my_number_get as extern fn(&Object, Sel) -> u32);
}

decl.register();
# }
```
*/

use std::error::Error;
use std::ffi::CString;
use std::fmt;
use std::mem;

use {Encode, Message};
use runtime::{Class, Imp, NO, Object, Sel, self};
use verify::EncodeArguments;

/// An error returned from `MethodImplementation::imp_for` to indicate that a
/// selector and function accept unequal numbers of arguments.
#[derive(Clone, PartialEq, Debug)]
pub struct UnequalArgsError {
    sel_args: usize,
    fn_args: usize,
}

impl fmt::Display for UnequalArgsError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Selector accepts {} arguments, but function accepts {}",
            self.sel_args, self.fn_args)
    }
}

impl Error for UnequalArgsError {
    fn description(&self) -> &str {
        "Selector and function accept unequal numbers of arguments"
    }
}

/// Types that can be used as the implementation of an Objective-C method.
pub trait MethodImplementation {
    /// The callee type of the method.
    type Callee: Message;
    /// The return type of the method.
    type Ret: Encode;

    type Args: EncodeArguments;

    /// Returns self as an `Imp` of a method for the given selector.
    ///
    /// Returns an error if self and the selector do not accept the same number
    /// of arguments.
    fn imp_for(self, sel: Sel) -> Result<Imp, UnequalArgsError>;
}

macro_rules! count_idents {
    () => (0);
    ($a:ident) => (1);
    ($a:ident, $($b:ident),+) => (1 + count_idents!($($b),*));
}

macro_rules! method_decl_impl {
    (-$s:ident, $r:ident, $f:ty, $($t:ident),*) => (
        impl<$s, $r $(, $t)*> MethodImplementation for $f
                where $s: Message, $r: Encode $(, $t: Encode)* {
            type Callee = $s;
            type Ret = $r;
            type Args = ($($t,)*);

            fn imp_for(self, sel: Sel) -> Result<Imp, UnequalArgsError> {
                // Add 2 to the arguments for self and _cmd
                let fn_args = 2 + count_idents!($($t),*);
                let sel_args = 2 + sel.name().chars().filter(|&c| c == ':').count();
                if sel_args == fn_args {
                    unsafe { Ok(mem::transmute(self)) }
                } else {
                    Err(UnequalArgsError { sel_args: sel_args, fn_args: fn_args })
                }
            }
        }
    );
    ($($t:ident),*) => (
        method_decl_impl!(-T, R, extern fn(&T, Sel $(, $t)*) -> R, $($t),*);
        method_decl_impl!(-T, R, extern fn(&mut T, Sel $(, $t)*) -> R, $($t),*);
    );
}

method_decl_impl!();
method_decl_impl!(A);
method_decl_impl!(A, B);
method_decl_impl!(A, B, C);
method_decl_impl!(A, B, C, D);
method_decl_impl!(A, B, C, D, E);
method_decl_impl!(A, B, C, D, E, F);
method_decl_impl!(A, B, C, D, E, F, G);
method_decl_impl!(A, B, C, D, E, F, G, H);
method_decl_impl!(A, B, C, D, E, F, G, H, I);
method_decl_impl!(A, B, C, D, E, F, G, H, I, J);
method_decl_impl!(A, B, C, D, E, F, G, H, I, J, K);
method_decl_impl!(A, B, C, D, E, F, G, H, I, J, K, L);

fn method_type_encoding<F>() -> CString where F: MethodImplementation {
    let mut types = F::Ret::encode().as_str().to_owned();
    types.extend(F::Args::encodings().iter().map(|e| e.as_str()));
    CString::new(types).unwrap()
}

/// A type for declaring a new class and adding new methods and ivars to it
/// before registering it.
pub struct ClassDecl {
    cls: *mut Class,
}

impl ClassDecl {
    /// Constructs a `ClassDecl` with the given superclass and name.
    /// Returns `None` if the class couldn't be allocated.
    pub fn new(superclass: &Class, name: &str) -> Option<ClassDecl> {
        let name = CString::new(name).unwrap();
        let cls = unsafe {
            runtime::objc_allocateClassPair(superclass, name.as_ptr(), 0)
        };
        if cls.is_null() {
            None
        } else {
            Some(ClassDecl { cls: cls })
        }
    }

    /// Adds a method with the given name and implementation to self.
    /// Panics if the method wasn't sucessfully added
    /// or if the selector and function take different numbers of arguments.
    /// Unsafe because the caller must ensure that the types match those that
    /// are expected when the method is invoked from Objective-C.
    pub unsafe fn add_method<F>(&mut self, sel: Sel, func: F)
            where F: MethodImplementation<Callee=Object> {
        let types = method_type_encoding::<F>();
        let imp = match func.imp_for(sel) {
            Ok(imp) => imp,
            Err(err) => panic!("{}", err),
        };

        let success = runtime::class_addMethod(self.cls, sel, imp,
            types.as_ptr());
        assert!(success != NO, "Failed to add method {:?}", sel);
    }

    /// Adds a class method with the given name and implementation to self.
    /// Panics if the method wasn't sucessfully added
    /// or if the selector and function take different numbers of arguments.
    /// Unsafe because the caller must ensure that the types match those that
    /// are expected when the method is invoked from Objective-C.
    pub unsafe fn add_class_method<F>(&mut self, sel: Sel, func: F)
            where F: MethodImplementation<Callee=Class> {
        let types = method_type_encoding::<F>();
        let imp = match func.imp_for(sel) {
            Ok(imp) => imp,
            Err(err) => panic!("{}", err),
        };

        let cls_obj = self.cls as *const Object;
        let metaclass = runtime::object_getClass(cls_obj) as *mut Class;
        let success = runtime::class_addMethod(metaclass, sel, imp,
            types.as_ptr());
        assert!(success != NO, "Failed to add class method {:?}", sel);
    }

    /// Adds an ivar with type `T` and the provided name to self.
    /// Panics if the ivar wasn't successfully added.
    pub fn add_ivar<T>(&mut self, name: &str) where T: Encode {
        let c_name = CString::new(name).unwrap();
        let encoding = CString::new(T::encode().as_str()).unwrap();
        let size = mem::size_of::<T>();
        let align = mem::align_of::<T>() as u8;
        let success = unsafe {
            runtime::class_addIvar(self.cls, c_name.as_ptr(), size, align,
                encoding.as_ptr())
        };
        assert!(success != NO, "Failed to add ivar {}", name);
    }

    /// Registers self, consuming it and returning a reference to the
    /// newly registered `Class`.
    pub fn register(self) -> &'static Class {
        unsafe {
            let cls = self.cls;
            runtime::objc_registerClassPair(cls);
            // Forget self otherwise the class will be disposed in drop
            mem::forget(self);
            &*cls
        }
    }
}

impl Drop for ClassDecl {
    fn drop(&mut self) {
        unsafe {
            runtime::objc_disposeClassPair(self.cls);
        }
    }
}

#[cfg(test)]
mod tests {
    use runtime::{Object, Sel};
    use test_utils;
    use super::MethodImplementation;

    #[test]
    fn test_custom_class() {
        // Registering the custom class is in test_utils
        let obj = test_utils::custom_object();
        unsafe {
            let _: () = msg_send![obj, setFoo:13u32];
            let result: u32 = msg_send![obj, foo];
            assert!(result == 13);
        }
    }

    #[test]
    fn test_class_method() {
        let cls = test_utils::custom_class();
        unsafe {
            let result: u32 = msg_send![cls, classFoo];
            assert!(result == 7);
        }
    }

    #[test]
    fn test_mismatched_args() {
        extern fn wrong_num_args_method(_obj: &Object, _cmd: Sel, _a: i32) { }

        let sel = sel!(doSomethingWithFoo:bar:);
        let f: extern fn(&Object, Sel, i32) = wrong_num_args_method;
        let imp = f.imp_for(sel);
        assert!(imp.is_err());
    }
}
<|endoftext|>


<commit_before>use std::ascii::AsciiExt;
use std::collections::HashMap;

use redis;
use rustc_serialize;

#[derive(Debug, Clone, PartialEq)]
enum DecoderStatus {
    Unnamed,
    Normal,
    Reference,
}

#[derive(Debug)]
pub enum DecoderError {
    NotImplementedYet,
    ExpectedError(String, String),
    RedisError(redis::RedisError),
    ApplicationError(String),
}

impl From<redis::RedisError> for DecoderError {
    fn from(e: redis::RedisError) -> DecoderError {
        DecoderError::RedisError(e)
    }
}

type DecodeResult<T> = Result<T, DecoderError>;

pub struct Decoder {
    properties: HashMap<String, String>,
    stack: Vec<Option<String>>,
    status: DecoderStatus,
}

impl Decoder {
    pub fn new(properties: HashMap<String, String>) -> Decoder {
        Decoder {
            properties: properties,
            stack: vec![],
            status: DecoderStatus::Unnamed,
        }
    }
}

macro_rules! read_primitive {
    ($name:ident, $ty:ident) => {
        fn $name(&mut self) -> DecodeResult<$ty> {
            match self.stack.pop() {
                Some(opt_s) => match opt_s {
                    Some(s) => match s.parse() {
                        Ok(v) => Ok(v),
                        Err(_) => Err(DecoderError::ExpectedError("Number".to_string(), s)),
                    },
                    None => Err(DecoderError::ExpectedError("Number".to_string(), "None".to_string()))
                },
                None => Err(DecoderError::ExpectedError("Number".to_string(), "Not found".to_string()))
            }
        }
    }
}

impl rustc_serialize::Decoder for Decoder {
    type Error = DecoderError;

    fn read_nil(&mut self) -> DecodeResult<()> {
        Ok(())
    }

    fn read_usize(&mut self) -> DecodeResult<usize> {
        let v = match self.stack.pop() {
            Some(opt_s) => match opt_s {
                Some(s) => match s.parse() {
                    Ok(v) => v,
                    Err(_) => return Err(DecoderError::ExpectedError("Number".to_string(), s)),
                },
                None => return Err(DecoderError::ExpectedError("Number".to_string(), "None".to_string()))
            },
            None => return Err(DecoderError::ExpectedError("Number".to_string(), "Not found".to_string()))
        };
        self.status = DecoderStatus::Normal;
        Ok(v)
    }

    read_primitive! { read_u8, u8 }
    read_primitive! { read_u16, u16 }
    read_primitive! { read_u32, u32 }
    read_primitive! { read_u64, u64 }
    read_primitive! { read_isize, isize }
    read_primitive! { read_i8, i8 }
    read_primitive! { read_i16, i16 }
    read_primitive! { read_i32, i32 }
    read_primitive! { read_i64, i64 }

    fn read_f32(&mut self) -> DecodeResult<f32> {
        Err(DecoderError::NotImplementedYet)
    }

    fn read_f64(&mut self) -> DecodeResult<f64> {
        Err(DecoderError::NotImplementedYet)
    }

    fn read_bool(&mut self) -> DecodeResult<bool> {
        Err(DecoderError::NotImplementedYet)
    }

    fn read_char(&mut self) -> DecodeResult<char> {
        Err(DecoderError::NotImplementedYet)
    }

    fn read_str(&mut self) -> DecodeResult<String> {
        match self.stack.pop() {
            Some(opt_s) => match opt_s {
                Some(s) => Ok(s),
                None => Err(DecoderError::ExpectedError("String".to_string(), "None".to_string()))
            },
            None => Err(DecoderError::ExpectedError("String".to_string(), "Not found".to_string()))
        }
    }

    fn read_enum<T, F>(&mut self, _name: &str, f: F) -> DecodeResult<T> where
        F: FnOnce(&mut Decoder) -> DecodeResult<T>,
    {
        f(self)
    }

    fn read_enum_variant<T, F>(&mut self, _names: &[&str],
                               mut _f: F) -> DecodeResult<T>
        where F: FnMut(&mut Decoder, usize) -> DecodeResult<T>,
    {
        Err(DecoderError::NotImplementedYet)
    }

    fn read_enum_variant_arg<T, F>(&mut self, _idx: usize, f: F) -> DecodeResult<T> where
        F: FnOnce(&mut Decoder) -> DecodeResult<T>,
    {
        f(self)
    }

    fn read_enum_struct_variant<T, F>(&mut self, names: &[&str], f: F) -> DecodeResult<T> where
        F: FnMut(&mut Decoder, usize) -> DecodeResult<T>,
    {
        self.read_enum_variant(names, f)
    }

    fn read_enum_struct_variant_field<T, F>(&mut self,
                                         _name: &str,
                                         idx: usize,
                                         f: F)
                                         -> DecodeResult<T> where
        F: FnOnce(&mut Decoder) -> DecodeResult<T>,
    {
        self.read_enum_variant_arg(idx, f)
    }

    fn read_struct<T, F>(&mut self, _name: &str, _len: usize, f: F) -> DecodeResult<T> where
        F: FnOnce(&mut Decoder) -> DecodeResult<T>,
    {
        f(self)
    }

    fn read_struct_field<T, F>(&mut self,
                               name: &str,
                               _idx: usize,
                               f: F)
                               -> DecodeResult<T> where
        F: FnOnce(&mut Decoder) -> DecodeResult<T>,
    {
        if self.status != DecoderStatus::Reference {
            match self.properties.remove(name) {
                Some(v) => self.stack.push(Some(v)),
                None => {
                    match self.properties.remove(&*format!("{}_id", name).to_ascii_lowercase()) {
                        Some(id) => {
                            self.status = DecoderStatus::Reference;
                            self.stack.push(Some(id));
                        },
                        None => {
                            self.stack.push(None);
                        }
                    }
                }
            }
        }
        f(self)
    }

    fn read_tuple<T, F>(&mut self, _tuple_len: usize, _f: F) -> DecodeResult<T> where
        F: FnOnce(&mut Decoder) -> DecodeResult<T>,
    {
        Err(DecoderError::NotImplementedYet)
    }

    fn read_tuple_arg<T, F>(&mut self, idx: usize, f: F) -> DecodeResult<T> where
        F: FnOnce(&mut Decoder) -> DecodeResult<T>,
    {
        self.read_seq_elt(idx, f)
    }

    fn read_tuple_struct<T, F>(&mut self,
                               _name: &str,
                               len: usize,
                               f: F)
                               -> DecodeResult<T> where
        F: FnOnce(&mut Decoder) -> DecodeResult<T>,
    {
        self.read_tuple(len, f)
    }

    fn read_tuple_struct_arg<T, F>(&mut self,
                                   idx: usize,
                                   f: F)
                                   -> DecodeResult<T> where
        F: FnOnce(&mut Decoder) -> DecodeResult<T>,
    {
        self.read_tuple_arg(idx, f)
    }

    fn read_option<T, F>(&mut self, mut f: F) -> DecodeResult<T> where
        F: FnMut(&mut Decoder, bool) -> DecodeResult<T>,
    {
        let opt = match self.stack.last() {
            Some(ref el) => el.is_some(),
            None => return Err(DecoderError::ExpectedError("Option".to_string(), "Not found".to_string())),
        };
        f(self, opt)
    }

    fn read_seq<T, F>(&mut self, _f: F) -> DecodeResult<T> where
        F: FnOnce(&mut Decoder, usize) -> DecodeResult<T>,
    {
        Err(DecoderError::NotImplementedYet)
    }

    fn read_seq_elt<T, F>(&mut self, _idx: usize, f: F) -> DecodeResult<T> where
        F: FnOnce(&mut Decoder) -> DecodeResult<T>,
    {
        f(self)
    }

    fn read_map<T, F>(&mut self, _f: F) -> DecodeResult<T> where
        F: FnOnce(&mut Decoder, usize) -> DecodeResult<T>,
    {
        Err(DecoderError::NotImplementedYet)
    }

    fn read_map_elt_key<T, F>(&mut self, _idx: usize, f: F) -> DecodeResult<T> where
       F: FnOnce(&mut Decoder) -> DecodeResult<T>,
    {
        f(self)
    }

    fn read_map_elt_val<T, F>(&mut self, _idx: usize, f: F) -> DecodeResult<T> where
       F: FnOnce(&mut Decoder) -> DecodeResult<T>,
    {
        f(self)
    }

    fn error(&mut self, err: &str) -> DecoderError {
        DecoderError::ApplicationError(err.to_string())
    }
}
<commit_msg>Decode floats and bool<commit_after>use std::ascii::AsciiExt;
use std::collections::HashMap;

use redis;
use rustc_serialize;

#[derive(Debug, Clone, PartialEq)]
enum DecoderStatus {
    Unnamed,
    Normal,
    Reference,
}

#[derive(Debug)]
pub enum DecoderError {
    NotImplementedYet,
    ExpectedError(String, String),
    RedisError(redis::RedisError),
    ApplicationError(String),
}

impl From<redis::RedisError> for DecoderError {
    fn from(e: redis::RedisError) -> DecoderError {
        DecoderError::RedisError(e)
    }
}

type DecodeResult<T> = Result<T, DecoderError>;

pub struct Decoder {
    properties: HashMap<String, String>,
    stack: Vec<Option<String>>,
    status: DecoderStatus,
}

impl Decoder {
    pub fn new(properties: HashMap<String, String>) -> Decoder {
        Decoder {
            properties: properties,
            stack: vec![],
            status: DecoderStatus::Unnamed,
        }
    }
}

macro_rules! read_primitive {
    ($name:ident, $ty:ident) => {
        fn $name(&mut self) -> DecodeResult<$ty> {
            match self.stack.pop() {
                Some(opt_s) => match opt_s {
                    Some(s) => match s.parse() {
                        Ok(v) => Ok(v),
                        Err(_) => Err(DecoderError::ExpectedError("Number".to_string(), s)),
                    },
                    None => Err(DecoderError::ExpectedError("Number".to_string(), "None".to_string()))
                },
                None => Err(DecoderError::ExpectedError("Number".to_string(), "Not found".to_string()))
            }
        }
    }
}

impl rustc_serialize::Decoder for Decoder {
    type Error = DecoderError;

    fn read_nil(&mut self) -> DecodeResult<()> {
        Ok(())
    }

    fn read_usize(&mut self) -> DecodeResult<usize> {
        let v = match self.stack.pop() {
            Some(opt_s) => match opt_s {
                Some(s) => match s.parse() {
                    Ok(v) => v,
                    Err(_) => return Err(DecoderError::ExpectedError("Number".to_string(), s)),
                },
                None => return Err(DecoderError::ExpectedError("Number".to_string(), "None".to_string()))
            },
            None => return Err(DecoderError::ExpectedError("Number".to_string(), "Not found".to_string()))
        };
        self.status = DecoderStatus::Normal;
        Ok(v)
    }

    read_primitive! { read_u8, u8 }
    read_primitive! { read_u16, u16 }
    read_primitive! { read_u32, u32 }
    read_primitive! { read_u64, u64 }
    read_primitive! { read_isize, isize }
    read_primitive! { read_i8, i8 }
    read_primitive! { read_i16, i16 }
    read_primitive! { read_i32, i32 }
    read_primitive! { read_i64, i64 }
    read_primitive! { read_f32, f32 }
    read_primitive! { read_f64, f64 }

    fn read_bool(&mut self) -> DecodeResult<bool> {
        match self.stack.pop() {
            Some(opt_s) => match opt_s {
                Some(s) => match &*s {
                    "0" => Ok(false),
                    "1" => Ok(true),
                    _ => Err(DecoderError::ExpectedError("Boolean".to_string(), s)),
                },
                None => Err(DecoderError::ExpectedError("Boolean".to_string(), "None".to_string()))
            },
            None => Err(DecoderError::ExpectedError("Boolean".to_string(), "Not found".to_string()))
        }
    }

    fn read_char(&mut self) -> DecodeResult<char> {
        Err(DecoderError::NotImplementedYet)
    }

    fn read_str(&mut self) -> DecodeResult<String> {
        match self.stack.pop() {
            Some(opt_s) => match opt_s {
                Some(s) => Ok(s),
                None => Err(DecoderError::ExpectedError("String".to_string(), "None".to_string()))
            },
            None => Err(DecoderError::ExpectedError("String".to_string(), "Not found".to_string()))
        }
    }

    fn read_enum<T, F>(&mut self, _name: &str, f: F) -> DecodeResult<T> where
        F: FnOnce(&mut Decoder) -> DecodeResult<T>,
    {
        f(self)
    }

    fn read_enum_variant<T, F>(&mut self, _names: &[&str],
                               mut _f: F) -> DecodeResult<T>
        where F: FnMut(&mut Decoder, usize) -> DecodeResult<T>,
    {
        Err(DecoderError::NotImplementedYet)
    }

    fn read_enum_variant_arg<T, F>(&mut self, _idx: usize, f: F) -> DecodeResult<T> where
        F: FnOnce(&mut Decoder) -> DecodeResult<T>,
    {
        f(self)
    }

    fn read_enum_struct_variant<T, F>(&mut self, names: &[&str], f: F) -> DecodeResult<T> where
        F: FnMut(&mut Decoder, usize) -> DecodeResult<T>,
    {
        self.read_enum_variant(names, f)
    }

    fn read_enum_struct_variant_field<T, F>(&mut self,
                                         _name: &str,
                                         idx: usize,
                                         f: F)
                                         -> DecodeResult<T> where
        F: FnOnce(&mut Decoder) -> DecodeResult<T>,
    {
        self.read_enum_variant_arg(idx, f)
    }

    fn read_struct<T, F>(&mut self, _name: &str, _len: usize, f: F) -> DecodeResult<T> where
        F: FnOnce(&mut Decoder) -> DecodeResult<T>,
    {
        f(self)
    }

    fn read_struct_field<T, F>(&mut self,
                               name: &str,
                               _idx: usize,
                               f: F)
                               -> DecodeResult<T> where
        F: FnOnce(&mut Decoder) -> DecodeResult<T>,
    {
        if self.status != DecoderStatus::Reference {
            match self.properties.remove(name) {
                Some(v) => self.stack.push(Some(v)),
                None => {
                    match self.properties.remove(&*format!("{}_id", name).to_ascii_lowercase()) {
                        Some(id) => {
                            self.status = DecoderStatus::Reference;
                            self.stack.push(Some(id));
                        },
                        None => {
                            self.stack.push(None);
                        }
                    }
                }
            }
        }
        f(self)
    }

    fn read_tuple<T, F>(&mut self, _tuple_len: usize, _f: F) -> DecodeResult<T> where
        F: FnOnce(&mut Decoder) -> DecodeResult<T>,
    {
        Err(DecoderError::NotImplementedYet)
    }

    fn read_tuple_arg<T, F>(&mut self, idx: usize, f: F) -> DecodeResult<T> where
        F: FnOnce(&mut Decoder) -> DecodeResult<T>,
    {
        self.read_seq_elt(idx, f)
    }

    fn read_tuple_struct<T, F>(&mut self,
                               _name: &str,
                               len: usize,
                               f: F)
                               -> DecodeResult<T> where
        F: FnOnce(&mut Decoder) -> DecodeResult<T>,
    {
        self.read_tuple(len, f)
    }

    fn read_tuple_struct_arg<T, F>(&mut self,
                                   idx: usize,
                                   f: F)
                                   -> DecodeResult<T> where
        F: FnOnce(&mut Decoder) -> DecodeResult<T>,
    {
        self.read_tuple_arg(idx, f)
    }

    fn read_option<T, F>(&mut self, mut f: F) -> DecodeResult<T> where
        F: FnMut(&mut Decoder, bool) -> DecodeResult<T>,
    {
        let opt = match self.stack.last() {
            Some(ref el) => el.is_some(),
            None => return Err(DecoderError::ExpectedError("Option".to_string(), "Not found".to_string())),
        };
        f(self, opt)
    }

    fn read_seq<T, F>(&mut self, _f: F) -> DecodeResult<T> where
        F: FnOnce(&mut Decoder, usize) -> DecodeResult<T>,
    {
        Err(DecoderError::NotImplementedYet)
    }

    fn read_seq_elt<T, F>(&mut self, _idx: usize, f: F) -> DecodeResult<T> where
        F: FnOnce(&mut Decoder) -> DecodeResult<T>,
    {
        f(self)
    }

    fn read_map<T, F>(&mut self, _f: F) -> DecodeResult<T> where
        F: FnOnce(&mut Decoder, usize) -> DecodeResult<T>,
    {
        Err(DecoderError::NotImplementedYet)
    }

    fn read_map_elt_key<T, F>(&mut self, _idx: usize, f: F) -> DecodeResult<T> where
       F: FnOnce(&mut Decoder) -> DecodeResult<T>,
    {
        f(self)
    }

    fn read_map_elt_val<T, F>(&mut self, _idx: usize, f: F) -> DecodeResult<T> where
       F: FnOnce(&mut Decoder) -> DecodeResult<T>,
    {
        f(self)
    }

    fn error(&mut self, err: &str) -> DecoderError {
        DecoderError::ApplicationError(err.to_string())
    }
}
<|endoftext|>


<commit_before>use types::{OscPacket, OscType, Result, OscMessage, OscMidiMessage, OscColor, OscBundle};
use errors::OscError;
use encoder;

use std::{io, char};
use std::io::{Read, BufRead};

use byteorder::{BigEndian, ReadBytesExt};

/// Common MTU size for ethernet
pub const MTU: usize = 1536;

/// Takes an byte slice as argument and returns an
/// OSC packet on success or an `OscError` if the slice
/// does not contain a valid OSC message.
pub fn decode(msg: &[u8]) -> Result<OscPacket> {
    if msg.len() == 0 {
        return Err(OscError::BadPacket("Empty packet."));
    }

    match msg[0] as char {
        '/' => decode_message(msg),
        '#' => decode_bundle(msg),
        _ => Err(OscError::BadPacket("Unknown message format.")),
    }
}

fn decode_message(msg: &[u8]) -> Result<OscPacket> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(msg);

    let addr: String = try!(read_osc_string(&mut cursor));
    let type_tags: String = try!(read_osc_string(&mut cursor));

    if type_tags.len() > 1 {
        let args: Vec<OscType> = try!(read_osc_args(&mut cursor, type_tags));

        Ok(OscPacket::Message(OscMessage {
            addr: addr,
            args: Some(args),
        }))
    } else {
        Ok(OscPacket::Message(OscMessage {
            addr: addr,
            args: None,
        }))
    }
}

fn decode_bundle(msg: &[u8]) -> Result<OscPacket> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(msg);

    let bundle_tag = try!(read_osc_string(&mut cursor));
    if bundle_tag != "#bundle" {
        return Err(OscError::BadBundle(format!("Wrong bundle specifier: {}", bundle_tag)));
    }

    let time_tag = try!(read_time_tag(&mut cursor));

    let mut bundle: Vec<OscPacket> = Vec::new();

    let mut elem_size = try!(read_bundle_element_size(&mut cursor));

    while msg.len() >= (cursor.position() as usize) + elem_size {
        let packet = try!(read_bundle_element(&mut cursor, elem_size));
        bundle.push(packet);

        if msg.len() == cursor.position() as usize {
            break;
        }

        elem_size = try!(read_bundle_element_size(&mut cursor));
    }

    Ok(OscPacket::Bundle(OscBundle {
        timetag: time_tag,
        content: bundle,
    }))
}

fn read_bundle_element_size(cursor: &mut io::Cursor<&[u8]>) -> Result<usize> {
    cursor.read_u32::<BigEndian>()
          .map(|size| size as usize)
          .map_err(OscError::ByteOrderError)
}

fn read_bundle_element(cursor: &mut io::Cursor<&[u8]>, elem_size: usize) -> Result<OscPacket> {
    let mut buf: Vec<u8> = Vec::with_capacity(elem_size);

    let mut handle = cursor.take(elem_size as u64);

    let cnt = try!(handle.read_to_end(&mut buf)
                         .map_err(OscError::ReadError));

    if cnt == elem_size {
        decode(&mut buf)
    } else {
        Err(OscError::BadBundle("Bundle shorter than expected!".to_string()))
    }
}

fn read_osc_string(cursor: &mut io::Cursor<&[u8]>) -> Result<String> {
    let mut str_buf: Vec<u8> = Vec::new();
    try!(cursor.read_until(0, &mut str_buf)
               .map_err(OscError::ReadError)); // ignore returned byte count
    pad_cursor(cursor);
    // convert to String and remove nul bytes
    String::from_utf8(str_buf)
        .map_err(|e| OscError::StringError(e))
        .map(|s| {
            s.trim_matches(0u8 as char)
             .to_string()
        })
}

fn read_osc_args(cursor: &mut io::Cursor<&[u8]>, raw_type_tags: String) -> Result<Vec<OscType>> {
    let type_tags: Vec<char> = raw_type_tags.chars()
                                            .skip(1)
                                            .collect();

    let mut args: Vec<OscType> = Vec::with_capacity(type_tags.len());
    for tag in type_tags {
        let arg: OscType = try!(read_osc_arg(cursor, tag));
        args.push(arg);
    }
    Ok(args)
}

fn read_osc_arg(cursor: &mut io::Cursor<&[u8]>, tag: char) -> Result<OscType> {
    match tag {
        'f' => {
            cursor.read_f32::<BigEndian>()
                  .map(OscType::Float)
                  .map_err(OscError::ByteOrderError)
        }
        'd' => {
            cursor.read_f64::<BigEndian>()
                  .map(OscType::Double)
                  .map_err(OscError::ByteOrderError)
        }
        'i' => {
            cursor.read_i32::<BigEndian>()
                  .map(OscType::Int)
                  .map_err(OscError::ByteOrderError)
        }
        'h' => {
            cursor.read_i64::<BigEndian>()
                  .map(OscType::Long)
                  .map_err(OscError::ByteOrderError)
        }
        's' => read_osc_string(cursor).map(|s| OscType::String(s)),
        't' => read_time_tag(cursor),
        'b' => read_blob(cursor),
        'r' => read_osc_color(cursor),
        'T' => Ok(OscType::Bool(true)),
        'F' => Ok(OscType::Bool(false)),
        'N' => Ok(OscType::Nil),
        'I' => Ok(OscType::Inf),
        'c' => read_char(cursor),
        'm' => read_midi_message(cursor),
        _ => Err(OscError::BadArg(format!("Type tag \"{}\" is not implemented!", tag))),
    }
}

fn read_char(cursor: &mut io::Cursor<&[u8]>) -> Result<OscType> {
    let opt_char = try!(cursor.read_u32::<BigEndian>()
                              .map(char::from_u32)
                              .map_err(OscError::ByteOrderError));
    match opt_char {
        Some(c) => Ok(OscType::Char(c)),
        None => Err(OscError::BadArg("Argument is not a char!".to_string())),
    }
}

fn read_blob(cursor: &mut io::Cursor<&[u8]>) -> Result<OscType> {
    let size: usize = try!(cursor.read_u32::<BigEndian>()
                                 .map_err(OscError::ByteOrderError)) as usize;
    let mut byte_buf: Vec<u8> = Vec::with_capacity(size);

    try!(cursor.take(size as u64)
               .read_to_end(&mut byte_buf)
               .map_err(OscError::ReadError));

    pad_cursor(cursor);

    Ok(OscType::Blob(byte_buf))
}

fn read_time_tag(cursor: &mut io::Cursor<&[u8]>) -> Result<OscType> {
    let date = try!(cursor.read_u32::<BigEndian>()
                          .map_err(OscError::ByteOrderError));
    let frac = try!(cursor.read_u32::<BigEndian>()
                          .map_err(OscError::ByteOrderError));

    Ok(OscType::Time(date, frac))
}

fn read_midi_message(cursor: &mut io::Cursor<&[u8]>) -> Result<OscType> {
    let mut buf: Vec<u8> = Vec::with_capacity(4);
    try!(cursor.take(4).read_to_end(&mut buf).map_err(OscError::ReadError));

    Ok(OscType::Midi(OscMidiMessage {
        port: buf[0],
        status: buf[1],
        data1: buf[2],
        data2: buf[3],
    }))

}

fn read_osc_color(cursor: &mut io::Cursor<&[u8]>) -> Result<OscType> {
    let mut buf: Vec<u8> = Vec::with_capacity(4);
    try!(cursor.take(4).read_to_end(&mut buf).map_err(OscError::ReadError));

    Ok(OscType::Color(OscColor {
        red: buf[0],
        green: buf[1],
        blue: buf[2],
        alpha: buf[3],
    }))
}

fn pad_cursor(cursor: &mut io::Cursor<&[u8]>) {
    let pos = cursor.position();
    cursor.set_position(encoder::pad(pos));
}
<commit_msg>Replace with non-mutable borrow<commit_after>use types::{OscPacket, OscType, Result, OscMessage, OscMidiMessage, OscColor, OscBundle};
use errors::OscError;
use encoder;

use std::{io, char};
use std::io::{Read, BufRead};

use byteorder::{BigEndian, ReadBytesExt};

/// Common MTU size for ethernet
pub const MTU: usize = 1536;

/// Takes an byte slice as argument and returns an
/// OSC packet on success or an `OscError` if the slice
/// does not contain a valid OSC message.
pub fn decode(msg: &[u8]) -> Result<OscPacket> {
    if msg.len() == 0 {
        return Err(OscError::BadPacket("Empty packet."));
    }

    match msg[0] as char {
        '/' => decode_message(msg),
        '#' => decode_bundle(msg),
        _ => Err(OscError::BadPacket("Unknown message format.")),
    }
}

fn decode_message(msg: &[u8]) -> Result<OscPacket> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(msg);

    let addr: String = try!(read_osc_string(&mut cursor));
    let type_tags: String = try!(read_osc_string(&mut cursor));

    if type_tags.len() > 1 {
        let args: Vec<OscType> = try!(read_osc_args(&mut cursor, type_tags));

        Ok(OscPacket::Message(OscMessage {
            addr: addr,
            args: Some(args),
        }))
    } else {
        Ok(OscPacket::Message(OscMessage {
            addr: addr,
            args: None,
        }))
    }
}

fn decode_bundle(msg: &[u8]) -> Result<OscPacket> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(msg);

    let bundle_tag = try!(read_osc_string(&mut cursor));
    if bundle_tag != "#bundle" {
        return Err(OscError::BadBundle(format!("Wrong bundle specifier: {}", bundle_tag)));
    }

    let time_tag = try!(read_time_tag(&mut cursor));

    let mut bundle: Vec<OscPacket> = Vec::new();

    let mut elem_size = try!(read_bundle_element_size(&mut cursor));

    while msg.len() >= (cursor.position() as usize) + elem_size {
        let packet = try!(read_bundle_element(&mut cursor, elem_size));
        bundle.push(packet);

        if msg.len() == cursor.position() as usize {
            break;
        }

        elem_size = try!(read_bundle_element_size(&mut cursor));
    }

    Ok(OscPacket::Bundle(OscBundle {
        timetag: time_tag,
        content: bundle,
    }))
}

fn read_bundle_element_size(cursor: &mut io::Cursor<&[u8]>) -> Result<usize> {
    cursor.read_u32::<BigEndian>()
          .map(|size| size as usize)
          .map_err(OscError::ByteOrderError)
}

fn read_bundle_element(cursor: &mut io::Cursor<&[u8]>, elem_size: usize) -> Result<OscPacket> {
    let mut buf: Vec<u8> = Vec::with_capacity(elem_size);

    let mut handle = cursor.take(elem_size as u64);

    let cnt = try!(handle.read_to_end(&mut buf)
                         .map_err(OscError::ReadError));

    if cnt == elem_size {
        decode(&buf)
    } else {
        Err(OscError::BadBundle("Bundle shorter than expected!".to_string()))
    }
}

fn read_osc_string(cursor: &mut io::Cursor<&[u8]>) -> Result<String> {
    let mut str_buf: Vec<u8> = Vec::new();
    try!(cursor.read_until(0, &mut str_buf)
               .map_err(OscError::ReadError)); // ignore returned byte count
    pad_cursor(cursor);
    // convert to String and remove nul bytes
    String::from_utf8(str_buf)
        .map_err(|e| OscError::StringError(e))
        .map(|s| {
            s.trim_matches(0u8 as char)
             .to_string()
        })
}

fn read_osc_args(cursor: &mut io::Cursor<&[u8]>, raw_type_tags: String) -> Result<Vec<OscType>> {
    let type_tags: Vec<char> = raw_type_tags.chars()
                                            .skip(1)
                                            .collect();

    let mut args: Vec<OscType> = Vec::with_capacity(type_tags.len());
    for tag in type_tags {
        let arg: OscType = try!(read_osc_arg(cursor, tag));
        args.push(arg);
    }
    Ok(args)
}

fn read_osc_arg(cursor: &mut io::Cursor<&[u8]>, tag: char) -> Result<OscType> {
    match tag {
        'f' => {
            cursor.read_f32::<BigEndian>()
                  .map(OscType::Float)
                  .map_err(OscError::ByteOrderError)
        }
        'd' => {
            cursor.read_f64::<BigEndian>()
                  .map(OscType::Double)
                  .map_err(OscError::ByteOrderError)
        }
        'i' => {
            cursor.read_i32::<BigEndian>()
                  .map(OscType::Int)
                  .map_err(OscError::ByteOrderError)
        }
        'h' => {
            cursor.read_i64::<BigEndian>()
                  .map(OscType::Long)
                  .map_err(OscError::ByteOrderError)
        }
        's' => read_osc_string(cursor).map(|s| OscType::String(s)),
        't' => read_time_tag(cursor),
        'b' => read_blob(cursor),
        'r' => read_osc_color(cursor),
        'T' => Ok(OscType::Bool(true)),
        'F' => Ok(OscType::Bool(false)),
        'N' => Ok(OscType::Nil),
        'I' => Ok(OscType::Inf),
        'c' => read_char(cursor),
        'm' => read_midi_message(cursor),
        _ => Err(OscError::BadArg(format!("Type tag \"{}\" is not implemented!", tag))),
    }
}

fn read_char(cursor: &mut io::Cursor<&[u8]>) -> Result<OscType> {
    let opt_char = try!(cursor.read_u32::<BigEndian>()
                              .map(char::from_u32)
                              .map_err(OscError::ByteOrderError));
    match opt_char {
        Some(c) => Ok(OscType::Char(c)),
        None => Err(OscError::BadArg("Argument is not a char!".to_string())),
    }
}

fn read_blob(cursor: &mut io::Cursor<&[u8]>) -> Result<OscType> {
    let size: usize = try!(cursor.read_u32::<BigEndian>()
                                 .map_err(OscError::ByteOrderError)) as usize;
    let mut byte_buf: Vec<u8> = Vec::with_capacity(size);

    try!(cursor.take(size as u64)
               .read_to_end(&mut byte_buf)
               .map_err(OscError::ReadError));

    pad_cursor(cursor);

    Ok(OscType::Blob(byte_buf))
}

fn read_time_tag(cursor: &mut io::Cursor<&[u8]>) -> Result<OscType> {
    let date = try!(cursor.read_u32::<BigEndian>()
                          .map_err(OscError::ByteOrderError));
    let frac = try!(cursor.read_u32::<BigEndian>()
                          .map_err(OscError::ByteOrderError));

    Ok(OscType::Time(date, frac))
}

fn read_midi_message(cursor: &mut io::Cursor<&[u8]>) -> Result<OscType> {
    let mut buf: Vec<u8> = Vec::with_capacity(4);
    try!(cursor.take(4).read_to_end(&mut buf).map_err(OscError::ReadError));

    Ok(OscType::Midi(OscMidiMessage {
        port: buf[0],
        status: buf[1],
        data1: buf[2],
        data2: buf[3],
    }))

}

fn read_osc_color(cursor: &mut io::Cursor<&[u8]>) -> Result<OscType> {
    let mut buf: Vec<u8> = Vec::with_capacity(4);
    try!(cursor.take(4).read_to_end(&mut buf).map_err(OscError::ReadError));

    Ok(OscType::Color(OscColor {
        red: buf[0],
        green: buf[1],
        blue: buf[2],
        alpha: buf[3],
    }))
}

fn pad_cursor(cursor: &mut io::Cursor<&[u8]>) {
    let pos = cursor.position();
    cursor.set_position(encoder::pad(pos));
}
<|endoftext|>


<commit_before>// Copyright 2015 The tiny-http Contributors
// Copyright 2015 The rust-chunked-transfer Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::io::Result as IoResult;
use std::io::Read;
use std::io::Error as IoError;
use std::io::ErrorKind;
use std::fmt;
use std::error::Error;

/// Reads HTTP chunks and sends back real data.
///
/// # Example
///
/// ```
/// use chunked_transfer::Decoder;
/// use std::io::Read;
///
/// let encoded = b"3\r\nhel\r\nb\r\nlo world!!!\r\n0\r\n\r\n";
/// let mut decoded = String::new();
///
/// let mut decoder = Decoder::new(encoded as &[u8]);
/// decoder.read_to_string(&mut decoded);
///
/// assert_eq!(decoded, "hello world!!!");
/// ```
pub struct Decoder<R> {
    // where the chunks come from
    source: R,

    // remaining size of the chunk being read
    // none if we are not in a chunk
    remaining_chunks_size: Option<usize>,
}

impl<R> Decoder<R> where R: Read {
    pub fn new(source: R) -> Decoder<R> {
        Decoder {
            source: source,
            remaining_chunks_size: None,
        }
    }

    fn read_chunk_size(&mut self) -> IoResult<usize> {
        let mut chunk_size = Vec::new();

        loop {
            let byte = match self.source.by_ref().bytes().next() {
                Some(b) => try!(b),
                None => return Err(IoError::new(ErrorKind::InvalidInput, DecoderError)),
            };

            if byte == b'\r' {
                break;
            }

            chunk_size.push(byte);
        }

        match self.source.by_ref().bytes().next() {
            Some(Ok(b'\n')) => (),
            _ => return Err(IoError::new(ErrorKind::InvalidInput, DecoderError)),
        }

        let chunk_size = match String::from_utf8(chunk_size) {
            Ok(c) => c,
            Err(_) => return Err(IoError::new(ErrorKind::InvalidInput, DecoderError))
        };

        let chunk_size = match usize::from_str_radix(&chunk_size, 16) {
            Ok(c) => c,
            Err(_) => return Err(IoError::new(ErrorKind::InvalidInput, DecoderError))
        };

        Ok(chunk_size)
    }
}

impl<R> Read for Decoder<R> where R: Read {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
        let remaining_chunks_size = match self.remaining_chunks_size {
            Some(c) => c,
            None => {
                // first possibility: we are not in a chunk, so we'll attempt to determine
                // the chunks size
                let chunk_size = try!(self.read_chunk_size());

                // if the chunk size is 0, we are at EOF
                if chunk_size == 0 {
                    match self.source.by_ref().bytes().next() {
                        Some(Ok(b'\r')) => (),
                        _ => return Err(IoError::new(ErrorKind::InvalidInput, DecoderError)),
                    }

                    match self.source.by_ref().bytes().next() {
                        Some(Ok(b'\n')) => (),
                        _ => return Err(IoError::new(ErrorKind::InvalidInput, DecoderError)),
                    }

                    return Ok(0);
                }

                // now that we now the current chunk size, calling ourselves recursively
                self.remaining_chunks_size = Some(chunk_size);
                return self.read(buf);
            }
        };

        // second possibility: we continue reading from a chunk
        if buf.len() < remaining_chunks_size {
            let read = try!(self.source.read(buf));
            self.remaining_chunks_size = Some(remaining_chunks_size - read);
            return Ok(read);
        }

        // third possibility: the read request goes further than the current chunk
        // we simply read until the end of the chunk and return
        assert!(buf.len() >= remaining_chunks_size);

        let buf = &mut buf[.. remaining_chunks_size];
        let read = try!(self.source.read(buf));

        self.remaining_chunks_size = if read == remaining_chunks_size {
            match self.source.by_ref().bytes().next() {
                Some(Ok(b'\r')) => (),
                _ => return Err(IoError::new(ErrorKind::InvalidInput, DecoderError)),
            }

            match self.source.by_ref().bytes().next() {
                Some(Ok(b'\n')) => (),
                _ => return Err(IoError::new(ErrorKind::InvalidInput, DecoderError)),
            }

            None
        } else {
            Some(remaining_chunks_size - read)
        };

        return Ok(read);
    }
}

#[derive(Debug, Copy, Clone)]
struct DecoderError;

impl fmt::Display for DecoderError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "Error while decoding chunks")
    }
}

impl Error for DecoderError {
    fn description(&self) -> &str {
        "Error while decoding chunks"
    }
}

#[cfg(test)]
mod test {
    use super::Decoder;
    use std::io;
    use std::io::Read;

    #[test]
    fn test_valid_chunk_decode() {
        let source = io::Cursor::new("3\r\nhel\r\nb\r\nlo world!!!\r\n0\r\n\r\n".to_string().into_bytes());
        let mut decoded = Decoder::new(source);

        let mut string = String::new();
        decoded.read_to_string(&mut string).unwrap();

        assert_eq!(string, "hello world!!!");
    }

    #[test]
    fn test_decode_zero_length() {
        let mut decoder = Decoder::new(b"0\r\n\r\n" as &[u8]);

        let mut decoded = String::new();
        decoder.read_to_string(&mut decoded).unwrap();

        assert_eq!(decoded, "");
    }

    #[test]
    fn test_decode_invalid_chunk_length() {
        let mut decoder = Decoder::new(b"m\r\n\r\n" as &[u8]);

        let mut decoded = String::new();
        assert!(decoder.read_to_string(&mut decoded).is_err());
    }

    #[test]
    fn invalid_input1() {
        let source = io::Cursor::new("2\r\nhel\r\nb\r\nlo world!!!\r\n0\r\n".to_string().into_bytes());
        let mut decoded = Decoder::new(source);

        let mut string = String::new();
        decoded.read_to_string(&mut string).is_err();
    }

    #[test]
    fn invalid_input2() {
        let source = io::Cursor::new("3\rhel\r\nb\r\nlo world!!!\r\n0\r\n".to_string().into_bytes());
        let mut decoded = Decoder::new(source);

        let mut string = String::new();
        decoded.read_to_string(&mut string).is_err();
    }
}
<commit_msg>Combine common logic<commit_after>// Copyright 2015 The tiny-http Contributors
// Copyright 2015 The rust-chunked-transfer Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::io::Result as IoResult;
use std::io::Read;
use std::io::Error as IoError;
use std::io::ErrorKind;
use std::fmt;
use std::error::Error;

/// Reads HTTP chunks and sends back real data.
///
/// # Example
///
/// ```
/// use chunked_transfer::Decoder;
/// use std::io::Read;
///
/// let encoded = b"3\r\nhel\r\nb\r\nlo world!!!\r\n0\r\n\r\n";
/// let mut decoded = String::new();
///
/// let mut decoder = Decoder::new(encoded as &[u8]);
/// decoder.read_to_string(&mut decoded);
///
/// assert_eq!(decoded, "hello world!!!");
/// ```
pub struct Decoder<R> {
    // where the chunks come from
    source: R,

    // remaining size of the chunk being read
    // none if we are not in a chunk
    remaining_chunks_size: Option<usize>,
}

impl<R> Decoder<R> where R: Read {
    pub fn new(source: R) -> Decoder<R> {
        Decoder {
            source: source,
            remaining_chunks_size: None,
        }
    }

    fn read_chunk_size(&mut self) -> IoResult<usize> {
        let mut chunk_size = Vec::new();

        loop {
            let byte = match self.source.by_ref().bytes().next() {
                Some(b) => try!(b),
                None => return Err(IoError::new(ErrorKind::InvalidInput, DecoderError)),
            };

            if byte == b'\r' {
                break;
            }

            chunk_size.push(byte);
        }

        try!(self.read_line_feed());

        let chunk_size = match String::from_utf8(chunk_size) {
            Ok(c) => c,
            Err(_) => return Err(IoError::new(ErrorKind::InvalidInput, DecoderError))
        };

        let chunk_size = match usize::from_str_radix(&chunk_size, 16) {
            Ok(c) => c,
            Err(_) => return Err(IoError::new(ErrorKind::InvalidInput, DecoderError))
        };

        Ok(chunk_size)
    }

    fn read_carriage_return(&mut self) -> IoResult<()> {
        match self.source.by_ref().bytes().next() {
            Some(Ok(b'\r')) => Ok(()),
            _ => Err(IoError::new(ErrorKind::InvalidInput, DecoderError)),
        }
    }

    fn read_line_feed(&mut self) -> IoResult<()> {
        match self.source.by_ref().bytes().next() {
            Some(Ok(b'\n')) => Ok(()),
            _ => Err(IoError::new(ErrorKind::InvalidInput, DecoderError)),
        }
    }
}

impl<R> Read for Decoder<R> where R: Read {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
        let remaining_chunks_size = match self.remaining_chunks_size {
            Some(c) => c,
            None => {
                // first possibility: we are not in a chunk, so we'll attempt to determine
                // the chunks size
                let chunk_size = try!(self.read_chunk_size());

                // if the chunk size is 0, we are at EOF
                if chunk_size == 0 {
                    try!(self.read_carriage_return());
                    try!(self.read_line_feed());
                    return Ok(0);
                }

                // now that we now the current chunk size, calling ourselves recursively
                self.remaining_chunks_size = Some(chunk_size);
                return self.read(buf);
            }
        };

        // second possibility: we continue reading from a chunk
        if buf.len() < remaining_chunks_size {
            let read = try!(self.source.read(buf));
            self.remaining_chunks_size = Some(remaining_chunks_size - read);
            return Ok(read);
        }

        // third possibility: the read request goes further than the current chunk
        // we simply read until the end of the chunk and return
        assert!(buf.len() >= remaining_chunks_size);

        let buf = &mut buf[.. remaining_chunks_size];
        let read = try!(self.source.read(buf));

        self.remaining_chunks_size = if read == remaining_chunks_size {
            try!(self.read_carriage_return());
            try!(self.read_line_feed());
            None
        } else {
            Some(remaining_chunks_size - read)
        };

        return Ok(read);
    }
}

#[derive(Debug, Copy, Clone)]
struct DecoderError;

impl fmt::Display for DecoderError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "Error while decoding chunks")
    }
}

impl Error for DecoderError {
    fn description(&self) -> &str {
        "Error while decoding chunks"
    }
}

#[cfg(test)]
mod test {
    use super::Decoder;
    use std::io;
    use std::io::Read;

    #[test]
    fn test_valid_chunk_decode() {
        let source = io::Cursor::new("3\r\nhel\r\nb\r\nlo world!!!\r\n0\r\n\r\n".to_string().into_bytes());
        let mut decoded = Decoder::new(source);

        let mut string = String::new();
        decoded.read_to_string(&mut string).unwrap();

        assert_eq!(string, "hello world!!!");
    }

    #[test]
    fn test_decode_zero_length() {
        let mut decoder = Decoder::new(b"0\r\n\r\n" as &[u8]);

        let mut decoded = String::new();
        decoder.read_to_string(&mut decoded).unwrap();

        assert_eq!(decoded, "");
    }

    #[test]
    fn test_decode_invalid_chunk_length() {
        let mut decoder = Decoder::new(b"m\r\n\r\n" as &[u8]);

        let mut decoded = String::new();
        assert!(decoder.read_to_string(&mut decoded).is_err());
    }

    #[test]
    fn invalid_input1() {
        let source = io::Cursor::new("2\r\nhel\r\nb\r\nlo world!!!\r\n0\r\n".to_string().into_bytes());
        let mut decoded = Decoder::new(source);

        let mut string = String::new();
        decoded.read_to_string(&mut string).is_err();
    }

    #[test]
    fn invalid_input2() {
        let source = io::Cursor::new("3\rhel\r\nb\r\nlo world!!!\r\n0\r\n".to_string().into_bytes());
        let mut decoded = Decoder::new(source);

        let mut string = String::new();
        decoded.read_to_string(&mut string).is_err();
    }
}
<|endoftext|>


<commit_before>use crate::{At, Entry, History, Record};
#[cfg(feature = "chrono")]
use chrono::{DateTime, Local, Utc};
use colored::{Color, Colorize};
use std::fmt::{self, Write};

/// Configurable display formatting of structures.
///
/// # Examples
/// ```
/// # use undo::{Command, History};
/// # fn foo() -> History<String> {
/// let history = History::default();
/// println!(
///     "{}",
///     history.display().graph(true).colored(true).ligatures(true)
/// );
/// # history
/// # }
/// ```
#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
pub struct Display<'a, T> {
    data: &'a T,
    view: View,
}

impl<T> Display<'_, T> {
    /// Show colored output (off by default).
    #[inline]
    pub fn colored(&mut self, on: bool) -> &mut Self {
        self.view.colored = on;
        self
    }

    /// Show the current position in the output (on by default).
    #[inline]
    pub fn current(&mut self, on: bool) -> &mut Self {
        self.view.current = on;
        self
    }

    /// Show detailed output (on by default).
    #[inline]
    pub fn detailed(&mut self, on: bool) -> &mut Self {
        self.view.detailed = on;
        self
    }

    /// Use ligature (unicode) in the output (off by default).
    ///
    /// The ligatures might only work as expected with monospaced fonts.
    #[inline]
    pub fn ligatures(&mut self, on: bool) -> &mut Self {
        self.view.ligatures = on;
        self
    }

    /// Show the position of the command (on by default).
    #[inline]
    pub fn position(&mut self, on: bool) -> &mut Self {
        self.view.position = on;
        self
    }

    /// Show the saved command (on by default).
    #[inline]
    pub fn saved(&mut self, on: bool) -> &mut Self {
        self.view.saved = on;
        self
    }
}

impl<R> Display<'_, History<R>> {
    /// Show the history as a graph (off by default).
    #[inline]
    pub fn graph(&mut self, on: bool) -> &mut Self {
        self.view.graph = on;
        self
    }
}

impl<R> Display<'_, Record<R>> {
    #[inline]
    fn fmt_list(&self, f: &mut fmt::Formatter, at: At, entry: &Entry<R>) -> fmt::Result {
        self.view.mark(f, 0)?;
        self.view.position(f, at, false)?;
        if self.view.detailed {
            #[cfg(feature = "chrono")]
            self.view.timestamp(f, &entry.timestamp)?;
        }
        self.view.current(
            f,
            at,
            At {
                branch: 0,
                current: self.data.current(),
            },
        )?;
        self.view.saved(
            f,
            at,
            self.data.saved.map(|saved| At {
                branch: 0,
                current: saved,
            }),
        )?;
        if self.view.detailed {
            writeln!(f)?;
            self.view.message(f, entry, 0)
        } else {
            f.write_char(' ')?;
            self.view.message(f, entry, 0)?;
            writeln!(f)
        }
    }
}

impl<R> Display<'_, History<R>> {
    #[inline]
    fn fmt_list(
        &self,
        f: &mut fmt::Formatter,
        at: At,
        entry: &Entry<R>,
        level: usize,
    ) -> fmt::Result {
        self.view.mark(f, level)?;
        self.view.position(f, at, true)?;
        if self.view.detailed {
            #[cfg(feature = "chrono")]
            self.view.timestamp(f, &entry.timestamp)?;
        }
        self.view.current(
            f,
            at,
            At {
                branch: self.data.branch(),
                current: self.data.current(),
            },
        )?;
        self.view.saved(
            f,
            at,
            self.data
                .record
                .saved
                .map(|saved| At {
                    branch: self.data.branch(),
                    current: saved,
                })
                .or(self.data.saved),
        )?;
        if self.view.detailed {
            writeln!(f)?;
            self.view.message(f, entry, level)
        } else {
            f.write_char(' ')?;
            self.view.message(f, entry, level)?;
            writeln!(f)
        }
    }

    #[inline]
    fn fmt_graph(
        &self,
        f: &mut fmt::Formatter,
        at: At,
        entry: &Entry<R>,
        level: usize,
    ) -> fmt::Result {
        for (&i, branch) in self
            .data
            .branches
            .iter()
            .filter(|(_, branch)| branch.parent == at)
        {
            for (j, cmd) in branch.commands.iter().enumerate().rev() {
                let at = At {
                    branch: i,
                    current: j + branch.parent.current + 1,
                };
                self.fmt_graph(f, at, cmd, level + 1)?;
            }
            for j in 0..level {
                self.view.edge(f, j)?;
                f.write_char(' ')?;
            }
            self.view.split(f, level)?;
            writeln!(f)?;
        }
        for i in 0..level {
            self.view.edge(f, i)?;
            f.write_char(' ')?;
        }
        self.fmt_list(f, at, entry, level)
    }
}

impl<'a, T> From<&'a T> for Display<'a, T> {
    #[inline]
    fn from(data: &'a T) -> Self {
        Display {
            data,
            view: View::default(),
        }
    }
}

impl<R> fmt::Display for Display<'_, Record<R>> {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for (i, cmd) in self.data.commands.iter().enumerate().rev() {
            let at = At {
                branch: 0,
                current: i + 1,
            };
            self.fmt_list(f, at, cmd)?;
        }
        Ok(())
    }
}

impl<R> fmt::Display for Display<'_, History<R>> {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for (i, cmd) in self.data.record.commands.iter().enumerate().rev() {
            let at = At {
                branch: self.data.branch(),
                current: i + 1,
            };
            if self.view.graph {
                self.fmt_graph(f, at, cmd, 0)?;
            } else {
                self.fmt_list(f, at, cmd, 0)?;
            }
        }
        Ok(())
    }
}

#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
struct View {
    colored: bool,
    current: bool,
    detailed: bool,
    graph: bool,
    ligatures: bool,
    position: bool,
    saved: bool,
}

impl Default for View {
    #[inline]
    fn default() -> Self {
        View {
            colored: false,
            current: true,
            detailed: true,
            graph: false,
            ligatures: false,
            position: true,
            saved: true,
        }
    }
}

impl View {
    #[inline]
    fn message(self, f: &mut fmt::Formatter, msg: &impl ToString, level: usize) -> fmt::Result {
        let msg = msg.to_string();
        let lines = msg.lines();
        if self.detailed {
            for line in lines {
                for i in 0..=level {
                    self.edge(f, i)?;
                    f.write_char(' ')?;
                }
                writeln!(f, "{}", line.trim())?;
            }
        } else if let Some(line) = lines.map(str::trim).find(|s| !s.is_empty()) {
            f.write_str(&line)?;
        }
        Ok(())
    }

    #[inline]
    fn mark(self, f: &mut fmt::Formatter, level: usize) -> fmt::Result {
        match (self.colored, self.ligatures) {
            (true, true) => write!(f, "{}", "\u{25CF}".color(color(level))),
            (true, false) => write!(f, "{}", "*".color(color(level))),
            (false, true) => f.write_char('\u{25CF}'),
            (false, false) => f.write_char('*'),
        }
    }

    #[inline]
    fn edge(self, f: &mut fmt::Formatter, level: usize) -> fmt::Result {
        match (self.colored, self.ligatures) {
            (true, true) => write!(f, "{}", "\u{2502}".color(color(level))),
            (true, false) => write!(f, "{}", "|".color(color(level))),
            (false, true) => f.write_char('\u{2502}'),
            (false, false) => f.write_char('|'),
        }
    }

    #[inline]
    fn split(self, f: &mut fmt::Formatter, level: usize) -> fmt::Result {
        match (self.colored, self.ligatures) {
            (true, true) => write!(
                f,
                "{}{}{}",
                "\u{251C}".color(color(level)),
                "\u{2500}".color(color(level + 1)),
                "\u{256F}".color(color(level + 1))
            ),
            (true, false) => write!(
                f,
                "{}{}",
                "|".color(color(level)),
                "/".color(color(level + 1))
            ),
            (false, true) => f.write_str("\u{251C}\u{2500}\u{256F}"),
            (false, false) => f.write_str("|/"),
        }
    }

    #[inline]
    fn position(self, f: &mut fmt::Formatter, at: At, use_branch: bool) -> fmt::Result {
        if self.position {
            if self.colored {
                let position = if use_branch {
                    format!("[{}:{}]", at.branch, at.current)
                } else {
                    format!("[{}]", at.current)
                };
                write!(f, " {}", position.yellow())
            } else if use_branch {
                write!(f, " [{}:{}]", at.branch, at.current)
            } else {
                write!(f, " [{}]", at.current)
            }
        } else {
            Ok(())
        }
    }

    #[inline]
    fn current(self, f: &mut fmt::Formatter, at: At, current: At) -> fmt::Result {
        if self.current && at == current {
            if self.colored {
                write!(f, " {}{}{}", "(".yellow(), "current".cyan(), ")".yellow())
            } else {
                f.write_str(" (current)")
            }
        } else {
            Ok(())
        }
    }

    #[inline]
    fn saved(self, f: &mut fmt::Formatter, at: At, saved: Option<At>) -> fmt::Result {
        if self.saved && saved.map_or(false, |saved| saved == at) {
            if self.colored {
                write!(
                    f,
                    " {}{}{}",
                    "(".yellow(),
                    "saved".bright_green(),
                    ")".yellow()
                )
            } else {
                f.write_str(" (saved)")
            }
        } else {
            Ok(())
        }
    }

    #[inline]
    #[cfg(feature = "chrono")]
    fn timestamp(self, f: &mut fmt::Formatter, timestamp: &DateTime<Utc>) -> fmt::Result {
        if self.colored {
            write!(
                f,
                " {}{}{}",
                "[".yellow(),
                timestamp.with_timezone(&Local).to_rfc2822().yellow(),
                "]".yellow()
            )
        } else {
            write!(f, " [{}]", timestamp.with_timezone(&Local).to_rfc2822())
        }
    }
}

#[inline]
fn color(i: usize) -> Color {
    match i % 6 {
        0 => Color::Cyan,
        1 => Color::Red,
        2 => Color::Magenta,
        3 => Color::Yellow,
        4 => Color::Green,
        5 => Color::Blue,
        _ => unreachable!(),
    }
}
<commit_msg>Update timestamp method<commit_after>use crate::{At, Entry, History, Record};
#[cfg(feature = "chrono")]
use chrono::{DateTime, Local, Utc};
use colored::{Color, Colorize};
use std::fmt::{self, Write};

/// Configurable display formatting of structures.
///
/// # Examples
/// ```
/// # use undo::{Command, History};
/// # fn foo() -> History<String> {
/// let history = History::default();
/// println!(
///     "{}",
///     history.display().graph(true).colored(true).ligatures(true)
/// );
/// # history
/// # }
/// ```
#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
pub struct Display<'a, T> {
    data: &'a T,
    view: View,
}

impl<T> Display<'_, T> {
    /// Show colored output (off by default).
    #[inline]
    pub fn colored(&mut self, on: bool) -> &mut Self {
        self.view.colored = on;
        self
    }

    /// Show the current position in the output (on by default).
    #[inline]
    pub fn current(&mut self, on: bool) -> &mut Self {
        self.view.current = on;
        self
    }

    /// Show detailed output (on by default).
    #[inline]
    pub fn detailed(&mut self, on: bool) -> &mut Self {
        self.view.detailed = on;
        self
    }

    /// Use ligature (unicode) in the output (off by default).
    ///
    /// The ligatures might only work as expected with monospaced fonts.
    #[inline]
    pub fn ligatures(&mut self, on: bool) -> &mut Self {
        self.view.ligatures = on;
        self
    }

    /// Show the position of the command (on by default).
    #[inline]
    pub fn position(&mut self, on: bool) -> &mut Self {
        self.view.position = on;
        self
    }

    /// Show the saved command (on by default).
    #[inline]
    pub fn saved(&mut self, on: bool) -> &mut Self {
        self.view.saved = on;
        self
    }
}

impl<R> Display<'_, History<R>> {
    /// Show the history as a graph (off by default).
    #[inline]
    pub fn graph(&mut self, on: bool) -> &mut Self {
        self.view.graph = on;
        self
    }
}

impl<R> Display<'_, Record<R>> {
    #[inline]
    fn fmt_list(&self, f: &mut fmt::Formatter, at: At, entry: &Entry<R>) -> fmt::Result {
        self.view.mark(f, 0)?;
        self.view.position(f, at, false)?;
        if self.view.detailed {
            #[cfg(feature = "chrono")]
            self.view.timestamp(f, &entry.timestamp)?;
        }
        self.view.current(
            f,
            at,
            At {
                branch: 0,
                current: self.data.current(),
            },
        )?;
        self.view.saved(
            f,
            at,
            self.data.saved.map(|saved| At {
                branch: 0,
                current: saved,
            }),
        )?;
        if self.view.detailed {
            writeln!(f)?;
            self.view.message(f, entry, 0)
        } else {
            f.write_char(' ')?;
            self.view.message(f, entry, 0)?;
            writeln!(f)
        }
    }
}

impl<R> Display<'_, History<R>> {
    #[inline]
    fn fmt_list(
        &self,
        f: &mut fmt::Formatter,
        at: At,
        entry: &Entry<R>,
        level: usize,
    ) -> fmt::Result {
        self.view.mark(f, level)?;
        self.view.position(f, at, true)?;
        if self.view.detailed {
            #[cfg(feature = "chrono")]
            self.view.timestamp(f, &entry.timestamp)?;
        }
        self.view.current(
            f,
            at,
            At {
                branch: self.data.branch(),
                current: self.data.current(),
            },
        )?;
        self.view.saved(
            f,
            at,
            self.data
                .record
                .saved
                .map(|saved| At {
                    branch: self.data.branch(),
                    current: saved,
                })
                .or(self.data.saved),
        )?;
        if self.view.detailed {
            writeln!(f)?;
            self.view.message(f, entry, level)
        } else {
            f.write_char(' ')?;
            self.view.message(f, entry, level)?;
            writeln!(f)
        }
    }

    #[inline]
    fn fmt_graph(
        &self,
        f: &mut fmt::Formatter,
        at: At,
        entry: &Entry<R>,
        level: usize,
    ) -> fmt::Result {
        for (&i, branch) in self
            .data
            .branches
            .iter()
            .filter(|(_, branch)| branch.parent == at)
        {
            for (j, cmd) in branch.commands.iter().enumerate().rev() {
                let at = At {
                    branch: i,
                    current: j + branch.parent.current + 1,
                };
                self.fmt_graph(f, at, cmd, level + 1)?;
            }
            for j in 0..level {
                self.view.edge(f, j)?;
                f.write_char(' ')?;
            }
            self.view.split(f, level)?;
            writeln!(f)?;
        }
        for i in 0..level {
            self.view.edge(f, i)?;
            f.write_char(' ')?;
        }
        self.fmt_list(f, at, entry, level)
    }
}

impl<'a, T> From<&'a T> for Display<'a, T> {
    #[inline]
    fn from(data: &'a T) -> Self {
        Display {
            data,
            view: View::default(),
        }
    }
}

impl<R> fmt::Display for Display<'_, Record<R>> {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for (i, cmd) in self.data.commands.iter().enumerate().rev() {
            let at = At {
                branch: 0,
                current: i + 1,
            };
            self.fmt_list(f, at, cmd)?;
        }
        Ok(())
    }
}

impl<R> fmt::Display for Display<'_, History<R>> {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for (i, cmd) in self.data.record.commands.iter().enumerate().rev() {
            let at = At {
                branch: self.data.branch(),
                current: i + 1,
            };
            if self.view.graph {
                self.fmt_graph(f, at, cmd, 0)?;
            } else {
                self.fmt_list(f, at, cmd, 0)?;
            }
        }
        Ok(())
    }
}

#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
struct View {
    colored: bool,
    current: bool,
    detailed: bool,
    graph: bool,
    ligatures: bool,
    position: bool,
    saved: bool,
}

impl Default for View {
    #[inline]
    fn default() -> Self {
        View {
            colored: false,
            current: true,
            detailed: true,
            graph: false,
            ligatures: false,
            position: true,
            saved: true,
        }
    }
}

impl View {
    #[inline]
    fn message(self, f: &mut fmt::Formatter, msg: &impl ToString, level: usize) -> fmt::Result {
        let msg = msg.to_string();
        let lines = msg.lines();
        if self.detailed {
            for line in lines {
                for i in 0..=level {
                    self.edge(f, i)?;
                    f.write_char(' ')?;
                }
                writeln!(f, "{}", line.trim())?;
            }
        } else if let Some(line) = lines.map(str::trim).find(|s| !s.is_empty()) {
            f.write_str(&line)?;
        }
        Ok(())
    }

    #[inline]
    fn mark(self, f: &mut fmt::Formatter, level: usize) -> fmt::Result {
        match (self.colored, self.ligatures) {
            (true, true) => write!(f, "{}", "\u{25CF}".color(color(level))),
            (true, false) => write!(f, "{}", "*".color(color(level))),
            (false, true) => f.write_char('\u{25CF}'),
            (false, false) => f.write_char('*'),
        }
    }

    #[inline]
    fn edge(self, f: &mut fmt::Formatter, level: usize) -> fmt::Result {
        match (self.colored, self.ligatures) {
            (true, true) => write!(f, "{}", "\u{2502}".color(color(level))),
            (true, false) => write!(f, "{}", "|".color(color(level))),
            (false, true) => f.write_char('\u{2502}'),
            (false, false) => f.write_char('|'),
        }
    }

    #[inline]
    fn split(self, f: &mut fmt::Formatter, level: usize) -> fmt::Result {
        match (self.colored, self.ligatures) {
            (true, true) => write!(
                f,
                "{}{}{}",
                "\u{251C}".color(color(level)),
                "\u{2500}".color(color(level + 1)),
                "\u{256F}".color(color(level + 1))
            ),
            (true, false) => write!(
                f,
                "{}{}",
                "|".color(color(level)),
                "/".color(color(level + 1))
            ),
            (false, true) => f.write_str("\u{251C}\u{2500}\u{256F}"),
            (false, false) => f.write_str("|/"),
        }
    }

    #[inline]
    fn position(self, f: &mut fmt::Formatter, at: At, use_branch: bool) -> fmt::Result {
        if self.position {
            if self.colored {
                let position = if use_branch {
                    format!("[{}:{}]", at.branch, at.current)
                } else {
                    format!("[{}]", at.current)
                };
                write!(f, " {}", position.yellow())
            } else if use_branch {
                write!(f, " [{}:{}]", at.branch, at.current)
            } else {
                write!(f, " [{}]", at.current)
            }
        } else {
            Ok(())
        }
    }

    #[inline]
    fn current(self, f: &mut fmt::Formatter, at: At, current: At) -> fmt::Result {
        if self.current && at == current {
            if self.colored {
                write!(f, " {}{}{}", "(".yellow(), "current".cyan(), ")".yellow())
            } else {
                f.write_str(" (current)")
            }
        } else {
            Ok(())
        }
    }

    #[inline]
    fn saved(self, f: &mut fmt::Formatter, at: At, saved: Option<At>) -> fmt::Result {
        if self.saved && saved.map_or(false, |saved| saved == at) {
            if self.colored {
                write!(
                    f,
                    " {}{}{}",
                    "(".yellow(),
                    "saved".bright_green(),
                    ")".yellow()
                )
            } else {
                f.write_str(" (saved)")
            }
        } else {
            Ok(())
        }
    }

    #[inline]
    #[cfg(feature = "chrono")]
    fn timestamp(self, f: &mut fmt::Formatter, timestamp: &DateTime<Utc>) -> fmt::Result {
        let rfc2822 = timestamp.with_timezone(&Local).to_rfc2822();
        if self.colored {
            write!(f, " {}{}{}", "[".yellow(), rfc2822.yellow(), "]".yellow())
        } else {
            write!(f, " [{}]", rfc2822)
        }
    }
}

#[inline]
fn color(i: usize) -> Color {
    match i % 6 {
        0 => Color::Cyan,
        1 => Color::Red,
        2 => Color::Magenta,
        3 => Color::Yellow,
        4 => Color::Green,
        5 => Color::Blue,
        _ => unreachable!(),
    }
}
<|endoftext|>