<commit_before>// ! Spit string with a delimeter.

// xxx

pub( crate ) mod internal
{

  /* xxx : qqq : tab after git sync */

// use woptions::*; /* xxx : use prelude */

///
/// Either delimeter or delimeted with the slice on its string.
///

#[allow(dead_code)]
#[ derive( Debug ) ]
pub struct Split< 'a >
{
  string : &'a str,
  typ : SplitType,
}

impl< 'a > From< Split< 'a > > for String
{
  fn from( src : Split ) -> Self
  {
    src.string.into()
  }
}

///
/// Either delimeter or delimeted
///

#[ derive( Debug ) ]
pub enum SplitType
{
  /// Substring of the original string with text inbetween delimeters.
  Delimeted,
  /// Delimeter.
  Delimeter,
}

///
/// Find first match in the string.
///

pub trait Searcher
{
  /// Find positions of delimeter.
  fn pos( &self, src : &str ) -> Option< ( usize, usize ) >;
}

impl Searcher for &str
{
  fn pos( &self, src : &str ) -> Option< ( usize, usize ) >
  {
    src.find( self ).map( | start | ( start, start + self.len() ) )
  }
}

///
/// Split iterator.
///

#[ derive( Debug ) ]
pub struct SplitIterator< 'a, D >
where
  D : Searcher
{
  iterable : &'a str,
  counter : i32,
  delimeter : D,
  preserving_empty : bool,
  preserving_delimeters : bool,
  stripping : bool,
  stop_empty : bool,
}

//

impl< 'a, D : Searcher > SplitIterator< 'a, D >
{
  fn new
  (
    src : &'a str,
    delimeter : D,
    preserving_empty : bool,
    preserving_delimeters : bool,
    stripping : bool
  ) -> Self
  {
    Self
    {
      iterable : src,
      delimeter,
      counter : 0,
      preserving_empty,
      preserving_delimeters,
      stripping,
      stop_empty : false,
    }
  }
}

//

impl< 'a, D > Iterator for SplitIterator< 'a, D >
where
  D : Searcher
{
  type Item = Split< 'a >;

  fn next( &mut self ) -> Option< Self::Item >
  {
    self.counter += 1;

    if self.counter % 2 == 1
    {
      let positions = self.delimeter.pos( self.iterable );
      if let Some( ( mut start, end ) ) = positions
      {
        if self.iterable == "" && start == end
        {
          if self.stop_empty
          {
            return None;
          }
          else
          {
            self.counter -= 1;
            self.stop_empty = true;
            return Some( Split { string : "", typ : SplitType::Delimeted } );
          }
        }
        let mut next = &self.iterable[ ..start ];
        if start == end
        {
          if self.counter >= 3
          {
            next = &self.iterable[ ..start+1 ];
            start += 1;
          }
        }
        if self.stripping
        {
          next = next.trim();
        }

        self.iterable = &self.iterable[ start.. ];

        Some( Split { string : next, typ : SplitType::Delimeted } )
      }
      else
      {
        return self.next_end_split();
      }
    }
    else
    {
      if self.delimeter.pos( self.iterable ).is_none()
      {
        self.iterable = "";
        return None;
      }

      let ( start, end ) = self.delimeter.pos( self.iterable ).unwrap();
      let mut string = &self.iterable[ start..end ];
      self.iterable = &self.iterable[ end.. ];

      if self.stripping
      {
        string = string.trim();

        if string.is_empty() && !self.preserving_empty
        {
          return self.next_odd_split();
        }
      }

      if self.preserving_delimeters
      {
        return Some( Split { string, typ : SplitType::Delimeter } );
      }
      else
      {
        return self.next_odd_split();
      }
    }
  }
}

impl< 'a, D > SplitIterator< 'a, D >
where
  D : Searcher
{
  fn next_end_split( &mut self ) -> Option< Split< 'a > >
  {
    if self.iterable == ""
    {
      return None;
    }
    else
    {
      let mut string = self.iterable;
      if self.stripping
      {
        string = string.trim();
      }
      let r = Split { string, typ : SplitType::Delimeted };
      self.iterable = "";
      return Some( r );
    }
  }

  fn next_odd_split( &mut self ) -> Option< Split< 'a > >
  {
    match self.delimeter.pos( self.iterable )
    {
      Some( ( start, mut end ) ) =>
      {
        let mut string = &self.iterable[ ..start ];

        if start == end
        {
          string = &self.iterable[ ..start+1 ];
          end += 1;
        }
        self.iterable = &self.iterable[ end.. ];
        if self.stripping
        {
          string = string.trim();
        }
        return Some( Split { string, typ : SplitType::Delimeted } );
      },
      None =>
      {
        self.next_end_split()
      },
    }
  }
}

///
/// Options of function split.
///

#[ derive( Debug ) ]
pub struct SplitOptions< 'a, D >
where
  D : Searcher + Default + Clone
{
  src : &'a str,
  delimeter : D,
  preserving_empty : bool,
  preserving_delimeters : bool,
  stripping : bool,
}

//

macro_rules! builder_impls_from
{
  ( $name : ident, $( ( $field : ident, $type : ty ) ),* $( , )? ) =>
  {
    impl< 'a, D > $name< 'a, D >
    where
      D : Searcher + Default + Clone
    {
      $(
        pub fn $field( mut self, value : $type ) -> $name< 'a, D >
        {
          assert!( !self.formed, "Already formed" );
          self.$field = value;
          self
        }
      )*

      pub fn form( mut self ) -> $name< 'a, D >
      {
        assert!( !self.formed, "Already formed" );
        self.formed = true;
        self
      }
    }
  }
}

/// Builder.
#[ derive( Debug ) ]
pub struct SplitOptionsBuilder< 'a, D >
where
  D : Searcher + Default + Clone
{

  src : &'a str,
  delimeter : D,
  preserving_empty : bool,
  preserving_delimeters : bool,
  stripping : bool,
  formed : bool,
}
builder_impls_from!( SplitOptionsBuilder, ( src, &'a str ), ( preserving_empty, bool ), ( preserving_delimeters, bool ), ( stripping, bool ) );

impl< 'a, D > SplitOptionsBuilder< 'a, D >
where
  D : Searcher + Default + Clone
{
  pub fn new( delimeter : D ) -> SplitOptionsBuilder< 'a, D >
  {
    Self
    {
      src : "",
      delimeter,
      preserving_empty : true,
      preserving_delimeters : true,
      stripping : true,
      formed : false,
    }
  }

  pub fn delimeter( mut self, value : D ) -> SplitOptionsBuilder< 'a, D >
  {
    assert!( !self.formed, "Already formed" );
    self.delimeter = value;
    self
  }

  pub fn perform( &self ) -> SplitIterator< 'a, D >
  {
    let opts = SplitOptions
    {
      src : self.src,
      delimeter : self.delimeter.clone(),
      preserving_empty : self.preserving_empty,
      preserving_delimeters : self.preserving_delimeters,
      stripping : self.stripping,
    };
    opts.split()
  }
}

///
/// Adapter for Split Options.
///

pub trait SplitOptionsAdapter< 'a, D >
{
  /// A string to split.
  fn src( &self ) -> &'a str;
  /// A delimeter to split string.
  fn delimeter( &self ) -> D;
  /// Preserving or dropping empty splits.
  fn preserving_empty( &self ) -> bool;
  /// Preserving or dropping delimeters.
  fn preserving_delimeters( &self ) -> bool;
  /// Stripping.
  fn stripping( &self ) -> bool;
  /// Do splitting.
  fn split( self ) -> SplitIterator< 'a, D >
  where
    Self : Sized,
    D : Searcher + Default,
  {
    SplitIterator::new
    (
      self.src(),
      self.delimeter(),
      self.preserving_empty(),
      self.preserving_delimeters(),
      self.stripping()
    )
  }
}

//

impl< 'a, D > SplitOptionsAdapter< 'a, D > for SplitOptions< 'a, D >
where
  D : Searcher + Default + Clone,
{
  fn src( &self ) -> &'a str
  {
    self.src
  }
  fn delimeter( &self ) -> D
  {
    self.delimeter.clone()
  }
  fn preserving_empty( &self ) -> bool
  {
    self.preserving_empty
  }
  fn preserving_delimeters( &self ) -> bool
  {
    self.preserving_delimeters
  }
  fn stripping( &self ) -> bool
  {
    self.stripping
  }
}

///
/// Function to split a string.
///
/// It produces former. To convert former into options and run algorithm of splitting call `form()`.
///
/// # Sample
/// ```
///   let iter = wstring_tools::string::split()
///   .src( "abc def" )
///   .delimeter( " " )
///   .perform();
/// ```

pub fn split< 'a >() -> SplitOptionsBuilder< 'a, &'a str >
{
  SplitOptionsBuilder::new( < &str >::default() )
}

}

/// Owned namespace of the module.
pub mod own
{
  use super::internal as i;

  pub use i::Split;
  pub use i::SplitType;
  pub use i::SplitIterator;
  pub use i::SplitOptions;
  pub use i::SplitOptionsAdapter;
  pub use i::split;
}

pub use own::*;

/// Exposed namespace of the module.
pub mod exposed
{
  use super::internal as i;

  pub use i::SplitOptionsAdapter;
  pub use i::split;
}

/// Namespace of the module to include with `use module::*`.
pub mod prelude
{
  use super::internal as i;

  pub use i::SplitOptionsAdapter;
}
<commit_msg>Extend module `split`, implement trait `Searcher` for vector of string slices<commit_after>// ! Spit string with a delimeter.

// xxx

pub( crate ) mod internal
{

  /* xxx : qqq : tab after git sync */

// use woptions::*; /* xxx : use prelude */

///
/// Either delimeter or delimeted with the slice on its string.
///

#[allow(dead_code)]
#[ derive( Debug ) ]
pub struct Split< 'a >
{
  string : &'a str,
  typ : SplitType,
}

impl< 'a > From< Split< 'a > > for String
{
  fn from( src : Split ) -> Self
  {
    src.string.into()
  }
}

///
/// Either delimeter or delimeted
///

#[ derive( Debug ) ]
pub enum SplitType
{
  /// Substring of the original string with text inbetween delimeters.
  Delimeted,
  /// Delimeter.
  Delimeter,
}

///
/// Find first match in the string.
///

pub trait Searcher
{
  /// Find positions of delimeter.
  fn pos( &self, src : &str ) -> Option< ( usize, usize ) >;
}

impl Searcher for &str
{
  fn pos( &self, src : &str ) -> Option< ( usize, usize ) >
  {
    src.find( self ).map( | start | ( start, start + self.len() ) )
  }
}

impl Searcher for String
{
  fn pos( &self, src : &str ) -> Option< ( usize, usize ) >
  {
    src.find( self ).map( | start | ( start, start + self.len() ) )
  }
}

impl Searcher for Vec<&str>
{
  fn pos( &self, src : &str ) -> Option< ( usize, usize ) >
  {
    let mut r = vec![];
    for pat in self
    {
      match src.find( pat )
      {
        Some( x ) => r.push( ( x, x + pat.len() ) ),
        None => (),
      }
    }

    if r.is_empty()
    {
      return None;
    }

    r.into_iter().reduce( | accum, item |
    {
      if accum.0 > item.0
      {
        item
      }
      else
      {
        if accum.1 > item.1
        {
          item
        }
        else
        {
          accum
        }
      }
    })
  }
}

///
/// Split iterator.
///

#[ derive( Debug ) ]
pub struct SplitIterator< 'a, D >
where
  D : Searcher
{
  iterable : &'a str,
  counter : i32,
  delimeter : D,
  preserving_empty : bool,
  preserving_delimeters : bool,
  stripping : bool,
  stop_empty : bool,
}

//

impl< 'a, D : Searcher > SplitIterator< 'a, D >
{
  fn new
  (
    src : &'a str,
    delimeter : D,
    preserving_empty : bool,
    preserving_delimeters : bool,
    stripping : bool
  ) -> Self
  {
    Self
    {
      iterable : src,
      delimeter,
      counter : 0,
      preserving_empty,
      preserving_delimeters,
      stripping,
      stop_empty : false,
    }
  }
}

//

impl< 'a, D > Iterator for SplitIterator< 'a, D >
where
  D : Searcher
{
  type Item = Split< 'a >;

  fn next( &mut self ) -> Option< Self::Item >
  {
    self.counter += 1;

    if self.counter % 2 == 1
    {
      let positions = self.delimeter.pos( self.iterable );
      if let Some( ( mut start, end ) ) = positions
      {
        if self.iterable == "" && start == end
        {
          if self.stop_empty
          {
            return None;
          }
          else
          {
            self.counter -= 1;
            self.stop_empty = true;
            return Some( Split { string : "", typ : SplitType::Delimeted } );
          }
        }
        let mut next = &self.iterable[ ..start ];
        if start == end
        {
          if self.counter >= 3
          {
            next = &self.iterable[ ..start + 1 ];
            start += 1;
          }
        }
        if self.stripping
        {
          next = next.trim();
        }

        self.iterable = &self.iterable[ start.. ];

        Some( Split { string : next, typ : SplitType::Delimeted } )
      }
      else
      {
        return self.next_end_split();
      }
    }
    else
    {
      if self.delimeter.pos( self.iterable ).is_none()
      {
        self.iterable = "";
        return None;
      }

      let ( start, end ) = self.delimeter.pos( self.iterable ).unwrap();
      let mut string = &self.iterable[ start..end ];
      self.iterable = &self.iterable[ end.. ];

      if self.stripping
      {
        string = string.trim();

        if string.is_empty() && !self.preserving_empty
        {
          return self.next_odd_split();
        }
      }

      if self.preserving_delimeters
      {
        return Some( Split { string, typ : SplitType::Delimeter } );
      }
      else
      {
        return self.next_odd_split();
      }
    }
  }
}

impl< 'a, D > SplitIterator< 'a, D >
where
  D : Searcher
{
  fn next_end_split( &mut self ) -> Option< Split< 'a > >
  {
    if self.iterable == ""
    {
      return None;
    }
    else
    {
      let mut string = self.iterable;
      if self.stripping
      {
        string = string.trim();
      }
      let r = Split { string, typ : SplitType::Delimeted };
      self.iterable = "";
      return Some( r );
    }
  }

  fn next_odd_split( &mut self ) -> Option< Split< 'a > >
  {
    match self.delimeter.pos( self.iterable )
    {
      Some( ( start, mut end ) ) =>
      {
        let mut string = &self.iterable[ ..start ];

        if start == end
        {
          string = &self.iterable[ ..start + 1 ];
          end += 1;
        }
        self.iterable = &self.iterable[ end.. ];
        if self.stripping
        {
          string = string.trim();
        }
        return Some( Split { string, typ : SplitType::Delimeted } );
      },
      None =>
      {
        self.next_end_split()
      },
    }
  }
}

///
/// Options of function split.
///

#[ derive( Debug ) ]
pub struct SplitOptions< 'a, D >
where
  D : Searcher + Default + Clone
{
  src : &'a str,
  delimeter : D,
  preserving_empty : bool,
  preserving_delimeters : bool,
  stripping : bool,
}

//

macro_rules! builder_impls_from
{
  ( $name : ident, $( ( $field : ident, $type : ty ) ),* $( , )? ) =>
  {
    impl< 'a, D > $name< 'a, D >
    where
      D : Searcher + Default + Clone
    {
      $(
        pub fn $field( mut self, value : $type ) -> $name< 'a, D >
        {
          assert!( !self.formed, "Already formed" );
          self.$field = value;
          self
        }
      )*

      pub fn form( mut self ) -> $name< 'a, D >
      {
        assert!( !self.formed, "Already formed" );
        self.formed = true;
        self
      }
    }
  }
}

/// Builder.
#[ derive( Debug ) ]
pub struct SplitOptionsBuilder< 'a, D >
where
  D : Searcher + Default + Clone
{

  src : &'a str,
  delimeter : D,
  preserving_empty : bool,
  preserving_delimeters : bool,
  stripping : bool,
  formed : bool,
}
builder_impls_from!( SplitOptionsBuilder, ( src, &'a str ), ( preserving_empty, bool ), ( preserving_delimeters, bool ), ( stripping, bool ) );

impl< 'a, D > SplitOptionsBuilder< 'a, D >
where
  D : Searcher + Default + Clone
{
  pub fn new( delimeter : D ) -> SplitOptionsBuilder< 'a, D >
  {
    Self
    {
      src : "",
      delimeter,
      preserving_empty : true,
      preserving_delimeters : true,
      stripping : true,
      formed : false,
    }
  }

  pub fn delimeter( mut self, value : D ) -> SplitOptionsBuilder< 'a, D >
  {
    assert!( !self.formed, "Already formed" );
    self.delimeter = value;
    self
  }

  pub fn perform( &mut self ) -> SplitIterator< 'a, D >
  {
    if !self.formed
    {
      self.formed = true;
    }

    let opts = SplitOptions
    {
      src : self.src,
      delimeter : self.delimeter.clone(),
      preserving_empty : self.preserving_empty,
      preserving_delimeters : self.preserving_delimeters,
      stripping : self.stripping,
    };
    opts.split()
  }
}

///
/// Adapter for Split Options.
///

pub trait SplitOptionsAdapter< 'a, D >
{
  /// A string to split.
  fn src( &self ) -> &'a str;
  /// A delimeter to split string.
  fn delimeter( &self ) -> D;
  /// Preserving or dropping empty splits.
  fn preserving_empty( &self ) -> bool;
  /// Preserving or dropping delimeters.
  fn preserving_delimeters( &self ) -> bool;
  /// Stripping.
  fn stripping( &self ) -> bool;
  /// Do splitting.
  fn split( self ) -> SplitIterator< 'a, D >
  where
    Self : Sized,
    D : Searcher + Default,
  {
    SplitIterator::new
    (
      self.src(),
      self.delimeter(),
      self.preserving_empty(),
      self.preserving_delimeters(),
      self.stripping()
    )
  }
}

//

impl< 'a, D > SplitOptionsAdapter< 'a, D > for SplitOptions< 'a, D >
where
  D : Searcher + Default + Clone,
{
  fn src( &self ) -> &'a str
  {
    self.src
  }
  fn delimeter( &self ) -> D
  {
    self.delimeter.clone()
  }
  fn preserving_empty( &self ) -> bool
  {
    self.preserving_empty
  }
  fn preserving_delimeters( &self ) -> bool
  {
    self.preserving_delimeters
  }
  fn stripping( &self ) -> bool
  {
    self.stripping
  }
}

///
/// Function to split a string.
///
/// It produces former. To convert former into options and run algorithm of splitting call `form()`.
///
/// # Sample
/// ```
///   let iter = wstring_tools::string::split()
///   .src( "abc def" )
///   .delimeter( " " )
///   .perform();
/// ```

pub fn split< 'a >() -> SplitOptionsBuilder< 'a, &'a str >
{
  SplitOptionsBuilder::new( < &str >::default() )
}

///

pub fn split_generic< 'a, D : Searcher + Default + Clone >() -> SplitOptionsBuilder< 'a, D >
{
  SplitOptionsBuilder::new( <D>::default() )
}

}

/// Owned namespace of the module.
pub mod own
{
  use super::internal as i;

  pub use i::Split;
  pub use i::SplitType;
  pub use i::SplitIterator;
  pub use i::SplitOptions;
  pub use i::SplitOptionsAdapter;
  pub use i::split;
  pub use i::split_generic;
}

pub use own::*;

/// Exposed namespace of the module.
pub mod exposed
{
  use super::internal as i;

  pub use i::SplitOptionsAdapter;
  pub use i::split;
  pub use i::split_generic;
}

/// Namespace of the module to include with `use module::*`.
pub mod prelude
{
  use super::internal as i;

  pub use i::SplitOptionsAdapter;
}
<|endoftext|>


<commit_before>pub mod specifiers_iterator;

use std::ffi::CString;
use std::vec::Vec;

/// A common trait for all types that can be passed into `fmt!`.
pub trait Printfable {
    /// The type this converts to through `to_c_repr`.
    type Holder;

    /// Converts Self into a type that C language (and thus `snprintf`) understands.
    fn to_c_repr(self: &Self) -> <Self as Printfable>::Holder;
}

impl Printfable for i32 {
    type Holder = i32;
    fn to_c_repr(self: &Self) -> <Self as Printfable>::Holder {
        *self
    }
}

impl Printfable for u32 {
    type Holder = u32;
    fn to_c_repr(self: &Self) -> <Self as Printfable>::Holder {
        *self
    }
}

impl Printfable for i64 {
    type Holder = i64;
    fn to_c_repr(self: &Self) -> <Self as Printfable>::Holder {
        *self
    }
}

impl Printfable for u64 {
    type Holder = u64;
    fn to_c_repr(self: &Self) -> <Self as Printfable>::Holder {
        *self
    }
}

/// `f32` can't be passed to variadic functions like `snprintf`, so it's converted into `f64`
impl Printfable for f32 {
    type Holder = f64;
    fn to_c_repr(self: &Self) -> <Self as Printfable>::Holder {
        *self as f64
    }
}

impl Printfable for f64 {
    type Holder = f64;
    fn to_c_repr(self: &Self) -> <Self as Printfable>::Holder {
        *self
    }
}

/// Helper function for `fmt!`. Don't use directly.
pub fn fmt_arg<T>(format: &str, arg: T) -> Option<String>
where
    T: Printfable,
{
    // Might fail if `format` contains a null byte. TODO decide if this is a good
    // error-handling strategy, or we should report back to user, or panic, or what
    CString::new(format).ok().and_then(|local_format_cstring| {
        let buf_size = 1024usize;
        let mut buffer = Vec::<u8>::with_capacity(buf_size);
        // Filling the vector with ones because CString::new() doesn't want any zeroes in
        // there. The last byte is left unused, so that CString::new() can put a terminating
        // zero byte without triggering a re-allocation.
        buffer.resize(buf_size - 1, 1);
        CString::new(buffer).ok().and_then(|buffer| unsafe {
            let buffer_ptr = buffer.into_raw();
            // TODO: check how many bytes were written
            let bytes_written = libc::snprintf(
                buffer_ptr,
                buf_size as libc::size_t,
                local_format_cstring.as_ptr() as *const libc::c_char,
                arg.to_c_repr(),
            );
            let buffer = CString::from_raw(buffer_ptr);
            let _bytes_written = bytes_written as usize;
            buffer.into_string().ok()
        })
    })
}

/// A safe-ish wrapper around `libc::snprintf`.
#[macro_export]
macro_rules! fmt {
    ( $format:expr ) => {
        {
            let format: &str = $format;
            String::from(format)
        }
    };

    ( $format:expr, $( $arg:expr ),+ ) => {
        {
            let format: &str = $format;

            let mut result = String::new();

            use $crate::specifiers_iterator::SpecifiersIterator;
            let mut specifiers = SpecifiersIterator::from(format);

            $(
                let local_format = specifiers.next().unwrap_or("");
                if let Some(formatted_string) = $crate::fmt_arg(local_format, $arg) {
                    result.push_str(&formatted_string);
                }
            )+

            result
        }
    };
}

#[cfg(test)]
mod tests {
    #[test]
    fn returns_first_argument_if_it_is_the_only_one() {
        let input = String::from("Hello, world!");
        assert_eq!(fmt!(&input), input);
    }

    #[test]
    fn replaces_printf_format_with_text_representation_of_an_argument() {
        assert_eq!(fmt!("%i", 42), "42");
        assert_eq!(fmt!("%i", -13), "-13");
        assert_eq!(fmt!("%.3f", 3.1416), "3.142");
        assert_eq!(fmt!("%i %i", 100500, -191), "100500 -191");
    }

    #[test]
    fn formats_i32() {
        assert_eq!(fmt!("%i", 42i32), "42");
        assert_eq!(fmt!("%i", std::i32::MIN), "-2147483648");
        assert_eq!(fmt!("%i", std::i32::MAX), "2147483647");
    }

    #[test]
    fn formats_u32() {
        assert_eq!(fmt!("%u", 42u32), "42");
        assert_eq!(fmt!("%u", 0u32), "0");
        assert_eq!(fmt!("%u", std::u32::MAX), "4294967295");
    }

    #[test]
    fn formats_i64() {
        assert_eq!(fmt!("%li", 42i64), "42");
        assert_eq!(fmt!("%li", std::i32::MIN as i64 - 1), "-2147483649");
        assert_eq!(fmt!("%li", std::i32::MAX as i64 + 1), "2147483648");

        assert_eq!(fmt!("%lli", 42i64), "42");
        assert_eq!(fmt!("%lli", std::i64::MIN), "-9223372036854775808");
        assert_eq!(fmt!("%lli", std::i64::MAX), "9223372036854775807");
    }

    #[test]
    fn formats_u64() {
        assert_eq!(fmt!("%lu", 42u64), "42");
        assert_eq!(fmt!("%lu", 0u64), "0");
        assert_eq!(fmt!("%lu", std::u64::MAX), "18446744073709551615");

        assert_eq!(fmt!("%llu", 42u64), "42");
        assert_eq!(fmt!("%llu", 0u64), "0");
        assert_eq!(fmt!("%llu", std::u64::MAX), "18446744073709551615");
    }

    /*
    TEST_CASE("strprintf::fmt() formats void*", "[strprintf]")
    {
            const auto x = 42;
            REQUIRE_FALSE(strprintf::fmt("%p", reinterpret_cast<const void*>(&x)).empty());
    }

    TEST_CASE("strprintf::fmt() formats nullptr", "[strprintf]")
    {
            REQUIRE_FALSE(strprintf::fmt("%p", nullptr) == "(null)");
    }
    */

    #[test]
    fn formats_float() {
        let x = 42.0f32;
        assert_eq!(fmt!("%f", x), "42.000000");
        assert_eq!(fmt!("%.3f", x), "42.000");

        let y = 42e3f32;
        assert_eq!(fmt!("%e", y), "4.200000e+04");
        assert_eq!(fmt!("%.3e", y), "4.200e+04");

        assert_eq!(fmt!("%f", std::f32::INFINITY), "inf");
        assert_eq!(fmt!("%F", std::f32::INFINITY), "INF");

        assert_eq!(fmt!("%f", std::f32::NEG_INFINITY), "-inf");
        assert_eq!(fmt!("%F", std::f32::NEG_INFINITY), "-INF");

        assert_eq!(fmt!("%f", std::f32::NAN), "nan");
        assert_eq!(fmt!("%F", std::f32::NAN), "NAN");
    }

    #[test]
    fn formats_double() {
        let x = 42.0f64;
        assert_eq!(fmt!("%f", x), "42.000000");
        assert_eq!(fmt!("%.3f", x), "42.000");

        let y = 42e138f64;
        assert_eq!(fmt!("%e", y), "4.200000e+139");
        assert_eq!(fmt!("%.3e", y), "4.200e+139");

        assert_eq!(fmt!("%f", std::f64::INFINITY), "inf");
        assert_eq!(fmt!("%F", std::f64::INFINITY), "INF");

        assert_eq!(fmt!("%f", std::f64::NEG_INFINITY), "-inf");
        assert_eq!(fmt!("%F", std::f64::NEG_INFINITY), "-INF");

        assert_eq!(fmt!("%f", std::f64::NAN), "nan");
        assert_eq!(fmt!("%F", std::f64::NAN), "NAN");
    }

    /*
    // TODO: write the same test for str
    // TODO: write the same test for &str
    // TODO: write the same test for String
    TEST_CASE("strprintf::fmt() formats std::string", "[strprintf]")
    {
            const auto input = std::string("Hello, world!");
            REQUIRE(strprintf::fmt("%s", input) == input);
    }

    TEST_CASE("strprintf::fmt() works fine with 1MB format string", "[strprintf]")
    {
            const auto format = std::string(1024 * 1024, ' ');
            REQUIRE(strprintf::fmt(format) == format);
    }
    */
}
<commit_msg>Implement fmt! for &str<commit_after>extern crate libc;

pub mod specifiers_iterator;

// TODO: move traits into a separate mod, they occupy too much space here
// TODO: write an internal module doc explaining the interplay between traits, fmt_arg, and fmt!

use std::ffi::CString;
use std::vec::Vec;

pub trait Printfable {
    type Holder: CReprHolder;
    fn to_c_repr_holder(self: &Self) -> Option<<Self as Printfable>::Holder>;
}

impl Printfable for i32 {
    type Holder = i32;
    fn to_c_repr_holder(self: &Self) -> Option<<Self as Printfable>::Holder> {
        Some(*self)
    }
}

impl Printfable for u32 {
    type Holder = u32;
    fn to_c_repr_holder(self: &Self) -> Option<<Self as Printfable>::Holder> {
        Some(*self)
    }
}

impl Printfable for i64 {
    type Holder = i64;
    fn to_c_repr_holder(self: &Self) -> Option<<Self as Printfable>::Holder> {
        Some(*self)
    }
}

impl Printfable for u64 {
    type Holder = u64;
    fn to_c_repr_holder(self: &Self) -> Option<<Self as Printfable>::Holder> {
        Some(*self)
    }
}

/// `f32` can't be passed to variadic functions like `snprintf`, so it's converted into `f64`
impl Printfable for f32 {
    type Holder = f64;
    fn to_c_repr_holder(self: &Self) -> Option<<Self as Printfable>::Holder> {
        Some(*self as f64)
    }
}

impl Printfable for f64 {
    type Holder = f64;
    fn to_c_repr_holder(self: &Self) -> Option<<Self as Printfable>::Holder> {
        Some(*self)
    }
}

impl<'a> Printfable for &'a str {
    type Holder = CString;
    fn to_c_repr_holder(self: &Self) -> Option<<Self as Printfable>::Holder> {
        CString::new(*self).ok()
    }
}

pub trait CReprHolder {
    type Output;
    fn to_c_repr(self: &Self) -> <Self as CReprHolder>::Output;
}

impl CReprHolder for i32 {
    type Output = i32;
    fn to_c_repr(self: &Self) -> <Self as CReprHolder>::Output {
        *self
    }
}

impl CReprHolder for u32 {
    type Output = u32;
    fn to_c_repr(self: &Self) -> <Self as CReprHolder>::Output {
        *self
    }
}

impl CReprHolder for i64 {
    type Output = i64;
    fn to_c_repr(self: &Self) -> <Self as CReprHolder>::Output {
        *self
    }
}

impl CReprHolder for u64 {
    type Output = u64;
    fn to_c_repr(self: &Self) -> <Self as CReprHolder>::Output {
        *self
    }
}

// No need to implement CReprHolder for f32, as this trait is only invoked on results of
// `Printfable::to_c_repr_holder`, and that converts f32 to f64

impl CReprHolder for f64 {
    type Output = f64;
    fn to_c_repr(self: &Self) -> <Self as CReprHolder>::Output {
        *self
    }
}

impl CReprHolder for CString {
    type Output = *const libc::c_char;
    fn to_c_repr(self: &Self) -> <Self as CReprHolder>::Output {
        self.as_ptr()
    }
}

/// Helper function for `fmt!`. Don't use directly.
pub fn fmt_arg<T>(format: &str, arg: T) -> Option<String>
where
    T: Printfable,
{
    // Might fail if `format` contains a null byte. TODO decide if this is a good
    // error-handling strategy, or we should report back to user, or panic, or what
    CString::new(format).ok().and_then(|local_format_cstring| {
        let buf_size = 1024usize;
        let mut buffer = Vec::<u8>::with_capacity(buf_size);
        // Filling the vector with ones because CString::new() doesn't want any zeroes in
        // there. The last byte is left unused, so that CString::new() can put a terminating
        // zero byte without triggering a re-allocation.
        buffer.resize(buf_size - 1, 1);
        CString::new(buffer).ok().and_then(|buffer| unsafe {
            let buffer_ptr = buffer.into_raw();
            // TODO: check how many bytes were written
            arg.to_c_repr_holder().and_then(|arg_c_repr_holder| {
                let bytes_written = libc::snprintf(
                    buffer_ptr,
                    buf_size as libc::size_t,
                    local_format_cstring.as_ptr() as *const libc::c_char,
                    arg_c_repr_holder.to_c_repr(),
                );
                let buffer = CString::from_raw(buffer_ptr);
                let _bytes_written = bytes_written as usize;
                buffer.into_string().ok()
            })
        })
    })
}

/// A safe-ish wrapper around `libc::snprintf`.
#[macro_export]
macro_rules! fmt {
    ( $format:expr ) => {
        {
            let format: &str = $format;
            String::from(format)
        }
    };

    ( $format:expr, $( $arg:expr ),+ ) => {
        {
            let format: &str = $format;

            let mut result = String::new();

            use $crate::specifiers_iterator::SpecifiersIterator;
            let mut specifiers = SpecifiersIterator::from(format);

            $(
                let local_format = specifiers.next().unwrap_or("");
                if let Some(formatted_string) = $crate::fmt_arg(local_format, $arg) {
                    result.push_str(&formatted_string);
                }
            )+

            result
        }
    };
}

#[cfg(test)]
mod tests {
    extern crate libc;
    use std;

    #[test]
    fn returns_first_argument_if_it_is_the_only_one() {
        let input = String::from("Hello, world!");
        assert_eq!(fmt!(&input), input);
    }

    #[test]
    fn replaces_printf_format_with_text_representation_of_an_argument() {
        assert_eq!(fmt!("%i", 42), "42");
        assert_eq!(fmt!("%i", -13), "-13");
        assert_eq!(fmt!("%.3f", 3.1416), "3.142");
        assert_eq!(fmt!("%i %i", 100500, -191), "100500 -191");
    }

    #[test]
    fn formats_i32() {
        assert_eq!(fmt!("%i", 42i32), "42");
        assert_eq!(fmt!("%i", std::i32::MIN), "-2147483648");
        assert_eq!(fmt!("%i", std::i32::MAX), "2147483647");
    }

    #[test]
    fn formats_u32() {
        assert_eq!(fmt!("%u", 42u32), "42");
        assert_eq!(fmt!("%u", 0u32), "0");
        assert_eq!(fmt!("%u", std::u32::MAX), "4294967295");
    }

    #[test]
    fn formats_i64() {
        assert_eq!(fmt!("%li", 42i64), "42");
        assert_eq!(fmt!("%li", std::i32::MIN as i64 - 1), "-2147483649");
        assert_eq!(fmt!("%li", std::i32::MAX as i64 + 1), "2147483648");

        assert_eq!(fmt!("%lli", 42i64), "42");
        assert_eq!(fmt!("%lli", std::i64::MIN), "-9223372036854775808");
        assert_eq!(fmt!("%lli", std::i64::MAX), "9223372036854775807");
    }

    #[test]
    fn formats_u64() {
        assert_eq!(fmt!("%lu", 42u64), "42");
        assert_eq!(fmt!("%lu", 0u64), "0");
        assert_eq!(fmt!("%lu", std::u64::MAX), "18446744073709551615");

        assert_eq!(fmt!("%llu", 42u64), "42");
        assert_eq!(fmt!("%llu", 0u64), "0");
        assert_eq!(fmt!("%llu", std::u64::MAX), "18446744073709551615");
    }

    /*
    TEST_CASE("strprintf::fmt() formats void*", "[strprintf]")
    {
            const auto x = 42;
            REQUIRE_FALSE(strprintf::fmt("%p", reinterpret_cast<const void*>(&x)).empty());
    }

    TEST_CASE("strprintf::fmt() formats nullptr", "[strprintf]")
    {
            REQUIRE_FALSE(strprintf::fmt("%p", nullptr) == "(null)");
    }
    */

    #[test]
    fn formats_float() {
        let x = 42.0f32;
        assert_eq!(fmt!("%f", x), "42.000000");
        assert_eq!(fmt!("%.3f", x), "42.000");

        let y = 42e3f32;
        assert_eq!(fmt!("%e", y), "4.200000e+04");
        assert_eq!(fmt!("%.3e", y), "4.200e+04");

        assert_eq!(fmt!("%f", std::f32::INFINITY), "inf");
        assert_eq!(fmt!("%F", std::f32::INFINITY), "INF");

        assert_eq!(fmt!("%f", std::f32::NEG_INFINITY), "-inf");
        assert_eq!(fmt!("%F", std::f32::NEG_INFINITY), "-INF");

        assert_eq!(fmt!("%f", std::f32::NAN), "nan");
        assert_eq!(fmt!("%F", std::f32::NAN), "NAN");
    }

    #[test]
    fn formats_double() {
        let x = 42.0f64;
        assert_eq!(fmt!("%f", x), "42.000000");
        assert_eq!(fmt!("%.3f", x), "42.000");

        let y = 42e138f64;
        assert_eq!(fmt!("%e", y), "4.200000e+139");
        assert_eq!(fmt!("%.3e", y), "4.200e+139");

        assert_eq!(fmt!("%f", std::f64::INFINITY), "inf");
        assert_eq!(fmt!("%F", std::f64::INFINITY), "INF");

        assert_eq!(fmt!("%f", std::f64::NEG_INFINITY), "-inf");
        assert_eq!(fmt!("%F", std::f64::NEG_INFINITY), "-INF");

        assert_eq!(fmt!("%f", std::f64::NAN), "nan");
        assert_eq!(fmt!("%F", std::f64::NAN), "NAN");
    }

    #[test]
    fn formats_str_slice() {
        let input = "Hello, world!";
        assert_eq!(fmt!("%s", input), input);
    }

    /*
    // TODO: write the same test for str
    // TODO: write the same test for String
    TEST_CASE("strprintf::fmt() formats std::string", "[strprintf]")
    {
            const auto input = std::string("Hello, world!");
            REQUIRE(strprintf::fmt("%s", input) == input);
    }

    TEST_CASE("strprintf::fmt() works fine with 1MB format string", "[strprintf]")
    {
            const auto format = std::string(1024 * 1024, ' ');
            REQUIRE(strprintf::fmt(format) == format);
    }
    */
}
<|endoftext|>


<commit_before>use std::marker::PhantomData;
use std::error;
use std::fmt;
use std::mem;
use std::ptr;
use std::sync::Arc;

use buffer::Buffer;
use buffer::BufferSlice;
use format::StrongStorage;

use Error;
use OomError;
use VulkanObject;
use VulkanPointers;
use check_errors;
use vk;

/// Represents a way for the GPU to interpret buffer data.
///
/// Note that a buffer view is only required for some operations. For example using a buffer as a
/// uniform buffer doesn't require creating a `BufferView`.
pub struct BufferView<F, B> where B: Buffer {
    view: vk::BufferView,
    buffer: Arc<B>,
    marker: PhantomData<F>,
    atomic_accesses: bool,
}

impl<F, B> BufferView<F, B> where B: Buffer {
    /// Builds a new buffer view.
    ///
    /// The format of the view will be automatically determined by the `T` parameter.
    ///
    /// The buffer must have been created with either the `uniform_texel_buffer` or
    /// the `storage_texel_buffer` usage or an error will occur.
    pub fn new<'a, S>(buffer: S, format: F)
                      -> Result<Arc<BufferView<F, B>>, BufferViewCreationError>
        where S: Into<BufferSlice<'a, [F::Pixel], B>>, B: 'static, F: StrongStorage + 'static
    {
        let buffer = buffer.into();
        let device = buffer.resource.inner_buffer().device();
        let format = format.format();

        if !buffer.buffer().inner_buffer().usage_uniform_texel_buffer() &&
           !buffer.buffer().inner_buffer().usage_storage_texel_buffer()
        {
            return Err(BufferViewCreationError::WrongBufferUsage);
        }

        let format_props = unsafe {
            let vk_i = device.instance().pointers();
            let mut output = mem::uninitialized();
            vk_i.GetPhysicalDeviceFormatProperties(device.physical_device().internal_object(),
                                                   format as u32, &mut output);
            output.bufferFeatures
        };

        if buffer.buffer().inner_buffer().usage_uniform_texel_buffer() {
            if (format_props & vk::FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT) == 0 {
                return Err(BufferViewCreationError::UnsupportedFormat);
            }
        }

        if buffer.buffer().inner_buffer().usage_storage_texel_buffer() {
            if (format_props & vk::FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT) == 0 {
                return Err(BufferViewCreationError::UnsupportedFormat);
            }
        }

        let infos = vk::BufferViewCreateInfo {
            sType: vk::STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO,
            pNext: ptr::null(),
            flags: 0,   // reserved,
            buffer: buffer.resource.inner_buffer().internal_object(),
            format: format as u32,
            offset: buffer.offset as u64,
            range: buffer.size as u64,
        };

        let view = unsafe {
            let vk = device.pointers();
            let mut output = mem::uninitialized();
            try!(check_errors(vk.CreateBufferView(device.internal_object(), &infos,
                                                  ptr::null(), &mut output)));
            output
        };

        Ok(Arc::new(BufferView {
            view: view,
            buffer: buffer.resource.clone(),
            marker: PhantomData,
            atomic_accesses: (format_props &
                              vk::FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT) != 0,
        }))
    }
}

unsafe impl<F, B> VulkanObject for BufferView<F, B> where B: Buffer {
    type Object = vk::BufferView;

    #[inline]
    fn internal_object(&self) -> vk::BufferView {
        self.view
    }
}

impl<F, B> Drop for BufferView<F, B> where B: Buffer {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.buffer.inner_buffer().device().pointers();
            vk.DestroyBufferView(self.buffer.inner_buffer().device().internal_object(), self.view,
                                 ptr::null());
        }
    }
}

/// Error that can happen when creating a buffer view.
#[derive(Debug, Copy, Clone)]
pub enum BufferViewCreationError {
    /// Out of memory.
    OomError(OomError),

    /// The buffer was not creating with one of the `storage_texel_buffer` or
    /// `uniform_texel_buffer` usages.
    WrongBufferUsage,

    /// The requested format is not supported for this usage.
    UnsupportedFormat,
}

impl error::Error for BufferViewCreationError {
    #[inline]
    fn description(&self) -> &str {
        match *self {
            BufferViewCreationError::OomError(_) => "out of memory when creating buffer view",
            BufferViewCreationError::WrongBufferUsage => "the buffer is missing correct usage \
                                                          flags",
            BufferViewCreationError::UnsupportedFormat => "the requested format is not supported \
                                                           for this usage",
        }
    }

    #[inline]
    fn cause(&self) -> Option<&error::Error> {
        match *self {
            BufferViewCreationError::OomError(ref err) => Some(err),
            _ => None,
        }
    }
}

impl fmt::Display for BufferViewCreationError {
    #[inline]
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "{}", error::Error::description(self))
    }
}

impl From<OomError> for BufferViewCreationError {
    #[inline]
    fn from(err: OomError) -> BufferViewCreationError {
        BufferViewCreationError::OomError(err)
    }
}

impl From<Error> for BufferViewCreationError {
    #[inline]
    fn from(err: Error) -> BufferViewCreationError {
        OomError::from(err).into()
    }
}

#[cfg(test)]
mod tests {
    use buffer::BufferView;
    use buffer::sys::Usage;
    use buffer::view::BufferViewCreationError;
    use buffer::immutable::ImmutableBuffer;
    use format;

    #[test]
    fn create_uniform() {
        // `VK_FORMAT_R8G8B8A8_UNORM` guaranteed to be a supported format
        let (device, queue) = gfx_dev_and_queue!();

        let usage = Usage {
            uniform_texel_buffer: true,
            .. Usage::none()
        };

        let buffer = ImmutableBuffer::<[[u8; 4]]>::array(&device, 128, &usage,
                                                         Some(queue.family())).unwrap();
        let _ = BufferView::new(&buffer, format::R8G8B8A8Unorm).unwrap();
    }

    #[test]
    fn create_storage() {
        // `VK_FORMAT_R8G8B8A8_UNORM` guaranteed to be a supported format
        let (device, queue) = gfx_dev_and_queue!();

        let usage = Usage {
            storage_texel_buffer: true,
            .. Usage::none()
        };

        let buffer = ImmutableBuffer::<[[u8; 4]]>::array(&device, 128, &usage,
                                                         Some(queue.family())).unwrap();
        let _ = BufferView::new(&buffer, format::R8G8B8A8Unorm).unwrap();
    }

    #[test]
    fn wrong_usage() {
        // `VK_FORMAT_R8G8B8A8_UNORM` guaranteed to be a supported format
        let (device, queue) = gfx_dev_and_queue!();

        let buffer = ImmutableBuffer::<[[u8; 4]]>::array(&device, 128, &Usage::none(),
                                                         Some(queue.family())).unwrap();

        match BufferView::new(&buffer, format::R8G8B8A8Unorm) {
            Err(BufferViewCreationError::WrongBufferUsage) => (),
            _ => panic!()
        }
    }

    #[test]
    fn unsupported_format() {
        let (device, queue) = gfx_dev_and_queue!();

        let usage = Usage {
            uniform_texel_buffer: true,
            storage_texel_buffer: true,
            .. Usage::none()
        };

        let buffer = ImmutableBuffer::<[[f64; 4]]>::array(&device, 128, &usage,
                                                          Some(queue.family())).unwrap();

        // TODO: what if R64G64B64A64Sfloat is supported?
        match BufferView::new(&buffer, format::R64G64B64A64Sfloat) {
            Err(BufferViewCreationError::UnsupportedFormat) => (),
            _ => panic!()
        }
    }
}
<commit_msg>Add getters for buffer views usages<commit_after>use std::marker::PhantomData;
use std::error;
use std::fmt;
use std::mem;
use std::ptr;
use std::sync::Arc;

use buffer::Buffer;
use buffer::BufferSlice;
use format::StrongStorage;

use Error;
use OomError;
use VulkanObject;
use VulkanPointers;
use check_errors;
use vk;

/// Represents a way for the GPU to interpret buffer data.
///
/// Note that a buffer view is only required for some operations. For example using a buffer as a
/// uniform buffer doesn't require creating a `BufferView`.
pub struct BufferView<F, B> where B: Buffer {
    view: vk::BufferView,
    buffer: Arc<B>,
    marker: PhantomData<F>,
    atomic_accesses: bool,
}

impl<F, B> BufferView<F, B> where B: Buffer {
    /// Builds a new buffer view.
    ///
    /// The format of the view will be automatically determined by the `T` parameter.
    ///
    /// The buffer must have been created with either the `uniform_texel_buffer` or
    /// the `storage_texel_buffer` usage or an error will occur.
    pub fn new<'a, S>(buffer: S, format: F)
                      -> Result<Arc<BufferView<F, B>>, BufferViewCreationError>
        where S: Into<BufferSlice<'a, [F::Pixel], B>>, B: 'static, F: StrongStorage + 'static
    {
        let buffer = buffer.into();
        let device = buffer.resource.inner_buffer().device();
        let format = format.format();

        if !buffer.buffer().inner_buffer().usage_uniform_texel_buffer() &&
           !buffer.buffer().inner_buffer().usage_storage_texel_buffer()
        {
            return Err(BufferViewCreationError::WrongBufferUsage);
        }

        let format_props = unsafe {
            let vk_i = device.instance().pointers();
            let mut output = mem::uninitialized();
            vk_i.GetPhysicalDeviceFormatProperties(device.physical_device().internal_object(),
                                                   format as u32, &mut output);
            output.bufferFeatures
        };

        if buffer.buffer().inner_buffer().usage_uniform_texel_buffer() {
            if (format_props & vk::FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT) == 0 {
                return Err(BufferViewCreationError::UnsupportedFormat);
            }
        }

        if buffer.buffer().inner_buffer().usage_storage_texel_buffer() {
            if (format_props & vk::FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT) == 0 {
                return Err(BufferViewCreationError::UnsupportedFormat);
            }
        }

        let infos = vk::BufferViewCreateInfo {
            sType: vk::STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO,
            pNext: ptr::null(),
            flags: 0,   // reserved,
            buffer: buffer.resource.inner_buffer().internal_object(),
            format: format as u32,
            offset: buffer.offset as u64,
            range: buffer.size as u64,
        };

        let view = unsafe {
            let vk = device.pointers();
            let mut output = mem::uninitialized();
            try!(check_errors(vk.CreateBufferView(device.internal_object(), &infos,
                                                  ptr::null(), &mut output)));
            output
        };

        Ok(Arc::new(BufferView {
            view: view,
            buffer: buffer.resource.clone(),
            marker: PhantomData,
            atomic_accesses: (format_props &
                              vk::FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT) != 0,
        }))
    }

    /// Returns true if the buffer view can be used as a uniform texel buffer.
    #[inline]
    pub fn uniform_texel_buffer(&self) -> bool {
        self.buffer.inner_buffer().usage_uniform_texel_buffer()
    }

    /// Returns true if the buffer view can be used as a storage texel buffer.
    #[inline]
    pub fn storage_texel_buffer(&self) -> bool {
        self.buffer.inner_buffer().usage_storage_texel_buffer()
    }

    /// Returns true if the buffer view can be used as a storage texel buffer with atomic accesses.
    #[inline]
    pub fn storage_texel_buffer_atomic(&self) -> bool {
        self.atomic_accesses && self.storage_texel_buffer()
    }
}

unsafe impl<F, B> VulkanObject for BufferView<F, B> where B: Buffer {
    type Object = vk::BufferView;

    #[inline]
    fn internal_object(&self) -> vk::BufferView {
        self.view
    }
}

impl<F, B> Drop for BufferView<F, B> where B: Buffer {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.buffer.inner_buffer().device().pointers();
            vk.DestroyBufferView(self.buffer.inner_buffer().device().internal_object(), self.view,
                                 ptr::null());
        }
    }
}

/// Error that can happen when creating a buffer view.
#[derive(Debug, Copy, Clone)]
pub enum BufferViewCreationError {
    /// Out of memory.
    OomError(OomError),

    /// The buffer was not creating with one of the `storage_texel_buffer` or
    /// `uniform_texel_buffer` usages.
    WrongBufferUsage,

    /// The requested format is not supported for this usage.
    UnsupportedFormat,
}

impl error::Error for BufferViewCreationError {
    #[inline]
    fn description(&self) -> &str {
        match *self {
            BufferViewCreationError::OomError(_) => "out of memory when creating buffer view",
            BufferViewCreationError::WrongBufferUsage => "the buffer is missing correct usage \
                                                          flags",
            BufferViewCreationError::UnsupportedFormat => "the requested format is not supported \
                                                           for this usage",
        }
    }

    #[inline]
    fn cause(&self) -> Option<&error::Error> {
        match *self {
            BufferViewCreationError::OomError(ref err) => Some(err),
            _ => None,
        }
    }
}

impl fmt::Display for BufferViewCreationError {
    #[inline]
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "{}", error::Error::description(self))
    }
}

impl From<OomError> for BufferViewCreationError {
    #[inline]
    fn from(err: OomError) -> BufferViewCreationError {
        BufferViewCreationError::OomError(err)
    }
}

impl From<Error> for BufferViewCreationError {
    #[inline]
    fn from(err: Error) -> BufferViewCreationError {
        OomError::from(err).into()
    }
}

#[cfg(test)]
mod tests {
    use buffer::BufferView;
    use buffer::sys::Usage;
    use buffer::view::BufferViewCreationError;
    use buffer::immutable::ImmutableBuffer;
    use format;

    #[test]
    fn create_uniform() {
        // `VK_FORMAT_R8G8B8A8_UNORM` guaranteed to be a supported format
        let (device, queue) = gfx_dev_and_queue!();

        let usage = Usage {
            uniform_texel_buffer: true,
            .. Usage::none()
        };

        let buffer = ImmutableBuffer::<[[u8; 4]]>::array(&device, 128, &usage,
                                                         Some(queue.family())).unwrap();
        let view = BufferView::new(&buffer, format::R8G8B8A8Unorm).unwrap();

        assert!(view.uniform_texel_buffer());
    }

    #[test]
    fn create_storage() {
        // `VK_FORMAT_R8G8B8A8_UNORM` guaranteed to be a supported format
        let (device, queue) = gfx_dev_and_queue!();

        let usage = Usage {
            storage_texel_buffer: true,
            .. Usage::none()
        };

        let buffer = ImmutableBuffer::<[[u8; 4]]>::array(&device, 128, &usage,
                                                         Some(queue.family())).unwrap();
        let view = BufferView::new(&buffer, format::R8G8B8A8Unorm).unwrap();

        assert!(view.storage_texel_buffer());
    }

    #[test]
    fn create_storage_atomic() {
        // `VK_FORMAT_R32_UINT` guaranteed to be a supported format for atomics
        let (device, queue) = gfx_dev_and_queue!();

        let usage = Usage {
            storage_texel_buffer: true,
            .. Usage::none()
        };

        let buffer = ImmutableBuffer::<[u32]>::array(&device, 128, &usage,
                                                     Some(queue.family())).unwrap();
        let view = BufferView::new(&buffer, format::R32Uint).unwrap();

        assert!(view.storage_texel_buffer());
        assert!(view.storage_texel_buffer_atomic());
    }

    #[test]
    fn wrong_usage() {
        // `VK_FORMAT_R8G8B8A8_UNORM` guaranteed to be a supported format
        let (device, queue) = gfx_dev_and_queue!();

        let buffer = ImmutableBuffer::<[[u8; 4]]>::array(&device, 128, &Usage::none(),
                                                         Some(queue.family())).unwrap();

        match BufferView::new(&buffer, format::R8G8B8A8Unorm) {
            Err(BufferViewCreationError::WrongBufferUsage) => (),
            _ => panic!()
        }
    }

    #[test]
    fn unsupported_format() {
        let (device, queue) = gfx_dev_and_queue!();

        let usage = Usage {
            uniform_texel_buffer: true,
            storage_texel_buffer: true,
            .. Usage::none()
        };

        let buffer = ImmutableBuffer::<[[f64; 4]]>::array(&device, 128, &usage,
                                                          Some(queue.family())).unwrap();

        // TODO: what if R64G64B64A64Sfloat is supported?
        match BufferView::new(&buffer, format::R64G64B64A64Sfloat) {
            Err(BufferViewCreationError::UnsupportedFormat) => (),
            _ => panic!()
        }
    }
}
<|endoftext|>


<commit_before>use std::{
    env,
    io::ErrorKind,
    os::unix::net::UnixStream,
    os::unix::prelude::FromRawFd,
    path::PathBuf,
    sync::{
        atomic::{AtomicBool, Ordering},
        Arc,
    },
};

use wayland_backend::{
    client::{Backend, InvalidId, ObjectData, ObjectId, ReadEventsGuard, WaylandError},
    protocol::{ObjectInfo, ProtocolError},
};

use nix::{fcntl, Error};

use crate::{protocol::wl_display::WlDisplay, EventQueue, Proxy};

/// The Wayland connection
///
/// This is the main type representing your connection to the Wayland server, though most of the interaction
/// with the protocol are actually done using other types. The two main an simple app as for the
/// [`Connection`] are:
///
/// - Obtaining the initial [`WlDisplay`] through the [`display()`](Connection::display) method.
/// - Creating new [`EventQueue`]s with the [`new_event_queue()`](Connection::new_event_queue) method.
///
/// It can be created through the [`connect_to_env()`](Connection::connect_to_env) method to follow the
/// configuration from the environment (which is what you'll do most of the time), or using the
/// [`from_socket()`](Connection::from_socket) method if you retrieved your connected Wayland socket through
/// other means.
///
/// In case you need to plug yourself into an external Wayland connection that you don't control, you'll
/// likely get access to it as a [`Backend`], in which case you can create a [`Connection`] from it using
/// the [`from_backend`](Connection::from_backend) method.
#[derive(Debug, Clone)]
pub struct Connection {
    pub(crate) backend: Backend,
}

impl Connection {
    /// Try to connect to the Wayland server following the environment
    ///
    /// This is the standard way to initialize a Wayland connection.
    pub fn connect_to_env() -> Result<Self, ConnectError> {
        let stream = if let Ok(txt) = env::var("WAYLAND_SOCKET") {
            // We should connect to the provided WAYLAND_SOCKET
            let fd = txt.parse::<i32>().map_err(|_| ConnectError::InvalidFd)?;
            // remove the variable so any child processes don't see it
            env::remove_var("WAYLAND_SOCKET");
            // set the CLOEXEC flag on this FD
            let flags = fcntl::fcntl(fd, fcntl::FcntlArg::F_GETFD);
            let result = flags
                .map(|f| fcntl::FdFlag::from_bits(f).unwrap() | fcntl::FdFlag::FD_CLOEXEC)
                .and_then(|f| fcntl::fcntl(fd, fcntl::FcntlArg::F_SETFD(f)));
            match result {
                Ok(_) => {
                    // setting the O_CLOEXEC worked
                    unsafe { FromRawFd::from_raw_fd(fd) }
                }
                Err(_) => {
                    // something went wrong in F_GETFD or F_SETFD
                    let _ = ::nix::unistd::close(fd);
                    return Err(ConnectError::InvalidFd);
                }
            }
        } else {
            let mut socket_path = env::var_os("XDG_RUNTIME_DIR")
                .map(Into::<PathBuf>::into)
                .ok_or(ConnectError::NoCompositor)?;
            socket_path.push(env::var_os("WAYLAND_DISPLAY").ok_or(ConnectError::NoCompositor)?);

            UnixStream::connect(socket_path).map_err(|_| ConnectError::NoCompositor)?
        };

        let backend = Backend::connect(stream).map_err(|_| ConnectError::NoWaylandLib)?;
        Ok(Self { backend })
    }

    /// Initialize a Wayland connection from an already existing Unix stream
    pub fn from_socket(stream: UnixStream) -> Result<Self, ConnectError> {
        let backend = Backend::connect(stream).map_err(|_| ConnectError::NoWaylandLib)?;
        Ok(Self { backend })
    }

    /// Get the `WlDisplay` associated with this connection
    pub fn display(&self) -> WlDisplay {
        let display_id = self.backend.display_id();
        Proxy::from_id(self, display_id).unwrap()
    }

    /// Create a new event queue
    pub fn new_event_queue<State>(&self) -> EventQueue<State> {
        EventQueue::new(self.clone())
    }

    /// Wrap an existing [`Backend`] into a [`Connection`]
    pub fn from_backend(backend: Backend) -> Self {
        Self { backend }
    }

    /// Get the [`Backend`] underlying this [`Connection`]
    pub fn backend(&self) -> Backend {
        self.backend.clone()
    }

    /// Flush pending outgoing events to the server
    ///
    /// This needs to be done regularly to ensure the server receives all your requests, though several
    /// dispatching methods do it implicitly (this is stated in their documentation when they do).
    pub fn flush(&self) -> Result<(), WaylandError> {
        self.backend.flush()
    }

    /// Start a synchronized read from the socket
    ///
    /// This is needed if you plan to wait on readiness of the Wayland socket using an event loop. See
    /// [`ReadEventsGuard`] for details. Once the events are received, you'll then need to dispatch them from
    /// their event queues using [`EventQueue::dispatch_pending()`](EventQueue::dispatch_pending).
    ///
    /// If you don't need to manage multiple event sources, see
    /// [`blocking_dispatch()`](EventQueue::blocking_dispatch) for a simpler mechanism.
    pub fn prepare_read(&self) -> Result<ReadEventsGuard, WaylandError> {
        self.backend.prepare_read()
    }

    /// Do a roundtrip to the server
    ///
    /// This method will block until the Wayland server has processed and answered all your
    /// preceding requests. This is notably useful during the initial setup of an app, to wait for
    /// the initial state from the server.
    ///
    /// See [`EventQueue::roundtrip()`] for a version that includes the dispatching of the event queue.
    pub fn roundtrip(&self) -> Result<usize, WaylandError> {
        let done = Arc::new(SyncData::default());
        let display = self.display();
        self.send_request(
            &display,
            crate::protocol::wl_display::Request::Sync {},
            Some(done.clone()),
        )
        .map_err(|_| WaylandError::Io(Error::EPIPE.into()))?;

        let mut dispatched = 0;

        loop {
            self.backend.flush()?;

            // first, prepare the read
            let guard = self.backend.prepare_read()?;

            // If another thread processed events prior to prepare_read, we might already be done.
            if done.done.load(Ordering::Relaxed) {
                break;
            }

            dispatched += blocking_read(guard)?;

            // see if the successful read included our callback
            if done.done.load(Ordering::Relaxed) {
                break;
            }
        }

        Ok(dispatched)
    }

    /// Retrieve the protocol error that occured on the connection if any
    ///
    /// If this method returns `Some`, it means your Wayland connection is already dead.
    pub fn protocol_error(&self) -> Option<ProtocolError> {
        match dbg!(self.backend.last_error())? {
            WaylandError::Protocol(err) => Some(err),
            WaylandError::Io(_) => None,
        }
    }

    /// Send a request associated with the provided object
    ///
    /// This is a low-level interface used by the code generated by `wayland-scanner`, you will likely
    /// instead use the methods of the types representing each interface, or the [`Proxy::send_request`] and
    /// [`Proxy::send_constructor`]
    pub fn send_request<I: Proxy>(
        &self,
        proxy: &I,
        request: I::Request,
        data: Option<Arc<dyn ObjectData>>,
    ) -> Result<ObjectId, InvalidId> {
        let (msg, child_spec) = proxy.write_request(self, request)?;
        self.backend.send_request(msg, data, child_spec)
    }

    /// Get the protocol information related to given object ID
    pub fn object_info(&self, id: ObjectId) -> Result<ObjectInfo, InvalidId> {
        self.backend.info(id)
    }

    /// Get the object data for a given object ID
    ///
    /// This is a low-level interface used by the code generated by `wayland-scanner`, a higher-level
    /// interface for manipulating the user-data assocated to [`Dispatch`](crate::Dispatch) implementations
    /// is given as [`Proxy::data()`]. Also see [`Proxy::object_data()`].
    pub fn get_object_data(&self, id: ObjectId) -> Result<Arc<dyn ObjectData>, InvalidId> {
        self.backend.get_data(id)
    }
}

pub(crate) fn blocking_read(guard: ReadEventsGuard) -> Result<usize, WaylandError> {
    let mut fds = [nix::poll::PollFd::new(
        guard.connection_fd(),
        nix::poll::PollFlags::POLLIN | nix::poll::PollFlags::POLLERR,
    )];

    loop {
        match nix::poll::poll(&mut fds, -1) {
            Ok(_) => break,
            Err(nix::errno::Errno::EINTR) => continue,
            Err(e) => return Err(WaylandError::Io(e.into())),
        }
    }

    // at this point the fd is ready
    match guard.read() {
        Ok(n) => Ok(n),
        // if we are still "wouldblock", just return 0; the caller will retry.
        Err(WaylandError::Io(e)) if e.kind() == ErrorKind::WouldBlock => Ok(0),
        Err(e) => Err(e),
    }
}

/// An error when trying to establish a Wayland connection.
#[derive(thiserror::Error, Debug)]
pub enum ConnectError {
    /// The wayland library could not be loaded.
    #[error("The wayland library could not be loaded")]
    NoWaylandLib,

    /// Could not find wayland compositor
    #[error("Could not find wayland compositor")]
    NoCompositor,

    /// `WAYLAND_SOCKET` was set but contained garbage
    #[error("WAYLAND_SOCKET was set but contained garbage")]
    InvalidFd,
}

/*
    wl_callback object data for wl_display.sync
*/

#[derive(Default)]
pub(crate) struct SyncData {
    pub(crate) done: AtomicBool,
}

impl ObjectData for SyncData {
    fn event(
        self: Arc<Self>,
        _handle: &Backend,
        _msg: wayland_backend::protocol::Message<ObjectId>,
    ) -> Option<Arc<dyn ObjectData>> {
        self.done.store(true, Ordering::Relaxed);
        None
    }

    fn destroyed(&self, _: ObjectId) {}
}
<commit_msg>client: doc fixup<commit_after>use std::{
    env,
    io::ErrorKind,
    os::unix::net::UnixStream,
    os::unix::prelude::FromRawFd,
    path::PathBuf,
    sync::{
        atomic::{AtomicBool, Ordering},
        Arc,
    },
};

use wayland_backend::{
    client::{Backend, InvalidId, ObjectData, ObjectId, ReadEventsGuard, WaylandError},
    protocol::{ObjectInfo, ProtocolError},
};

use nix::{fcntl, Error};

use crate::{protocol::wl_display::WlDisplay, EventQueue, Proxy};

/// The Wayland connection
///
/// This is the main type representing your connection to the Wayland server, though most of the interaction
/// with the protocol are actually done using other types. The two main uses a simple app has for the
/// [`Connection`] are:
///
/// - Obtaining the initial [`WlDisplay`] through the [`display()`](Connection::display) method.
/// - Creating new [`EventQueue`]s with the [`new_event_queue()`](Connection::new_event_queue) method.
///
/// It can be created through the [`connect_to_env()`](Connection::connect_to_env) method to follow the
/// configuration from the environment (which is what you'll do most of the time), or using the
/// [`from_socket()`](Connection::from_socket) method if you retrieved your connected Wayland socket through
/// other means.
///
/// In case you need to plug yourself into an external Wayland connection that you don't control, you'll
/// likely get access to it as a [`Backend`], in which case you can create a [`Connection`] from it using
/// the [`from_backend`](Connection::from_backend) method.
#[derive(Debug, Clone)]
pub struct Connection {
    pub(crate) backend: Backend,
}

impl Connection {
    /// Try to connect to the Wayland server following the environment
    ///
    /// This is the standard way to initialize a Wayland connection.
    pub fn connect_to_env() -> Result<Self, ConnectError> {
        let stream = if let Ok(txt) = env::var("WAYLAND_SOCKET") {
            // We should connect to the provided WAYLAND_SOCKET
            let fd = txt.parse::<i32>().map_err(|_| ConnectError::InvalidFd)?;
            // remove the variable so any child processes don't see it
            env::remove_var("WAYLAND_SOCKET");
            // set the CLOEXEC flag on this FD
            let flags = fcntl::fcntl(fd, fcntl::FcntlArg::F_GETFD);
            let result = flags
                .map(|f| fcntl::FdFlag::from_bits(f).unwrap() | fcntl::FdFlag::FD_CLOEXEC)
                .and_then(|f| fcntl::fcntl(fd, fcntl::FcntlArg::F_SETFD(f)));
            match result {
                Ok(_) => {
                    // setting the O_CLOEXEC worked
                    unsafe { FromRawFd::from_raw_fd(fd) }
                }
                Err(_) => {
                    // something went wrong in F_GETFD or F_SETFD
                    let _ = ::nix::unistd::close(fd);
                    return Err(ConnectError::InvalidFd);
                }
            }
        } else {
            let mut socket_path = env::var_os("XDG_RUNTIME_DIR")
                .map(Into::<PathBuf>::into)
                .ok_or(ConnectError::NoCompositor)?;
            socket_path.push(env::var_os("WAYLAND_DISPLAY").ok_or(ConnectError::NoCompositor)?);

            UnixStream::connect(socket_path).map_err(|_| ConnectError::NoCompositor)?
        };

        let backend = Backend::connect(stream).map_err(|_| ConnectError::NoWaylandLib)?;
        Ok(Self { backend })
    }

    /// Initialize a Wayland connection from an already existing Unix stream
    pub fn from_socket(stream: UnixStream) -> Result<Self, ConnectError> {
        let backend = Backend::connect(stream).map_err(|_| ConnectError::NoWaylandLib)?;
        Ok(Self { backend })
    }

    /// Get the `WlDisplay` associated with this connection
    pub fn display(&self) -> WlDisplay {
        let display_id = self.backend.display_id();
        Proxy::from_id(self, display_id).unwrap()
    }

    /// Create a new event queue
    pub fn new_event_queue<State>(&self) -> EventQueue<State> {
        EventQueue::new(self.clone())
    }

    /// Wrap an existing [`Backend`] into a [`Connection`]
    pub fn from_backend(backend: Backend) -> Self {
        Self { backend }
    }

    /// Get the [`Backend`] underlying this [`Connection`]
    pub fn backend(&self) -> Backend {
        self.backend.clone()
    }

    /// Flush pending outgoing events to the server
    ///
    /// This needs to be done regularly to ensure the server receives all your requests, though several
    /// dispatching methods do it implicitly (this is stated in their documentation when they do).
    pub fn flush(&self) -> Result<(), WaylandError> {
        self.backend.flush()
    }

    /// Start a synchronized read from the socket
    ///
    /// This is needed if you plan to wait on readiness of the Wayland socket using an event loop. See
    /// [`ReadEventsGuard`] for details. Once the events are received, you'll then need to dispatch them from
    /// their event queues using [`EventQueue::dispatch_pending()`](EventQueue::dispatch_pending).
    ///
    /// If you don't need to manage multiple event sources, see
    /// [`blocking_dispatch()`](EventQueue::blocking_dispatch) for a simpler mechanism.
    pub fn prepare_read(&self) -> Result<ReadEventsGuard, WaylandError> {
        self.backend.prepare_read()
    }

    /// Do a roundtrip to the server
    ///
    /// This method will block until the Wayland server has processed and answered all your
    /// preceding requests. This is notably useful during the initial setup of an app, to wait for
    /// the initial state from the server.
    ///
    /// See [`EventQueue::roundtrip()`] for a version that includes the dispatching of the event queue.
    pub fn roundtrip(&self) -> Result<usize, WaylandError> {
        let done = Arc::new(SyncData::default());
        let display = self.display();
        self.send_request(
            &display,
            crate::protocol::wl_display::Request::Sync {},
            Some(done.clone()),
        )
        .map_err(|_| WaylandError::Io(Error::EPIPE.into()))?;

        let mut dispatched = 0;

        loop {
            self.backend.flush()?;

            // first, prepare the read
            let guard = self.backend.prepare_read()?;

            // If another thread processed events prior to prepare_read, we might already be done.
            if done.done.load(Ordering::Relaxed) {
                break;
            }

            dispatched += blocking_read(guard)?;

            // see if the successful read included our callback
            if done.done.load(Ordering::Relaxed) {
                break;
            }
        }

        Ok(dispatched)
    }

    /// Retrieve the protocol error that occured on the connection if any
    ///
    /// If this method returns `Some`, it means your Wayland connection is already dead.
    pub fn protocol_error(&self) -> Option<ProtocolError> {
        match dbg!(self.backend.last_error())? {
            WaylandError::Protocol(err) => Some(err),
            WaylandError::Io(_) => None,
        }
    }

    /// Send a request associated with the provided object
    ///
    /// This is a low-level interface used by the code generated by `wayland-scanner`, you will likely
    /// instead use the methods of the types representing each interface, or the [`Proxy::send_request`] and
    /// [`Proxy::send_constructor`]
    pub fn send_request<I: Proxy>(
        &self,
        proxy: &I,
        request: I::Request,
        data: Option<Arc<dyn ObjectData>>,
    ) -> Result<ObjectId, InvalidId> {
        let (msg, child_spec) = proxy.write_request(self, request)?;
        self.backend.send_request(msg, data, child_spec)
    }

    /// Get the protocol information related to given object ID
    pub fn object_info(&self, id: ObjectId) -> Result<ObjectInfo, InvalidId> {
        self.backend.info(id)
    }

    /// Get the object data for a given object ID
    ///
    /// This is a low-level interface used by the code generated by `wayland-scanner`, a higher-level
    /// interface for manipulating the user-data assocated to [`Dispatch`](crate::Dispatch) implementations
    /// is given as [`Proxy::data()`]. Also see [`Proxy::object_data()`].
    pub fn get_object_data(&self, id: ObjectId) -> Result<Arc<dyn ObjectData>, InvalidId> {
        self.backend.get_data(id)
    }
}

pub(crate) fn blocking_read(guard: ReadEventsGuard) -> Result<usize, WaylandError> {
    let mut fds = [nix::poll::PollFd::new(
        guard.connection_fd(),
        nix::poll::PollFlags::POLLIN | nix::poll::PollFlags::POLLERR,
    )];

    loop {
        match nix::poll::poll(&mut fds, -1) {
            Ok(_) => break,
            Err(nix::errno::Errno::EINTR) => continue,
            Err(e) => return Err(WaylandError::Io(e.into())),
        }
    }

    // at this point the fd is ready
    match guard.read() {
        Ok(n) => Ok(n),
        // if we are still "wouldblock", just return 0; the caller will retry.
        Err(WaylandError::Io(e)) if e.kind() == ErrorKind::WouldBlock => Ok(0),
        Err(e) => Err(e),
    }
}

/// An error when trying to establish a Wayland connection.
#[derive(thiserror::Error, Debug)]
pub enum ConnectError {
    /// The wayland library could not be loaded.
    #[error("The wayland library could not be loaded")]
    NoWaylandLib,

    /// Could not find wayland compositor
    #[error("Could not find wayland compositor")]
    NoCompositor,

    /// `WAYLAND_SOCKET` was set but contained garbage
    #[error("WAYLAND_SOCKET was set but contained garbage")]
    InvalidFd,
}

/*
    wl_callback object data for wl_display.sync
*/

#[derive(Default)]
pub(crate) struct SyncData {
    pub(crate) done: AtomicBool,
}

impl ObjectData for SyncData {
    fn event(
        self: Arc<Self>,
        _handle: &Backend,
        _msg: wayland_backend::protocol::Message<ObjectId>,
    ) -> Option<Arc<dyn ObjectData>> {
        self.done.store(true, Ordering::Relaxed);
        None
    }

    fn destroyed(&self, _: ObjectId) {}
}
<|endoftext|>


<commit_before>use sass::output_style::SassOutputStyle;
use token::{Lexeme, Token};
use ast::number_value::NumberValue;
use context::Context;
use error::{Result, SassError, ErrorKind};

#[derive(Debug, Clone, PartialEq)]
pub enum Expression {
    List(Vec<Expression>),
    Number(NumberValue),
    Operator(Lexeme),
    String(Lexeme),
}

impl Expression {
    #[allow(unused_variables)]
    pub fn to_string(&self, style: SassOutputStyle) -> String {
        match *self {
            Expression::List(ref elements) => {
                elements.iter().map(|e|
                    e.to_string(style)
                ).collect::<Vec<_>>().join(" ")
            },
            Expression::Number(ref nv) => nv.to_string(),
            Expression::Operator(ref lex) => lex.token.to_string(),
            Expression::String(ref lex) => lex.token.to_string(),
        }
    }

    pub fn parse<T: Iterator<Item = Result<Lexeme>>>(tokenizer: &mut T) -> Result<Expression> {
        let mut list = vec![];
        while let Some(Ok(lexeme)) = tokenizer.next() {
            match lexeme.token {
                Token::Semicolon => {
                    if list.len() == 1 {
                        return Ok(list.pop().unwrap())
                    } else {
                        return Ok(Expression::List(list))
                    }
                },
                Token::Number(_, _) => {
                    list.push(Expression::Number(NumberValue::from_scalar(lexeme)));
                },
                Token::Plus | Token::Minus | Token::Star | Token::Slash | Token::Percent => {
                    list.push(Expression::Operator(lexeme));
                },
                _ => {
                    list.push(Expression::String(lexeme));
                }
            }
        }

        let error_offset = match list.pop() {
            Some(Expression::String(lexeme)) => lexeme.offset.unwrap_or(0),
            Some(Expression::Operator(lexeme)) => lexeme.offset.unwrap_or(0),
            Some(Expression::Number(nv)) => nv.offset().unwrap_or(0),
            Some(Expression::List(_)) => unreachable!(), // for now until nested lists
            None => 0,
        };
        Err(SassError {
            offset: error_offset,
            kind: ErrorKind::UnexpectedEof,
            message: String::from(
                "Expected semicolon while parsing a value expression; reached EOF instead."
            ),
        })
    }

    fn evaluate_list(self, context: &Context, force_slash: bool) -> Expression {
        if let Expression::List(exprs) = self {
            let mut last_was_an_operator = true;
            // TODO: I'd love to have more types here, to ensure only values are
            // on the value stack and only operators are on the operator stack...
            let mut value_stack: Vec<Expression> = Vec::new();
            let mut op_stack: Vec<Expression> = Vec::new();

            // Split into value stacks and operator stacks

            let mut exprs = exprs.into_iter();
            while let Some(part) = exprs.next() {
                match part {
                    Expression::Number(nv) => {
                        if last_was_an_operator {
                            value_stack.push(Expression::Number(nv));
                        } else {
                            let list = create_list(
                                value_stack.pop(),
                                Expression::Number(nv),
                            );
                            value_stack.push(list);
                        }
                        last_was_an_operator = false;
                    },
                    Expression::Operator(op) => {
                        op_stack.push(Expression::Operator(op));
                        last_was_an_operator = true;
                    },
                    Expression::String(lex) => {
                        let var_eval = context.get_variable(&lex)
                                        .unwrap_or(Expression::String(lex));

                        if last_was_an_operator {
                            value_stack.push(var_eval);
                        } else {
                            let list = create_list(
                                value_stack.pop(),
                                var_eval,
                            );
                            value_stack.push(list);
                        }
                        last_was_an_operator = false;
                    },
                    Expression::List(list) => {
                        value_stack.push(Expression::List(list));
                        last_was_an_operator = false;
                    },
                }
            }

            // Process the stacks
            while !op_stack.is_empty() {
                let op = op_stack.pop().unwrap();
                let second = value_stack.pop().expect("Expected a second argument on the value stack");
                let first = value_stack.pop().expect("Expected a first argument on the value stack");

                value_stack.push(first.apply_math(op, second, context, force_slash));
            }

            value_stack.pop().unwrap()
        } else {
            self
        }
    }

    pub fn evaluate(self, context: &Context) -> Expression {
        match self {
            Expression::Number(nv) => Expression::Number(nv),
            Expression::Operator(op) => Expression::Operator(op),
            Expression::String(lex) => {
                context.get_variable(&lex).unwrap_or(Expression::String(lex))
            },
            Expression::List(exprs) => {
                Expression::List(exprs).evaluate_list(context, false)
            },
        }
    }

    fn apply_math(self, operator: Expression, second: Expression, context: &Context, force_slash: bool) -> Expression {
        match (self.clone(), second.clone()) {
            (Expression::Number(f), Expression::Number(s)) => {
                match operator {
                    Expression::Operator(ref o) if o.token == Token::Slash => {
                        if force_slash || (f.computed || s.computed) {
                            let result = f.apply_math(&o, &s);
                            Expression::Number(result)
                        } else {
                            Expression::List(vec![self, operator.clone(), second.clone()])
                        }
                    },
                    Expression::Operator(o) => {
                        let result = f.apply_math(&o, &s);
                        Expression::Number(result)
                    },
                    _ => unreachable!(),
                }
            },
            (Expression::List(f), Expression::List(s)) => {
                let eval_first = Expression::List(f).evaluate_list(context, true);
                let eval_second = Expression::List(s).evaluate_list(context, true);
                eval_first.apply_math(operator, eval_second, context, true)
            },
            _ => unimplemented!(),
        }
    }
}

fn create_list(head: Option<Expression>, tail: Expression) -> Expression {
    let mut list = match head {
        Some(Expression::List(v)) => v,
        Some(e) => vec![e],
        None => vec![],
    };
    list.push(tail);
    Expression::List(list)
}

#[cfg(test)]
mod tests {
    use super::*;
    use token::{Lexeme, Token};
    use ast::number_value::NumberValue;
    use context::Context;

    fn semicolon() -> Lexeme {
        Lexeme { token: Token::Semicolon, offset: None }
    }

    fn blue() -> Lexeme {
        Lexeme { token: Token::String("blue".into()), offset: None }
    }

    fn plus() -> Lexeme {
        Lexeme { token: Token::Plus, offset: None }
    }

    fn slash() -> Lexeme {
        Lexeme { token: Token::Slash, offset: None }
    }

    fn one() -> Lexeme {
        Lexeme { token: Token::Number(1.0, None), offset: None }
    }

    fn two() -> Lexeme {
        Lexeme { token: Token::Number(2.0, None), offset: None }
    }

    fn one_px() -> Lexeme {
        Lexeme { token: Token::Number(1.0, Some("px".into())), offset: None }
    }

    #[test]
    fn it_parses_a_single_string() {
        let mut fake_tokenizer = vec![Ok(blue()), Ok(semicolon())].into_iter();
        assert_eq!(
            Expression::parse(&mut fake_tokenizer),
            Ok(Expression::String(blue()))
        );
    }

    #[test]
    fn it_parses_a_list() {
        let mut fake_tokenizer = vec![
            Ok(one()),
            Ok(plus()),
            Ok(one()),
            Ok(semicolon())
        ].into_iter();
        assert_eq!(
            Expression::parse(&mut fake_tokenizer),
            Ok(Expression::List(vec![
                Expression::Number(NumberValue::from_scalar(one())),
                Expression::Operator(plus()),
                Expression::Number(NumberValue::from_scalar(one())),
            ]))
        );
    }

    #[test]
    fn it_parses_a_number_without_units() {
        let mut fake_tokenizer = vec![Ok(one()), Ok(semicolon())].into_iter();
        assert_eq!(
            Expression::parse(&mut fake_tokenizer),
            Ok(Expression::Number(NumberValue::from_scalar(one())))
        );
    }

    #[test]
    fn it_parses_a_number_with_units() {
        let mut fake_tokenizer = vec![Ok(one_px()), Ok(semicolon())].into_iter();
        assert_eq!(
            Expression::parse(&mut fake_tokenizer),
            Ok(Expression::Number(NumberValue::from_scalar(one_px())))
        );
    }

    #[test]
    fn it_evaluates_a_list() {
        let ex = Expression::List(vec![
            Expression::List(vec![
                Expression::Number(NumberValue::from_scalar(one())),
                Expression::Operator(slash()),
                Expression::Number(NumberValue::from_scalar(two())),
            ]),
            Expression::Operator(plus()),
            Expression::List(vec![
                Expression::Number(NumberValue::from_scalar(one())),
                Expression::Operator(slash()),
                Expression::Number(NumberValue::from_scalar(two())),
            ]),
        ]);
        let fake_context = Context::new();
        assert_eq!(
            ex.evaluate(&fake_context),
            Expression::Number(NumberValue { scalar: one(), computed: true })
        );
    }
}
<commit_msg>Handle the List + Number and Number + List cases<commit_after>use sass::output_style::SassOutputStyle;
use token::{Lexeme, Token};
use ast::number_value::NumberValue;
use context::Context;
use error::{Result, SassError, ErrorKind};

#[derive(Debug, Clone, PartialEq)]
pub enum Expression {
    List(Vec<Expression>),
    Number(NumberValue),
    Operator(Lexeme),
    String(Lexeme),
}

impl Expression {
    #[allow(unused_variables)]
    pub fn to_string(&self, style: SassOutputStyle) -> String {
        match *self {
            Expression::List(ref elements) => {
                elements.iter().map(|e|
                    e.to_string(style)
                ).collect::<Vec<_>>().join(" ")
            },
            Expression::Number(ref nv) => nv.to_string(),
            Expression::Operator(ref lex) => lex.token.to_string(),
            Expression::String(ref lex) => lex.token.to_string(),
        }
    }

    pub fn parse<T: Iterator<Item = Result<Lexeme>>>(tokenizer: &mut T) -> Result<Expression> {
        let mut list = vec![];
        while let Some(Ok(lexeme)) = tokenizer.next() {
            match lexeme.token {
                Token::Semicolon => {
                    if list.len() == 1 {
                        return Ok(list.pop().unwrap())
                    } else {
                        return Ok(Expression::List(list))
                    }
                },
                Token::Number(_, _) => {
                    list.push(Expression::Number(NumberValue::from_scalar(lexeme)));
                },
                Token::Plus | Token::Minus | Token::Star | Token::Slash | Token::Percent => {
                    list.push(Expression::Operator(lexeme));
                },
                _ => {
                    list.push(Expression::String(lexeme));
                }
            }
        }

        let error_offset = match list.pop() {
            Some(Expression::String(lexeme)) => lexeme.offset.unwrap_or(0),
            Some(Expression::Operator(lexeme)) => lexeme.offset.unwrap_or(0),
            Some(Expression::Number(nv)) => nv.offset().unwrap_or(0),
            Some(Expression::List(_)) => unreachable!(), // for now until nested lists
            None => 0,
        };
        Err(SassError {
            offset: error_offset,
            kind: ErrorKind::UnexpectedEof,
            message: String::from(
                "Expected semicolon while parsing a value expression; reached EOF instead."
            ),
        })
    }

    fn evaluate_list(self, context: &Context, force_slash: bool) -> Expression {
        if let Expression::List(exprs) = self {
            let mut last_was_an_operator = true;
            // TODO: I'd love to have more types here, to ensure only values are
            // on the value stack and only operators are on the operator stack...
            let mut value_stack: Vec<Expression> = Vec::new();
            let mut op_stack: Vec<Expression> = Vec::new();

            // Split into value stacks and operator stacks

            let mut exprs = exprs.into_iter();
            while let Some(part) = exprs.next() {
                match part {
                    Expression::Number(nv) => {
                        if last_was_an_operator {
                            value_stack.push(Expression::Number(nv));
                        } else {
                            let list = create_list(
                                value_stack.pop(),
                                Expression::Number(nv),
                            );
                            value_stack.push(list);
                        }
                        last_was_an_operator = false;
                    },
                    Expression::Operator(op) => {
                        op_stack.push(Expression::Operator(op));
                        last_was_an_operator = true;
                    },
                    Expression::String(lex) => {
                        let var_eval = context.get_variable(&lex)
                                        .unwrap_or(Expression::String(lex));

                        if last_was_an_operator {
                            value_stack.push(var_eval);
                        } else {
                            let list = create_list(
                                value_stack.pop(),
                                var_eval,
                            );
                            value_stack.push(list);
                        }
                        last_was_an_operator = false;
                    },
                    Expression::List(list) => {
                        value_stack.push(Expression::List(list));
                        last_was_an_operator = false;
                    },
                }
            }

            // Process the stacks
            while !op_stack.is_empty() {
                let op = op_stack.pop().unwrap();
                let second = value_stack.pop().expect("Expected a second argument on the value stack");
                let first = value_stack.pop().expect("Expected a first argument on the value stack");

                value_stack.push(first.apply_math(op, second, context, force_slash));
            }

            value_stack.pop().unwrap()
        } else {
            self
        }
    }

    pub fn evaluate(self, context: &Context) -> Expression {
        match self {
            Expression::Number(nv) => Expression::Number(nv),
            Expression::Operator(op) => Expression::Operator(op),
            Expression::String(lex) => {
                context.get_variable(&lex).unwrap_or(Expression::String(lex))
            },
            Expression::List(exprs) => {
                Expression::List(exprs).evaluate_list(context, false)
            },
        }
    }

    fn apply_math(self, operator: Expression, second: Expression, context: &Context, force_slash: bool) -> Expression {
        match (self.clone(), second.clone()) {
            (Expression::Number(f), Expression::Number(s)) => {
                match operator {
                    Expression::Operator(ref o) if o.token == Token::Slash => {
                        if force_slash || (f.computed || s.computed) {
                            let result = f.apply_math(&o, &s);
                            Expression::Number(result)
                        } else {
                            Expression::List(vec![self, operator.clone(), second.clone()])
                        }
                    },
                    Expression::Operator(o) => {
                        let result = f.apply_math(&o, &s);
                        Expression::Number(result)
                    },
                    _ => unreachable!(),
                }
            },
            (Expression::List(f), Expression::List(s)) => {
                let eval_first = Expression::List(f).evaluate_list(context, true);
                let eval_second = Expression::List(s).evaluate_list(context, true);
                eval_first.apply_math(operator, eval_second, context, true)
            },
            (Expression::List(f), Expression::Number(s)) => {
                let eval_first = Expression::List(f).evaluate_list(context, true);
                eval_first.apply_math(operator, Expression::Number(s), context, true)
            },
            (Expression::Number(f), Expression::List(s)) => {
                let eval_second = Expression::List(s).evaluate_list(context, true);
                Expression::Number(f).apply_math(operator, eval_second, context, true)
            },
            _ => unimplemented!(),
        }
    }
}

fn create_list(head: Option<Expression>, tail: Expression) -> Expression {
    let mut list = match head {
        Some(Expression::List(v)) => v,
        Some(e) => vec![e],
        None => vec![],
    };
    list.push(tail);
    Expression::List(list)
}

#[cfg(test)]
mod tests {
    use super::*;
    use token::{Lexeme, Token};
    use ast::number_value::NumberValue;
    use context::Context;

    fn semicolon() -> Lexeme {
        Lexeme { token: Token::Semicolon, offset: None }
    }

    fn blue() -> Lexeme {
        Lexeme { token: Token::String("blue".into()), offset: None }
    }

    fn plus() -> Lexeme {
        Lexeme { token: Token::Plus, offset: None }
    }

    fn slash() -> Lexeme {
        Lexeme { token: Token::Slash, offset: None }
    }

    fn one() -> Lexeme {
        Lexeme { token: Token::Number(1.0, None), offset: None }
    }

    fn two() -> Lexeme {
        Lexeme { token: Token::Number(2.0, None), offset: None }
    }

    fn one_px() -> Lexeme {
        Lexeme { token: Token::Number(1.0, Some("px".into())), offset: None }
    }

    #[test]
    fn it_parses_a_single_string() {
        let mut fake_tokenizer = vec![Ok(blue()), Ok(semicolon())].into_iter();
        assert_eq!(
            Expression::parse(&mut fake_tokenizer),
            Ok(Expression::String(blue()))
        );
    }

    #[test]
    fn it_parses_a_list() {
        let mut fake_tokenizer = vec![
            Ok(one()),
            Ok(plus()),
            Ok(one()),
            Ok(semicolon())
        ].into_iter();
        assert_eq!(
            Expression::parse(&mut fake_tokenizer),
            Ok(Expression::List(vec![
                Expression::Number(NumberValue::from_scalar(one())),
                Expression::Operator(plus()),
                Expression::Number(NumberValue::from_scalar(one())),
            ]))
        );
    }

    #[test]
    fn it_parses_a_number_without_units() {
        let mut fake_tokenizer = vec![Ok(one()), Ok(semicolon())].into_iter();
        assert_eq!(
            Expression::parse(&mut fake_tokenizer),
            Ok(Expression::Number(NumberValue::from_scalar(one())))
        );
    }

    #[test]
    fn it_parses_a_number_with_units() {
        let mut fake_tokenizer = vec![Ok(one_px()), Ok(semicolon())].into_iter();
        assert_eq!(
            Expression::parse(&mut fake_tokenizer),
            Ok(Expression::Number(NumberValue::from_scalar(one_px())))
        );
    }

    #[test]
    fn it_evaluates_a_list() {
        let ex = Expression::List(vec![
            Expression::List(vec![
                Expression::Number(NumberValue::from_scalar(one())),
                Expression::Operator(slash()),
                Expression::Number(NumberValue::from_scalar(two())),
            ]),
            Expression::Operator(plus()),
            Expression::List(vec![
                Expression::Number(NumberValue::from_scalar(one())),
                Expression::Operator(slash()),
                Expression::Number(NumberValue::from_scalar(two())),
            ]),
        ]);
        let fake_context = Context::new();
        assert_eq!(
            ex.evaluate(&fake_context),
            Expression::Number(NumberValue { scalar: one(), computed: true })
        );
    }
}
<|endoftext|>