<commit_before>use std::any::{TypeId, Any};
use std::clone::Clone;
use std::fmt::{Display, Debug, Formatter, Error as FmtError};

pub struct Variant<'a> {
   data: *mut (),
   vtable: &'a VTable,
}

pub struct VariantRef<'a> {
   data: &'a (),
   vtable: &'a VTable,
}

pub struct VariantRefMut<'a> {
   data: &'a mut (),
   vtable: &'a VTable,
}

pub struct VTable {
   id: TypeId,
   clone: CloneFn,
   drop: DropFn,
   display: DisplayFn,
   debug: DebugFn,
}

type CloneFn = for<'b> fn(&Variant<'b>) -> Variant<'b>;

type DropFn = for<'b> fn(&mut Variant<'b>);

type DisplayFn = for<'b> fn(&Variant<'b>, f: &mut Formatter) -> Result<(), FmtError>;

type DebugFn = DisplayFn;

impl<'a> Variant<'a> {
   pub fn new<T: Any>(value: T, vtable: &'a VTable) -> Self {
      Variant {
         data: Box::into_raw(Box::new(value)) as *mut (),
         vtable: vtable,
      }
   }

   #[inline]
   pub fn is<T: Any>(&self) -> bool {
      self.vtable.id == TypeId::of::<T>()
   }

   #[inline]
   pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
      if self.is::<T>() {
         unsafe { Some(&*(self.data as *const T)) }
      } else {
         None
      }
   }

   #[inline]
   pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
      if self.is::<T>() {
         unsafe { Some(&mut *(self.data as *mut T)) }
      } else {
         None
      }
   }

   #[inline]
   pub unsafe fn downcast_ref_unchecked<T: Any>(&self) -> &T {
      debug_assert!(self.is::<T>());

      &*(self.data as *const T)
   }

   #[inline]
   pub unsafe fn downcast_mut_unchecked<T: Any>(&mut self) -> &mut T {
      debug_assert!(self.is::<T>());

      &mut *(self.data as *mut T)
   }
}

impl<'a> AsRef<VariantRef<'a>> for Variant<'a> {
   fn as_ref(&self) -> &VariantRef<'a> {
      unsafe { &*(self as *const _ as *const VariantRef<'a>) }
   }
}

impl<'a> AsMut<VariantRefMut<'a>> for Variant<'a> {
   fn as_mut(&mut self) -> &mut VariantRefMut<'a> {
      unsafe { &mut *(self as *mut _ as *mut VariantRefMut<'a>) }
   }
}

impl<'a> VariantRef<'a> {
   pub fn new<T: Any>(value: &'a T, vtable: &'a VTable) -> Self {
      VariantRef {
         data: unsafe { &*(value as *const _ as *const ()) },
         vtable: vtable,
      }
   }

   #[inline]
   pub fn is<T: Any>(&self) -> bool {
      self.vtable.id == TypeId::of::<T>()
   }

   #[inline]
   pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
      if self.is::<T>() {
         unsafe { Some(&*(self.data as *const _ as *const T)) }
      } else {
         None
      }
   }

   #[inline]
   pub unsafe fn downcast_ref_unchecked<T: Any>(&self) -> &T {
      debug_assert!(self.is::<T>());

      &*(self.data as *const _ as *const T)
   }
}

impl<'a> VariantRefMut<'a> {
   pub fn new<T: Any>(value: &'a mut T, vtable: &'a VTable) -> Self {
      VariantRefMut {
         data: unsafe { &mut *(value as *mut _ as *mut ()) },
         vtable: vtable,
      }
   }

   #[inline]
   pub fn is<T: Any>(&self) -> bool {
      self.vtable.id == TypeId::of::<T>()
   }

   #[inline]
   pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
      if self.is::<T>() {
         unsafe { Some(&*(self.data as *const _ as *const T)) }
      } else {
         None
      }
   }

   #[inline]
   pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
      if self.is::<T>() {
         unsafe { Some(&mut *(self.data as *mut _ as *mut T)) }
      } else {
         None
      }
   }

   #[inline]
   pub unsafe fn downcast_ref_unchecked<T: Any>(&self) -> &T {
      debug_assert!(self.is::<T>());

      &*(self.data as *const _ as *const T)
   }

   #[inline]
   pub unsafe fn downcast_mut_unchecked<T: Any>(&mut self) -> &mut T {
      debug_assert!(self.is::<T>());

      &mut *(self.data as *mut _ as *mut T)
   }
}

impl<'a> Clone for Variant<'a> {
   fn clone(&self) -> Self {
      (self.vtable.clone)(self)
   }
}

impl<'a> Drop for Variant<'a> {
   fn drop(&mut self) {
      (self.vtable.drop)(self)
   }
}

impl<'a> Display for Variant<'a> {
   fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
      (self.vtable.display)(self, f)
   }
}

impl<'a> Debug for Variant<'a> {
   fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
      (self.vtable.debug)(self, f)
   }
}

impl VTable {
   pub fn new<T: Any + Clone + Display + Debug>() -> Self {
      VTable {
         id: TypeId::of::<T>(),
         clone: clone_variant::<T>,
         drop: drop_variant::<T>,
         display: display_variant::<T>,
         debug: debug_variant::<T>,
      }
   }

   pub fn variant<T: Any>(&self, value: T) -> Variant {
      Variant::new(value, self)
   }

   pub fn variant_ref<'a, T: Any>(&'a self, value: &'a T) -> VariantRef<'a> {
      VariantRef::new(value, self)
   }

   pub fn variant_ref_mut<'a, T: Any>(&'a self, value: &'a mut T) -> VariantRefMut<'a> {
      VariantRefMut::new(value, self)
   }
}

fn clone_variant<'a, T: Any + Clone>(variant: &Variant<'a>) -> Variant<'a> {
   Variant::new(unsafe { variant.downcast_ref_unchecked() as &T }.clone(), variant.vtable)
}

fn drop_variant<T>(variant: &mut Variant) {
   drop(unsafe { *Box::from_raw(variant.data as *mut T) });
}

fn display_variant<T: Any + Display>(variant: &Variant, f: &mut Formatter) -> Result<(), FmtError> {
   Display::fmt(unsafe { variant.downcast_ref_unchecked() as &T }, f)
}

fn debug_variant<T: Any + Debug>(variant: &Variant, f: &mut Formatter) -> Result<(), FmtError> {
   Debug::fmt(unsafe { variant.downcast_ref_unchecked() as &T }, f)
}

#[cfg(test)]
mod tests {
   use std::fmt::{Display, Debug};

   use super::*;

   #[test]
   fn clone() {
      let vtable = VTable::new::<i64>();
      let origin = vtable.variant(1234_i64);
      let cloned = origin.clone();
      assert_eq!(origin.downcast_ref::<i64>(), cloned.downcast_ref::<i64>());
      assert_eq!(Some(&1234_i64), cloned.downcast_ref::<i64>());
   }

   #[test]
   fn drop_count() {
      #[derive(Clone, Debug)]
      struct Dropper(*mut usize);

      impl Drop for Dropper {
         fn drop(&mut self) {
            unsafe { *self.0 += 1 };
         }
      }

      impl Display for Dropper {
         fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
            Debug::fmt(self, f)
         }
      }

      let vtable = VTable::new::<Dropper>();
      let mut dropped: usize = 0;
      let variant = vtable.variant(Dropper(&mut dropped));
      drop(variant);
      assert_eq!(dropped, 1);

      dropped = 0;
      let variant = vtable.variant(Dropper(&mut dropped));
      let clone = variant.clone();
      drop(variant);
      drop(clone);
      assert_eq!(dropped, 2);
   }

   #[test]
   fn debug() {
      let vtable = VTable::new::<&str>();
      let variant = vtable.variant("data");
      assert_eq!("\"data\"", format!("{:?}", variant));

      let vtable = VTable::new::<i64>();
      let variant = vtable.variant(1234_i64);
      assert_eq!("1234", format!("{:?}", variant));
   }

   #[test]
   fn display() {
      let vtable = VTable::new::<&str>();
      let variant = vtable.variant("data");
      assert_eq!("data", format!("{}", variant));

      let vtable = VTable::new::<i64>();
      let variant = vtable.variant(1234_i64);
      assert_eq!("1234", format!("{}", variant));
   }

   #[test]
   fn as_ref() {
      let vtable = VTable::new::<i64>();
      let variant = vtable.variant(1234_i64);

      fn inner(variant: &VariantRef) {
         assert_eq!(Some(&1234_i64), variant.downcast_ref::<i64>());
      }

      inner(variant.as_ref());
   }

   #[test]
   fn as_mut() {
      let vtable = VTable::new::<i64>();
      let mut variant = vtable.variant(1234_i64);

      fn inner(variant: &mut VariantRefMut) {
         *variant.downcast_mut::<i64>().unwrap() *= 2;
      }

      inner(variant.as_mut());

      assert_eq!(Some(&2468_i64), variant.downcast_ref::<i64>());
   }

   #[test]
   fn stack_ref() {
      let vtable = VTable::new::<i64>();
      let values: [i64; 4] = [0, 2, 5, 6];
      let variants = [
         vtable.variant_ref(&values[0]),
         vtable.variant_ref(&values[1]),
         vtable.variant_ref(&values[2]),
         vtable.variant_ref(&values[3]),
      ];
      let mut sum: i64 = 0;
      for variant in &variants {
         sum += *variant.downcast_ref::<i64>().unwrap();
      }
      assert_eq!(13_i64, sum);
   }
}
<commit_msg>Debug and Display impl for VariantRef and VariantRefMut<commit_after>use std::any::{TypeId, Any};
use std::clone::Clone;
use std::fmt::{Display, Debug, Formatter, Error as FmtError};

pub struct Variant<'a> {
   data: *mut (),
   vtable: &'a VTable,
}

pub struct VariantRef<'a> {
   data: &'a (),
   vtable: &'a VTable,
}

pub struct VariantRefMut<'a> {
   data: &'a mut (),
   vtable: &'a VTable,
}

pub struct VTable {
   id: TypeId,
   clone: CloneFn,
   drop: DropFn,
   display: DisplayFn,
   debug: DebugFn,
}

type CloneFn = for<'b> fn(&VariantRef<'b>) -> Variant<'b>;

type DropFn = for<'b> fn(&mut Variant<'b>);

type DisplayFn = for<'b> fn(&VariantRef<'b>, f: &mut Formatter) -> Result<(), FmtError>;

type DebugFn = DisplayFn;

impl<'a> Variant<'a> {
   pub fn new<T: Any>(value: T, vtable: &'a VTable) -> Self {
      Variant {
         data: Box::into_raw(Box::new(value)) as *mut (),
         vtable: vtable,
      }
   }

   #[inline]
   pub fn is<T: Any>(&self) -> bool {
      self.vtable.id == TypeId::of::<T>()
   }

   #[inline]
   pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
      if self.is::<T>() {
         unsafe { Some(&*(self.data as *const T)) }
      } else {
         None
      }
   }

   #[inline]
   pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
      if self.is::<T>() {
         unsafe { Some(&mut *(self.data as *mut T)) }
      } else {
         None
      }
   }

   #[inline]
   pub unsafe fn downcast_ref_unchecked<T: Any>(&self) -> &T {
      debug_assert!(self.is::<T>());

      &*(self.data as *const T)
   }

   #[inline]
   pub unsafe fn downcast_mut_unchecked<T: Any>(&mut self) -> &mut T {
      debug_assert!(self.is::<T>());

      &mut *(self.data as *mut T)
   }
}

impl<'a> AsRef<VariantRef<'a>> for Variant<'a> {
   fn as_ref(&self) -> &VariantRef<'a> {
      unsafe { &*(self as *const _ as *const VariantRef<'a>) }
   }
}

impl<'a> AsMut<VariantRefMut<'a>> for Variant<'a> {
   fn as_mut(&mut self) -> &mut VariantRefMut<'a> {
      unsafe { &mut *(self as *mut _ as *mut VariantRefMut<'a>) }
   }
}

impl<'a> Clone for Variant<'a> {
   fn clone(&self) -> Self {
      (self.vtable.clone)(self.as_ref())
   }
}

impl<'a> Drop for Variant<'a> {
   fn drop(&mut self) {
      (self.vtable.drop)(self)
   }
}

impl<'a> Display for Variant<'a> {
   fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
      (self.vtable.display)(self.as_ref(), f)
   }
}

impl<'a> Debug for Variant<'a> {
   fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
      (self.vtable.debug)(self.as_ref(), f)
   }
}

impl<'a> VariantRef<'a> {
   pub fn new<T: Any>(value: &'a T, vtable: &'a VTable) -> Self {
      VariantRef {
         data: unsafe { &*(value as *const _ as *const ()) },
         vtable: vtable,
      }
   }

   #[inline]
   pub fn is<T: Any>(&self) -> bool {
      self.vtable.id == TypeId::of::<T>()
   }

   #[inline]
   pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
      if self.is::<T>() {
         unsafe { Some(&*(self.data as *const _ as *const T)) }
      } else {
         None
      }
   }

   #[inline]
   pub unsafe fn downcast_ref_unchecked<T: Any>(&self) -> &T {
      debug_assert!(self.is::<T>());

      &*(self.data as *const _ as *const T)
   }
}

impl<'a> Display for VariantRef<'a> {
   fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
      (self.vtable.display)(self, f)
   }
}

impl<'a> Debug for VariantRef<'a> {
   fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
      (self.vtable.debug)(self, f)
   }
}

impl<'a> VariantRefMut<'a> {
   pub fn new<T: Any>(value: &'a mut T, vtable: &'a VTable) -> Self {
      VariantRefMut {
         data: unsafe { &mut *(value as *mut _ as *mut ()) },
         vtable: vtable,
      }
   }

   #[inline]
   pub fn is<T: Any>(&self) -> bool {
      self.vtable.id == TypeId::of::<T>()
   }

   #[inline]
   pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
      if self.is::<T>() {
         unsafe { Some(&*(self.data as *const _ as *const T)) }
      } else {
         None
      }
   }

   #[inline]
   pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
      if self.is::<T>() {
         unsafe { Some(&mut *(self.data as *mut _ as *mut T)) }
      } else {
         None
      }
   }

   #[inline]
   pub unsafe fn downcast_ref_unchecked<T: Any>(&self) -> &T {
      debug_assert!(self.is::<T>());

      &*(self.data as *const _ as *const T)
   }

   #[inline]
   pub unsafe fn downcast_mut_unchecked<T: Any>(&mut self) -> &mut T {
      debug_assert!(self.is::<T>());

      &mut *(self.data as *mut _ as *mut T)
   }
}

impl<'a> AsRef<VariantRef<'a>> for VariantRefMut<'a> {
   fn as_ref(&self) -> &VariantRef<'a> {
      unsafe { &*(self as *const _ as *const VariantRef<'a>) }
   }
}

impl<'a> Display for VariantRefMut<'a> {
   fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
      (self.vtable.display)(self.as_ref(), f)
   }
}

impl<'a> Debug for VariantRefMut<'a> {
   fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
      (self.vtable.debug)(self.as_ref(), f)
   }
}

impl VTable {
   pub fn new<T: Any + Clone + Display + Debug>() -> Self {
      VTable {
         id: TypeId::of::<T>(),
         clone: clone_variant::<T>,
         drop: drop_variant::<T>,
         display: display_variant::<T>,
         debug: debug_variant::<T>,
      }
   }

   pub fn variant<T: Any>(&self, value: T) -> Variant {
      Variant::new(value, self)
   }

   pub fn variant_ref<'a, T: Any>(&'a self, value: &'a T) -> VariantRef<'a> {
      VariantRef::new(value, self)
   }

   pub fn variant_ref_mut<'a, T: Any>(&'a self, value: &'a mut T) -> VariantRefMut<'a> {
      VariantRefMut::new(value, self)
   }
}

fn clone_variant<'a, T: Any + Clone>(variant: &VariantRef<'a>) -> Variant<'a> {
   Variant::new(unsafe { variant.downcast_ref_unchecked() as &T }.clone(), variant.vtable)
}

fn drop_variant<T>(variant: &mut Variant) {
   drop(unsafe { *Box::from_raw(variant.data as *mut T) });
}

fn display_variant<T: Any + Display>(
   variant: &VariantRef,
   f: &mut Formatter,
) -> Result<(), FmtError> {
   Display::fmt(unsafe { variant.downcast_ref_unchecked() as &T }, f)
}

fn debug_variant<T: Any + Debug>(variant: &VariantRef, f: &mut Formatter) -> Result<(), FmtError> {
   Debug::fmt(unsafe { variant.downcast_ref_unchecked() as &T }, f)
}

#[cfg(test)]
mod tests {
   use std::fmt::{Display, Debug};

   use super::*;

   #[test]
   fn clone() {
      let vtable = VTable::new::<i64>();
      let origin = vtable.variant(1234_i64);
      let cloned = origin.clone();
      assert_eq!(origin.downcast_ref::<i64>(), cloned.downcast_ref::<i64>());
      assert_eq!(Some(&1234_i64), cloned.downcast_ref::<i64>());
   }

   #[test]
   fn drop_count() {
      #[derive(Clone, Debug)]
      struct Dropper(*mut usize);

      impl Drop for Dropper {
         fn drop(&mut self) {
            unsafe { *self.0 += 1 };
         }
      }

      impl Display for Dropper {
         fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
            Debug::fmt(self, f)
         }
      }

      let vtable = VTable::new::<Dropper>();
      let mut dropped: usize = 0;
      let variant = vtable.variant(Dropper(&mut dropped));
      drop(variant);
      assert_eq!(dropped, 1);

      dropped = 0;
      let variant = vtable.variant(Dropper(&mut dropped));
      let clone = variant.clone();
      drop(variant);
      drop(clone);
      assert_eq!(dropped, 2);
   }

   #[test]
   fn debug() {
      let vtable = VTable::new::<&str>();
      let variant = vtable.variant("data");
      assert_eq!("\"data\"", format!("{:?}", variant));

      let vtable = VTable::new::<i64>();
      let variant = vtable.variant(1234_i64);
      assert_eq!("1234", format!("{:?}", variant));
   }

   #[test]
   fn debug_ref() {
      let vtable = VTable::new::<&str>();
      let data = "data";
      let variant_ref = vtable.variant_ref(&data);
      assert_eq!("\"data\"", format!("{:?}", variant_ref));

      let vtable = VTable::new::<i64>();
      let data = 1234_i64;
      let variant_ref = vtable.variant_ref(&data);
      assert_eq!("1234", format!("{:?}", variant_ref));
   }

   #[test]
   fn debug_ref_mut() {
      let vtable = VTable::new::<&str>();
      let mut data = "data";
      let variant_ref = vtable.variant_ref_mut(&mut data);
      assert_eq!("\"data\"", format!("{:?}", variant_ref));

      let vtable = VTable::new::<i64>();
      let mut data = 1234_i64;
      let variant_ref = vtable.variant_ref_mut(&mut data);
      assert_eq!("1234", format!("{:?}", variant_ref));
   }

   #[test]
   fn display() {
      let vtable = VTable::new::<&str>();
      let variant = vtable.variant("data");
      assert_eq!("data", format!("{}", variant));

      let vtable = VTable::new::<i64>();
      let variant = vtable.variant(1234_i64);
      assert_eq!("1234", format!("{}", variant));
   }

   #[test]
   fn display_ref() {
      let vtable = VTable::new::<&str>();
      let data = "data";
      let variant = vtable.variant_ref(&data);
      assert_eq!("data", format!("{}", variant));

      let vtable = VTable::new::<i64>();
      let data = 1234_i64;
      let variant = vtable.variant_ref(&data);
      assert_eq!("1234", format!("{}", variant));
   }

   #[test]
   fn display_ref_mut() {
      let vtable = VTable::new::<&str>();
      let mut data = "data";
      let variant = vtable.variant_ref_mut(&mut data);
      assert_eq!("data", format!("{}", variant));

      let vtable = VTable::new::<i64>();
      let mut data = 1234_i64;
      let variant = vtable.variant_ref_mut(&mut data);
      assert_eq!("1234", format!("{}", variant));
   }

   #[test]
   fn as_ref() {
      let vtable = VTable::new::<i64>();
      let variant = vtable.variant(1234_i64);

      fn inner(variant: &VariantRef) {
         assert_eq!(Some(&1234_i64), variant.downcast_ref::<i64>());
      }

      inner(variant.as_ref());
   }

   #[test]
   fn as_mut() {
      let vtable = VTable::new::<i64>();
      let mut variant = vtable.variant(1234_i64);

      fn inner(variant: &mut VariantRefMut) {
         *variant.downcast_mut::<i64>().unwrap() *= 2;
      }

      inner(variant.as_mut());

      assert_eq!(Some(&2468_i64), variant.downcast_ref::<i64>());
   }

   #[test]
   fn stack_ref() {
      let vtable = VTable::new::<i64>();
      let values: [i64; 4] = [0, 2, 5, 6];
      let variants = [
         vtable.variant_ref(&values[0]),
         vtable.variant_ref(&values[1]),
         vtable.variant_ref(&values[2]),
         vtable.variant_ref(&values[3]),
      ];
      let mut sum: i64 = 0;
      for variant in &variants {
         sum += *variant.downcast_ref::<i64>().unwrap();
      }
      assert_eq!(13_i64, sum);
   }
}
<|endoftext|>


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

struct Keypad {
    layout: HashMap<u8, Key>,
    current_value: u8,
}

impl Keypad {
    fn new() -> Keypad {
        let mut layout = HashMap::new();

        layout.insert(1, Key {
           value: 1,
           left: None,
           up: None,
           right: Some(2),
           down: Some(4),
        });

        layout.insert(2, Key {
           value: 2,
           left: Some(1),
           up: None,
           right: Some(3),
           down: Some(5),
        });

        layout.insert(3, Key {
           value: 3,
           left: Some(2),
           up: None,
           right: None,
           down: Some(6),
        });

        layout.insert(4, Key {
           value: 4,
           left: None,
           up: Some(1),
           right: Some(5),
           down: Some(7),
        });

        layout.insert(5, Key {
           value: 5,
           left: Some(4),
           up: Some(2),
           right: Some(6),
           down: Some(8),
        });

        layout.insert(6, Key {
           value: 6,
           left: Some(5),
           up: Some(3),
           right: None,
           down: Some(9),
        });

        layout.insert(7, Key {
           value: 7,
           left: None,
           up: Some(4),
           right: Some(8),
           down: None,
        });

        layout.insert(8, Key {
           value: 1,
           left: Some(7),
           up: Some(5),
           right: Some(9),
           down: None,
        });

        layout.insert(9, Key {
           value: 9,
           left: Some(8),
           up: Some(6),
           right: None,
           down: None,
        });

        Keypad {
            layout: layout,
            current_value: 5,
        }
    }
}

struct Key {
    value: u8,
    left: Option<u8>,
    right: Option<u8>,
    up: Option<u8>,
    down: Option<u8>,
}

pub fn puzzle(input: &str) -> u8 {
    let keypad = Keypad::new();
    1
}

#[cfg(test)]
mod test {
    use super::*;
}
<commit_msg>Implement moving around the board<commit_after>use std::collections::HashMap;

pub struct Keypad {
    layout: HashMap<u8, Key>,
    current_value: u8,
}

impl Keypad {
    fn new() -> Keypad {
        let mut layout = HashMap::new();

        layout.insert(1, Key {
           value: 1,
           left: None,
           up: None,
           right: Some(2),
           down: Some(4),
        });

        layout.insert(2, Key {
           value: 2,
           left: Some(1),
           up: None,
           right: Some(3),
           down: Some(5),
        });

        layout.insert(3, Key {
           value: 3,
           left: Some(2),
           up: None,
           right: None,
           down: Some(6),
        });

        layout.insert(4, Key {
           value: 4,
           left: None,
           up: Some(1),
           right: Some(5),
           down: Some(7),
        });

        layout.insert(5, Key {
           value: 5,
           left: Some(4),
           up: Some(2),
           right: Some(6),
           down: Some(8),
        });

        layout.insert(6, Key {
           value: 6,
           left: Some(5),
           up: Some(3),
           right: None,
           down: Some(9),
        });

        layout.insert(7, Key {
           value: 7,
           left: None,
           up: Some(4),
           right: Some(8),
           down: None,
        });

        layout.insert(8, Key {
           value: 1,
           left: Some(7),
           up: Some(5),
           right: Some(9),
           down: None,
        });

        layout.insert(9, Key {
           value: 9,
           left: Some(8),
           up: Some(6),
           right: None,
           down: None,
        });

        Keypad {
            layout: layout,
            current_value: 5,
        }
    }

    fn move_a_key(&mut self, instruction: char) {
        let current_key = self.layout.get(&self.current_value)
                                     .expect("impossible missing key");

        let next_key_value = match instruction {
            'U' => current_key.up.unwrap_or(current_key.value),
            'D' => current_key.down.unwrap_or(current_key.value),
            'L' => current_key.left.unwrap_or(current_key.value),
            'R' => current_key.right.unwrap_or(current_key.value),
            other => panic!("Don't know how to move ({})!", other),
        };

        self.current_value = next_key_value;
    }
}

struct Key {
    value: u8,
    left: Option<u8>,
    right: Option<u8>,
    up: Option<u8>,
    down: Option<u8>,
}

pub fn puzzle(input: &str) -> u8 {
    let keypad = Keypad::new();
    1
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn regular_move() {
        let mut keypad = Keypad::new();

        keypad.move_a_key('U');
        assert_eq!(keypad.current_value, 2);
    }

    #[test]
    fn ignored_move() {
        let mut keypad = Keypad::new();

        keypad.move_a_key('U');
        keypad.move_a_key('U');
        assert_eq!(keypad.current_value, 2);
    }
}
<|endoftext|>


<commit_before>// Module for parsing ISO Base Media Format aka video/mp4 streams.

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

/// Basic ISO box structure.
pub struct Mp4Box {
    /// Four character box type
    name: u32,
    /// Size of the box in bytes
    size: u64,
}

/// File type box 'ftyp'.
pub struct Mp4FileTypeBox {
    name: u32,
    size: u64,
    major_brand: u32,
    minor_version: u32,
    compatible_brands: Vec<u32>,
}

extern crate byteorder;
use byteorder::{BigEndian, ReadBytesExt};

/// Parse a box out of a data buffer.
pub fn read_box<T: ReadBytesExt>(src: &mut T) -> Option<Mp4Box> {
    let tmp_size = src.read_u32::<BigEndian>().unwrap();
    let name = src.read_u32::<BigEndian>().unwrap();
    let size = match tmp_size {
        1 => src.read_u64::<BigEndian>().unwrap(),
        _ => tmp_size as u64,
    };
    Some(Mp4Box{
        name: name,
        size: size,
    })
}

/// Parse an ftype box.
pub fn read_ftype<T: ReadBytesExt>(src: &mut T) -> Option<Mp4FileTypeBox> {
    let head = read_box(src).unwrap();
    let major = src.read_u32::<BigEndian>().unwrap();
    let minor = src.read_u32::<BigEndian>().unwrap();
    let brand_count = (head.size - 8 - 8) /4;
    let mut brands = Vec::new();
    for _ in 0..brand_count {
        brands.push(src.read_u32::<BigEndian>().unwrap());
    }
    Some(Mp4FileTypeBox{
        name: head.name,
        size: head.size,
        major_brand: major,
        minor_version: minor,
        compatible_brands: brands,
    })
}

use std::fmt;
impl fmt::Display for Mp4Box {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let to_vec = |x| vec!((x >> 24 & 0xffu32) as u8,
                              (x >> 16 & 0xffu32) as u8,
                              (x >>  8 & 0xffu32) as u8,
                              (x & 0xffu32) as u8);
        let name_bytes = to_vec(self.name);
        let name = String::from_utf8_lossy(&name_bytes);
        write!(f, "'{}' {} bytes", name, self.size)
    }
}

#[test]
fn test_read_box() {
    use std::io::Cursor;
    use std::io::Write;
    let mut test: Vec<u8> = vec![0, 0, 0, 8];  // minimal box length
    write!(&mut test, "test").unwrap(); // box type
    let mut stream = Cursor::new(test);
    let parsed = read_box(&mut stream).unwrap();
    assert_eq!(parsed.name, 1952805748);
    assert_eq!(parsed.size, 8);
    println!("box {}", parsed);
}

#[test]
fn test_read_box_long() {
    use std::io::Cursor;
    let mut test: Vec<u8> = vec![0, 0, 0, 1]; // long box extension code
    test.extend("long".to_string().into_bytes()); // box type
    test.extend(vec![0, 0, 0, 0, 0, 0, 16, 0]); // 64 bit size
    // Skip generating box content.
    let mut stream = Cursor::new(test);
    let parsed = read_box(&mut stream).unwrap();
    assert_eq!(parsed.name, 1819242087);
    assert_eq!(parsed.size, 4096);
    println!("box {}", parsed);
}
<commit_msg>Add unit test for read_ftyp.<commit_after>// Module for parsing ISO Base Media Format aka video/mp4 streams.

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

/// Basic ISO box structure.
pub struct Mp4Box {
    /// Four character box type
    name: u32,
    /// Size of the box in bytes
    size: u64,
}

/// File type box 'ftyp'.
pub struct Mp4FileTypeBox {
    name: u32,
    size: u64,
    major_brand: u32,
    minor_version: u32,
    compatible_brands: Vec<u32>,
}

extern crate byteorder;
use byteorder::{BigEndian, ReadBytesExt};

/// Parse a box out of a data buffer.
pub fn read_box<T: ReadBytesExt>(src: &mut T) -> Option<Mp4Box> {
    let tmp_size = src.read_u32::<BigEndian>().unwrap();
    let name = src.read_u32::<BigEndian>().unwrap();
    let size = match tmp_size {
        1 => src.read_u64::<BigEndian>().unwrap(),
        _ => tmp_size as u64,
    };
    Some(Mp4Box{
        name: name,
        size: size,
    })
}

/// Parse an ftype box.
pub fn read_ftyp<T: ReadBytesExt>(src: &mut T) -> Option<Mp4FileTypeBox> {
    let head = read_box(src).unwrap();
    let major = src.read_u32::<BigEndian>().unwrap();
    let minor = src.read_u32::<BigEndian>().unwrap();
    let brand_count = (head.size - 8 - 8) /4;
    let mut brands = Vec::new();
    for _ in 0..brand_count {
        brands.push(src.read_u32::<BigEndian>().unwrap());
    }
    Some(Mp4FileTypeBox{
        name: head.name,
        size: head.size,
        major_brand: major,
        minor_version: minor,
        compatible_brands: brands,
    })
}

use std::fmt;
impl fmt::Display for Mp4Box {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let to_vec = |x| vec!((x >> 24 & 0xffu32) as u8,
                              (x >> 16 & 0xffu32) as u8,
                              (x >>  8 & 0xffu32) as u8,
                              (x & 0xffu32) as u8);
        let name_bytes = to_vec(self.name);
        let name = String::from_utf8_lossy(&name_bytes);
        write!(f, "'{}' {} bytes", name, self.size)
    }
}

#[test]
fn test_read_box() {
    use std::io::Cursor;
    use std::io::Write;
    let mut test: Vec<u8> = vec![0, 0, 0, 8];  // minimal box length
    write!(&mut test, "test").unwrap(); // box type
    let mut stream = Cursor::new(test);
    let parsed = read_box(&mut stream).unwrap();
    assert_eq!(parsed.name, 1952805748);
    assert_eq!(parsed.size, 8);
    println!("box {}", parsed);
}

#[test]
fn test_read_box_long() {
    use std::io::Cursor;
    let mut test: Vec<u8> = vec![0, 0, 0, 1]; // long box extension code
    test.extend("long".to_string().into_bytes()); // box type
    test.extend(vec![0, 0, 0, 0, 0, 0, 16, 0]); // 64 bit size
    // Skip generating box content.
    let mut stream = Cursor::new(test);
    let parsed = read_box(&mut stream).unwrap();
    assert_eq!(parsed.name, 1819242087);
    assert_eq!(parsed.size, 4096);
    println!("box {}", parsed);
}

#[test]
fn test_read_ftyp() {
    use std::io::Cursor;
    use std::io::Write;
    let mut test: Vec<u8> = vec![0, 0, 0, 24]; // size
    write!(&mut test, "ftyp").unwrap(); // type
    write!(&mut test, "mp42").unwrap(); // major brand
    test.extend(vec![0, 0, 0, 0]);      // minor version
    write!(&mut test, "isom").unwrap(); // compatible brands...
    write!(&mut test, "mp42").unwrap();
    assert_eq!(test.len(), 24);

    let mut stream = Cursor::new(test);
    let parsed = read_ftyp(&mut stream).unwrap();
    println!("box {} size {}", parsed.name, parsed.size);
    assert_eq!(parsed.name, 1718909296);
    assert_eq!(parsed.size, 24);
    assert_eq!(parsed.major_brand, 1836069938);
    assert_eq!(parsed.minor_version, 0);
    assert_eq!(parsed.compatible_brands.len(), 2);
}
<|endoftext|>


<commit_before>extern crate curl;
extern crate url;

mod util;

use std::str;
use std::collections::HashMap;

use curl::http;
use url::Url;

#[derive(Clone)]
pub struct Firebase {
    url: Url,
}

impl Firebase {
    pub fn new(url: &str) -> Result<Self, ParseError> {
        let url = util::add_https(&url);
        let url = try!( parse(&url) );
        try!( unwrap_path(&url) );

        Ok(Firebase {
            url: url,
        })
    }

    pub fn from_url(url: &Url) -> Result<Self, ParseError> {
        let url = url.clone();
        try!( unwrap_path(&url) );

        Ok(Firebase {
            url: url,
        })
    }

    pub fn authed(url: &str, auth_token: &str) -> Result<Self, ParseError> {
        let url = util::add_https(&url);
        let mut url = try!( parse(&url) );
        try!( unwrap_path(&url) );

        let opts = vec![ ("auth", auth_token) ];
        url.set_query_from_pairs(opts.into_iter());

        Ok(Firebase {
            url: url,
        })
    }

    pub fn at(&self, add_path: &str) -> Result<Self, ParseError> {
        let mut url = self.url.clone();

        { // Add path to original path, already checked for path.
            let mut path = url.path_mut().unwrap();
            // Remove .json from the old path's end.
            if let Some(end) = path.pop() {
                let new_end = util::trim_right(&end, ".json").to_string();
                path.push(new_end);
            }
            let add_path = util::trim_right(add_path, "/");
            let add_path = util::trim_left(add_path, "/");
            let add_path = util::add_right(add_path, ".json");

            for component in add_path.split("/").into_iter() {
                path.push(component.to_string());
            }
        }

        Ok(Firebase {
            url: url,
        })
    }

    pub fn ops(&self, opts: &FbOps) -> FirebaseParams {
        FirebaseParams::from_ops(&self.url, opts)
    }

    fn with_params<T: ToString>(&self, key: &'static str, value: T) -> FirebaseParams {
        FirebaseParams::new(&self.url, key, value)
    }

    pub fn get(&self) -> Result<Response, ReqErr> {
        self.request(Method::GET, None)
    }

    pub fn set(&self, data: &str) -> Result<Response, ReqErr> {
        self.request(Method::PUT, Some(data))
    }

    pub fn push(&self, data: &str) -> Result<Response, ReqErr> {
        self.request(Method::POST, Some(data))
    }

    pub fn update(&self, data: &str) -> Result<Response, ReqErr> {
        self.request(Method::PATCH, Some(data))
    }

    pub fn remove(&self) -> Result<Response, ReqErr> {
        self.request(Method::DELETE, None)
    }

    pub fn order_by(&self, key: &str) -> FirebaseParams {
        self.with_params(ORDER_BY, key)
    }

    pub fn limit_to_first(&self, count: u32) -> FirebaseParams {
        self.with_params(LIMIT_TO_FIRST, count)
    }

    pub fn limit_to_last(&self, count: u32) -> FirebaseParams {
        self.with_params(LIMIT_TO_LAST, count)
    }

    pub fn start_at(&self, index: u32) -> FirebaseParams {
        self.with_params(START_AT, index)
    }

    pub fn end_at(&self, index: u32) -> FirebaseParams {
        self.with_params(END_AT, index)
    }

    pub fn equal_to(&self, value: u32) -> FirebaseParams {
        self.with_params(EQUAL_TO, value)
    }

    pub fn shallow(&self, flag: bool) -> FirebaseParams {
        self.with_params(SHALLOW, flag)
    }

    pub fn format(&self) -> FirebaseParams {
        self.with_params(FORMAT, EXPORT)
    }

    pub fn get_url(&self) -> String {
        self.url.serialize()
    }

    #[inline]
    fn request(&self, method: Method, data: Option<&str>) -> Result<Response, ReqErr> {
        Firebase::request_url(&self.url, method, data)
    }

    fn request_url(url: &Url, method: Method, data: Option<&str>) -> Result<Response, ReqErr> {
        let mut handler = http::handle();

        let req = match method {
            Method::GET     => handler.get(   url),
            Method::POST    => handler.post(  url, data.unwrap()),
            Method::PUT     => handler.put(   url, data.unwrap()),
            Method::PATCH   => handler.patch( url, data.unwrap()),
            Method::DELETE  => handler.delete(url),
        };

        let res = match req.exec() {
            Ok(r)  => r,
            Err(e) => return Err(ReqErr::NetworkErr(e)),
        };

        let body = match str::from_utf8(res.get_body()) {
            Ok(b)  => b,
            Err(e) => return Err(ReqErr::RespNotUTF8(e)),
        };

        Ok(Response {
            body: body.to_string(),
            code: res.get_code(),
        })
    }
}

#[derive(Clone)]
pub struct FirebaseParams {
    url: Url,
    params: HashMap<&'static str, String>,
}

impl FirebaseParams {
    pub fn order_by(self, key: &str) -> Self {
        self.add_param(ORDER_BY, key)
    }

    pub fn limit_to_first(self, count: u32) -> Self {
        self.add_param(LIMIT_TO_FIRST, count)
    }

    pub fn limit_to_last(self, count: u32) -> Self {
        self.add_param(LIMIT_TO_LAST, count)
    }

    pub fn start_at(self, index: u32) -> Self {
        self.add_param(START_AT, index)
    }

    pub fn end_at(self, index: u32) -> Self {
        self.add_param(END_AT, index)
    }

    pub fn equal_to(self, value: u32) -> Self {
        self.add_param(EQUAL_TO, value)
    }

    pub fn shallow(self, flag: bool) -> Self {
        self.add_param(SHALLOW, flag)
    }

    pub fn format(self) -> Self {
        self.add_param(FORMAT, EXPORT)
    }

    pub fn get_url(&self) -> String {
        self.url.serialize()
    }

    fn add_param<T: ToString>(mut self, key: &'static str, value: T) -> Self {
        let value = value.to_string();
        self.params.insert(key, value);
        self.set_params();
        self
    }

    fn set_params(&mut self) {
        self.url.set_query_from_pairs(self.params.iter().map(|(&k, v)| (k, v as &str)));
    }

    fn new<T: ToString>(url: &Url, key: &'static str, value: T) -> Self {
        let me = FirebaseParams {
            url: url.clone(),
            params: HashMap::new(),
        };
        me.add_param(key, value)
    }

    fn from_ops(url: &Url, opts: &FbOps) -> Self {
        let mut me = FirebaseParams {
            url: url.clone(),
            params: HashMap::new(),
        };
        if let Some(order) = opts.order_by {
            me.params.insert(ORDER_BY, order.to_string());
        }
        if let Some(first) = opts.limit_to_first {
            me.params.insert(LIMIT_TO_FIRST, first.to_string());
        }
        if let Some(last) = opts.limit_to_last {
            me.params.insert(LIMIT_TO_LAST, last.to_string());
        }
        if let Some(start) = opts.start_at {
            me.params.insert(START_AT, start.to_string());
        }
        if let Some(end) = opts.end_at {
            me.params.insert(END_AT, end.to_string());
        }
        if let Some(equal) = opts.equal_to {
            me.params.insert(EQUAL_TO, equal.to_string());
        }
        if let Some(shallow) = opts.shallow {
            me.params.insert(SHALLOW, shallow.to_string());
        }
        if let Some(format) = opts.format {
            if format {
                me.params.insert(FORMAT, EXPORT.to_string());
            }
        }
        // Copy all of the params into the url.
        me.set_params();
        me
    }

    pub fn get(&self) -> Result<Response, ReqErr> {
        Firebase::request_url(&self.url, Method::GET, None)
    }
}

enum Method {
    GET,
    POST,
    PUT,
    PATCH,
    DELETE,
}

const ORDER_BY:       &'static str = "orderBy";
const LIMIT_TO_FIRST: &'static str = "limitToFirst";
const LIMIT_TO_LAST:  &'static str = "limitToLast";
const START_AT:       &'static str = "startAt";
const END_AT:         &'static str = "endAt";
const EQUAL_TO:       &'static str = "equalTo";
const SHALLOW:        &'static str = "shallow";
const FORMAT:         &'static str = "format";
const EXPORT:         &'static str = "export";

pub struct FbOps<'l> {
    order_by:       Option<&'l str>,
    limit_to_first: Option<u32>,
    limit_to_last:  Option<u32>,
    start_at:       Option<u32>,
    end_at:         Option<u32>,
    equal_to:       Option<u32>,
    shallow:        Option<bool>,
    format:         Option<bool>,
}

pub const DEFAULT: FbOps<'static> = FbOps {
    order_by:       None,
    limit_to_first: None,
    limit_to_last:  None,
    start_at:       None,
    end_at:         None,
    equal_to:       None,
    shallow:        None,
    format:         None,
};

pub enum ReqErr {
    RespNotUTF8(str::Utf8Error),
    NetworkErr(curl::ErrCode),
}

pub enum ParseError {
    UrlHasNoPath,
    Parser(url::ParseError),
}

pub struct Response {
    pub body: String,
    pub code: u32,
}

impl Response {
    pub fn is_success(&self) -> bool {
        self.code < 400
    }
}

fn parse(url: &str) -> Result<Url, ParseError> {
    match Url::parse(&url) {
        Ok(u)  => Ok(u),
        Err(e) => Err(ParseError::Parser(e)),
    }
}

fn unwrap_path(url: &Url) -> Result<&[String], ParseError> {
    match url.path() {
        None    => return Err(ParseError::UrlHasNoPath),
        Some(p) => return Ok(p),
    }
}
<commit_msg>All tests work, all tests pass.<commit_after>extern crate curl;
extern crate url;

mod util;

use std::str;
use std::collections::HashMap;

use curl::http;
use url::Url;

#[derive(Clone)]
pub struct Firebase {
    url: Url,
}

impl Firebase {
    pub fn new(url: &str) -> Result<Self, ParseError> {
        let url = util::add_https(&url);
        let url = try!( parse(&url) );
        try!( unwrap_path(&url) );

        Ok(Firebase {
            url: url,
        })
    }

    pub fn from_url(url: &Url) -> Result<Self, ParseError> {
        let url = url.clone();
        try!( unwrap_path(&url) );

        Ok(Firebase {
            url: url,
        })
    }

    pub fn authed(url: &str, auth_token: &str) -> Result<Self, ParseError> {
        let url = util::add_https(&url);
        let mut url = try!( parse(&url) );
        try!( unwrap_path(&url) );

        let opts = vec![ (AUTH, auth_token) ];
        url.set_query_from_pairs(opts.into_iter());

        Ok(Firebase {
            url: url,
        })
    }

    pub fn at(&self, add_path: &str) -> Result<Self, ParseError> {
        let mut url = self.url.clone();

        { // Add path to original path, already checked for path.
            let mut path = url.path_mut().unwrap();
            // Remove .json from the old path's end.
            if let Some(end) = path.pop() {
                let new_end = util::trim_right(&end, ".json").to_string();
                path.push(new_end);
            }
            let add_path = util::trim_right(add_path, "/");
            let add_path = util::trim_left(add_path, "/");
            let add_path = util::add_right(add_path, ".json");

            for component in add_path.split("/").into_iter() {
                path.push(component.to_string());
            }
        }

        Ok(Firebase {
            url: url,
        })
    }

    pub fn ops(&self, opts: &FbOps) -> FirebaseParams {
        FirebaseParams::from_ops(&self.url, opts)
    }

    fn with_params<T: ToString>(&self, key: &'static str, value: T) -> FirebaseParams {
        FirebaseParams::new(&self.url, key, value)
    }

    pub fn get(&self) -> Result<Response, ReqErr> {
        self.request(Method::GET, None)
    }

    pub fn set(&self, data: &str) -> Result<Response, ReqErr> {
        self.request(Method::PUT, Some(data))
    }

    pub fn push(&self, data: &str) -> Result<Response, ReqErr> {
        self.request(Method::POST, Some(data))
    }

    pub fn update(&self, data: &str) -> Result<Response, ReqErr> {
        self.request(Method::PATCH, Some(data))
    }

    pub fn remove(&self) -> Result<Response, ReqErr> {
        self.request(Method::DELETE, None)
    }

    pub fn order_by(&self, key: &str) -> FirebaseParams {
        self.with_params(ORDER_BY, key)
    }

    pub fn limit_to_first(&self, count: u32) -> FirebaseParams {
        self.with_params(LIMIT_TO_FIRST, count)
    }

    pub fn limit_to_last(&self, count: u32) -> FirebaseParams {
        self.with_params(LIMIT_TO_LAST, count)
    }

    pub fn start_at(&self, index: u32) -> FirebaseParams {
        self.with_params(START_AT, index)
    }

    pub fn end_at(&self, index: u32) -> FirebaseParams {
        self.with_params(END_AT, index)
    }

    pub fn equal_to(&self, value: u32) -> FirebaseParams {
        self.with_params(EQUAL_TO, value)
    }

    pub fn shallow(&self, flag: bool) -> FirebaseParams {
        self.with_params(SHALLOW, flag)
    }

    pub fn format(&self) -> FirebaseParams {
        self.with_params(FORMAT, EXPORT)
    }

    pub fn get_url(&self) -> String {
        self.url.serialize()
    }

    #[inline]
    fn request(&self, method: Method, data: Option<&str>) -> Result<Response, ReqErr> {
        Firebase::request_url(&self.url, method, data)
    }

    fn request_url(url: &Url, method: Method, data: Option<&str>) -> Result<Response, ReqErr> {
        let mut handler = http::handle();

        let req = match method {
            Method::GET     => handler.get(   url),
            Method::POST    => handler.post(  url, data.unwrap()),
            Method::PUT     => handler.put(   url, data.unwrap()),
            Method::PATCH   => handler.patch( url, data.unwrap()),
            Method::DELETE  => handler.delete(url),
        };

        let res = match req.exec() {
            Ok(r)  => r,
            Err(e) => return Err(ReqErr::NetworkErr(e)),
        };

        let body = match str::from_utf8(res.get_body()) {
            Ok(b)  => b,
            Err(e) => return Err(ReqErr::RespNotUTF8(e)),
        };

        Ok(Response {
            body: body.to_string(),
            code: res.get_code(),
        })
    }
}

#[derive(Clone)]
pub struct FirebaseParams {
    url: Url,
    params: HashMap<&'static str, String>,
}

impl FirebaseParams {
    pub fn order_by(self, key: &str) -> Self {
        self.add_param(ORDER_BY, key)
    }

    pub fn limit_to_first(self, count: u32) -> Self {
        self.add_param(LIMIT_TO_FIRST, count)
    }

    pub fn limit_to_last(self, count: u32) -> Self {
        self.add_param(LIMIT_TO_LAST, count)
    }

    pub fn start_at(self, index: u32) -> Self {
        self.add_param(START_AT, index)
    }

    pub fn end_at(self, index: u32) -> Self {
        self.add_param(END_AT, index)
    }

    pub fn equal_to(self, value: u32) -> Self {
        self.add_param(EQUAL_TO, value)
    }

    pub fn shallow(self, flag: bool) -> Self {
        self.add_param(SHALLOW, flag)
    }

    pub fn format(self) -> Self {
        self.add_param(FORMAT, EXPORT)
    }

    pub fn get_url(&self) -> String {
        self.url.serialize()
    }

    fn add_param<T: ToString>(mut self, key: &'static str, value: T) -> Self {
        let value = value.to_string();
        self.params.insert(key, value);
        self.set_params();
        self
    }

    fn set_params(&mut self) {
        self.url.set_query_from_pairs(self.params.iter().map(|(&k, v)| (k, v as &str)));
    }

    fn get_auth(url: &Url) -> HashMap<&'static str, String> {
        let mut pair: HashMap<&'static str, String> = HashMap::new();

        if let Some(queries) = url.query_pairs() {
            for &(ref k, ref v) in queries.iter() {
                if k == AUTH {
                    pair.insert(AUTH, v.to_string());
                }
            }
        }
        pair
    }

    fn new<T: ToString>(url: &Url, key: &'static str, value: T) -> Self {
        let me = FirebaseParams {
            url: url.clone(),
            params: FirebaseParams::get_auth(&url),
        };
        me.add_param(key, value)
    }

    fn from_ops(url: &Url, opts: &FbOps) -> Self {
        let mut me = FirebaseParams {
            url: url.clone(),
            params: FirebaseParams::get_auth(&url),
        };
        if let Some(order) = opts.order_by {
            me.params.insert(ORDER_BY, order.to_string());
        }
        if let Some(first) = opts.limit_to_first {
            me.params.insert(LIMIT_TO_FIRST, first.to_string());
        }
        if let Some(last) = opts.limit_to_last {
            me.params.insert(LIMIT_TO_LAST, last.to_string());
        }
        if let Some(start) = opts.start_at {
            me.params.insert(START_AT, start.to_string());
        }
        if let Some(end) = opts.end_at {
            me.params.insert(END_AT, end.to_string());
        }
        if let Some(equal) = opts.equal_to {
            me.params.insert(EQUAL_TO, equal.to_string());
        }
        if let Some(shallow) = opts.shallow {
            me.params.insert(SHALLOW, shallow.to_string());
        }
        if let Some(format) = opts.format {
            if format {
                me.params.insert(FORMAT, EXPORT.to_string());
            }
        }
        // Copy all of the params into the url.
        me.set_params();
        me
    }

    pub fn get(&self) -> Result<Response, ReqErr> {
        Firebase::request_url(&self.url, Method::GET, None)
    }
}

enum Method {
    GET,
    POST,
    PUT,
    PATCH,
    DELETE,
}

const ORDER_BY:       &'static str = "orderBy";
const LIMIT_TO_FIRST: &'static str = "limitToFirst";
const LIMIT_TO_LAST:  &'static str = "limitToLast";
const START_AT:       &'static str = "startAt";
const END_AT:         &'static str = "endAt";
const EQUAL_TO:       &'static str = "equalTo";
const SHALLOW:        &'static str = "shallow";
const FORMAT:         &'static str = "format";
const EXPORT:         &'static str = "export";
const AUTH:           &'static str = "auth";

pub struct FbOps<'l> {
    order_by:       Option<&'l str>,
    limit_to_first: Option<u32>,
    limit_to_last:  Option<u32>,
    start_at:       Option<u32>,
    end_at:         Option<u32>,
    equal_to:       Option<u32>,
    shallow:        Option<bool>,
    format:         Option<bool>,
}

pub const DEFAULT: FbOps<'static> = FbOps {
    order_by:       None,
    limit_to_first: None,
    limit_to_last:  None,
    start_at:       None,
    end_at:         None,
    equal_to:       None,
    shallow:        None,
    format:         None,
};

pub enum ReqErr {
    RespNotUTF8(str::Utf8Error),
    NetworkErr(curl::ErrCode),
}

pub enum ParseError {
    UrlHasNoPath,
    Parser(url::ParseError),
}

pub struct Response {
    pub body: String,
    pub code: u32,
}

impl Response {
    pub fn is_success(&self) -> bool {
        self.code < 400
    }
}

fn parse(url: &str) -> Result<Url, ParseError> {
    match Url::parse(&url) {
        Ok(u)  => Ok(u),
        Err(e) => Err(ParseError::Parser(e)),
    }
}

fn unwrap_path(url: &Url) -> Result<&[String], ParseError> {
    match url.path() {
        None    => return Err(ParseError::UrlHasNoPath),
        Some(p) => return Ok(p),
    }
}
<|endoftext|>


<commit_before>//! # Test CLI Applications
//!
//! This crate's goal is to provide you some very easy tools to test your CLI
//! applications. It can currently execute child processes and validate their
//! exit status as well as stdout output against your assertions.
//!
//! ## Examples
//!
//! Here's a trivial example:
//!
//! ```rust extern crate assert_cli;
//!
//! assert_cli::Assert::command(&["echo", "42"])
//!     .succeeds()
//!     .and().prints("42")
//!     .unwrap();
//! ```
//!
//! And here is one that will fail:
//!
//! ```rust,should_panic
//! assert_cli::Assert::command(&["echo", "42"])
//!     .prints("1337")
//!     .unwrap();
//! ```
//!
//! this will show a nice, colorful diff in your terminal, like this:
//!
//! ```diff
//! -1337
//! +42
//! ```
//!
//! If you are testing a Rust binary crate, you can start with
//! `Assert::main_binary()` to use `cargo run` as command. Or, if you want to
//! run a specific binary (if you have more than one), use
//! `Assert::cargo_binary`.
//!
//! Alternatively, you can use the `assert_cmd!` macro to construct the command:
//!
//! ```rust
//! #[macro_use] extern crate assert_cli;
//!
//! # fn main() {
//! assert_cmd!(echo 42).succeeds().prints("42").unwrap();
//! # }
//! ```
//!
//! (Make sure to include the crate as `#[macro_use] extern crate assert_cli;`!)
//!
//! If you don't want it to panic when the assertions are not met, simply call
//! `.execute` instead of `.unwrap` to get a `Result`:
//!
//! ```rust
//! #[macro_use] extern crate assert_cli;
//!
//! # fn main() {
//! let x = assert_cmd!(echo 1337).prints_exactly("42").execute();
//! assert!(x.is_err());
//! # }
//! ```

#![deny(warnings, missing_docs)]

extern crate difference;
#[macro_use] extern crate error_chain;

use std::process::Command;

use difference::Changeset;

mod errors;
use errors::*;

mod diff;

/// Assertions for a specific command
#[derive(Debug)]
pub struct Assert {
    cmd: Vec<String>,
    expect_success: bool,
    expect_exit_code: Option<i32>,
    expect_output: Option<String>,
    fuzzy_output: bool,
    expect_error_output: Option<String>,
    fuzzy_error_output: bool,
}

impl std::default::Default for Assert {
    /// Construct an assert using `cargo run --` as command.
    fn default() -> Self {
        Assert {
            cmd: vec!["cargo", "run", "--"]
                .into_iter().map(String::from).collect(),
            expect_success: true,
            expect_exit_code: None,
            expect_output: None,
            fuzzy_output: false,
            expect_error_output: None,
            fuzzy_error_output: false,
        }
    }
}

impl Assert {
    /// Use the crate's main binary as command
    pub fn main_binary() -> Self {
        Assert::default()
    }

    /// Use the crate's main binary as command
    pub fn cargo_binary(name: &str) -> Self {
        Assert {
            cmd: vec!["cargo", "run", "--bin", name, "--"]
                .into_iter().map(String::from).collect(),
            ..Self::default()
        }
    }

    /// Use custom command
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["echo", "1337"])
    ///     .succeeds()
    ///     .unwrap();
    /// ```
    pub fn command(cmd: &[&str]) -> Self {
        Assert {
            cmd: cmd.into_iter().cloned().map(String::from).collect(),
            ..Self::default()
        }
    }

    /// Add arguments to the command
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["echo"])
    ///     .with_args(&["42"])
    ///     .succeeds()
    ///     .prints("42")
    ///     .unwrap();
    /// ```
    pub fn with_args(mut self, args: &[&str]) -> Self {
        self.cmd.extend(args.into_iter().cloned().map(String::from));
        self
    }

    /// Small helper to make chains more readable
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["echo", "42"])
    ///     .succeeds().and().prints("42")
    ///     .unwrap();
    /// ```
    pub fn and(self) -> Self {
        self
    }

    /// Expect the command to be executed successfully
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["echo", "42"])
    ///     .succeeds()
    ///     .unwrap();
    /// ```
    pub fn succeeds(mut self) -> Self {
        self.expect_success = true;
        self
    }

    /// Expect the command to fail
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["cat", "non-exisiting-file"])
    ///     .fails()
    ///     .unwrap();
    /// ```
    pub fn fails(mut self) -> Self {
        self.expect_success = false;
        self
    }

    /// Expect the command to fail and return a specific error code
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["cat", "non-exisiting-file"])
    ///     .fails_with(1)
    ///     .unwrap();
    /// ```
    pub fn fails_with(mut self, expect_exit_code: i32) -> Self {
        self.expect_success = false;
        self.expect_exit_code = Some(expect_exit_code);
        self
    }

    /// Expect the command's output to contain `output`
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["echo", "42"])
    ///     .prints("42")
    ///     .unwrap();
    /// ```
    pub fn prints<O: Into<String>>(mut self, output: O) -> Self {
        self.expect_output = Some(output.into());
        self.fuzzy_output = true;
        self
    }

    /// Expect the command to output exactly this `output`
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["echo", "42"])
    ///     .prints_exactly("42")
    ///     .unwrap();
    /// ```
    pub fn prints_exactly<O: Into<String>>(mut self, output: O) -> Self {
        self.expect_output = Some(output.into());
        self.fuzzy_output = false;
        self
    }

    /// Expect the command's stderr output to contain `output`
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["cat", "non-exisiting-file"])
    ///     .fails()
    ///     .prints_error("non-exisiting-file")
    ///     .unwrap();
    /// ```
    pub fn prints_error<O: Into<String>>(mut self, output: O) -> Self {
        self.expect_error_output = Some(output.into());
        self.fuzzy_error_output = true;
        self
    }

    /// Expect the command to output exactly this `output` to stderr
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["cat", "non-exisiting-file"])
    ///     .fails()
    ///     .prints_error_exactly("cat: non-exisiting-file: No such file or directory")
    ///     .unwrap();
    /// ```
    pub fn prints_error_exactly<O: Into<String>>(mut self, output: O) -> Self {
        self.expect_error_output = Some(output.into());
        self.fuzzy_error_output = false;
        self
    }

    /// Execute the command and check the assertions
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// let test = assert_cli::Assert::command(&["echo", "42"])
    ///     .succeeds()
    ///     .execute();
    /// assert!(test.is_ok());
    /// ```
    pub fn execute(self) -> Result<()> {
        let cmd = &self.cmd[0];
        let args: Vec<_> = self.cmd.iter().skip(1).collect();
        let mut command = Command::new(cmd);
        let command = command.args(&args);
        let output = command.output()?;

        if self.expect_success != output.status.success() {
            bail!(ErrorKind::StatusMismatch(
                self.cmd.clone(),
                self.expect_success.clone(),
            ));
        }

        if self.expect_exit_code.is_some() &&
            self.expect_exit_code != output.status.code() {
            bail!(ErrorKind::ExitCodeMismatch(
                self.cmd.clone(),
                self.expect_exit_code,
                output.status.code(),
            ));
        }

        let stdout = String::from_utf8_lossy(&output.stdout);
        match (self.expect_output, self.fuzzy_output) {
            (Some(ref expected_output), true) if !stdout.contains(expected_output) => {
                bail!(ErrorKind::OutputMismatch(
                    expected_output.clone(),
                    stdout.into(),
                ));
            },
            (Some(ref expected_output), false) => {
                let differences = Changeset::new(expected_output.trim(), stdout.trim(), "\n");
                if differences.distance > 0 {
                    let nice_diff = diff::render(&differences)?;
                    bail!(ErrorKind::ExactOutputMismatch(nice_diff));
                }
            },
            _ => {},
        }

        let stderr = String::from_utf8_lossy(&output.stderr);
        match (self.expect_error_output, self.fuzzy_error_output) {
            (Some(ref expected_output), true) if !stderr.contains(expected_output) => {
                bail!(ErrorKind::ErrorOutputMismatch(
                    expected_output.clone(),
                    stderr.into(),
                ));
            },
            (Some(ref expected_output), false) => {
                let differences = Changeset::new(expected_output.trim(), stderr.trim(), "\n");
                if differences.distance > 0 {
                    let nice_diff = diff::render(&differences)?;
                    bail!(ErrorKind::ExactErrorOutputMismatch(nice_diff));
                }
            },
            _ => {},
        }

        Ok(())
    }

    /// Execute the command, check the assertions, and panic when they fail
    ///
    /// # Examples
    ///
    /// ```rust,should_panic="Assert CLI failure"
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["echo", "42"])
    ///     .fails()
    ///     .unwrap(); // panics
    /// ```
    pub fn unwrap(self) {
        if let Err(err) = self.execute() {
            panic!("Assert CLI failure:\n{}", err);
        }
    }
}

/// Easily construct an `Assert` with a custom command
///
/// Make sure to include the crate as `#[macro_use] extern crate assert_cli;` if
/// you want to use this macro.
///
/// # Examples
///
/// To test that our very complex cli applications succeeds and prints some
/// text to stdout that contains
///
/// ```plain
/// No errors whatsoever
/// ```
///
/// you would call it like this:
///
/// ```rust
/// #[macro_use] extern crate assert_cli;
/// # fn main() {
/// assert_cmd!(echo "Launch sequence initiated.\nNo errors whatsoever!\n")
///     .succeeds()
///     .prints("No errors whatsoever")
///     .unwrap();
/// # }
/// ```
///
/// The macro will try to convert its arguments as strings, but is limited by
/// Rust's default tokenizer, e.g., you always need to quote CLI arguments
/// like `"--verbose"`.
#[macro_export]
macro_rules! assert_cmd {
    ($($x:tt)+) => {{
        $crate::Assert::command(
            &[$(stringify!($x)),*]
        )
    }}
}
<commit_msg>documentation tweaks<commit_after>//! # Test CLI Applications
//!
//! This crate's goal is to provide you some very easy tools to test your CLI
//! applications. It can currently execute child processes and validate their
//! exit status as well as stdout and stderr output against your assertions.
//!
//! Include the crate like
//!
//! ```rust
//! #[macro_use] // <-- import the convenience macro (optional)
//! extern crate assert_cli;
//! # fn main() { }
//! ```
//!
//! ## Basic Examples
//!
//! Here's a trivial example:
//!
//! ```rust
//! assert_cli::Assert::command(&["echo", "42"])
//!     .succeeds()
//!     .and().prints("42")
//!     .unwrap();
//! ```
//!
//! And here is one that will fail:
//!
//! ```rust,should_panic
//! assert_cli::Assert::command(&["echo", "42"])
//!     .prints_exactly("1337")
//!     .unwrap();
//! ```
//!
//! this will show a nice, colorful diff in your terminal, like this:
//!
//! ```diff
//! -1337
//! +42
//! ```
//!
//! ## Assert CLI Crates
//!
//! If you are testing a Rust binary crate, you can start with
//! `Assert::main_binary()` to use `cargo run` as command. Or, if you want to
//! run a specific binary (if you have more than one), use
//! `Assert::cargo_binary`.
//!
//! ## `assert_cmd!` Macro
//!
//! Alternatively, you can use the `assert_cmd!` macro to construct the command more conveniently:
//!
//! ```rust
//! # #[macro_use] extern crate assert_cli;
//! # fn main() {
//! assert_cmd!(echo 42).succeeds().prints("42").unwrap();
//! # }
//! ```
//!
//! Don't forget to import the crate with `#[macro_use]`. ;-)
//!
//! ## Don't Panic!
//!
//! If you don't want it to panic when the assertions are not met, simply call
//! `.execute` instead of `.unwrap` to get a `Result`:
//!
//! ```rust
//! # #[macro_use] extern crate assert_cli;
//! # fn main() {
//! let x = assert_cmd!(echo 1337).prints_exactly("42").execute();
//! assert!(x.is_err());
//! # }
//! ```

#![deny(warnings, missing_docs)]

extern crate difference;
#[macro_use] extern crate error_chain;

use std::process::Command;

use difference::Changeset;

mod errors;
use errors::*;

mod diff;

/// Assertions for a specific command.
#[derive(Debug)]
pub struct Assert {
    cmd: Vec<String>,
    expect_success: bool,
    expect_exit_code: Option<i32>,
    expect_output: Option<String>,
    fuzzy_output: bool,
    expect_error_output: Option<String>,
    fuzzy_error_output: bool,
}

impl std::default::Default for Assert {
    /// Construct an assert using `cargo run --` as command.
    ///
    /// Defaults to asserting _successful_ execution.
    fn default() -> Self {
        Assert {
            cmd: vec!["cargo", "run", "--"]
                .into_iter().map(String::from).collect(),
            expect_success: true,
            expect_exit_code: None,
            expect_output: None,
            fuzzy_output: false,
            expect_error_output: None,
            fuzzy_error_output: false,
        }
    }
}

impl Assert {
    /// Run the crate's main binary.
    ///
    /// Defaults to asserting _successful_ execution.
    pub fn main_binary() -> Self {
        Assert::default()
    }

    /// Run a specific binary of the current crate.
    ///
    /// Defaults to asserting _successful_ execution.
    pub fn cargo_binary(name: &str) -> Self {
        Assert {
            cmd: vec!["cargo", "run", "--bin", name, "--"]
                .into_iter().map(String::from).collect(),
            ..Self::default()
        }
    }

    /// Run a custom command.
    ///
    /// Defaults to asserting _successful_ execution.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["echo", "1337"])
    ///     .succeeds()
    ///     .unwrap();
    /// ```
    pub fn command(cmd: &[&str]) -> Self {
        Assert {
            cmd: cmd.into_iter().cloned().map(String::from).collect(),
            ..Self::default()
        }
    }

    /// Add arguments to the command.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["echo"])
    ///     .with_args(&["42"])
    ///     .succeeds()
    ///     .prints("42")
    ///     .unwrap();
    /// ```
    pub fn with_args(mut self, args: &[&str]) -> Self {
        self.cmd.extend(args.into_iter().cloned().map(String::from));
        self
    }

    /// Small helper to make chains more readable.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["echo", "42"])
    ///     .succeeds().and().prints("42")
    ///     .unwrap();
    /// ```
    pub fn and(self) -> Self {
        self
    }

    /// Expect the command to be executed successfully.
    ///
    /// Note: This is already set by default, so you only need this for explicitness.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["echo", "42"])
    ///     .succeeds()
    ///     .unwrap();
    /// ```
    pub fn succeeds(mut self) -> Self {
        self.expect_success = true;
        self
    }

    /// Expect the command to fail.
    ///
    /// Note: This does not include shell failures like `command not found`. I.e. the
    ///       command must _run_ and fail for this assertion to pass.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["cat", "non-exisiting-file"])
    ///     .fails()
    ///     .unwrap();
    /// ```
    pub fn fails(mut self) -> Self {
        self.expect_success = false;
        self
    }

    /// Expect the command to fail and return a specific error code.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["cat", "non-exisiting-file"])
    ///     .fails_with(1)
    ///     .unwrap();
    /// ```
    pub fn fails_with(mut self, expect_exit_code: i32) -> Self {
        self.expect_success = false;
        self.expect_exit_code = Some(expect_exit_code);
        self
    }

    /// Expect the command's output to contain `output`.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["echo", "42"])
    ///     .prints("42")
    ///     .unwrap();
    /// ```
    pub fn prints<O: Into<String>>(mut self, output: O) -> Self {
        self.expect_output = Some(output.into());
        self.fuzzy_output = true;
        self
    }

    /// Expect the command to output exactly this `output`.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["echo", "42"])
    ///     .prints_exactly("42")
    ///     .unwrap();
    /// ```
    pub fn prints_exactly<O: Into<String>>(mut self, output: O) -> Self {
        self.expect_output = Some(output.into());
        self.fuzzy_output = false;
        self
    }

    /// Expect the command's stderr output to contain `output`.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["cat", "non-exisiting-file"])
    ///     .fails()
    ///     .prints_error("non-exisiting-file")
    ///     .unwrap();
    /// ```
    pub fn prints_error<O: Into<String>>(mut self, output: O) -> Self {
        self.expect_error_output = Some(output.into());
        self.fuzzy_error_output = true;
        self
    }

    /// Expect the command to output exactly this `output` to stderr.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["cat", "non-exisiting-file"])
    ///     .fails()
    ///     .prints_error_exactly("cat: non-exisiting-file: No such file or directory")
    ///     .unwrap();
    /// ```
    pub fn prints_error_exactly<O: Into<String>>(mut self, output: O) -> Self {
        self.expect_error_output = Some(output.into());
        self.fuzzy_error_output = false;
        self
    }

    /// Execute the command and check the assertions.
    ///
    /// # Examples
    ///
    /// ```rust
    /// extern crate assert_cli;
    ///
    /// let test = assert_cli::Assert::command(&["echo", "42"])
    ///     .succeeds()
    ///     .execute();
    /// assert!(test.is_ok());
    /// ```
    pub fn execute(self) -> Result<()> {
        let cmd = &self.cmd[0];
        let args: Vec<_> = self.cmd.iter().skip(1).collect();
        let mut command = Command::new(cmd);
        let command = command.args(&args);
        let output = command.output()?;

        if self.expect_success != output.status.success() {
            bail!(ErrorKind::StatusMismatch(
                self.cmd.clone(),
                self.expect_success.clone(),
            ));
        }

        if self.expect_exit_code.is_some() &&
            self.expect_exit_code != output.status.code() {
            bail!(ErrorKind::ExitCodeMismatch(
                self.cmd.clone(),
                self.expect_exit_code,
                output.status.code(),
            ));
        }

        let stdout = String::from_utf8_lossy(&output.stdout);
        match (self.expect_output, self.fuzzy_output) {
            (Some(ref expected_output), true) if !stdout.contains(expected_output) => {
                bail!(ErrorKind::OutputMismatch(
                    expected_output.clone(),
                    stdout.into(),
                ));
            },
            (Some(ref expected_output), false) => {
                let differences = Changeset::new(expected_output.trim(), stdout.trim(), "\n");
                if differences.distance > 0 {
                    let nice_diff = diff::render(&differences)?;
                    bail!(ErrorKind::ExactOutputMismatch(nice_diff));
                }
            },
            _ => {},
        }

        let stderr = String::from_utf8_lossy(&output.stderr);
        match (self.expect_error_output, self.fuzzy_error_output) {
            (Some(ref expected_output), true) if !stderr.contains(expected_output) => {
                bail!(ErrorKind::ErrorOutputMismatch(
                    expected_output.clone(),
                    stderr.into(),
                ));
            },
            (Some(ref expected_output), false) => {
                let differences = Changeset::new(expected_output.trim(), stderr.trim(), "\n");
                if differences.distance > 0 {
                    let nice_diff = diff::render(&differences)?;
                    bail!(ErrorKind::ExactErrorOutputMismatch(nice_diff));
                }
            },
            _ => {},
        }

        Ok(())
    }

    /// Execute the command, check the assertions, and panic when they fail.
    ///
    /// # Examples
    ///
    /// ```rust,should_panic="Assert CLI failure"
    /// extern crate assert_cli;
    ///
    /// assert_cli::Assert::command(&["echo", "42"])
    ///     .fails()
    ///     .unwrap(); // panics
    /// ```
    pub fn unwrap(self) {
        if let Err(err) = self.execute() {
            panic!("Assert CLI failure:\n{}", err);
        }
    }
}

/// Easily construct an `Assert` with a custom command.
///
/// Make sure to include the crate as `#[macro_use] extern crate assert_cli;` if
/// you want to use this macro.
///
/// # Examples
///
/// To test that our very complex cli applications succeeds and prints some
/// text to stdout that contains
///
/// ```plain
/// No errors whatsoever
/// ```
///
/// ...,  you would call it like this:
///
/// ```rust
/// #[macro_use] extern crate assert_cli;
/// # fn main() {
/// assert_cmd!(echo "Launch sequence initiated.\nNo errors whatsoever!\n")
///     .succeeds()
///     .prints("No errors whatsoever")
///     .unwrap();
/// # }
/// ```
///
/// The macro will try to convert its arguments as strings, but is limited by
/// Rust's default tokenizer, e.g., you always need to quote CLI arguments
/// like `"--verbose"`.
#[macro_export]
macro_rules! assert_cmd {
    ($($x:tt)+) => {{
        $crate::Assert::command(
            &[$(stringify!($x)),*]
        )
    }}
}
<|endoftext|>


<commit_before>#[macro_use] extern crate bitflags;
extern crate gl as gl_lib;
#[cfg(feature = "cgmath")] extern crate cgmath as cgmath_lib;
#[cfg(feature = "image")] extern crate image as image_lib;

mod ref_into;

#[macro_use] mod macros;
mod context;
mod buffer;
mod shader;
mod program;
mod framebuffer;
mod renderbuffer;
mod texture;
mod texture_units;
mod image_data;
mod vertex_data;
mod vertex_buffer;
mod index_data;
mod uniform_data;
mod types;

#[cfg(feature = "cgmath")] mod cgmath_features;
#[cfg(feature = "image")] mod image_features;

pub use gl_lib as gl;
#[cfg(feature = "cgmath")] pub use cgmath_lib as cgmath;
#[cfg(feature = "image")] pub use image_lib as image;

pub use context::*;
pub use buffer::*;
pub use shader::*;
pub use program::*;
pub use framebuffer::*;
pub use renderbuffer::*;
pub use texture::*;
pub use texture_units::*;
pub use image_data::*;
pub use vertex_data::*;
pub use vertex_buffer::*;
pub use index_data::*;
pub use uniform_data::*;
pub use types::*;

pub mod prelude {
    pub use buffer::BufferBinding;
    pub use texture_units::TextureUnit;
    pub use texture::TextureBinding;
}
<commit_msg>Add `BufferContext` traits to the prelude module<commit_after>#[macro_use] extern crate bitflags;
extern crate gl as gl_lib;
#[cfg(feature = "cgmath")] extern crate cgmath as cgmath_lib;
#[cfg(feature = "image")] extern crate image as image_lib;

mod ref_into;

#[macro_use] mod macros;
mod context;
mod buffer;
mod shader;
mod program;
mod framebuffer;
mod renderbuffer;
mod texture;
mod texture_units;
mod image_data;
mod vertex_data;
mod vertex_buffer;
mod index_data;
mod uniform_data;
mod types;

#[cfg(feature = "cgmath")] mod cgmath_features;
#[cfg(feature = "image")] mod image_features;

pub use gl_lib as gl;
#[cfg(feature = "cgmath")] pub use cgmath_lib as cgmath;
#[cfg(feature = "image")] pub use image_lib as image;

pub use context::*;
pub use buffer::*;
pub use shader::*;
pub use program::*;
pub use framebuffer::*;
pub use renderbuffer::*;
pub use texture::*;
pub use texture_units::*;
pub use image_data::*;
pub use vertex_data::*;
pub use vertex_buffer::*;
pub use index_data::*;
pub use uniform_data::*;
pub use types::*;

pub mod prelude {
    pub use buffer::{BufferBinding, BufferContext,
                     ArrayBufferContext, ElementArrayBufferContext};
    pub use texture_units::TextureUnit;
    pub use texture::TextureBinding;
}
<|endoftext|>


<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2015 dinowernli
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

extern crate rand;
#[macro_use] extern crate log;

pub mod agent;
pub mod bitstring;
pub mod environment;
pub mod logger;
pub mod predictor;
pub mod random;
pub mod types;

// Unit test modules.

#[cfg(test)]
pub mod agent_test;

#[cfg(test)]
pub mod bitstring_test;

<commit_msg>Make the module declarations more compact.<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2015 dinowernli
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

extern crate rand;
#[macro_use] extern crate log;

pub mod agent;
pub mod bitstring;
pub mod environment;
pub mod logger;
pub mod predictor;
pub mod random;
pub mod types;

// Unit test modules.

#[cfg(test)] pub mod agent_test;
#[cfg(test)] pub mod bitstring_test;

<|endoftext|>


<commit_before>#![doc(html_root_url = "https://docs.rs/hyper/0.13.2")]
#![deny(missing_docs)]
#![deny(missing_debug_implementations)]
#![cfg_attr(test, deny(rust_2018_idioms))]
#![cfg_attr(test, deny(warnings))]
#![cfg_attr(all(test, feature = "nightly"), feature(test))]

//! # hyper
//!
//! hyper is a **fast** and **correct** HTTP implementation written in and for Rust.
//!
//! ## Features
//!
//! - HTTP/1 and HTTP/2
//! - Asynchronous design
//! - Leading in performance
//! - Tested and **correct**
//! - Extensive production use
//! - [Client](client/index.html) and [Server](server/index.html) APIs
//!
//! If just starting out, **check out the [Guides](https://hyper.rs/guides)
//! first.**
//!
//! ## "Low-level"
//!
//! hyper is a lower-level HTTP library, meant to be a building block
//! for libaries and applications.
//!
//! If looking for just a convenient HTTP client, consider the
//! [reqwest](https://crates.io/crates/reqwest) crate.
//!
//! # Optional Features
//!
//! The following optional features are available:
//!
//! - `runtime` (*enabled by default*): Enables convenient integration with
//!   `tokio`, providing connectors and acceptors for TCP, and a default
//!   executor.
//! - `tcp` (*enabled by default*): Enables convenient implementations over
//!   TCP (using tokio).
//! - `stream` (*enabled by default*): Provides `futures::Stream` capabilities.

#[doc(hidden)]
pub use http;
#[macro_use]
extern crate log;

#[cfg(all(test, feature = "nightly"))]
extern crate test;

pub use http::{header, HeaderMap, Method, Request, Response, StatusCode, Uri, Version};

pub use crate::body::Body;
pub use crate::client::Client;
pub use crate::error::{Error, Result};
pub use crate::server::Server;

#[macro_use]
mod common;
pub mod body;
pub mod client;
pub mod error;
mod headers;
#[cfg(test)]
mod mock;
mod proto;
pub mod rt;
pub mod server;
pub mod service;
pub mod upgrade;
<commit_msg>doc(lib): hide error module documentation<commit_after>#![doc(html_root_url = "https://docs.rs/hyper/0.13.2")]
#![deny(missing_docs)]
#![deny(missing_debug_implementations)]
#![cfg_attr(test, deny(rust_2018_idioms))]
#![cfg_attr(test, deny(warnings))]
#![cfg_attr(all(test, feature = "nightly"), feature(test))]

//! # hyper
//!
//! hyper is a **fast** and **correct** HTTP implementation written in and for Rust.
//!
//! ## Features
//!
//! - HTTP/1 and HTTP/2
//! - Asynchronous design
//! - Leading in performance
//! - Tested and **correct**
//! - Extensive production use
//! - [Client](client/index.html) and [Server](server/index.html) APIs
//!
//! If just starting out, **check out the [Guides](https://hyper.rs/guides)
//! first.**
//!
//! ## "Low-level"
//!
//! hyper is a lower-level HTTP library, meant to be a building block
//! for libaries and applications.
//!
//! If looking for just a convenient HTTP client, consider the
//! [reqwest](https://crates.io/crates/reqwest) crate.
//!
//! # Optional Features
//!
//! The following optional features are available:
//!
//! - `runtime` (*enabled by default*): Enables convenient integration with
//!   `tokio`, providing connectors and acceptors for TCP, and a default
//!   executor.
//! - `tcp` (*enabled by default*): Enables convenient implementations over
//!   TCP (using tokio).
//! - `stream` (*enabled by default*): Provides `futures::Stream` capabilities.

#[doc(hidden)]
pub use http;
#[macro_use]
extern crate log;

#[cfg(all(test, feature = "nightly"))]
extern crate test;

pub use http::{header, HeaderMap, Method, Request, Response, StatusCode, Uri, Version};

pub use crate::body::Body;
pub use crate::client::Client;
pub use crate::error::{Error, Result};
pub use crate::server::Server;

#[macro_use]
mod common;
pub mod body;
pub mod client;
#[doc(hidden)] // Mistakenly public...
pub mod error;
mod headers;
#[cfg(test)]
mod mock;
mod proto;
pub mod rt;
pub mod server;
pub mod service;
pub mod upgrade;
<|endoftext|>


<commit_before>extern crate iron;
extern crate rustc_serialize;
extern crate url;
extern crate filetime;

pub use self::static_dir::StaticDir;
pub use self::respond_with_dir::AsJson;

mod static_dir;
mod errors;
pub mod respond_with_dir;
<commit_msg>fixed pub<commit_after>extern crate iron;
extern crate rustc_serialize;
extern crate url;
extern crate filetime;

pub use self::static_dir::StaticDir;
pub use self::static_dir::ResponseStrategy;
pub use self::respond_with_dir::AsJson;

mod static_dir;
pub mod errors;
mod respond_with_dir;
<|endoftext|>