<commit_before>#![allow(unstable)]
extern crate hue;
use std::os;

fn main() {
    let args = os::args();
    if args.len() < 4 {
        println!("usage : {} <username> <light_id>,<light_id>,... on|off|bri:hue:sat [transition_time]", args[0]);
        return
    }
    let bridge = ::hue::bridge::Bridge::discover_required().with_user(args[1].clone());
    let ref lights = args[2];
    let ref command = args[3];
    let parsed = match command.as_slice() {
        "on" => hue::bridge::CommandLight::on(),
        "off" => hue::bridge::CommandLight::off(),
        _ => panic!("can not understand command {:?}", command)
    };
    bridge.set_light_state(8, parsed);
    //println!("{:?}", parsed)
}
<commit_msg>simple set_light_state<commit_after>#![allow(unstable)]
extern crate hue;
extern crate regex;
use std::os;
use regex::Regex;

fn main() {
    let args = os::args();
    if args.len() < 4 {
        println!("usage : {} <username> <light_id>,<light_id>,... on|off|bri:hue:sat [transition_time]", args[0]);
        return
    }
    let bridge = ::hue::bridge::Bridge::discover_required().with_user(args[1].clone());
    let ref lights:Vec<usize> = args[2].split_str(",").map(|s| s.parse::<usize>().unwrap() ).collect();
    println!("lights: {:?}", lights);
    let ref command = args[3];
    let re = Regex::new("([0-9]{0,3}):([0-9]{0,5}):([0-9]{0,3})").unwrap();
    let mut parsed = match command.as_slice() {
        "on" => hue::bridge::CommandLight::on(),
        "off" => hue::bridge::CommandLight::off(),
        _ if re.is_match(command.as_slice()) => {
            let caps = re.captures(command.as_slice()).unwrap();
            let mut command = hue::bridge::CommandLight::on();
            command.bri = caps.at(1).and_then( |s| s.parse::<u8>() );
            command.hue = caps.at(2).and_then( |s| s.parse::<u16>() );
            command.sat = caps.at(3).and_then( |s| s.parse::<u8>() );
            command
        }
        _ => panic!("can not understand command {:?}", command)
    };
    if args.len() == 5 {
        parsed.transitiontime = args[4].parse::<u16>();
    }
    for l in lights.iter() {
        bridge.set_light_state(*l, parsed);
    }
    //println!("{:?}", parsed)
}
<|endoftext|>


<commit_before>use image2d::Image2D;
use helper::generic::f64_to_float;
use math;
use rect::Rect;
use traits::{Pixel, Primitive};

use failure::Error;
use num_traits::{NumCast, Zero, Float};

use std::ops::Add;

/// Symmetric odd kernel, whose center is the kernel origin.
#[derive(Debug)]
pub struct Kernel<T> {
    elems: Vec<T>,
    radius: u32
}

impl<T> Kernel<T> where T: Primitive {
    /// Create a new kernel.
    ///
    /// *Error*: if `elems` has an incorrect size, that is `elems.len()` != ((2 * radius) + 1)2
    pub fn new(elems: Vec<T>, radius: u32) -> Result<Kernel<T>, Error> {
        let mut s = 2 * radius + 1;
        s *= s;
        ensure!(elems.len() == s as usize, "Vector has an incorrect size: {} (expected {})", elems.len(), s);

        Ok(Kernel { elems: elems, radius: radius })
    }

    /// Convolve an image with the kernel. Uses zero-padding for borders.
    pub fn convolve
(&self, img: &Image2D
) -> Image2D

        where P: Pixel<Subpixel=S> + Zero + Add,
              S: Primitive
    {
        let d = 2 * self.radius + 1;
        let n_elems = d * d;
        let n_channels =
::N_CHANNELS;
        let mut out = img.clone();
        let mut region_accu = Vec::with_capacity((n_elems * n_channels) as usize);
        let mut pix_accu_t = vec![<T as Zero>::zero(); n_channels as usize];
        let mut pix_accu_s = vec![<S as Zero>::zero(); n_channels as usize];
        for ((y, x), dst_pix) in out.enumerate_pixels_mut() {
            let rx = (x as u32).saturating_sub(self.radius);
            let ry = (y as u32).saturating_sub(self.radius);
            let rect = Rect::new(rx, ry, d, d).crop_to_image(img).unwrap();
            for (p, e) in img.rect_iterator(&rect).zip(self.elems.iter()) {
                // Perform the convolution on the kernel floating point type.
                region_accu.extend(p.channels().into_iter().map(|c| *e * <T as NumCast>::from::<S>(*c).unwrap()));
            }
            pix_accu_t.as_mut_slice().into_iter().map(|c| *c = <T as Zero>::zero()).count();
            for convolved_pix in region_accu.as_slice().chunks(n_channels as usize) {
                for i in 0usize..n_channels as usize {
                    pix_accu_t[i] += convolved_pix[i];
                }
            }
            region_accu.clear();
            for i in 0usize..n_channels as usize {
                pix_accu_s[i] = <S as NumCast>::from::<T>(pix_accu_t[i]).unwrap_or_else(<S as Zero>::zero);
            }
            *dst_pix = P::from_slice(&pix_accu_s);
        }
        out
    }
}

impl<T> Kernel<T> where T: Primitive + Float {
/// Return a gaussian kernel
    pub fn gaussian(sigma: T, radius: u32) -> Kernel<T> {
        let d = 2 * radius + 1;
        let n = d * d;
        let mut v = Vec::with_capacity(n as usize);
        let r = <i64 as From<u32>>::from(radius + 1);
        for y in -r..r {
            for x in -r..r {
                v.push(math::gaussian_2d(f64_to_float::<T>(x as f64), f64_to_float::<T>(y as f64), sigma));
            }
        }
        Kernel::new(v, radius).unwrap()
    }

    /// Return a box kernel
    pub fn box_(radius: u32) -> Kernel<T> {
        let d = 2 * radius + 1;
        let n = d * d;
        let v = vec![f64_to_float::<T>(1. / <f64 as From<u32>>::from(n)); n as usize];
        Kernel::new(v, radius).unwrap()
    }
}

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

    #[test]
    fn test_box_filter() {
    }
}
<commit_msg>Fix gaussian kernel construction<commit_after>use image2d::Image2D;
use helper::generic::f64_to_float;
use math;
use rect::Rect;
use traits::{Pixel, Primitive};

use failure::Error;
use num_traits::{NumCast, Zero, Float};

use std::ops::Add;

/// Symmetric odd kernel, whose center is the kernel origin.
#[derive(Debug)]
pub struct Kernel<T> {
    elems: Vec<T>,
    radius: u32
}

impl<T> Kernel<T> where T: Primitive {
    /// Create a new kernel.
    ///
    /// *Error*: if `elems` has an incorrect size, that is `elems.len()` != ((2 * radius) + 1)2
    pub fn new(elems: Vec<T>, radius: u32) -> Result<Kernel<T>, Error> {
        let mut s = 2 * radius + 1;
        s *= s;
        ensure!(elems.len() == s as usize, "Vector has an incorrect size: {} (expected {})", elems.len(), s);

        Ok(Kernel { elems: elems, radius: radius })
    }

    /// Convolve an image with the kernel. Uses zero-padding for borders.
    pub fn convolve
(&self, img: &Image2D
) -> Image2D

        where P: Pixel<Subpixel=S> + Zero + Add,
              S: Primitive
    {
        let d = 2 * self.radius + 1;
        let n_elems = d * d;
        let n_channels =
::N_CHANNELS;
        let mut out = img.clone();
        let mut region_accu = Vec::with_capacity((n_elems * n_channels) as usize);
        let mut pix_accu_t = vec![<T as Zero>::zero(); n_channels as usize];
        let mut pix_accu_s = vec![<S as Zero>::zero(); n_channels as usize];
        for ((y, x), dst_pix) in out.enumerate_pixels_mut() {
            let rx = (x as u32).saturating_sub(self.radius);
            let ry = (y as u32).saturating_sub(self.radius);
            let rect = Rect::new(rx, ry, d, d).crop_to_image(img).unwrap();
            for (p, e) in img.rect_iterator(&rect).zip(self.elems.iter()) {
                // Perform the convolution on the kernel floating point type.
                region_accu.extend(p.channels().into_iter().map(|c| *e * <T as NumCast>::from::<S>(*c).unwrap()));
            }
            pix_accu_t.as_mut_slice().into_iter().map(|c| *c = <T as Zero>::zero()).count();
            for convolved_pix in region_accu.as_slice().chunks(n_channels as usize) {
                for i in 0usize..n_channels as usize {
                    pix_accu_t[i] += convolved_pix[i];
                }
            }
            region_accu.clear();
            for i in 0usize..n_channels as usize {
                pix_accu_s[i] = <S as NumCast>::from::<T>(pix_accu_t[i]).unwrap_or_else(<S as Zero>::zero);
            }
            *dst_pix = P::from_slice(&pix_accu_s);
        }
        out
    }
}

impl<T> Kernel<T> where T: Primitive + Float {
/// Return a gaussian kernel
    pub fn gaussian(sigma: T, radius: u32) -> Kernel<T> {
        let d = 2 * radius + 1;
        let n = d * d;
        let mut v = Vec::with_capacity(n as usize);
        let r = <i64 as From<u32>>::from(radius);
        for y in -r..r+1 {
            for x in -r..r+1 {
                v.push(math::gaussian_2d(f64_to_float::<T>(x as f64), f64_to_float::<T>(y as f64), sigma));
            }
        }
        Kernel::new(v, radius).unwrap()
    }

    /// Return a box kernel
    pub fn box_(radius: u32) -> Kernel<T> {
        let d = 2 * radius + 1;
        let n = d * d;
        let v = vec![f64_to_float::<T>(1. / <f64 as From<u32>>::from(n)); n as usize];
        Kernel::new(v, radius).unwrap()
    }
}

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

    #[test]
    fn test_box_filter() {
    }
}
<|endoftext|>


<commit_before>/// Internal namespace.
pub( crate ) mod private
{
  use crate::exposed::*;
  use type_constructor::prelude::*;

  ///
  /// Pair of syntax elements.
  ///

  // zzz : use pair
  #[ derive( Debug, PartialEq, Eq, Clone ) ]
  pub struct Pair< T1, T2 >
  ( pub T1, pub T2 )
  where
    T1 : syn::parse::Parse + quote::ToTokens,
    T2 : syn::parse::Parse + quote::ToTokens,
  ;

  impl< T1, T2 > Pair< T1, T2 >
  where
    T1 : syn::parse::Parse + quote::ToTokens,
    T2 : syn::parse::Parse + quote::ToTokens,
  {
    /// Constructor.
    pub fn new( src1 : T1, src2 : T2 ) -> Self
    {
      Self( src1, src2 )
    }
  }

  impl< T1, T2 > syn::parse::Parse for Pair< T1, T2 >
  where
    T1 : syn::parse::Parse + quote::ToTokens,
    T2 : syn::parse::Parse + quote::ToTokens,
  {
    fn parse( input : ParseStream< '_ > ) -> Result< Self >
    {
      Ok( Self( input.parse()?, input.parse()? ) )
    }
  }

  impl< T1, T2 > quote::ToTokens for Pair< T1, T2 >
  where
    T1 : syn::parse::Parse + quote::ToTokens,
    T2 : syn::parse::Parse + quote::ToTokens,
  {
    fn to_tokens( &self, tokens : &mut proc_macro2::TokenStream )
    {
      self.0.to_tokens( tokens );
      self.1.to_tokens( tokens );
    }
  }

//   ///
//   /// Parse as much elements as possible.
//   ///
//
//   #[ derive( Debug, PartialEq, Eq, Clone ) ]
//   pub struct Many< T > ( pub Vec< T > )
//   where
//     T : quote::ToTokens,
//   ;

  types!
  {
    ///
    /// Parse as much elements as possible.
    ///

    #[ derive( Debug, PartialEq, Eq, Clone ) ]
    pub many Many : < T : quote::ToTokens >
  }

//   ///
//   /// Attribute which is inner.
//   ///
//   /// For example: `#![ warn( missing_docs ) ]`.
//   ///
//
//   #[ derive( Debug, PartialEq, Eq, Clone ) ]
//   pub many AttributesInner : syn::Attribute;

  impl< T > Many< T >
  where
    T : quote::ToTokens,
  {
    /// Constructor.
    pub fn new() -> Self
    {
      Self( Vec::new() )
    }
    /// Constructor.
    pub fn new_with( src : Vec< T > ) -> Self
    {
      Self( src )
    }
  }

  impl< T > quote::ToTokens
  for Many< T >
  where
    T : quote::ToTokens,
  {
    fn to_tokens( &self, tokens : &mut proc_macro2::TokenStream )
    {
      use crate::quote::TokenStreamExt;
      tokens.append_all( self.0.iter() );
    }
  }

//   // zzz : macro?
//   impl< T > core::ops::Deref
//   for Many< T >
//   where
//     T : quote::ToTokens,
//   {
//     type Target = Vec< T >;
//     fn deref( &self ) -> &Self::Target
//     {
//       &self.0
//     }
//   }
//
//   // zzz : macro?
//   impl< T > From< Vec< T > > for Many< T >
//   where
//     T : quote::ToTokens,
//   {
//     fn from( src : Vec< T > ) -> Self
//     {
//       Self( src )
//     }
//   }

  impl< T > From< Many< T > > for Vec< T >
  where
    T : quote::ToTokens,
  {
    fn from( src : Many< T > ) -> Self
    {
      src.0
    }
  }

  impl syn::parse::Parse
  for Many< AttributesInner >
  {
    fn parse( input : ParseStream< '_ > ) -> Result< Self >
    {
      let mut result = Self::new();
      loop
      {
        let lookahead = input.lookahead1();
        if !lookahead.peek( Token![ # ] )
        {
          break;
        }
        result.0.push( input.parse()? );
      }
      Ok( result )
    }
  }

  impl syn::parse::Parse
  for Many< AttributesOuter >
  {
    fn parse( input : ParseStream< '_ > ) -> Result< Self >
    {
      let mut result = Self::new();
      loop
      {
        let lookahead = input.lookahead1();
        if !lookahead.peek( Token![ # ] )
        {
          break;
        }
        result.0.push( input.parse()? );
      }
      Ok( result )
    }
  }

  impl syn::parse::Parse
  for Many< syn::Item >
  {
    fn parse( input : syn::parse::ParseStream< '_ > ) -> Result< Self >
    {
      let mut items = vec![];
      while !input.is_empty()
      {
        let item : syn::Item = input.parse()?;
        items.push( item );
      }
      Ok( Self( items ) )
    }
  }

  // =

  types!
  {

    ///
    /// Attribute which is inner.
    ///
    /// For example: `#![ warn( missing_docs ) ]`.
    ///

    #[ derive( Debug, PartialEq, Eq, Clone ) ]
    pub many AttributesInner : syn::Attribute;

  }

  impl syn::parse::Parse
  for AttributesInner
  {
    fn parse( input : ParseStream< '_ > ) -> Result< Self >
    {
      let input2;
      Ok( Self( vec![ syn::Attribute
      {
        pound_token : input.parse()?,
        style : syn::AttrStyle::Inner( input.parse()? ),
        bracket_token : bracketed!( input2 in input ),
        path : input2.call( syn::Path::parse_mod_style )?,
        tokens : input2.parse()?,
      }]))
      // Ok( ( input.call( syn::Attribute::parse_inner )? ).into() )
    }
  }

  impl quote::ToTokens
  for AttributesInner
  {
    fn to_tokens( &self, tokens : &mut proc_macro2::TokenStream )
    {
      use crate::quote::TokenStreamExt;
      tokens.append_all( self.0.iter() );
      // self.0.to_tokens( tokens );
    }
  }

  //

  types!
  {

    ///
    /// Attribute which is outer.
    ///
    /// For example: `#[ derive( Copy ) ]`.
    ///

    #[ derive( Debug, PartialEq, Eq, Clone ) ]
    pub many AttributesOuter : syn::Attribute;

  }

  impl syn::parse::Parse
  for AttributesOuter
  {
    fn parse( input : ParseStream< '_ > ) -> Result< Self >
    {
      let mut result : Self = make!();
      loop
      {
        // println!( "lookahead1" );
        let lookahead = input.lookahead1();
        if !lookahead.peek( Token![ # ] )
        {
          // dbg!( &input );
          break;
        }
        // println!( "lookahead1 : yes" );
        let input2;
        let element = syn::Attribute
        {
          pound_token : input.parse()?,
          style : syn::AttrStyle::Outer,
          bracket_token : bracketed!( input2 in input ),
          path : input2.call( syn::Path::parse_mod_style )?,
          tokens : input2.parse()?,
        };
        result.0.push( element );
      }
      Ok( result )
      // let input2;
      // // println!( "AttributesOuter::parse::a" );
      // Ok( Self( vec![ syn::Attribute
      // {
      //   pound_token : input.parse()?,
      //   style : syn::AttrStyle::Outer,
      //   bracket_token : bracketed!( input2 in input ),
      //   path : input2.call( syn::Path::parse_mod_style )?,
      //   tokens : input2.parse()?,
      // }]))
      // // Ok( ( input.call( syn::Attribute::parse_inner )? ).into() )
    }
  }

  impl quote::ToTokens
  for AttributesOuter
  {
    fn to_tokens( &self, tokens : &mut proc_macro2::TokenStream )
    {
      use crate::quote::TokenStreamExt;
      tokens.append_all( self.0.iter() );
    }
  }

  ///
  /// Attribute and ident.
  ///

  pub type AttributedIdent = Pair< Many< AttributesInner >, syn::Ident >;

  impl From< syn::Ident > for AttributedIdent
  {
    fn from( src : syn::Ident ) -> Self
    {
      Self( Vec::< AttributesInner >::new().into(), src )
    }
  }

  impl From< AttributedIdent > for syn::Ident
  {
    fn from( src : AttributedIdent ) -> Self
    {
      src.1
    }
  }

//   ///
//   /// Many items.
//   ///
//
//   // zzz : use Many instead
//   // #[ allow( dead_code ) ]
//   #[ derive( Debug ) ]
//   pub struct Items
//   (
//     pub Vec< syn::Item >,
//   );
//
//   impl syn::parse::Parse for Items
//   {
//     fn parse( input : syn::parse::ParseStream< '_ > ) -> Result< Self >
//     {
//
//       let mut items = vec![];
//       while !input.is_empty()
//       {
//         let item : syn::Item = input.parse()?;
//         items.push( item );
//       }
//
//       Ok( Self( items ) )
//     }
//   }
//
//   impl quote::ToTokens for Items
//   {
//     fn to_tokens( &self, tokens : &mut proc_macro2::TokenStream )
//     {
//       // use quote::ToTokens;
//       self.0.iter().for_each( | item | item.to_tokens( tokens ) );
//     }
//   }

}

/// Exposed namespace of the module.
pub mod exposed
{
  pub use super::prelude::*;
  pub use super::private::
  {
    Pair,
    Many,
    AttributesInner,
    AttributesOuter,
    AttributedIdent,
    // Items,
  };
}

pub use exposed::*;

/// Prelude to use essentials: `use my_module::prelude::*`.
pub mod prelude
{
}
<commit_msg>!test<commit_after>/// Internal namespace.
pub( crate ) mod private
{
  use crate::exposed::*;
  use type_constructor::prelude::*;

  ///
  /// Pair of syntax elements.
  ///

  // zzz : use pair
  #[ derive( Debug, PartialEq, Eq, Clone ) ]
  pub struct Pair< T1, T2 >
  ( pub T1, pub T2 )
  where
    T1 : syn::parse::Parse + quote::ToTokens,
    T2 : syn::parse::Parse + quote::ToTokens,
  ;

  impl< T1, T2 > Pair< T1, T2 >
  where
    T1 : syn::parse::Parse + quote::ToTokens,
    T2 : syn::parse::Parse + quote::ToTokens,
  {
    /// Constructor.
    pub fn new( src1 : T1, src2 : T2 ) -> Self
    {
      Self( src1, src2 )
    }
  }

  impl< T1, T2 > syn::parse::Parse for Pair< T1, T2 >
  where
    T1 : syn::parse::Parse + quote::ToTokens,
    T2 : syn::parse::Parse + quote::ToTokens,
  {
    fn parse( input : ParseStream< '_ > ) -> Result< Self >
    {
      Ok( Self( input.parse()?, input.parse()? ) )
    }
  }

  impl< T1, T2 > quote::ToTokens for Pair< T1, T2 >
  where
    T1 : syn::parse::Parse + quote::ToTokens,
    T2 : syn::parse::Parse + quote::ToTokens,
  {
    fn to_tokens( &self, tokens : &mut proc_macro2::TokenStream )
    {
      self.0.to_tokens( tokens );
      self.1.to_tokens( tokens );
    }
  }

//   ///
//   /// Parse as much elements as possible.
//   ///
//
//   #[ derive( Debug, PartialEq, Eq, Clone ) ]
//   pub struct Many< T > ( pub Vec< T > )
//   where
//     T : quote::ToTokens,
//   ;

  types!
  {
    ///
    /// Parse as much elements as possible.
    ///

    #[ derive( Debug, PartialEq, Eq, Clone ) ]
    pub many Many : < T : quote::ToTokens >
  }

//   ///
//   /// Attribute which is inner.
//   ///
//   /// For example: `#![ warn( missing_docs ) ]`.
//   ///
//
//   #[ derive( Debug, PartialEq, Eq, Clone ) ]
//   pub many AttributesInner : syn::Attribute;

  impl< T > Many< T >
  where
    T : quote::ToTokens,
  {
    /// Constructor.
    pub fn new() -> Self
    {
      Self( Vec::new() )
    }
    /// Constructor.
    pub fn new_with( src : Vec< T > ) -> Self
    {
      Self( src )
    }
  }

  impl< T > quote::ToTokens
  for Many< T >
  where
    T : quote::ToTokens,
  {
    fn to_tokens( &self, tokens : &mut proc_macro2::TokenStream )
    {
      use crate::quote::TokenStreamExt;
      tokens.append_all( self.0.iter() );
    }
  }

//   // zzz : macro?
//   impl< T > core::ops::Deref
//   for Many< T >
//   where
//     T : quote::ToTokens,
//   {
//     type Target = Vec< T >;
//     fn deref( &self ) -> &Self::Target
//     {
//       &self.0
//     }
//   }
//
//   // zzz : macro?
//   impl< T > From< Vec< T > > for Many< T >
//   where
//     T : quote::ToTokens,
//   {
//     fn from( src : Vec< T > ) -> Self
//     {
//       Self( src )
//     }
//   }

  impl< T > From< Many< T > > for Vec< T >
  where
    T : quote::ToTokens,
  {
    fn from( src : Many< T > ) -> Self
    {
      src.0
    }
  }

  impl syn::parse::Parse
  for Many< AttributesInner >
  {
    fn parse( input : ParseStream< '_ > ) -> Result< Self >
    {
      let mut result = Self::new();
      loop
      {
        let lookahead = input.lookahead1();
        if !lookahead.peek( Token![ # ] )
        {
          break;
        }
        result.0.push( input.parse()? );
      }
      Ok( result )
    }
  }

  impl syn::parse::Parse
  for Many< AttributesOuter >
  {
    fn parse( input : ParseStream< '_ > ) -> Result< Self >
    {
      let mut result = Self::new();
      loop
      {
        let lookahead = input.lookahead1();
        if !lookahead.peek( Token![ # ] )
        {
          break;
        }
        result.0.push( input.parse()? );
      }
      Ok( result )
    }
  }

  impl syn::parse::Parse
  for Many< syn::Item >
  {
    fn parse( input : syn::parse::ParseStream< '_ > ) -> Result< Self >
    {
      let mut items = vec![];
      while !input.is_empty()
      {
        let item : syn::Item = input.parse()?;
        items.push( item );
      }
      Ok( Self( items ) )
    }
  }

  // =

  types!
  {

    ///
    /// Attribute which is inner.
    ///
    /// For example: `#![ warn( missing_docs ) ]`.
    ///

    #[ derive( Debug, PartialEq, Eq, Clone ) ]
    pub many AttributesInner : syn::Attribute;

  }

  impl syn::parse::Parse
  for AttributesInner
  {
    fn parse( input : ParseStream< '_ > ) -> Result< Self >
    {
      let input2;
      Ok( Self( vec![ syn::Attribute
      {
        pound_token : input.parse()?,
        style : syn::AttrStyle::Inner( input.parse()? ),
        bracket_token : bracketed!( input2 in input ),
        path : input2.call( syn::Path::parse_mod_style )?,
        tokens : input2.parse()?,
      }]))
      // Ok( ( input.call( syn::Attribute::parse_inner )? ).into() )
    }
  }

  impl quote::ToTokens
  for AttributesInner
  {
    fn to_tokens( &self, tokens : &mut proc_macro2::TokenStream )
    {
      use crate::quote::TokenStreamExt;
      tokens.append_all( self.0.iter() );
      // self.0.to_tokens( tokens );
    }
  }

  //

  types!
  {

    ///
    /// Attribute which is outer.
    ///
    /// For example: `#[ derive( Copy ) ]`.
    ///

    #[ derive( Debug, PartialEq, Eq, Clone ) ]
    pub many AttributesOuter : syn::Attribute;

  }

  impl syn::parse::Parse
  for AttributesOuter
  {
    fn parse( input : ParseStream< '_ > ) -> Result< Self >
    {
      let mut result : Self = make!();
      loop
      {
        // println!( "lookahead1" );
        let lookahead = input.lookahead1();
        if !lookahead.peek( Token![ # ] )
        {
          // dbg!( &input );
          break;
        }
        // println!( "lookahead1 : yes" );
        let input2;
        let element = syn::Attribute
        {
          pound_token : input.parse()?,
          style : syn::AttrStyle::Outer,
          bracket_token : bracketed!( input2 in input ),
          path : input2.call( syn::Path::parse_mod_style )?,
          tokens : input2.parse()?,
        };
        result.0.push( element );
      }
      Ok( result )
      // let input2;
      // // println!( "AttributesOuter::parse::a" );
      // Ok( Self( vec![ syn::Attribute
      // {
      //   pound_token : input.parse()?,
      //   style : syn::AttrStyle::Outer,
      //   bracket_token : bracketed!( input2 in input ),
      //   path : input2.call( syn::Path::parse_mod_style )?,
      //   tokens : input2.parse()?,
      // }]))
      // // Ok( ( input.call( syn::Attribute::parse_inner )? ).into() )
    }
  }

  impl quote::ToTokens
  for AttributesOuter
  {
    fn to_tokens( &self, tokens : &mut proc_macro2::TokenStream )
    {
      use crate::quote::TokenStreamExt;
      tokens.append_all( self.0.iter() );
    }
  }

  ///
  /// Attribute and ident.
  ///

  pub type AttributedIdent = Pair< Many< AttributesInner >, syn::Ident >;

  impl From< syn::Ident > for AttributedIdent
  {
    fn from( src : syn::Ident ) -> Self
    {
      Self( Vec::< AttributesInner >::new().into(), src )
    }
  }

  impl From< AttributedIdent > for syn::Ident
  {
    fn from( src : AttributedIdent ) -> Self
    {
      src.1
    }
  }

//   ///
//   /// Many items.
//   ///
//
//   // zzz : use Many instead
//   // #[ allow( dead_code ) ]
//   #[ derive( Debug ) ]
//   pub struct Items
//   (
//     pub Vec< syn::Item >,
//   );
//
//   impl syn::parse::Parse for Items
//   {
//     fn parse( input : syn::parse::ParseStream< '_ > ) -> Result< Self >
//     {
//
//       let mut items = vec![];
//       while !input.is_empty()
//       {
//         let item : syn::Item = input.parse()?;
//         items.push( item );
//       }
//
//       Ok( Self( items ) )
//     }
//   }
//
//   impl quote::ToTokens for Items
//   {
//     fn to_tokens( &self, tokens : &mut proc_macro2::TokenStream )
//     {
//       // use quote::ToTokens;
//       self.0.iter().for_each( | item | item.to_tokens( tokens ) );
//     }
//   }

}

/// Exposed namespace of the module.
pub mod exposed
{
  pub use super::prelude::*;
  pub use super::private::
  {
    Pair,
    Many,
    AttributesInner,
    AttributesOuter,
    AttributedIdent,
    // Items,
  };
}

pub use exposed::*;

/// Prelude to use essentials: `use my_module::prelude::*`.
pub mod prelude
{
}

<|endoftext|>


<commit_before>///! Basic CSS block layout.

use style;
use style::StyledNode;
use css::{Keyword, Length, Px};
use std::default::Default;
use std::iter::AdditiveIterator; // for `sum`

// CSS box model. All sizes are in px.

#[deriving(Default, Show)]
pub struct Dimensions {
    // Position of the content area relative to the document origin:
    pub x: f32,
    pub y: f32,

    // Content area size:
    pub width: f32,
    pub height: f32,

    // Surrounding edges:
    pub padding: EdgeSizes,
    pub border: EdgeSizes,
    pub margin: EdgeSizes,
}

/// A node in the layout tree.
pub struct LayoutBox<'a> {
    pub box_type: BoxType<'a>,
    pub dimensions: Dimensions,
    pub children: Vec<LayoutBox<'a>>,
}

pub enum BoxType<'a> {
    BlockNode(&'a StyledNode<'a>),
    InlineNode(&'a StyledNode<'a>),
    InlineContainer,
}

impl<'a> LayoutBox<'a> {
    fn new(box_type: BoxType) -> LayoutBox {
        LayoutBox {
            box_type: box_type,
            dimensions: Default::default(),
            children: Vec::new(),
        }
    }

    fn style_node(&self) -> &'a StyledNode<'a> {
        match self.box_type {
            BlockNode(style_node) => style_node,
            InlineNode(style_node) => style_node,
            InlineContainer => fail!("Inline container has no style node")
        }
    }
}

#[deriving(Default, Show)]
struct EdgeSizes { left: f32, right: f32, top: f32, bottom: f32 }

/// Transform a style tree into a layout tree.
pub fn layout_tree<'a>(node: &'a StyledNode<'a>, containing_block: Dimensions) -> LayoutBox<'a> {
    let mut root_box = build_layout_tree(node);
    root_box.layout(containing_block);
    return root_box;
}

/// Build the tree of LayoutBoxes, but don't perform any layout calculations yet.
fn build_layout_tree<'a>(node: &'a StyledNode<'a>) -> LayoutBox<'a> {
    let mut root = LayoutBox::new(match node.display() {
        style::Block => BlockNode(node),
        style::Inline => InlineNode(node),
        style::None => fail!("Root node has display: none.")
    });

    for child in node.children.iter() {
        match child.display() {
            style::Block => root.push_block(build_layout_tree(child)),
            style::Inline => root.push_inline(build_layout_tree(child)),
            style::None => {} // Don't lay out nodes with `display: none;`
        }
    }
    return root;
}

impl<'a> LayoutBox<'a> {
    /// Lay out a single box and its descendants.
    pub fn layout(&mut self, containing_block: Dimensions) {
        match self.box_type {
            BlockNode(_) => self.layout_block(containing_block),
            _ => {} // TODO
        }
    }

    /// Lay out a block-level element and its descendants.
    fn layout_block(&mut self, containing_block: Dimensions) {
        // Child width can depend on parent width, so we need to calculate this node's width before
        // laying out its children.
        self.calculate_block_width(containing_block);

        // Recursively lay out the children of this node within its content area.
        self.layout_block_content(containing_block);

        // Parent height can depend on child height, so `calculate_height` must be called after the
        // content layout is finished.
        self.calculate_block_height();
    }

    /// Calculate the width of a block-level non-replaced element in normal flow.
    ///
    /// http://www.w3.org/TR/CSS2/visudet.html#blockwidth
    fn calculate_block_width(&mut self, containing_block: Dimensions) {
        let style = self.style_node();

        // `width` has initial value `auto`.
        let auto = Keyword("auto".to_string());
        let mut width = style.value("width").unwrap_or(auto.clone());

        // margin, border, and padding have initial value 0.
        let zero = Length(0.0, Px);

        let mut margin_left = style.lookup("margin-left", "margin", &zero);
        let mut margin_right = style.lookup("margin-right", "margin", &zero);

        let border_left = style.lookup("border-left-width", "border-width", &zero);
        let border_right = style.lookup("border-right-width", "border-width", &zero);

        let padding_left = style.lookup("padding-left", "padding", &zero);
        let padding_right = style.lookup("padding-right", "padding", &zero);

        let total = [&margin_left, &margin_right, &border_left, &border_right,
                     &padding_left, &padding_right, &width].iter().map(|v| v.to_px()).sum();

        // If width is not auto and the total is wider than the container, treat auto margins as 0.
        if width != auto && total > containing_block.width {
            if margin_left == auto {
                margin_left = Length(0.0, Px);
            }
            if margin_right == auto {
                margin_right = Length(0.0, Px);
            }
        }

        // Adjust used values so that the above sum equals `containing_block.width`.
        // Each arm of the `match` should increase the total width by exactly `underflow`,
        // and afterward all values should be absolute lengths in px.
        let underflow = containing_block.width - total;
        match (width == auto, margin_left == auto, margin_right == auto) {
            // If the values are overconstrained, calculate margin_right.
            (false, false, false) => {
                margin_right = Length(margin_right.to_px() + underflow, Px);
            }
            // If exactly one value is auto, its used value follows from the equality.
            (false, false, true) => {
                margin_right = Length(underflow, Px);
            }
            (false, true, false) => {
                margin_left = Length(underflow, Px);
            }
            // If width is set to auto, any other auto values become 0.
            (true, _, _) => {
                if margin_left == auto {
                    margin_left = Length(0.0, Px);
                }
                if margin_right == auto {
                    margin_right = Length(0.0, Px);
                }
                width = Length(underflow, Px);
            }
            (false, true, true) => {
                // If margin-left and margin-right are both auto, their used values are equal.
                margin_left = Length(underflow / 2.0, Px);
                margin_right = Length(underflow / 2.0, Px);
            }
        }

        let d = &mut self.dimensions;
        d.width = width.to_px();

        d.padding.left = padding_left.to_px();
        d.padding.right = padding_right.to_px();

        d.border.left = border_left.to_px();
        d.border.right = border_right.to_px();

        d.margin.left = margin_left.to_px();
        d.margin.right = margin_right.to_px();

        d.x = containing_block.x + d.margin.left + d.border.left + d.padding.left;
    }

    /// Lay out the node's children within its content area.
    ///
    /// http://www.w3.org/TR/CSS2/visudet.html#normal-block
    fn layout_block_content(&mut self, containing_block: Dimensions) {
        // First we need to find the position of the content area...
        let style = self.style_node();
        let d = &mut self.dimensions;

        // margin, border, and padding have initial value 0.
        let zero = Length(0.0, Px);

        // If margin-top or margin-bottom is `auto`, the used value is zero.
        d.margin.top = style.lookup("margin-top", "margin", &zero).to_px();
        d.margin.bottom = style.lookup("margin-bottom", "margin", &zero).to_px();

        d.border.top = style.lookup("border-top-width", "border-width", &zero).to_px();
        d.border.bottom = style.lookup("border-bottom-width", "border-width", &zero).to_px();

        d.padding.top = style.lookup("padding-top", "padding", &zero).to_px();
        d.padding.bottom = style.lookup("padding-bottom", "padding", &zero).to_px();

        d.y = containing_block.y + d.margin.top + d.border.top + d.padding.top;

        // Now we can lay out the children within the content area.
        let mut content_height = 0.0;
        for child in self.children.mut_iter() {
            child.layout(*d);

            // Position each child below the previous one. TODO: margin collapsing
            child.dimensions.y = d.y + content_height;
            content_height = content_height + child.dimensions.margin_box_height();
        }
        // Record the total height of the children.
        d.height = content_height;
    }

    /// Height of a block-level non-replaced element in normal flow with overflow visible.
    fn calculate_block_height(&mut self) {
        match self.style_node().value("height") {
            // If `height` is an absolute length, use it instead of the content height.
            Some(Length(h, Px)) => { self.dimensions.height = h; }
            _ => {}
        }
    }

    fn push_block(&mut self, child: LayoutBox<'a>) {
        self.children.push(child)
    }

    fn push_inline(&mut self, _child: LayoutBox<'a>) {
       // TODO
    }
}

impl Dimensions {
    /// Total height of a box including its margins, border, and padding.
    fn margin_box_height(&self) -> f32 {
        self.height + self.padding.top + self.padding.bottom
                    + self.border.top + self.border.bottom
                    + self.margin.top + self.margin.bottom
    }
}
<commit_msg>Anonymous block box generation<commit_after>///! Basic CSS block layout.

use style;
use style::StyledNode;
use css::{Keyword, Length, Px};
use std::default::Default;
use std::iter::AdditiveIterator; // for `sum`

// CSS box model. All sizes are in px.

#[deriving(Default, Show)]
pub struct Dimensions {
    // Position of the content area relative to the document origin:
    pub x: f32,
    pub y: f32,

    // Content area size:
    pub width: f32,
    pub height: f32,

    // Surrounding edges:
    pub padding: EdgeSizes,
    pub border: EdgeSizes,
    pub margin: EdgeSizes,
}

/// A node in the layout tree.
pub struct LayoutBox<'a> {
    pub box_type: BoxType<'a>,
    pub dimensions: Dimensions,
    pub children: Vec<LayoutBox<'a>>,
}

pub enum BoxType<'a> {
    BlockNode(&'a StyledNode<'a>),
    InlineNode(&'a StyledNode<'a>),
    InlineContainer,
}

impl<'a> LayoutBox<'a> {
    fn new(box_type: BoxType) -> LayoutBox {
        LayoutBox {
            box_type: box_type,
            dimensions: Default::default(),
            children: Vec::new(),
        }
    }

    fn style_node(&self) -> &'a StyledNode<'a> {
        match self.box_type {
            BlockNode(style_node) => style_node,
            InlineNode(style_node) => style_node,
            InlineContainer => fail!("Inline container has no style node")
        }
    }
}

#[deriving(Default, Show)]
struct EdgeSizes { left: f32, right: f32, top: f32, bottom: f32 }

/// Transform a style tree into a layout tree.
pub fn layout_tree<'a>(node: &'a StyledNode<'a>, containing_block: Dimensions) -> LayoutBox<'a> {
    let mut root_box = build_layout_tree(node);
    root_box.layout(containing_block);
    return root_box;
}

/// Build the tree of LayoutBoxes, but don't perform any layout calculations yet.
fn build_layout_tree<'a>(style_node: &'a StyledNode<'a>) -> LayoutBox<'a> {
    // Create the root box.
    let mut root = LayoutBox::new(match style_node.display() {
        style::Block => BlockNode(style_node),
        style::Inline => InlineNode(style_node),
        style::None => fail!("Root node has display: none.")
    });

    // Create the descendant boxes.
    for child in style_node.children.iter() {
        match child.display() {
            style::Block => root.children.push(build_layout_tree(child)),
            style::Inline => root.push_inline(build_layout_tree(child)),
            style::None => {} // Don't lay out nodes with `display: none;`
        }
    }
    return root;
}

impl<'a> LayoutBox<'a> {
    /// Lay out a single box and its descendants.
    fn layout(&mut self, containing_block: Dimensions) {
        match self.box_type {
            BlockNode(_) => self.layout_block(containing_block),
            InlineNode(_) => {} // TODO
            InlineContainer => {} // TODO
        }
    }

    /// Lay out a block-level element and its descendants.
    fn layout_block(&mut self, containing_block: Dimensions) {
        // Child width can depend on parent width, so we need to calculate this node's width before
        // laying out its children.
        self.calculate_block_width(containing_block);

        // Recursively lay out the children of this node within its content area.
        self.layout_block_content(containing_block);

        // Parent height can depend on child height, so `calculate_height` must be called after the
        // content layout is finished.
        self.calculate_block_height();
    }

    /// Calculate the width of a block-level non-replaced element in normal flow.
    ///
    /// http://www.w3.org/TR/CSS2/visudet.html#blockwidth
    fn calculate_block_width(&mut self, containing_block: Dimensions) {
        let style = self.style_node();

        // `width` has initial value `auto`.
        let auto = Keyword("auto".to_string());
        let mut width = style.value("width").unwrap_or(auto.clone());

        // margin, border, and padding have initial value 0.
        let zero = Length(0.0, Px);

        let mut margin_left = style.lookup("margin-left", "margin", &zero);
        let mut margin_right = style.lookup("margin-right", "margin", &zero);

        let border_left = style.lookup("border-left-width", "border-width", &zero);
        let border_right = style.lookup("border-right-width", "border-width", &zero);

        let padding_left = style.lookup("padding-left", "padding", &zero);
        let padding_right = style.lookup("padding-right", "padding", &zero);

        let total = [&margin_left, &margin_right, &border_left, &border_right,
                     &padding_left, &padding_right, &width].iter().map(|v| v.to_px()).sum();

        // If width is not auto and the total is wider than the container, treat auto margins as 0.
        if width != auto && total > containing_block.width {
            if margin_left == auto {
                margin_left = Length(0.0, Px);
            }
            if margin_right == auto {
                margin_right = Length(0.0, Px);
            }
        }

        // Adjust used values so that the above sum equals `containing_block.width`.
        // Each arm of the `match` should increase the total width by exactly `underflow`,
        // and afterward all values should be absolute lengths in px.
        let underflow = containing_block.width - total;
        match (width == auto, margin_left == auto, margin_right == auto) {
            // If the values are overconstrained, calculate margin_right.
            (false, false, false) => {
                margin_right = Length(margin_right.to_px() + underflow, Px);
            }
            // If exactly one value is auto, its used value follows from the equality.
            (false, false, true) => {
                margin_right = Length(underflow, Px);
            }
            (false, true, false) => {
                margin_left = Length(underflow, Px);
            }
            // If width is set to auto, any other auto values become 0.
            (true, _, _) => {
                if margin_left == auto {
                    margin_left = Length(0.0, Px);
                }
                if margin_right == auto {
                    margin_right = Length(0.0, Px);
                }
                width = Length(underflow, Px);
            }
            (false, true, true) => {
                // If margin-left and margin-right are both auto, their used values are equal.
                margin_left = Length(underflow / 2.0, Px);
                margin_right = Length(underflow / 2.0, Px);
            }
        }

        let d = &mut self.dimensions;
        d.width = width.to_px();

        d.padding.left = padding_left.to_px();
        d.padding.right = padding_right.to_px();

        d.border.left = border_left.to_px();
        d.border.right = border_right.to_px();

        d.margin.left = margin_left.to_px();
        d.margin.right = margin_right.to_px();

        d.x = containing_block.x + d.margin.left + d.border.left + d.padding.left;
    }

    /// Lay out the node's children within its content area.
    ///
    /// http://www.w3.org/TR/CSS2/visudet.html#normal-block
    fn layout_block_content(&mut self, containing_block: Dimensions) {
        // First we need to find the position of the content area...
        let style = self.style_node();
        let d = &mut self.dimensions;

        // margin, border, and padding have initial value 0.
        let zero = Length(0.0, Px);

        // If margin-top or margin-bottom is `auto`, the used value is zero.
        d.margin.top = style.lookup("margin-top", "margin", &zero).to_px();
        d.margin.bottom = style.lookup("margin-bottom", "margin", &zero).to_px();

        d.border.top = style.lookup("border-top-width", "border-width", &zero).to_px();
        d.border.bottom = style.lookup("border-bottom-width", "border-width", &zero).to_px();

        d.padding.top = style.lookup("padding-top", "padding", &zero).to_px();
        d.padding.bottom = style.lookup("padding-bottom", "padding", &zero).to_px();

        d.y = containing_block.y + d.margin.top + d.border.top + d.padding.top;

        // Now we can lay out the children within the content area.
        let mut content_height = 0.0;
        for child in self.children.mut_iter() {
            child.layout(*d);

            // Position each child below the previous one. TODO: margin collapsing
            child.dimensions.y = d.y + content_height;
            content_height = content_height + child.dimensions.margin_box_height();
        }
        // Record the total height of the children.
        d.height = content_height;
    }

    /// Height of a block-level non-replaced element in normal flow with overflow visible.
    fn calculate_block_height(&mut self) {
        match self.style_node().value("height") {
            // If `height` is an absolute length, use it instead of the content height.
            Some(Length(h, Px)) => { self.dimensions.height = h; }
            _ => {}
        }
    }

    /// Add an inline-level child.
    fn push_inline(&mut self, child: LayoutBox<'a>) {
        self.container_for_inline().children.push(child);
    }

    /// Where a new inline child should go.
    fn container_for_inline(&mut self) -> &mut LayoutBox<'a> {
        match self.box_type {
            InlineNode(_) | InlineContainer => self,
            BlockNode(_) => {
                // If we're in the middle of a series of inline nodes, keep using the existing
                // container.  Otherwise, create a new inline container.
                match self.children.last() {
                    Some(&LayoutBox { box_type: InlineContainer,..}) => {}
                    _ => self.children.push(LayoutBox::new(InlineContainer))
                }
                self.children.mut_last().unwrap()
            }
        }
    }
}

impl Dimensions {
    /// Total height of a box including its margins, border, and padding.
    fn margin_box_height(&self) -> f32 {
        self.height + self.padding.top + self.padding.bottom
                    + self.border.top + self.border.bottom
                    + self.margin.top + self.margin.bottom
    }
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate regex;

#[cfg(test)]
mod tests {
    include!("../clap-test.rs");
    use clap;
    use clap::{App, Arg, SubCommand, ErrorKind, AppSettings};

    fn setup_app_with_globals_and_subcommands<'a, 'b>() -> clap::App<'a, 'b> {
        let global_arg = Arg::with_name("GLOBAL_ARG")
            .long("global-arg")
            .help(
                "Specifies something needed by the subcommands",
            )
            .global(true)
            .takes_value(true);

        let double_sub_command = SubCommand::with_name("outer")
            .subcommand(SubCommand::with_name("inner"));

        App::new("myprog")
            .setting(AppSettings::PropagateGlobalValuesDown)
            .arg(global_arg)
            .subcommand(double_sub_command)
    }

    fn first_subcommand_can_access_global(arg_vector : Vec<&str>) {
        let matches = setup_app_with_globals_and_subcommands().get_matches_from(
            arg_vector
        );

        let sub_match = matches.subcommand_matches("outer").expect("could not access subcommand");

        assert_eq!(sub_match.value_of("GLOBAL_ARG").expect("subcommand could not access global arg"),
                    "some_value", "subcommand did not have expected value for global arg");

    }

    fn second_subcommand_can_access_global(arg_vector : Vec<&str>) {
        let matches = setup_app_with_globals_and_subcommands().get_matches_from(
            arg_vector
        );

        let sub_match = matches.subcommand_matches("outer").expect("could not access subcommand");
        let sub_sub_match = sub_match.subcommand_matches("inner").expect("could not access inner sub");

        assert_eq!(sub_sub_match.value_of("GLOBAL_ARG").expect("inner subcommand could not access global arg"),
                "some_value", "inner subcommand did not have expected value for global arg");
    }

    #[test]
    fn subcommand_can_access_global_arg_if_global_arg_is_first() {
        first_subcommand_can_access_global(vec!["myprog", "--global-arg", "some_value", "outer", "inner"]);
    }

    #[test]
    fn subcommand_can_access_global_arg_if_global_arg_is_in_the_middle() {
        first_subcommand_can_access_global(vec!["myprog", "outer",  "--global-arg", "some_value" ,"inner"]);
    }

    #[test]
    fn subcommand_can_access_global_arg_if_global_arg_is_last() {
        first_subcommand_can_access_global(vec!["myprog", "outer", "inner", "--global-arg", "some_value"]);
    }

    #[test]
    fn second_subcommand_can_access_global_arg_if_global_arg_is_first() {
        second_subcommand_can_access_global(vec!["myprog", "--global-arg", "some_value", "outer", "inner"]);
    }

    #[test]
    fn second_subcommand_can_access_global_arg_if_global_arg_is_in_the_middle() {
        second_subcommand_can_access_global(vec!["myprog", "outer",  "--global-arg", "some_value" ,"inner"]);
    }

    #[test]
    fn second_subcommand_can_access_global_arg_if_global_arg_is_last() {
        second_subcommand_can_access_global(vec!["myprog", "outer", "inner", "--global-arg", "some_value"]);
    }
}

<commit_msg>explanatory test comments<commit_after>extern crate clap;
extern crate regex;

#[cfg(test)]
mod tests {
    include!("../clap-test.rs");
    use clap;
    use clap::{App, Arg, SubCommand, AppSettings};

    fn setup_app_with_globals_and_subcommands<'a, 'b>() -> clap::App<'a, 'b> {
        let global_arg = Arg::with_name("GLOBAL_ARG")
            .long("global-arg")
            .help(
                "Specifies something needed by the subcommands",
            )
            .global(true)
            .takes_value(true);

        let double_sub_command = SubCommand::with_name("outer")
            .subcommand(SubCommand::with_name("inner"));

        App::new("myprog")
            .setting(AppSettings::PropagateGlobalValuesDown)
            .arg(global_arg)
            .subcommand(double_sub_command)
    }

    fn first_subcommand_can_access_global(arg_vector : Vec<&str>) {
        let matches = setup_app_with_globals_and_subcommands().get_matches_from(
            arg_vector
        );

        let sub_match = matches.subcommand_matches("outer").expect("could not access subcommand");

        assert_eq!(sub_match.value_of("GLOBAL_ARG").expect("subcommand could not access global arg"),
                    "some_value", "subcommand did not have expected value for global arg");

    }

    fn second_subcommand_can_access_global(arg_vector : Vec<&str>) {
        let matches = setup_app_with_globals_and_subcommands().get_matches_from(
            arg_vector
        );

        let sub_match = matches.subcommand_matches("outer").expect("could not access subcommand");
        let sub_sub_match = sub_match.subcommand_matches("inner").expect("could not access inner sub");

        assert_eq!(sub_sub_match.value_of("GLOBAL_ARG").expect("inner subcommand could not access global arg"),
                "some_value", "inner subcommand did not have expected value for global arg");
    }

    #[test]
    fn subcommand_can_access_global_arg_if_global_arg_is_first() {
        // currently passes
        first_subcommand_can_access_global(vec!["myprog", "--global-arg", "some_value", "outer", "inner"]);
    }

    #[test]
    fn subcommand_can_access_global_arg_if_global_arg_is_in_the_middle() {
        // currently passes
        first_subcommand_can_access_global(vec!["myprog", "outer",  "--global-arg", "some_value" ,"inner"]);
    }

    #[test]
    fn first_subcommand_can_access_global_arg_if_global_arg_is_last() {
        // currently fails - hypothesis - nothing propagates global args back up
        first_subcommand_can_access_global(vec!["myprog", "outer", "inner", "--global-arg", "some_value"]);
    }

    #[test]
    fn second_subcommand_can_access_global_arg_if_global_arg_is_first() {
        // currently passes
        second_subcommand_can_access_global(vec!["myprog", "--global-arg", "some_value", "outer", "inner"]);
    }

    #[test]
    fn second_subcommand_can_access_global_arg_if_global_arg_is_in_the_middle() {
        // currently fails - hypothesis: subcommands do not recursively propagate global args
        second_subcommand_can_access_global(vec!["myprog", "outer",  "--global-arg", "some_value" ,"inner"]);
    }

    #[test]
    fn second_subcommand_can_access_global_arg_if_global_arg_is_last() {
        // currently passes
        second_subcommand_can_access_global(vec!["myprog", "outer", "inner", "--global-arg", "some_value"]);
    }
}

<|endoftext|>


<commit_before>#![feature(const_fn)]
#![feature(type_ascription)]
#![allow(non_upper_case_globals)]

#[macro_use]
extern crate jasmin;
extern crate rand;
extern crate num;
extern crate num_traits;
extern crate num_bigint as bigint;

pub mod scalarmult;
pub mod digits;

#[cfg(test)]
mod tests {
    #![allow(unused_mut)]
    use jasmin::jasmin::*;
    use scalarmult::*;
    use digits::*;
    use bigint::{ToBigUint};

    #[test]
    fn test_fadd1() {
        let mut x;
        let mut y;
        let mut z;
        code! {
            x = [1,2,3,4];
            y = [1,1,1,1];
            x = fadd(x,y);
            z = [2,3,4,5];
        }
        assert_eq!(x,z)
    }

    #[test]
    fn test_fadd2() {

        let mut rng = ::rand::thread_rng();
        for _ in 0..1000 {
            let a = gen_num(&mut rng);
            let b = gen_num(&mut rng);
            let ab1 = (bigint_of_ds(a) + bigint_of_ds(b)) % p_mod();
            let ab = fadd(a,b);
            let ab2 = bigint_of_ds(ab) % p_mod();
            assert_eq!(ab1,ab2)
        }
    }

    #[test]
    fn test_sub1() {
        let mut x;
        let mut y;
        let mut z;

        code! {
            x = [1,2,3,4];
            y = [1,1,1,1];
            x = fsub(x,y);
            z = [0,1,2,3];
        }
        assert_eq!(x,z)
    }

    #[test]
    fn test_fsub2() {

        let mut rng = ::rand::thread_rng();
        for _ in 0..1000 {
            let a = gen_num(&mut rng);
            let b = gen_num(&mut rng);
            let ab1 = ((bigint_of_ds(a) + p_mod())
                       - (bigint_of_ds(b) % p_mod()))
                      % p_mod();
            let ab = fsub(a,b);
            let ab2 = bigint_of_ds(ab) % p_mod();
            assert_eq!(ab1,ab2)
        }
    }

    #[test]
    fn test_mul1() {
        let mut x;
        let mut y;
        let mut z;

        code! {
            x = [1,2,3,4];
            y = [1,0,0,0];
            z = fmul(x,y);
        }
        assert_eq!(z,x)
    }

    #[test]
    fn test_mul2() {
        let mut rng = ::rand::thread_rng();
        for _ in 0..1000 {
            let a = gen_num(&mut rng);
            let b = gen_num(&mut rng);
            let ab1 = (bigint_of_ds(a) * bigint_of_ds(b)) % p_mod();
            let ab = fmul(a,b);
            let ab2 = bigint_of_ds(ab) % p_mod();
            assert_eq!(ab1,ab2)
        }
    }

    #[test]
    fn test_square1() {
        let mut x;
        let mut y;
        let mut z;
        code! {
            x = [1,0,0,0];
            y = [1,0,0,0];
            z = fmul(x,y);
        }
        assert_eq!(z,x)
    }

    #[test]
    fn test_square2() {

        let mut rng = ::rand::thread_rng();
        for _ in 0..1000 {
            let a = gen_num(&mut rng);
            let ab1 = (bigint_of_ds(a) * bigint_of_ds(a)) % p_mod();
            let ab = fmul(a,a);
            let ab2 = bigint_of_ds(ab) % p_mod();
            assert_eq!(ab1,ab2)
        }
    }

    #[test]
    fn test_invert1() {

        let mut rng = ::rand::thread_rng();
        let mut a_inv;
        for _ in 0..1000 {
            let a = gen_num(&mut rng);
            a_inv = finvert(a);
            let res = (bigint_of_ds(a) * bigint_of_ds(a_inv)) % p_mod();
            assert_eq!(1.to_biguint().unwrap(),res)
        }
    }

    #[test]
    fn test_freeze() {
        let mut rng = ::rand::thread_rng();
        for _ in 0..1000 {
            let a = gen_num(&mut rng);
            let a_red = freeze(a.clone());
            let res = bigint_of_ds(a) % p_mod();
            assert_eq!(bigint_of_ds(a_red),res)
        }
    }

    #[test]
    fn test_swap() {
        let mut rng = ::rand::thread_rng();
        for _ in 0..1000 {
            let x2 = gen_num(&mut rng);
            let x3 = gen_num(&mut rng);
            let z2 = gen_num(&mut rng);
            let z3 = gen_num(&mut rng);
            let mut s;
            let mut x2_;
            let mut z2_;
            let mut x3_;
            let mut z3_;
            let mut x2__;
            let mut z2__;
            let mut x3__;
            let mut z3__;

            code! {
                s = #0;
                (x2_,z2_,x3_,z3_)     = cswap(x2,z2,x3,z3,s);
                s = #1;
                (x3__,z3__,x2__,z2__) = cswap(x2,z2,x3,z3,s);
            }
            assert_eq!(x2,x2_);
            assert_eq!(x2,x2__);
            assert_eq!(z2,z2_);
            assert_eq!(z2,z2__);
            assert_eq!(x3,x3_);
            assert_eq!(x3,x3__);
            assert_eq!(z3,z3_);
            assert_eq!(z3,z3__);
        }
    }

    #[test]
    fn test_scalarmult() {
        let mut rng = ::rand::thread_rng();
        var! {
            p    : [b64; 4],
            s1   : [b64; 4],
            s2   : [b64; 4],
            p1   : [b64; 4],
            p12  : [b64; 4],
            p2   : [b64; 4],
            p21  : [b64; 4]
        }

        for _ in 0..1000 {
            p  = gen_num(&mut rng);
            s1 = gen_num(&mut rng);
            s2 = gen_num(&mut rng);
            p = ds_of_bigint(bigint_of_ds(p) % p_mod());
            code! {
                p1  = scalarmult(s1,p);
                p12 = scalarmult(s2,p1);
                p2  = scalarmult(s2,p);
                p21 = scalarmult(s1,p2);
            }
            assert_eq!(p12,p21);
        }
    }

    #[test]
    fn test_scalarmult_ext() {
        let mut rng = ::rand::thread_rng();
        var! {
            p_p  : b64,
            s_p  : b64,
            r_p  : b64,
            p    : [b64; 4],
            s1   : [b64; 4],
            s2   : [b64; 4],
            p1   : [b64; 4],
            p12  : [b64; 4],
            p2   : [b64; 4],
            p21  : [b64; 4]
        }

        for _ in 0..1000 {
            p  = gen_num(&mut rng);
            s1 = gen_num(&mut rng);
            s2 = gen_num(&mut rng);
            p = ds_of_bigint(bigint_of_ds(p) % p_mod());
            code! {
                p1  = [0; 4];
                p12 = [0; 4];
                p2  = [0; 4];
                p21 = [0; 4];
                p_p = #0*4*8;
                s_p = #1*4*8;
                r_p = #2*4*8;

                // s2*(s1*P)
                for i in (0..4) {
                    MEM[s_p + i*8] = s1[i];
                    MEM[p_p + i*8] = p[i];
                }
                scalarmult_ext(r_p,s_p,p_p);
                for i in (0..4) {
                    p1[i] = MEM[r_p + i*8];
                    MEM[s_p + i*8] = s2[i];
                    MEM[p_p + i*8] = p1[i];
                }
                scalarmult_ext(r_p,s_p,p_p);
                for i in (0..4) {
                    p12[i] = MEM[r_p + i*8];
                }

                // s1*(s2*P)
                for i in (0..4) {
                    MEM[p_p + i*8] = p[i];
                    MEM[s_p + i*8] = s2[i];
                }
                scalarmult_ext(r_p,s_p,p_p);
                for i in (0..4) {
                    p2[i] = MEM[r_p + i*8];
                    MEM[s_p + i*8] = s1[i];
                    MEM[p_p + i*8] = p2[i];
                }
                scalarmult_ext(r_p,s_p,p_p);
                for i in (0..4) {
                    p21[i] = MEM[r_p + i*8];
                }
            }
            assert_eq!(p12,p21);
            assert_eq!(bigint_of_ds(p12) % p_mod(),
                       bigint_of_ds(p21) % p_mod());
        }
    }

}
<commit_msg>wibble<commit_after>#![feature(const_fn)]
#![feature(type_ascription)]
#![allow(non_upper_case_globals)]

#[macro_use]
extern crate jasmin;
extern crate rand;
extern crate num;
extern crate num_traits;
extern crate num_bigint as bigint;

pub mod scalarmult;
pub mod digits;

#[cfg(test)]
mod tests {
    #![allow(unused_mut)]
    use jasmin::jasmin::*;
    use scalarmult::*;
    use digits::*;
    use bigint::{ToBigUint};

    #[test]
    fn test_fadd1() {
        let mut x;
        let mut y;
        let mut z;
        code! {
            x = [1,2,3,4];
            y = [1,1,1,1];
            x = fadd(x,y);
            z = [2,3,4,5];
        }
        assert_eq!(x,z)
    }

    #[test]
    fn test_fadd2() {

        let mut rng = ::rand::thread_rng();
        for _ in 0..1000 {
            let a = gen_num(&mut rng);
            let b = gen_num(&mut rng);
            let ab1 = (bigint_of_ds(a) + bigint_of_ds(b)) % p_mod();
            let ab = fadd(a,b);
            let ab2 = bigint_of_ds(ab) % p_mod();
            assert_eq!(ab1,ab2)
        }
    }

    #[test]
    fn test_sub1() {
        let mut x;
        let mut y;
        let mut z;

        code! {
            x = [1,2,3,4];
            y = [1,1,1,1];
            x = fsub(x,y);
            z = [0,1,2,3];
        }
        assert_eq!(x,z)
    }

    #[test]
    fn test_fsub2() {

        let mut rng = ::rand::thread_rng();
        for _ in 0..1000 {
            let a = gen_num(&mut rng);
            let b = gen_num(&mut rng);
            let ab1 = ((bigint_of_ds(a) + p_mod())
                       - (bigint_of_ds(b) % p_mod()))
                      % p_mod();
            let ab = fsub(a,b);
            let ab2 = bigint_of_ds(ab) % p_mod();
            assert_eq!(ab1,ab2)
        }
    }

    #[test]
    fn test_mul1() {
        let mut x;
        let mut y;
        let mut z;

        code! {
            x = [1,2,3,4];
            y = [1,0,0,0];
            z = fmul(x,y);
        }
        assert_eq!(z,x)
    }

    #[test]
    fn test_mul2() {
        let mut rng = ::rand::thread_rng();
        for _ in 0..1000 {
            let a = gen_num(&mut rng);
            let b = gen_num(&mut rng);
            let ab1 = (bigint_of_ds(a) * bigint_of_ds(b)) % p_mod();
            let ab = fmul(a,b);
            let ab2 = bigint_of_ds(ab) % p_mod();
            assert_eq!(ab1,ab2)
        }
    }

    #[test]
    fn test_square1() {
        let mut x;
        let mut y;
        let mut z;
        code! {
            x = [1,0,0,0];
            y = [1,0,0,0];
            z = fmul(x,y);
        }
        assert_eq!(z,x)
    }

    #[test]
    fn test_square2() {

        let mut rng = ::rand::thread_rng();
        for _ in 0..1000 {
            let a = gen_num(&mut rng);
            let ab1 = (bigint_of_ds(a) * bigint_of_ds(a)) % p_mod();
            let ab = fmul(a,a);
            let ab2 = bigint_of_ds(ab) % p_mod();
            assert_eq!(ab1,ab2)
        }
    }

    #[test]
    fn test_invert1() {

        let mut rng = ::rand::thread_rng();
        let mut a_inv;
        for _ in 0..1000 {
            let a = gen_num(&mut rng);
            a_inv = finvert(a);
            let res = (bigint_of_ds(a) * bigint_of_ds(a_inv)) % p_mod();
            assert_eq!(1.to_biguint().unwrap(),res)
        }
    }

    #[test]
    fn test_freeze() {
        let mut rng = ::rand::thread_rng();
        for _ in 0..1000 {
            let a = gen_num(&mut rng);
            let a_red = freeze(a.clone());
            let res = bigint_of_ds(a) % p_mod();
            assert_eq!(bigint_of_ds(a_red),res)
        }
    }

    #[test]
    fn test_swap() {
        let mut rng = ::rand::thread_rng();
        for _ in 0..1000 {
            let x2 = gen_num(&mut rng);
            let x3 = gen_num(&mut rng);
            let z2 = gen_num(&mut rng);
            let z3 = gen_num(&mut rng);
            let mut s;
            let mut x2_;
            let mut z2_;
            let mut x3_;
            let mut z3_;
            let mut x2__;
            let mut z2__;
            let mut x3__;
            let mut z3__;

            code! {
                s = #0;
                (x2_,z2_,x3_,z3_)     = cswap(x2,z2,x3,z3,s);
                s = #1;
                (x3__,z3__,x2__,z2__) = cswap(x2,z2,x3,z3,s);
            }
            assert_eq!(x2,x2_);
            assert_eq!(x2,x2__);
            assert_eq!(z2,z2_);
            assert_eq!(z2,z2__);
            assert_eq!(x3,x3_);
            assert_eq!(x3,x3__);
            assert_eq!(z3,z3_);
            assert_eq!(z3,z3__);
        }
    }

    #[test]
    fn test_scalarmult() {
        let mut rng = ::rand::thread_rng();
        var! {
            p    : [b64; 4],
            s1   : [b64; 4],
            s2   : [b64; 4],
            p1   : [b64; 4],
            p12  : [b64; 4],
            p2   : [b64; 4],
            p21  : [b64; 4]
        }

        for _ in 0..1000 {
            p  = gen_num(&mut rng);
            s1 = gen_num(&mut rng);
            s2 = gen_num(&mut rng);
            p = ds_of_bigint(bigint_of_ds(p) % p_mod());
            code! {
                p1  = scalarmult(s1,p);
                p12 = scalarmult(s2,p1);
                p2  = scalarmult(s2,p);
                p21 = scalarmult(s1,p2);
            }
            assert_eq!(p12,p21);
        }
    }

    #[test]
    fn test_scalarmult_ext() {
        let mut rng = ::rand::thread_rng();
        var! {
            p_p  : b64,
            s_p  : b64,
            r_p  : b64,
            p    : [b64; 4],
            s1   : [b64; 4],
            s2   : [b64; 4],
            p1   : [b64; 4],
            p12  : [b64; 4],
            p2   : [b64; 4],
            p21  : [b64; 4]
        }

        for _ in 0..1000 {
            p  = gen_num(&mut rng);
            s1 = gen_num(&mut rng);
            s2 = gen_num(&mut rng);
            p = ds_of_bigint(bigint_of_ds(p) % p_mod());
            code! {
                p1  = [0; 4];
                p12 = [0; 4];
                p2  = [0; 4];
                p21 = [0; 4];
                p_p = #0*4*8;
                s_p = #1*4*8;
                r_p = #2*4*8;

                // s2*(s1*P)
                for i in (0..4) {
                    MEM[s_p + i*8] = s1[i];
                    MEM[p_p + i*8] = p[i];
                }
                scalarmult_ext(r_p,s_p,p_p);
                for i in (0..4) {
                    p1[i] = MEM[r_p + i*8];
                    MEM[s_p + i*8] = s2[i];
                    MEM[p_p + i*8] = p1[i];
                }
                scalarmult_ext(r_p,s_p,p_p);
                for i in (0..4) {
                    p12[i] = MEM[r_p + i*8];
                }

                // s1*(s2*P)
                for i in (0..4) {
                    MEM[p_p + i*8] = p[i];
                    MEM[s_p + i*8] = s2[i];
                }
                scalarmult_ext(r_p,s_p,p_p);
                for i in (0..4) {
                    p2[i] = MEM[r_p + i*8];
                    MEM[s_p + i*8] = s1[i];
                    MEM[p_p + i*8] = p2[i];
                }
                scalarmult_ext(r_p,s_p,p_p);
                for i in (0..4) {
                    p21[i] = MEM[r_p + i*8];
                }
            }
            assert_eq!(p12,p21);
        }
    }
}
<|endoftext|>


<commit_before>use crate::context::Context;
use crate::instance::{
    siginfo_ext::SiginfoExt, FaultDetails, Instance, State, TerminationDetails, CURRENT_INSTANCE,
    HOST_CTX,
};
use crate::sysdeps::UContextPtr;
use failure::Error;
use lazy_static::lazy_static;
use libc::{c_int, c_void, siginfo_t, SIGBUS, SIGSEGV};
use lucet_module_data::TrapCode;
use nix::sys::signal::{
    pthread_sigmask, raise, sigaction, SaFlags, SigAction, SigHandler, SigSet, SigmaskHow, Signal,
};
use std::sync::Mutex;

lazy_static! {
    // TODO: work out an alternative to this that is signal-safe for `reraise_host_signal_in_handler`
    static ref LUCET_SIGNAL_STATE: Mutex<Option<SignalState>> = Mutex::new(None);
}

/// The value returned by
/// [`Instance.signal_handler`](struct.Instance.html#structfield.signal_handler) to determine the
/// outcome of a handled signal.
pub enum SignalBehavior {
    /// Use default behavior, which switches back to the host with `State::Fault` populated.
    Default,
    /// Override default behavior and cause the instance to continue.
    Continue,
    /// Override default behavior and cause the instance to terminate.
    Terminate,
}

pub type SignalHandler = dyn Fn(
    &Instance,
    &Option<TrapCode>,
    libc::c_int,
    *const siginfo_t,
    *const c_void,
) -> SignalBehavior;

pub fn signal_handler_none(
    _inst: &Instance,
    _trapcode: &Option<TrapCode>,
    _signum: libc::c_int,
    _siginfo_ptr: *const siginfo_t,
    _ucontext_ptr: *const c_void,
) -> SignalBehavior {
    SignalBehavior::Default
}

impl Instance {
    pub(crate) fn with_signals_on<F, R>(&mut self, f: F) -> Result<R, Error>
    where
        F: FnOnce(&mut Instance) -> Result<R, Error>,
    {
        // setup signal stack for this thread
        let guest_sigstack = SigStack::new(
            self.alloc.slot().sigstack,
            SigStackFlags::empty(),
            libc::SIGSTKSZ,
        );
        let saved_sigstack =
            unsafe { sigaltstack(&guest_sigstack).expect("saving sigaltstack succeeds") };

        let mut ostate = LUCET_SIGNAL_STATE.lock().unwrap();
        if let Some(ref mut state) = *ostate {
            state.counter += 1;
        } else {
            unsafe {
                setup_guest_signal_state(&mut ostate);
            }
        }
        drop(ostate);

        // run the body
        let res = f(self);

        let mut ostate = LUCET_SIGNAL_STATE.lock().unwrap();
        let counter_zero = if let Some(ref mut state) = *ostate {
            state.counter -= 1;
            if state.counter == 0 {
                unsafe {
                    // restore the host signal stack
                    sigaltstack(&saved_sigstack).expect("sigaltstack restoration succeeds");
                    restore_host_signal_state(state);
                }
                true
            } else {
                false
            }
        } else {
            panic!("signal handlers weren't installed at instance exit");
        };
        if counter_zero {
            *ostate = None;
        }

        res
    }
}

/// Signal handler installed during instance execution.
///
/// This function is only designed to handle signals that are the direct result of execution of a
/// hardware instruction from the faulting WASM thread. It thus safely assumes the signal is
/// directed specifically at this thread (i.e. not a different thread or the process as a whole).
extern "C" fn handle_signal(signum: c_int, siginfo_ptr: *mut siginfo_t, ucontext_ptr: *mut c_void) {
    let signal = Signal::from_c_int(signum).expect("signum is a valid signal");
    if !(signal == Signal::SIGBUS
        || signal == Signal::SIGSEGV
        || signal == Signal::SIGILL
        || signal == Signal::SIGFPE)
    {
        panic!("unexpected signal in guest signal handler: {:?}", signal);
    }
    assert!(!siginfo_ptr.is_null(), "siginfo must not be null");

    // Safety: when using a SA_SIGINFO sigaction, the third argument can be cast to a `ucontext_t`
    // pointer per the manpage
    assert!(!ucontext_ptr.is_null(), "ucontext_ptr must not be null");
    let ctx = UContextPtr::new(ucontext_ptr);
    let rip = ctx.get_ip();

    let switch_to_host = CURRENT_INSTANCE.with(|current_instance| {
        let mut current_instance = current_instance.borrow_mut();

        if current_instance.is_none() {
            // If there is no current instance, we've caught a signal raised by a thread that's not
            // running a lucet instance. Restore the host signal handler and reraise the signal,
            // then return if the host handler returns
            unsafe {
                reraise_host_signal_in_handler(signal, signum, siginfo_ptr, ucontext_ptr);
            }
            // don't try context-switching
            return false;
        }

        // Safety: the memory pointed to by CURRENT_INSTANCE should be a valid instance. This is not
        // a trivial property, but relies on the compiler not emitting guest programs that can
        // overwrite the instance.
        let inst = unsafe {
            current_instance
                .as_mut()
                .expect("current instance exists")
                .as_mut()
        };

        let trapcode = inst.module.lookup_trapcode(rip);

        let behavior = (inst.signal_handler)(inst, &trapcode, signum, siginfo_ptr, ucontext_ptr);
        match behavior {
            SignalBehavior::Continue => {
                // return to the guest context without making any modifications to the instance
                false
            }
            SignalBehavior::Terminate => {
                // set the state before jumping back to the host context
                inst.state = State::Terminated {
                    details: TerminationDetails::Signal,
                };
                true
            }
            SignalBehavior::Default => {
                // safety: pointer is checked for null at the top of the function, and the
                // manpage guarantees that a siginfo_t will be passed as the second argument
                let siginfo = unsafe { *siginfo_ptr };
                let rip_addr = rip as usize;
                // If the trap table lookup returned unknown, it is a fatal error
                let unknown_fault = trapcode.is_none();

                // If the trap was a segv or bus fault and the addressed memory was outside the
                // guard pages, it is also a fatal error
                let outside_guard = (siginfo.si_signo == SIGSEGV || siginfo.si_signo == SIGBUS)
                    && !inst.alloc.addr_in_heap_guard(siginfo.si_addr());

                // record the fault and jump back to the host context
                inst.state = State::Fault {
                    details: FaultDetails {
                        fatal: unknown_fault || outside_guard,
                        trapcode: trapcode,
                        rip_addr,
                        // Details set to `None` here: have to wait until `verify_trap_safety` to
                        // fill in these details, because access may not be signal safe.
                        rip_addr_details: None,
                    },
                    siginfo,
                    context: ctx.into(),
                };
                true
            }
        }
    });

    if switch_to_host {
        HOST_CTX.with(|host_ctx| unsafe {
            Context::set_from_signal(&*host_ctx.get())
                .expect("can successfully switch back to the host context");
        });
        unreachable!()
    }
}

struct SignalState {
    counter: usize,
    saved_sigbus: SigAction,
    saved_sigfpe: SigAction,
    saved_sigill: SigAction,
    saved_sigsegv: SigAction,
}

// raw pointers in the saved types
unsafe impl Send for SignalState {}

unsafe fn setup_guest_signal_state(ostate: &mut Option<SignalState>) {
    let mut masked_signals = SigSet::empty();
    masked_signals.add(Signal::SIGBUS);
    masked_signals.add(Signal::SIGFPE);
    masked_signals.add(Signal::SIGILL);
    masked_signals.add(Signal::SIGSEGV);

    // setup signal handlers
    let sa = SigAction::new(
        SigHandler::SigAction(handle_signal),
        SaFlags::SA_RESTART | SaFlags::SA_SIGINFO | SaFlags::SA_ONSTACK,
        masked_signals,
    );
    let saved_sigbus = sigaction(Signal::SIGBUS, &sa).expect("sigaction succeeds");
    let saved_sigfpe = sigaction(Signal::SIGFPE, &sa).expect("sigaction succeeds");
    let saved_sigill = sigaction(Signal::SIGILL, &sa).expect("sigaction succeeds");
    let saved_sigsegv = sigaction(Signal::SIGSEGV, &sa).expect("sigaction succeeds");

    *ostate = Some(SignalState {
        counter: 1,
        saved_sigbus,
        saved_sigfpe,
        saved_sigill,
        saved_sigsegv,
    });
}

unsafe fn restore_host_signal_state(state: &mut SignalState) {
    // restore signal handlers
    sigaction(Signal::SIGBUS, &state.saved_sigbus).expect("sigaction succeeds");
    sigaction(Signal::SIGFPE, &state.saved_sigfpe).expect("sigaction succeeds");
    sigaction(Signal::SIGILL, &state.saved_sigill).expect("sigaction succeeds");
    sigaction(Signal::SIGSEGV, &state.saved_sigsegv).expect("sigaction succeeds");
}

unsafe fn reraise_host_signal_in_handler(
    sig: Signal,
    signum: libc::c_int,
    siginfo_ptr: *mut libc::siginfo_t,
    ucontext_ptr: *mut c_void,
) {
    let saved_handler = {
        // TODO: avoid taking a mutex here, probably by having some static muts just for this
        // function
        if let Some(ref state) = *LUCET_SIGNAL_STATE.lock().unwrap() {
            match sig {
                Signal::SIGBUS => state.saved_sigbus.clone(),
                Signal::SIGFPE => state.saved_sigfpe.clone(),
                Signal::SIGILL => state.saved_sigill.clone(),
                Signal::SIGSEGV => state.saved_sigsegv.clone(),
                sig => panic!(
                    "unexpected signal in reraise_host_signal_in_handler: {:?}",
                    sig
                ),
            }
        } else {
            // this case is very fishy; it can arise when the last lucet instance spins down and
            // uninstalls the lucet handlers while a signal handler is running on this thread, but
            // before taking the mutex above. The theory is that if this has happened, the host
            // handler has been reinstalled, so we shouldn't end up back here if we reraise

            // unmask the signal to reraise; we don't have to restore it because the handler will return
            // after this. If it signals again between here and now, that's a double fault and the
            // process is going to die anyway
            let mut unmask = SigSet::empty();
            unmask.add(sig);
            pthread_sigmask(SigmaskHow::SIG_UNBLOCK, Some(&unmask), None)
                .expect("pthread_sigmask succeeds");
            // if there's no current signal state, just re-raise and hope for the best
            raise(sig).expect("raise succeeds");
            return;
        }
    };

    match saved_handler.handler() {
        SigHandler::SigDfl => {
            // reinstall default signal handler and reraise the signal; this should terminate the
            // program
            sigaction(sig, &saved_handler).expect("sigaction succeeds");
            let mut unmask = SigSet::empty();
            unmask.add(sig);
            pthread_sigmask(SigmaskHow::SIG_UNBLOCK, Some(&unmask), None)
                .expect("pthread_sigmask succeeds");
            raise(sig).expect("raise succeeds");
        }
        SigHandler::SigIgn => {
            // don't do anything; if we hit this case, whatever program is hosting us is almost
            // certainly doing something wrong, because our set of signals requires intervention to
            // proceed
            return;
        }
        SigHandler::Handler(f) => {
            // call the saved handler directly so there is no altstack confusion
            f(signum)
        }
        SigHandler::SigAction(f) => {
            // call the saved handler directly so there is no altstack confusion
            f(signum, siginfo_ptr, ucontext_ptr)
        }
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// A collection of wrappers that will be upstreamed to the `nix` crate eventually.
////////////////////////////////////////////////////////////////////////////////////////////////////

use bitflags::bitflags;

#[derive(Copy, Clone)]
pub struct SigStack {
    stack: libc::stack_t,
}

impl SigStack {
    pub fn new(sp: *mut libc::c_void, flags: SigStackFlags, size: libc::size_t) -> SigStack {
        let mut stack = unsafe { std::mem::uninitialized::<libc::stack_t>() };
        stack.ss_sp = sp;
        stack.ss_flags = flags.bits();
        stack.ss_size = size;
        SigStack { stack }
    }

    pub fn flags(&self) -> SigStackFlags {
        SigStackFlags::from_bits_truncate(self.stack.ss_flags)
    }
}

impl AsRef<libc::stack_t> for SigStack {
    fn as_ref(&self) -> &libc::stack_t {
        &self.stack
    }
}

impl AsMut<libc::stack_t> for SigStack {
    fn as_mut(&mut self) -> &mut libc::stack_t {
        &mut self.stack
    }
}

bitflags! {
    pub struct SigStackFlags: libc::c_int {
        const SS_ONSTACK = libc::SS_ONSTACK;
        const SS_DISABLE = libc::SS_DISABLE;
    }
}

pub unsafe fn sigaltstack(ss: &SigStack) -> nix::Result<SigStack> {
    let mut oldstack = std::mem::uninitialized::<libc::stack_t>();

    let res = libc::sigaltstack(
        &ss.stack as *const libc::stack_t,
        &mut oldstack as *mut libc::stack_t,
    );

    nix::errno::Errno::result(res).map(|_| SigStack { stack: oldstack })
}
<commit_msg>[lucet-runtime] silence panic output when terminating instances<commit_after>use crate::context::Context;
use crate::instance::{
    siginfo_ext::SiginfoExt, FaultDetails, Instance, State, TerminationDetails, CURRENT_INSTANCE,
    HOST_CTX,
};
use crate::sysdeps::UContextPtr;
use failure::Error;
use lazy_static::lazy_static;
use libc::{c_int, c_void, siginfo_t, SIGBUS, SIGSEGV};
use lucet_module_data::TrapCode;
use nix::sys::signal::{
    pthread_sigmask, raise, sigaction, SaFlags, SigAction, SigHandler, SigSet, SigmaskHow, Signal,
};
use std::panic;
use std::sync::{Arc, Mutex};

lazy_static! {
    // TODO: work out an alternative to this that is signal-safe for `reraise_host_signal_in_handler`
    static ref LUCET_SIGNAL_STATE: Mutex<Option<SignalState>> = Mutex::new(None);
}

/// The value returned by
/// [`Instance.signal_handler`](struct.Instance.html#structfield.signal_handler) to determine the
/// outcome of a handled signal.
pub enum SignalBehavior {
    /// Use default behavior, which switches back to the host with `State::Fault` populated.
    Default,
    /// Override default behavior and cause the instance to continue.
    Continue,
    /// Override default behavior and cause the instance to terminate.
    Terminate,
}

pub type SignalHandler = dyn Fn(
    &Instance,
    &Option<TrapCode>,
    libc::c_int,
    *const siginfo_t,
    *const c_void,
) -> SignalBehavior;

pub fn signal_handler_none(
    _inst: &Instance,
    _trapcode: &Option<TrapCode>,
    _signum: libc::c_int,
    _siginfo_ptr: *const siginfo_t,
    _ucontext_ptr: *const c_void,
) -> SignalBehavior {
    SignalBehavior::Default
}

impl Instance {
    pub(crate) fn with_signals_on<F, R>(&mut self, f: F) -> Result<R, Error>
    where
        F: FnOnce(&mut Instance) -> Result<R, Error>,
    {
        // setup signal stack for this thread
        let guest_sigstack = SigStack::new(
            self.alloc.slot().sigstack,
            SigStackFlags::empty(),
            libc::SIGSTKSZ,
        );
        let saved_sigstack =
            unsafe { sigaltstack(&guest_sigstack).expect("saving sigaltstack succeeds") };

        let mut ostate = LUCET_SIGNAL_STATE.lock().unwrap();
        if let Some(ref mut state) = *ostate {
            state.counter += 1;
        } else {
            unsafe {
                setup_guest_signal_state(&mut ostate);
            }
        }
        drop(ostate);

        // run the body
        let res = f(self);

        let mut ostate = LUCET_SIGNAL_STATE.lock().unwrap();
        let counter_zero = if let Some(ref mut state) = *ostate {
            state.counter -= 1;
            if state.counter == 0 {
                unsafe {
                    // restore the host signal stack
                    sigaltstack(&saved_sigstack).expect("sigaltstack restoration succeeds");
                    restore_host_signal_state(state);
                }
                true
            } else {
                false
            }
        } else {
            panic!("signal handlers weren't installed at instance exit");
        };
        if counter_zero {
            *ostate = None;
        }

        res
    }
}

/// Signal handler installed during instance execution.
///
/// This function is only designed to handle signals that are the direct result of execution of a
/// hardware instruction from the faulting WASM thread. It thus safely assumes the signal is
/// directed specifically at this thread (i.e. not a different thread or the process as a whole).
extern "C" fn handle_signal(signum: c_int, siginfo_ptr: *mut siginfo_t, ucontext_ptr: *mut c_void) {
    let signal = Signal::from_c_int(signum).expect("signum is a valid signal");
    if !(signal == Signal::SIGBUS
        || signal == Signal::SIGSEGV
        || signal == Signal::SIGILL
        || signal == Signal::SIGFPE)
    {
        panic!("unexpected signal in guest signal handler: {:?}", signal);
    }
    assert!(!siginfo_ptr.is_null(), "siginfo must not be null");

    // Safety: when using a SA_SIGINFO sigaction, the third argument can be cast to a `ucontext_t`
    // pointer per the manpage
    assert!(!ucontext_ptr.is_null(), "ucontext_ptr must not be null");
    let ctx = UContextPtr::new(ucontext_ptr);
    let rip = ctx.get_ip();

    let switch_to_host = CURRENT_INSTANCE.with(|current_instance| {
        let mut current_instance = current_instance.borrow_mut();

        if current_instance.is_none() {
            // If there is no current instance, we've caught a signal raised by a thread that's not
            // running a lucet instance. Restore the host signal handler and reraise the signal,
            // then return if the host handler returns
            unsafe {
                reraise_host_signal_in_handler(signal, signum, siginfo_ptr, ucontext_ptr);
            }
            // don't try context-switching
            return false;
        }

        // Safety: the memory pointed to by CURRENT_INSTANCE should be a valid instance. This is not
        // a trivial property, but relies on the compiler not emitting guest programs that can
        // overwrite the instance.
        let inst = unsafe {
            current_instance
                .as_mut()
                .expect("current instance exists")
                .as_mut()
        };

        let trapcode = inst.module.lookup_trapcode(rip);

        let behavior = (inst.signal_handler)(inst, &trapcode, signum, siginfo_ptr, ucontext_ptr);
        match behavior {
            SignalBehavior::Continue => {
                // return to the guest context without making any modifications to the instance
                false
            }
            SignalBehavior::Terminate => {
                // set the state before jumping back to the host context
                inst.state = State::Terminated {
                    details: TerminationDetails::Signal,
                };
                true
            }
            SignalBehavior::Default => {
                // safety: pointer is checked for null at the top of the function, and the
                // manpage guarantees that a siginfo_t will be passed as the second argument
                let siginfo = unsafe { *siginfo_ptr };
                let rip_addr = rip as usize;
                // If the trap table lookup returned unknown, it is a fatal error
                let unknown_fault = trapcode.is_none();

                // If the trap was a segv or bus fault and the addressed memory was outside the
                // guard pages, it is also a fatal error
                let outside_guard = (siginfo.si_signo == SIGSEGV || siginfo.si_signo == SIGBUS)
                    && !inst.alloc.addr_in_heap_guard(siginfo.si_addr());

                // record the fault and jump back to the host context
                inst.state = State::Fault {
                    details: FaultDetails {
                        fatal: unknown_fault || outside_guard,
                        trapcode: trapcode,
                        rip_addr,
                        // Details set to `None` here: have to wait until `verify_trap_safety` to
                        // fill in these details, because access may not be signal safe.
                        rip_addr_details: None,
                    },
                    siginfo,
                    context: ctx.into(),
                };
                true
            }
        }
    });

    if switch_to_host {
        HOST_CTX.with(|host_ctx| unsafe {
            Context::set_from_signal(&*host_ctx.get())
                .expect("can successfully switch back to the host context");
        });
        unreachable!()
    }
}

struct SignalState {
    counter: usize,
    saved_sigbus: SigAction,
    saved_sigfpe: SigAction,
    saved_sigill: SigAction,
    saved_sigsegv: SigAction,
    saved_panic_hook: Option<Arc<Box<dyn Fn(&panic::PanicInfo) + Sync + Send + 'static>>>,
}

// raw pointers in the saved types
unsafe impl Send for SignalState {}

unsafe fn setup_guest_signal_state(ostate: &mut Option<SignalState>) {
    let mut masked_signals = SigSet::empty();
    masked_signals.add(Signal::SIGBUS);
    masked_signals.add(Signal::SIGFPE);
    masked_signals.add(Signal::SIGILL);
    masked_signals.add(Signal::SIGSEGV);

    // setup signal handlers
    let sa = SigAction::new(
        SigHandler::SigAction(handle_signal),
        SaFlags::SA_RESTART | SaFlags::SA_SIGINFO | SaFlags::SA_ONSTACK,
        masked_signals,
    );
    let saved_sigbus = sigaction(Signal::SIGBUS, &sa).expect("sigaction succeeds");
    let saved_sigfpe = sigaction(Signal::SIGFPE, &sa).expect("sigaction succeeds");
    let saved_sigill = sigaction(Signal::SIGILL, &sa).expect("sigaction succeeds");
    let saved_sigsegv = sigaction(Signal::SIGSEGV, &sa).expect("sigaction succeeds");

    let saved_panic_hook = Some(setup_guest_panic_hook());

    *ostate = Some(SignalState {
        counter: 1,
        saved_sigbus,
        saved_sigfpe,
        saved_sigill,
        saved_sigsegv,
        saved_panic_hook,
    });
}

fn setup_guest_panic_hook() -> Arc<Box<dyn Fn(&panic::PanicInfo) + Sync + Send + 'static>> {
    let saved_panic_hook = Arc::new(panic::take_hook());
    let closure_saved_panic_hook = saved_panic_hook.clone();
    std::panic::set_hook(Box::new(move |panic_info| {
        if panic_info
            .payload()
            .downcast_ref::<TerminationDetails>()
            .is_none()
        {
            closure_saved_panic_hook(panic_info);
        } else {
            // this is a panic used to implement instance termination (such as
            // `lucet_hostcall_terminate!`), so we don't want to print a backtrace; instead, we do
            // nothing
        }
    }));
    saved_panic_hook
}

unsafe fn restore_host_signal_state(state: &mut SignalState) {
    // restore signal handlers
    sigaction(Signal::SIGBUS, &state.saved_sigbus).expect("sigaction succeeds");
    sigaction(Signal::SIGFPE, &state.saved_sigfpe).expect("sigaction succeeds");
    sigaction(Signal::SIGILL, &state.saved_sigill).expect("sigaction succeeds");
    sigaction(Signal::SIGSEGV, &state.saved_sigsegv).expect("sigaction succeeds");

    // restore panic hook
    drop(panic::take_hook());
    state
        .saved_panic_hook
        .take()
        .map(|hook| Arc::try_unwrap(hook).map(|hook| panic::set_hook(hook)));
}

unsafe fn reraise_host_signal_in_handler(
    sig: Signal,
    signum: libc::c_int,
    siginfo_ptr: *mut libc::siginfo_t,
    ucontext_ptr: *mut c_void,
) {
    let saved_handler = {
        // TODO: avoid taking a mutex here, probably by having some static muts just for this
        // function
        if let Some(ref state) = *LUCET_SIGNAL_STATE.lock().unwrap() {
            match sig {
                Signal::SIGBUS => state.saved_sigbus.clone(),
                Signal::SIGFPE => state.saved_sigfpe.clone(),
                Signal::SIGILL => state.saved_sigill.clone(),
                Signal::SIGSEGV => state.saved_sigsegv.clone(),
                sig => panic!(
                    "unexpected signal in reraise_host_signal_in_handler: {:?}",
                    sig
                ),
            }
        } else {
            // this case is very fishy; it can arise when the last lucet instance spins down and
            // uninstalls the lucet handlers while a signal handler is running on this thread, but
            // before taking the mutex above. The theory is that if this has happened, the host
            // handler has been reinstalled, so we shouldn't end up back here if we reraise

            // unmask the signal to reraise; we don't have to restore it because the handler will return
            // after this. If it signals again between here and now, that's a double fault and the
            // process is going to die anyway
            let mut unmask = SigSet::empty();
            unmask.add(sig);
            pthread_sigmask(SigmaskHow::SIG_UNBLOCK, Some(&unmask), None)
                .expect("pthread_sigmask succeeds");
            // if there's no current signal state, just re-raise and hope for the best
            raise(sig).expect("raise succeeds");
            return;
        }
    };

    match saved_handler.handler() {
        SigHandler::SigDfl => {
            // reinstall default signal handler and reraise the signal; this should terminate the
            // program
            sigaction(sig, &saved_handler).expect("sigaction succeeds");
            let mut unmask = SigSet::empty();
            unmask.add(sig);
            pthread_sigmask(SigmaskHow::SIG_UNBLOCK, Some(&unmask), None)
                .expect("pthread_sigmask succeeds");
            raise(sig).expect("raise succeeds");
        }
        SigHandler::SigIgn => {
            // don't do anything; if we hit this case, whatever program is hosting us is almost
            // certainly doing something wrong, because our set of signals requires intervention to
            // proceed
            return;
        }
        SigHandler::Handler(f) => {
            // call the saved handler directly so there is no altstack confusion
            f(signum)
        }
        SigHandler::SigAction(f) => {
            // call the saved handler directly so there is no altstack confusion
            f(signum, siginfo_ptr, ucontext_ptr)
        }
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// A collection of wrappers that will be upstreamed to the `nix` crate eventually.
////////////////////////////////////////////////////////////////////////////////////////////////////

use bitflags::bitflags;

#[derive(Copy, Clone)]
pub struct SigStack {
    stack: libc::stack_t,
}

impl SigStack {
    pub fn new(sp: *mut libc::c_void, flags: SigStackFlags, size: libc::size_t) -> SigStack {
        let mut stack = unsafe { std::mem::uninitialized::<libc::stack_t>() };
        stack.ss_sp = sp;
        stack.ss_flags = flags.bits();
        stack.ss_size = size;
        SigStack { stack }
    }

    pub fn flags(&self) -> SigStackFlags {
        SigStackFlags::from_bits_truncate(self.stack.ss_flags)
    }
}

impl AsRef<libc::stack_t> for SigStack {
    fn as_ref(&self) -> &libc::stack_t {
        &self.stack
    }
}

impl AsMut<libc::stack_t> for SigStack {
    fn as_mut(&mut self) -> &mut libc::stack_t {
        &mut self.stack
    }
}

bitflags! {
    pub struct SigStackFlags: libc::c_int {
        const SS_ONSTACK = libc::SS_ONSTACK;
        const SS_DISABLE = libc::SS_DISABLE;
    }
}

pub unsafe fn sigaltstack(ss: &SigStack) -> nix::Result<SigStack> {
    let mut oldstack = std::mem::uninitialized::<libc::stack_t>();

    let res = libc::sigaltstack(
        &ss.stack as *const libc::stack_t,
        &mut oldstack as *mut libc::stack_t,
    );

    nix::errno::Errno::result(res).map(|_| SigStack { stack: oldstack })
}
<|endoftext|>