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

use data::packet::Packet;
use data::frame::ArcFrame;

use error::*;
pub use common::CodecList;

pub trait Decoder {
    // TODO support codec configuration using set_option
    // fn open(&mut self) -> Result<()>;
    fn set_extradata(&mut self, extra: &[u8]);
    fn send_packet(&mut self, pkt: &Packet) -> Result<()>;
    fn receive_frame(&mut self) -> Result<ArcFrame>;
    fn configure(&mut self) -> Result<()>;
    fn flush(&mut self) -> Result<()>;
}

#[derive(Debug)]
pub struct Descr {
    pub codec: &'static str,
    pub name: &'static str,
    pub desc: &'static str,
    pub mime: &'static str,
    // TODO more fields regarding capabilities
}

pub struct Context {
    dec: Box<Decoder>,
    // TODO: Queue up packets/frames
}

impl Context {
    // TODO: More constructors
    pub fn by_name(codecs: &Codecs, name: &str) -> Option<Context> {
        if let Some(builder) = codecs.by_name(name) {
            let dec = builder.create();
            Some(Context { dec: dec })
        } else {
            None
        }
    }
    pub fn set_extradata(&mut self, extra: &[u8]) {
        self.dec.set_extradata(extra);
    }
    pub fn send_packet(&mut self, pkt: &Packet) -> Result<()> {
        self.dec.send_packet(pkt)
    }
    pub fn receive_frame(&mut self) -> Result<ArcFrame> {
        self.dec.receive_frame()
    }
    pub fn configure(&mut self) -> Result<()> {
        self.dec.configure()
    }

    pub fn flush(&mut self) -> Result<()> {
        self.dec.flush()
    }
}

pub trait Descriptor {
    fn create(&self) -> Box<Decoder>;
    fn describe<'a>(&'a self) -> &'a Descr;
}

pub struct Codecs {
    list: HashMap<&'static str, Vec<&'static Descriptor>>
}

impl CodecList for Codecs {
    type D = Descriptor;

    fn new() -> Codecs {
        Codecs { list: HashMap::new() }
    }

    // TODO more lookup functions
    fn by_name(&self, name: &str) -> Option<&'static Self::D> {
        if let Some(descs) = self.list.get(name) {
            Some(descs[0])
        } else {
            None
        }
    }

    fn append(&mut self, desc: &'static Self::D) {
        let codec_name = desc.describe().codec;

        self.list.entry(codec_name).or_insert(Vec::new()).push(desc);
    }
}

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

    mod dummy {
        use super::super::*;
        use std::rc::Rc;
        use data::pixel::Formaton;

        struct Dec {
            state: usize,
            format: Option<Rc<Formaton>>
        }

        pub struct Des {
            descr: Descr,
        }

        impl Descriptor for Des {
            fn create(&self) -> Box<Decoder> {
                box Dec { state: 0, format: None }
            }
            fn describe<'a>(&'a self) -> &'a Descr {
                &self.descr
            }
        }

        impl Decoder for Dec {
            fn configure(&mut self) -> Result<()> {
                Ok(())
            }
            fn set_extradata(&mut self, extra: &[u8]) {
                if extra.len() > 4 {
                    self.state = 42;
                } else {
                    self.state = 12;
                }
            }
            fn send_packet(&mut self, _packet: &Packet) -> Result<()> {
                self.state += 1;
                Ok(())
            }
            fn receive_frame(&mut self) -> Result<ArcFrame> {
                unimplemented!()
            }
            fn flush(&mut self) -> Result<()> {
                Ok(())
            }
        }

        pub const DUMMY_DESCR: &Des = &Des {
            descr: Descr {
                codec: "dummy",
                name: "dummy",
                desc: "Dummy encoder",
                mime: "x-application/dummy",
            }
        };
    }
    use self::dummy::DUMMY_DESCR;

    #[test]
    fn lookup() {
        let codecs = Codecs::from_list(&[DUMMY_DESCR]);

        let _dec = codecs.by_name("dummy").unwrap();
    }
}
<commit_msg>codec: Update the still unused format cache in the test<commit_after>use std::collections::HashMap;

use data::packet::Packet;
use data::frame::ArcFrame;

use error::*;
pub use common::CodecList;

pub trait Decoder {
    // TODO support codec configuration using set_option
    // fn open(&mut self) -> Result<()>;
    fn set_extradata(&mut self, extra: &[u8]);
    fn send_packet(&mut self, pkt: &Packet) -> Result<()>;
    fn receive_frame(&mut self) -> Result<ArcFrame>;
    fn configure(&mut self) -> Result<()>;
    fn flush(&mut self) -> Result<()>;
}

#[derive(Debug)]
pub struct Descr {
    pub codec: &'static str,
    pub name: &'static str,
    pub desc: &'static str,
    pub mime: &'static str,
    // TODO more fields regarding capabilities
}

pub struct Context {
    dec: Box<Decoder>,
    // TODO: Queue up packets/frames
}

impl Context {
    // TODO: More constructors
    pub fn by_name(codecs: &Codecs, name: &str) -> Option<Context> {
        if let Some(builder) = codecs.by_name(name) {
            let dec = builder.create();
            Some(Context { dec: dec })
        } else {
            None
        }
    }
    pub fn set_extradata(&mut self, extra: &[u8]) {
        self.dec.set_extradata(extra);
    }
    pub fn send_packet(&mut self, pkt: &Packet) -> Result<()> {
        self.dec.send_packet(pkt)
    }
    pub fn receive_frame(&mut self) -> Result<ArcFrame> {
        self.dec.receive_frame()
    }
    pub fn configure(&mut self) -> Result<()> {
        self.dec.configure()
    }

    pub fn flush(&mut self) -> Result<()> {
        self.dec.flush()
    }
}

pub trait Descriptor {
    fn create(&self) -> Box<Decoder>;
    fn describe<'a>(&'a self) -> &'a Descr;
}

pub struct Codecs {
    list: HashMap<&'static str, Vec<&'static Descriptor>>
}

impl CodecList for Codecs {
    type D = Descriptor;

    fn new() -> Codecs {
        Codecs { list: HashMap::new() }
    }

    // TODO more lookup functions
    fn by_name(&self, name: &str) -> Option<&'static Self::D> {
        if let Some(descs) = self.list.get(name) {
            Some(descs[0])
        } else {
            None
        }
    }

    fn append(&mut self, desc: &'static Self::D) {
        let codec_name = desc.describe().codec;

        self.list.entry(codec_name).or_insert(Vec::new()).push(desc);
    }
}

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

    mod dummy {
        use super::super::*;
        use std::sync::Arc;
        use data::pixel::Formaton;

        struct Dec {
            state: usize,
            format: Option<Arc<Formaton>>
        }

        pub struct Des {
            descr: Descr,
        }

        impl Descriptor for Des {
            fn create(&self) -> Box<Decoder> {
                box Dec { state: 0, format: None }
            }
            fn describe<'a>(&'a self) -> &'a Descr {
                &self.descr
            }
        }

        impl Decoder for Dec {
            fn configure(&mut self) -> Result<()> {
                Ok(())
            }
            fn set_extradata(&mut self, extra: &[u8]) {
                if extra.len() > 4 {
                    self.state = 42;
                } else {
                    self.state = 12;
                }
            }
            fn send_packet(&mut self, _packet: &Packet) -> Result<()> {
                self.state += 1;
                Ok(())
            }
            fn receive_frame(&mut self) -> Result<ArcFrame> {
                unimplemented!()
            }
            fn flush(&mut self) -> Result<()> {
                Ok(())
            }
        }

        pub const DUMMY_DESCR: &Des = &Des {
            descr: Descr {
                codec: "dummy",
                name: "dummy",
                desc: "Dummy encoder",
                mime: "x-application/dummy",
            }
        };
    }
    use self::dummy::DUMMY_DESCR;

    #[test]
    fn lookup() {
        let codecs = Codecs::from_list(&[DUMMY_DESCR]);

        let _dec = codecs.by_name("dummy").unwrap();
    }
}
<|endoftext|>


<commit_before>//
// Mnemosyne: a functional systems programming language.
// (c) 2015 Hawk Weisman
//
// Mnemosyne is released under the MIT License. Please refer to
// the LICENSE file at the top-level directory of this distribution
// or at https://github.com/hawkw/mnemosyne/.
//

use std::borrow::Borrow;
use std::collections::HashMap;
use std::hash::Hash;
use std::{ fmt
         , iter
         };
use std::fmt::Write;
use std::rc::Rc;

use itertools::Itertools;

use ::position::Positional;
use super::annotations::{ Annotated
                        , ScopednessTypestate
                        , ScopedState
                        , Scoped
                        };
use super::types;
use super::SymbolTable;

pub type Ident = Positional<String>;

pub type Expr<'a, S: ScopednessTypestate>
    = Annotated<'a
               , Form<'a, S>
               , S>;

pub type Body<'a, S: ScopednessTypestate> = Vec<Expr<'a, S>>;

pub type Bindings<'a, S: ScopednessTypestate>
    = Vec<Annotated<'a
                   , Binding<'a, S>
                   , S>>;

macro_rules! concat_exprs {
    ($it:expr, $level:expr) => {
        $it.iter()
           .map(|expr| expr.to_sexpr($level) )
           .intersperse(String::from(" "))
           .collect::<String>()
        };
    ($it:expr, $level:expr, $sep:expr) => {
        $it.iter()
           .map(|expr| expr.to_sexpr($level) )
           .intersperse(String::from($sep))
           .collect::<String>()
        }
}

/// Trait for a node in the abstract syntax tree.
///
/// This provides a visitor method for semantic analysis (which may be split
/// into multiple transforms later), and a method for formatting the AST node
/// as an S-expression.
pub trait Node {

   /// Pretty-print the AST node as an S-expression at the desired
   /// indentation level.]
   ///
   /// Note that this prints the desugared form and may not be a perfect
   /// match for the original source code.
   fn to_sexpr(&self, level: usize) -> String;

}

/// To format a node for display, just use the S-expression representation.
impl fmt::Display for Node + Sized {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.to_sexpr(0))
    }
}

pub trait AnnotateTypes<'a>: Sized {

   #[allow(unused_variables)]
   fn annotate_types(self, scope: SymbolTable) -> Scoped<'a, Self> {
       unimplemented!() //TODO: implement
   }
}

#[derive(PartialEq, Clone, Debug)]
pub struct Module<'a, S: ScopednessTypestate> {
    pub name: Ident
  , pub exporting: Vec<Ident>
  , pub body: Body<'a, S>
}

impl<'a, S> Module<'a, S> where S: ScopednessTypestate {

    /// Returns true if the namespace is exporting any names
    #[inline] pub fn is_lib (&self) -> bool { !self.exporting.is_empty() }

}

impl<'a> Scoped<'a, Module<'a, ScopedState>>{

    /// Returns true if the namespace contains a given name.
    pub fn contains_name<Q: ?Sized>(&self, name: &Q) -> bool
    where String: Borrow<Q>
        , String: PartialEq<Q>
        , Q: Hash + Eq
    {
        self.is_defined_here(name) &&
        self.node.exporting
            .iter()
            .find(|ref i| &i.value == name)
            .is_some()
    }

}

#[derive(PartialEq, Clone, Debug)]
pub enum Form<'a, S: ScopednessTypestate> {
    // TODO: maybe definitions aren't expressions?
    // (they don't return a value...)
    Define(DefForm<'a, S>)
  , If { condition: Rc<Expr<'a, S>>
       , if_clause: Rc<Expr<'a, S>>
       , else_clause: Option<Rc<Expr<'a, S>>>
       }
  , Let(LetForm<'a, S>)
  , Call { fun: Ident
         , body: Body<'a, S>
         }
  , Lambda(Function<'a, S>)
  , Logical(Logical<'a, S>)
  , Lit(Literal)
  , NameRef(NameRef)
}

#[derive(PartialEq, Clone, Debug)]
pub enum NameRef { Owned(Ident)
                 , Borrowed(Ident)
                 , Deref(Ident)
                 , Unique(Ident)
                 }

#[derive(PartialEq, Clone, Debug)]
pub struct Formal { pub name: Ident
                  , pub annot: Ident
                  }

#[derive(PartialEq, Clone, Debug)]
pub enum DefForm<'a, S: ScopednessTypestate> {
    TopLevel { name: Ident
             , annot: types::Type
             , value: Rc<Expr<'a, S>>
             }
  , Function { name: Ident
             , fun: Function<'a,S>
             }
}

#[derive(PartialEq, Clone, Debug)]
pub struct Class<'a, S: ScopednessTypestate> {
    pub name: Ident
  , pub ty_param: Ident
  , pub defs: Vec<Prototype<'a, S>>
}

#[derive(PartialEq, Clone, Debug)]
pub struct Instance<'a, S: ScopednessTypestate> {
    pub class: Ident
  , pub ty: types::Type
  , pub functions: Vec<Function<'a, S>>
}

/// Logical `and` and `or` expressions
///
/// The general expectation is that these will generally be parsed as infix.
#[derive(PartialEq, Clone, Debug)]
pub enum Logical<'a, S: ScopednessTypestate> {
    And { a: Rc<Expr<'a, S>>
        , b: Rc<Expr<'a, S>>
        }
  , Or { a: Rc<Expr<'a, S>>
       , b: Rc<Expr<'a, S>>
       }
}

#[derive(PartialEq, Clone, Debug)]
pub enum Literal { IntConst(i64)
                 , UintConst(u64)
                 , StringLit(String)
                 }

impl fmt::Display for Literal {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self { Literal::IntConst(ref n)    => write!(f, "{}", n)
                    , Literal::UintConst(ref n)   => write!(f, "{}", n)
                    , Literal::StringLit(ref s)   => write!(f, "{}", s)
                    }
    }
}

#[derive(PartialEq, Clone, Debug)]
pub enum LetForm<'a, S: ScopednessTypestate> {
    Let { bindings: Bindings<'a, S>
        , body: Body<'a, S>
        }
  , Invocation { proc_id: Ident
               , init: Binding<'a, S>
               , body: Body<'a, S>
               }
  , LetRec { bindings: Bindings<'a, S>
           , body: Body<'a, S>
           }
  , LetSplat { bindings: Bindings<'a, S>
             , body: Body<'a, S>
             }
}

#[derive(PartialEq, Clone, Debug)]
pub struct Binding<'a, S: ScopednessTypestate> {
    pub name: Ident
  , pub typ: types::Type
  , pub value: Rc<Expr<'a, S>>
}

#[derive(PartialEq, Clone, Debug)]
pub struct Function<'a, S: ScopednessTypestate> {
    pub sig: types::Signature
  , pub equations: Vec<Equation<'a, S>>
}

/// A pattern is a vector of pattern elements.
///
/// When entering a function scope that binds using patterns, we should
/// check that the pattern's length matches the arity of the function,
/// until autocurrying is implemented (after the Glorious Revolution).
pub type Pattern = Vec<PatElement>;

impl Node for Pattern {
   #[allow(unused_variables)]
   fn to_sexpr(&self, level: usize) -> String {
       format!( "({})", concat_exprs!(self, level) )
   }

}

/// An element in a pattern-matching expression.
///
/// A pattern element can be a name binding, a typed name binding,
/// a literal, or the magic underscore (anything). Destructuring bind
/// will come later, as will equality.
#[derive(PartialEq, Clone, Debug)]
pub enum PatElement { // eventually this could just be implemented using an Expr,
                      // but it's currently this way because the types of patterns
                      // that you can write are currently quite limited
                      Name(Ident)
                    , Typed { name: Ident, ty: types::Type }
                    , Lit(Literal)
                      // TODO: write literal types for other things (i.e. lists)
                    , Anything
                    }

impl Node for PatElement {
   #[allow(unused_variables)]
   fn to_sexpr(&self, level: usize) -> String {
       match *self {
           PatElement::Name(ref n) => n.to_sexpr(level)
         , PatElement::Typed { ref name, ref ty } =>
            format!( "{}: {}"
                   , name.to_sexpr(level)
                   , ty )
        , PatElement::Lit(ref c) => format!("{}", c)
        , PatElement::Anything => String::from("_")
       }
   }

}

/// A function equation definition
#[derive(PartialEq, Clone, Debug)]
pub struct Equation<'a, S: ScopednessTypestate> {
    pub pattern: Pattern
 ,  pub body: Body<'a, S>
}

#[derive(PartialEq, Clone, Debug)]
pub struct Prototype<'a, S: ScopednessTypestate> {
    pub formals: Vec<Annotated<'a, Formal, S>>
  , pub annot: Ident
}

pub type Variant<'a, S: ScopednessTypestate>
    = Vec<Annotated<'a, Formal, S>>;

#[derive(PartialEq, Clone, Debug)]
pub struct Data<'a, S: ScopednessTypestate> {
    pub name: Ident
  , pub variants: HashMap<Ident, Variant<'a, S>>
}

// #[derive(PartialEq, Clone, Debug)]
// pub enum Data<'a, S: ScopednessTypestate> {
//     Sum { name: Ident
//         , variants: Vec<Type> }
//   , Product { name: Ident
//             , fields: Vec<Binding<'a, S>> }
// }

impl<'a, S> Data<'a, S>
where S: ScopednessTypestate {

    /// Returns true if this ADT is a sum type
    pub fn is_sum_type(&self) -> bool {
        self.variants.len() > 1
    }

    /// Returns true if this ADT is a product type
    #[inline] pub fn is_product_type(&self) -> bool {
        !self.is_sum_type()
    }

    /// Returns the fields of a product type.
    ///
    /// # Returns
    ///  + A `Some<Vec<Annotated<'a, Formal, S>>>` representing
    ///    this type's fields, if this is the definition of a
    ///    product type.
    ///  + Otherwise, `None`
    pub fn get_product_fields(&self) -> Option<&Variant<'a, S>> {
        self.variants.get(&self.name)
    }
}

impl<'a, S> Node for Form<'a, S>
where S: ScopednessTypestate {
   #[allow(unused_variables)]
   fn to_sexpr(&self, level: usize) -> String {
       match *self {
           Form::Define(ref form)  => form.to_sexpr(level)
         , Form::Let(ref form)     => form.to_sexpr(level)
         , Form::If { .. }         => unimplemented!()
         , Form::Call { ref fun, ref body } =>
               format!( "({} {})"
                      , fun.to_sexpr(level)
                      , concat_exprs!(body, level) )
         , Form::Lambda(ref fun)   => fun.to_sexpr(level)
         , Form::Logical(ref form) => form.to_sexpr(level)
         , Form::Lit(ref c)   => format!("{}", c)
         , Form::NameRef(ref n)    => n.to_sexpr(level)
       }
   }

}

impl<'a, S> Node for DefForm<'a, S>
where S: ScopednessTypestate {

    fn to_sexpr(&self, level: usize) -> String {
        match *self {
            DefForm::TopLevel { ref name, ref annot, ref value } =>
                format!("{}(define {} {} {})"
                  , indent!(level)
                  , name.to_sexpr(level)
                  , annot
                  , value.to_sexpr(level + 1)
                  )
          , DefForm::Function { ref name, ref fun } =>
                format!("{}(define {} {}\n)"
                  , indent!(level)
                  , name.to_sexpr(level)
                  , fun.to_sexpr(level)
                  )
        }
    }

}

impl<'a, S> Node for LetForm<'a, S>
where S: ScopednessTypestate {

    fn to_sexpr(&self, level: usize) -> String {
        match *self {
            LetForm::Let { ref bindings, ref body } =>
                format!("{}(let [{}]\n{})"
                    , indent!(level)
                    , concat_exprs!(bindings, level, "\n")
                    , concat_exprs!(body, level + 1)
                    )
          , LetForm::LetRec { ref bindings, ref body } =>
                format!("{}(letrec [{}]\n{})"
                    , indent!(level)
                    , concat_exprs!(bindings, level, "\n")
                    , concat_exprs!(body, level + 1)
                    )
          , LetForm::LetSplat { ref bindings, ref body } =>
                format!("{}(let* [{}]\n{})"
                    , indent!(level)
                    , concat_exprs!(bindings, level, "\n")
                    , concat_exprs!(body, level + 1)
                    )
          , _ => unimplemented!()
        }
    }

}

impl<'a, S> Node for Logical<'a, S>
where S: ScopednessTypestate
{
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String {
        match *self {
            Logical::And { ref a, ref b } =>
                format!( "(and {} {})"
                       , a.to_sexpr(level)
                       , b.to_sexpr(level)
                       )
         ,  Logical::Or { ref a, ref b }  =>
                format!( "(and {} {})"
                       , a.to_sexpr(level)
                       , b.to_sexpr(level)
                       )
        }
    }
}

impl<'a, S> Node for Function<'a, S>
where S: ScopednessTypestate
{
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String {
        unimplemented!()
    }
}

impl<'a, S> Node for Binding<'a, S>
where S: ScopednessTypestate
{
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String {
        unimplemented!()
    }
}

impl Node for Formal {
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String {
        format!("{}: {}", *(self.name), *(self.annot))
    }

}

impl Node for NameRef {
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String {
        match *self  { NameRef::Owned(ref name)      => format!("{}", **name)
                     , NameRef::Borrowed(ref name)   => format!("&{}", **name)
                     , NameRef::Deref(ref name)      => format!("*{}", **name)
                     , NameRef::Unique(ref name)     => format!("@{}", **name)
                     }

    }
}

impl Node for Ident {
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String { self.value.clone() }

}
<commit_msg>Implemented Node for new function AST types<commit_after>//
// Mnemosyne: a functional systems programming language.
// (c) 2015 Hawk Weisman
//
// Mnemosyne is released under the MIT License. Please refer to
// the LICENSE file at the top-level directory of this distribution
// or at https://github.com/hawkw/mnemosyne/.
//

use std::borrow::Borrow;
use std::collections::HashMap;
use std::hash::Hash;
use std::{ fmt
         , iter
         };
use std::fmt::Write;
use std::rc::Rc;

use itertools::Itertools;

use ::chars;
use ::position::Positional;
use super::annotations::{ Annotated
                        , ScopednessTypestate
                        , ScopedState
                        , Scoped
                        };
use super::types;
use super::SymbolTable;

pub type Ident = Positional<String>;

pub type Expr<'a, S: ScopednessTypestate>
    = Annotated<'a
               , Form<'a, S>
               , S>;

pub type Body<'a, S: ScopednessTypestate> = Vec<Expr<'a, S>>;

pub type Bindings<'a, S: ScopednessTypestate>
    = Vec<Annotated<'a
                   , Binding<'a, S>
                   , S>>;

macro_rules! concat_exprs {
    ($it:expr, $level:expr) => {
        $it.iter()
           .map(|expr| expr.to_sexpr($level) )
           .intersperse(String::from(" "))
           .collect::<String>()
        };
    ($it:expr, $level:expr, $sep:expr) => {
        $it.iter()
           .map(|expr| expr.to_sexpr($level) )
           .intersperse(String::from($sep))
           .collect::<String>()
        }
}

/// Trait for a node in the abstract syntax tree.
///
/// This provides a visitor method for semantic analysis (which may be split
/// into multiple transforms later), and a method for formatting the AST node
/// as an S-expression.
pub trait Node {

   /// Pretty-print the AST node as an S-expression at the desired
   /// indentation level.]
   ///
   /// Note that this prints the desugared form and may not be a perfect
   /// match for the original source code.
   fn to_sexpr(&self, level: usize) -> String;

}

/// To format a node for display, just use the S-expression representation.
impl fmt::Display for Node + Sized {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.to_sexpr(0))
    }
}

pub trait AnnotateTypes<'a>: Sized {

   #[allow(unused_variables)]
   fn annotate_types(self, scope: SymbolTable) -> Scoped<'a, Self> {
       unimplemented!() //TODO: implement
   }
}

#[derive(PartialEq, Clone, Debug)]
pub struct Module<'a, S: ScopednessTypestate> {
    pub name: Ident
  , pub exporting: Vec<Ident>
  , pub body: Body<'a, S>
}

impl<'a, S> Module<'a, S> where S: ScopednessTypestate {

    /// Returns true if the namespace is exporting any names
    #[inline] pub fn is_lib (&self) -> bool { !self.exporting.is_empty() }

}

impl<'a> Scoped<'a, Module<'a, ScopedState>>{

    /// Returns true if the namespace contains a given name.
    pub fn contains_name<Q: ?Sized>(&self, name: &Q) -> bool
    where String: Borrow<Q>
        , String: PartialEq<Q>
        , Q: Hash + Eq
    {
        self.is_defined_here(name) &&
        self.node.exporting
            .iter()
            .find(|ref i| &i.value == name)
            .is_some()
    }

}

#[derive(PartialEq, Clone, Debug)]
pub enum Form<'a, S: ScopednessTypestate> {
    // TODO: maybe definitions aren't expressions?
    // (they don't return a value...)
    Define(DefForm<'a, S>)
  , If { condition: Rc<Expr<'a, S>>
       , if_clause: Rc<Expr<'a, S>>
       , else_clause: Option<Rc<Expr<'a, S>>>
       }
  , Let(LetForm<'a, S>)
  , Call { fun: Ident
         , body: Body<'a, S>
         }
  , Lambda(Function<'a, S>)
  , Logical(Logical<'a, S>)
  , Lit(Literal)
  , NameRef(NameRef)
}

#[derive(PartialEq, Clone, Debug)]
pub enum NameRef { Owned(Ident)
                 , Borrowed(Ident)
                 , Deref(Ident)
                 , Unique(Ident)
                 }

#[derive(PartialEq, Clone, Debug)]
pub struct Formal { pub name: Ident
                  , pub annot: Ident
                  }

#[derive(PartialEq, Clone, Debug)]
pub enum DefForm<'a, S: ScopednessTypestate> {
    TopLevel { name: Ident
             , annot: types::Type
             , value: Rc<Expr<'a, S>>
             }
  , Function { name: Ident
             , fun: Function<'a,S>
             }
}

#[derive(PartialEq, Clone, Debug)]
pub struct Class<'a, S: ScopednessTypestate> {
    pub name: Ident
  , pub ty_param: Ident
  , pub defs: Vec<Prototype<'a, S>>
}

#[derive(PartialEq, Clone, Debug)]
pub struct Instance<'a, S: ScopednessTypestate> {
    pub class: Ident
  , pub ty: types::Type
  , pub functions: Vec<Function<'a, S>>
}

/// Logical `and` and `or` expressions
///
/// The general expectation is that these will generally be parsed as infix.
#[derive(PartialEq, Clone, Debug)]
pub enum Logical<'a, S: ScopednessTypestate> {
    And { a: Rc<Expr<'a, S>>
        , b: Rc<Expr<'a, S>>
        }
  , Or { a: Rc<Expr<'a, S>>
       , b: Rc<Expr<'a, S>>
       }
}

#[derive(PartialEq, Clone, Debug)]
pub enum Literal { IntConst(i64)
                 , UintConst(u64)
                 , StringLit(String)
                 }

impl fmt::Display for Literal {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self { Literal::IntConst(ref n)    => write!(f, "{}", n)
                    , Literal::UintConst(ref n)   => write!(f, "{}", n)
                    , Literal::StringLit(ref s)   => write!(f, "{}", s)
                    }
    }
}

#[derive(PartialEq, Clone, Debug)]
pub enum LetForm<'a, S: ScopednessTypestate> {
    Let { bindings: Bindings<'a, S>
        , body: Body<'a, S>
        }
  , Invocation { proc_id: Ident
               , init: Binding<'a, S>
               , body: Body<'a, S>
               }
  , LetRec { bindings: Bindings<'a, S>
           , body: Body<'a, S>
           }
  , LetSplat { bindings: Bindings<'a, S>
             , body: Body<'a, S>
             }
}

#[derive(PartialEq, Clone, Debug)]
pub struct Binding<'a, S: ScopednessTypestate> {
    pub name: Ident
  , pub typ: types::Type
  , pub value: Rc<Expr<'a, S>>
}

#[derive(PartialEq, Clone, Debug)]
pub struct Function<'a, S: ScopednessTypestate> {
    pub sig: types::Signature
  , pub equations: Vec<Equation<'a, S>>
}

/// A pattern is a vector of pattern elements.
///
/// When entering a function scope that binds using patterns, we should
/// check that the pattern's length matches the arity of the function,
/// until autocurrying is implemented (after the Glorious Revolution).
pub type Pattern = Vec<PatElement>;

impl Node for Pattern {
   #[allow(unused_variables)]
   fn to_sexpr(&self, level: usize) -> String {
       format!( "({})", concat_exprs!(self, level) )
   }

}

/// An element in a pattern-matching expression.
///
/// A pattern element can be a name binding, a typed name binding,
/// a literal, or the magic underscore (anything). Destructuring bind
/// will come later, as will equality.
#[derive(PartialEq, Clone, Debug)]
pub enum PatElement { // eventually this could just be implemented using an Expr,
                      // but it's currently this way because the types of patterns
                      // that you can write are currently quite limited
                      Name(Ident)
                    , Typed { name: Ident, ty: types::Type }
                    , Lit(Literal)
                      // TODO: write literal types for other things (i.e. lists)
                    , Anything
                    }

impl Node for PatElement {
   #[allow(unused_variables)]
   fn to_sexpr(&self, level: usize) -> String {
       match *self {
           PatElement::Name(ref n) => n.to_sexpr(level)
         , PatElement::Typed { ref name, ref ty } =>
            format!( "{}: {}"
                   , name.to_sexpr(level)
                   , ty )
        , PatElement::Lit(ref c) => format!("{}", c)
        , PatElement::Anything => String::from("_")
       }
   }

}

/// A function equation definition
#[derive(PartialEq, Clone, Debug)]
pub struct Equation<'a, S: ScopednessTypestate> {
    pub pattern: Pattern
 ,  pub body: Body<'a, S>
}

impl<'a, S> Node for Equation<'a, S>
where S: ScopednessTypestate  {

    fn to_sexpr(&self, level: usize) -> String {
        format!( "({} {})"
               , self.pattern
                     .to_sexpr(level)
               , concat_exprs!( self.body
                              , level + 1
                              , format!("\n{}", indent!(level + 1))
                              )
              )
    }

}

#[derive(PartialEq, Clone, Debug)]
pub struct Prototype<'a, S: ScopednessTypestate> {
    pub formals: Vec<Annotated<'a, Formal, S>>
  , pub annot: Ident
}

pub type Variant<'a, S: ScopednessTypestate>
    = Vec<Annotated<'a, Formal, S>>;

#[derive(PartialEq, Clone, Debug)]
pub struct Data<'a, S: ScopednessTypestate> {
    pub name: Ident
  , pub variants: HashMap<Ident, Variant<'a, S>>
}

// #[derive(PartialEq, Clone, Debug)]
// pub enum Data<'a, S: ScopednessTypestate> {
//     Sum { name: Ident
//         , variants: Vec<Type> }
//   , Product { name: Ident
//             , fields: Vec<Binding<'a, S>> }
// }

impl<'a, S> Data<'a, S>
where S: ScopednessTypestate {

    /// Returns true if this ADT is a sum type
    pub fn is_sum_type(&self) -> bool {
        self.variants.len() > 1
    }

    /// Returns true if this ADT is a product type
    #[inline] pub fn is_product_type(&self) -> bool {
        !self.is_sum_type()
    }

    /// Returns the fields of a product type.
    ///
    /// # Returns
    ///  + A `Some<Vec<Annotated<'a, Formal, S>>>` representing
    ///    this type's fields, if this is the definition of a
    ///    product type.
    ///  + Otherwise, `None`
    pub fn get_product_fields(&self) -> Option<&Variant<'a, S>> {
        self.variants.get(&self.name)
    }
}

impl<'a, S> Node for Form<'a, S>
where S: ScopednessTypestate {
   #[allow(unused_variables)]
   fn to_sexpr(&self, level: usize) -> String {
       match *self {
           Form::Define(ref form)  => form.to_sexpr(level)
         , Form::Let(ref form)     => form.to_sexpr(level)
         , Form::If { .. }         => unimplemented!()
         , Form::Call { ref fun, ref body } =>
               format!( "({} {})"
                      , fun.to_sexpr(level)
                      , concat_exprs!(body, level) )
         , Form::Lambda(ref fun)   => fun.to_sexpr(level)
         , Form::Logical(ref form) => form.to_sexpr(level)
         , Form::Lit(ref c)   => format!("{}", c)
         , Form::NameRef(ref n)    => n.to_sexpr(level)
       }
   }

}

impl<'a, S> Node for DefForm<'a, S>
where S: ScopednessTypestate {

    fn to_sexpr(&self, level: usize) -> String {
        match *self {
            DefForm::TopLevel { ref name, ref annot, ref value } =>
                format!("{}(define {} {} {})"
                  , indent!(level)
                  , name.to_sexpr(level)
                  , annot
                  , value.to_sexpr(level + 1)
                  )
          , DefForm::Function { ref name, ref fun } =>
                format!("{}(define {} {}\n)"
                  , indent!(level)
                  , name.to_sexpr(level)
                  , fun.to_sexpr(level)
                  )
        }
    }

}

impl<'a, S> Node for LetForm<'a, S>
where S: ScopednessTypestate {

    fn to_sexpr(&self, level: usize) -> String {
        match *self {
            LetForm::Let { ref bindings, ref body } =>
                format!("{}(let [{}]\n{})"
                    , indent!(level)
                    , concat_exprs!(bindings, level, "\n")
                    , concat_exprs!(body, level + 1)
                    )
          , LetForm::LetRec { ref bindings, ref body } =>
                format!("{}(letrec [{}]\n{})"
                    , indent!(level)
                    , concat_exprs!(bindings, level, "\n")
                    , concat_exprs!(body, level + 1)
                    )
          , LetForm::LetSplat { ref bindings, ref body } =>
                format!("{}(let* [{}]\n{})"
                    , indent!(level)
                    , concat_exprs!(bindings, level, "\n")
                    , concat_exprs!(body, level + 1)
                    )
          , _ => unimplemented!()
        }
    }

}

impl<'a, S> Node for Logical<'a, S>
where S: ScopednessTypestate
{
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String {
        match *self {
            Logical::And { ref a, ref b } =>
                format!( "(and {} {})"
                       , a.to_sexpr(level)
                       , b.to_sexpr(level)
                       )
         ,  Logical::Or { ref a, ref b }  =>
                format!( "(and {} {})"
                       , a.to_sexpr(level)
                       , b.to_sexpr(level)
                       )
        }
    }
}

impl<'a, S> Node for Function<'a, S>
where S: ScopednessTypestate
{
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String {
        format!( "({} {}\n{}{})"
               , chars::LAMBDA
               , self.sig.to_sexpr(level)
               , indent!(level + 1)
               , concat_exprs!(self.equations, level + 1, "\n")
            )
    }
}

impl<'a, S> Node for Binding<'a, S>
where S: ScopednessTypestate
{
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String {
        unimplemented!()
    }
}

impl Node for Formal {
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String {
        format!("{}: {}", *(self.name), *(self.annot))
    }

}

impl Node for NameRef {
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String {
        match *self  { NameRef::Owned(ref name)      => format!("{}", **name)
                     , NameRef::Borrowed(ref name)   => format!("&{}", **name)
                     , NameRef::Deref(ref name)      => format!("*{}", **name)
                     , NameRef::Unique(ref name)     => format!("@{}", **name)
                     }

    }
}

impl Node for Ident {
    #[allow(unused_variables)]
    fn to_sexpr(&self, level: usize) -> String { self.value.clone() }

}
<|endoftext|>


<commit_before>//! SMTP client

use bufstream::BufStream;
use nom::ErrorKind as NomErrorKind;
use smtp::authentication::{Credentials, Mechanism};
use smtp::client::net::{ClientTlsParameters, Connector, NetworkStream, Timeout};
use smtp::commands::*;
use smtp::error::{Error, SmtpResult};
use smtp::response::Response;
use std::fmt::{Debug, Display};
use std::io::{self, BufRead, BufReader, Read, Write};
use std::net::ToSocketAddrs;
use std::string::String;
use std::time::Duration;

pub mod mock;
pub mod net;

/// The codec used for transparency
#[derive(Default, Clone, Copy, Debug)]
#[cfg_attr(feature = "serde-impls", derive(Serialize, Deserialize))]
pub struct ClientCodec {
    escape_count: u8,
}

impl ClientCodec {
    /// Creates a new client codec
    pub fn new() -> Self {
        ClientCodec::default()
    }
}

impl ClientCodec {
    /// Adds transparency
    /// TODO: replace CR and LF by CRLF
    fn encode(&mut self, frame: &[u8], buf: &mut Vec<u8>) -> Result<(), Error> {
        match frame.len() {
            0 => {
                match self.escape_count {
                    0 => buf.write_all(b"\r\n.\r\n")?,
                    1 => buf.write_all(b"\n.\r\n")?,
                    2 => buf.write_all(b".\r\n")?,
                    _ => unreachable!(),
                }
                self.escape_count = 0;
                Ok(())
            }
            _ => {
                let mut start = 0;
                for (idx, byte) in frame.iter().enumerate() {
                    match self.escape_count {
                        0 => self.escape_count = if *byte == b'\r' { 1 } else { 0 },
                        1 => self.escape_count = if *byte == b'\n' { 2 } else { 0 },
                        2 => self.escape_count = if *byte == b'.' { 3 } else { 0 },
                        _ => unreachable!(),
                    }
                    if self.escape_count == 3 {
                        self.escape_count = 0;
                        buf.write_all(&frame[start..idx])?;
                        buf.write_all(b".")?;
                        start = idx;
                    }
                }
                buf.write_all(&frame[start..])?;
                Ok(())
            }
        }
    }
}

/// Returns the string replacing all the CRLF with "\<CRLF\>"
/// Used for debug displays
fn escape_crlf(string: &str) -> String {
    string.replace("\r\n", "<CRLF>")
}

/// Structure that implements the SMTP client
#[derive(Debug, Default)]
pub struct InnerClient<S: Write + Read = NetworkStream> {
    /// TCP stream between client and server
    /// Value is None before connection
    stream: Option<BufStream<S>>,
}

macro_rules! return_err (
    ($err: expr, $client: ident) => ({
        return Err(From::from($err))
    })
);

#[cfg_attr(feature = "cargo-clippy", allow(new_without_default_derive))]
impl<S: Write + Read> InnerClient<S> {
    /// Creates a new SMTP client
    ///
    /// It does not connects to the server, but only creates the `Client`
    pub fn new() -> InnerClient<S> {
        InnerClient { stream: None }
    }
}

impl<S: Connector + Write + Read + Timeout + Debug> InnerClient<S> {
    /// Closes the SMTP transaction if possible
    pub fn close(&mut self) {
        let _ = self.command(QuitCommand);
        self.stream = None;
    }

    /// Sets the underlying stream
    pub fn set_stream(&mut self, stream: S) {
        self.stream = Some(BufStream::new(stream));
    }

    /// Upgrades the underlying connection to SSL/TLS
    pub fn upgrade_tls_stream(&mut self, tls_parameters: &ClientTlsParameters) -> io::Result<()> {
        match self.stream {
            Some(ref mut stream) => stream.get_mut().upgrade_tls(tls_parameters),
            None => Ok(()),
        }
    }

    /// Tells if the underlying stream is currently encrypted
    pub fn is_encrypted(&self) -> bool {
        match self.stream {
            Some(ref stream) => stream.get_ref().is_encrypted(),
            None => false,
        }
    }

    /// Set timeout
    pub fn set_timeout(&mut self, duration: Option<Duration>) -> io::Result<()> {
        match self.stream {
            Some(ref mut stream) => {
                stream.get_mut().set_read_timeout(duration)?;
                stream.get_mut().set_write_timeout(duration)?;
                Ok(())
            }
            None => Ok(()),
        }
    }

    /// Connects to the configured server
    pub fn connect<A: ToSocketAddrs>(
        &mut self,
        addr: &A,
        tls_parameters: Option<&ClientTlsParameters>,
    ) -> SmtpResult {
        // Connect should not be called when the client is already connected
        if self.stream.is_some() {
            return_err!("The connection is already established", self);
        }

        let mut addresses = addr.to_socket_addrs()?;

        let server_addr = match addresses.next() {
            Some(addr) => addr,
            None => return_err!("Could not resolve hostname", self),
        };

        debug!("connecting to {}", server_addr);

        // Try to connect
        self.set_stream(Connector::connect(&server_addr, tls_parameters)?);

        self.read_response()
    }

    /// Checks if the server is connected using the NOOP SMTP command
    #[cfg_attr(feature = "cargo-clippy", allow(wrong_self_convention))]
    pub fn is_connected(&mut self) -> bool {
        self.command(NoopCommand).is_ok()
    }

    /// Sends an AUTH command with the given mechanism, and handles challenge if needed
    pub fn auth(&mut self, mechanism: Mechanism, credentials: &Credentials) -> SmtpResult {
        // TODO
        let mut challenges = 10;
        let mut response = self.command(AuthCommand::new(mechanism, credentials.clone(), None)?)?;

        while challenges > 0 && response.has_code(334) {
            challenges -= 1;
            response = self.command(AuthCommand::new_from_response(
                mechanism,
                credentials.clone(),
                &response,
            )?)?;
        }

        if challenges == 0 {
            Err(Error::ResponseParsing("Unexpected number of challenges"))
        } else {
            Ok(response)
        }
    }

    /// Sends the message content
    pub fn message(&mut self, message: Box<Read>) -> SmtpResult {
        let mut out_buf: Vec<u8> = vec![];
        let mut codec = ClientCodec::new();

        let mut message_reader = BufReader::new(message);

        loop {
            out_buf.clear();

            let consumed = match message_reader.fill_buf() {
                Ok(bytes) => {
                    codec.encode(bytes, &mut out_buf)?;
                    bytes.len()
                }
                Err(ref err) => panic!("Failed with: {}", err),
            };
            message_reader.consume(consumed);

            if consumed == 0 {
                break;
            }

            self.write(out_buf.as_slice())?;
        }

        self.write(b"\r\n.\r\n")?;
        self.read_response()
    }

    /// Sends an SMTP command
    pub fn command<C: Display>(&mut self, command: C) -> SmtpResult {
        self.write(command.to_string().as_bytes())?;
        self.read_response()
    }

    /// Writes a string to the server
    fn write(&mut self, string: &[u8]) -> Result<(), Error> {
        if self.stream.is_none() {
            return Err(From::from("Connection closed"));
        }

        self.stream.as_mut().unwrap().write_all(string)?;
        self.stream.as_mut().unwrap().flush()?;

        debug!(
            "Wrote: {}",
            escape_crlf(String::from_utf8_lossy(string).as_ref())
        );
        Ok(())
    }

    /// Gets the SMTP response
    fn read_response(&mut self) -> SmtpResult {
        let mut raw_response = String::new();
        let mut response = raw_response.parse::<Response>();

        while response.is_err() {
            if response.as_ref().err().unwrap() != &NomErrorKind::Complete {
                break;
            }
            // TODO read more than one line
            self.stream.as_mut().unwrap().read_line(&mut raw_response)?;
            response = raw_response.parse::<Response>();
        }

        debug!("Read: {}", escape_crlf(raw_response.as_ref()));

        let final_response = response?;

        if final_response.is_positive() {
            Ok(final_response)
        } else {
            Err(From::from(final_response))
        }
    }
}

#[cfg(test)]
mod test {
    use super::{escape_crlf, ClientCodec};

    #[test]
    fn test_codec() {
        let mut codec = ClientCodec::new();
        let mut buf: Vec<u8> = vec![];

        assert!(codec.encode(b"test\r\n", &mut buf).is_ok());
        assert!(codec.encode(b".\r\n", &mut buf).is_ok());
        assert!(codec.encode(b"\r\ntest", &mut buf).is_ok());
        assert!(codec.encode(b"te\r\n.\r\nst", &mut buf).is_ok());
        assert!(codec.encode(b"test", &mut buf).is_ok());
        assert!(codec.encode(b"test.", &mut buf).is_ok());
        assert!(codec.encode(b"test\n", &mut buf).is_ok());
        assert!(codec.encode(b".test\n", &mut buf).is_ok());
        assert!(codec.encode(b"test", &mut buf).is_ok());
        assert_eq!(
            String::from_utf8(buf).unwrap(),
            "test\r\n..\r\n\r\ntestte\r\n..\r\nsttesttest.test\n.test\ntest"
        );
    }

    #[test]
    fn test_escape_crlf() {
        assert_eq!(escape_crlf("\r\n"), "<CRLF>");
        assert_eq!(escape_crlf("EHLO my_name\r\n"), "EHLO my_name<CRLF>");
        assert_eq!(
            escape_crlf("EHLO my_name\r\nSIZE 42\r\n"),
            "EHLO my_name<CRLF>SIZE 42<CRLF>"
        );
    }
}
<commit_msg>fix(smtp-transport): Client::read_response infinite loop<commit_after>//! SMTP client

use bufstream::BufStream;
use nom::ErrorKind as NomErrorKind;
use smtp::authentication::{Credentials, Mechanism};
use smtp::client::net::{ClientTlsParameters, Connector, NetworkStream, Timeout};
use smtp::commands::*;
use smtp::error::{Error, SmtpResult};
use smtp::response::Response;
use std::fmt::{Debug, Display};
use std::io::{self, BufRead, BufReader, Read, Write};
use std::net::ToSocketAddrs;
use std::string::String;
use std::time::Duration;

pub mod mock;
pub mod net;

/// The codec used for transparency
#[derive(Default, Clone, Copy, Debug)]
#[cfg_attr(feature = "serde-impls", derive(Serialize, Deserialize))]
pub struct ClientCodec {
    escape_count: u8,
}

impl ClientCodec {
    /// Creates a new client codec
    pub fn new() -> Self {
        ClientCodec::default()
    }
}

impl ClientCodec {
    /// Adds transparency
    /// TODO: replace CR and LF by CRLF
    fn encode(&mut self, frame: &[u8], buf: &mut Vec<u8>) -> Result<(), Error> {
        match frame.len() {
            0 => {
                match self.escape_count {
                    0 => buf.write_all(b"\r\n.\r\n")?,
                    1 => buf.write_all(b"\n.\r\n")?,
                    2 => buf.write_all(b".\r\n")?,
                    _ => unreachable!(),
                }
                self.escape_count = 0;
                Ok(())
            }
            _ => {
                let mut start = 0;
                for (idx, byte) in frame.iter().enumerate() {
                    match self.escape_count {
                        0 => self.escape_count = if *byte == b'\r' { 1 } else { 0 },
                        1 => self.escape_count = if *byte == b'\n' { 2 } else { 0 },
                        2 => self.escape_count = if *byte == b'.' { 3 } else { 0 },
                        _ => unreachable!(),
                    }
                    if self.escape_count == 3 {
                        self.escape_count = 0;
                        buf.write_all(&frame[start..idx])?;
                        buf.write_all(b".")?;
                        start = idx;
                    }
                }
                buf.write_all(&frame[start..])?;
                Ok(())
            }
        }
    }
}

/// Returns the string replacing all the CRLF with "\<CRLF\>"
/// Used for debug displays
fn escape_crlf(string: &str) -> String {
    string.replace("\r\n", "<CRLF>")
}

/// Structure that implements the SMTP client
#[derive(Debug, Default)]
pub struct InnerClient<S: Write + Read = NetworkStream> {
    /// TCP stream between client and server
    /// Value is None before connection
    stream: Option<BufStream<S>>,
}

macro_rules! return_err (
    ($err: expr, $client: ident) => ({
        return Err(From::from($err))
    })
);

#[cfg_attr(feature = "cargo-clippy", allow(new_without_default_derive))]
impl<S: Write + Read> InnerClient<S> {
    /// Creates a new SMTP client
    ///
    /// It does not connects to the server, but only creates the `Client`
    pub fn new() -> InnerClient<S> {
        InnerClient { stream: None }
    }
}

impl<S: Connector + Write + Read + Timeout + Debug> InnerClient<S> {
    /// Closes the SMTP transaction if possible
    pub fn close(&mut self) {
        let _ = self.command(QuitCommand);
        self.stream = None;
    }

    /// Sets the underlying stream
    pub fn set_stream(&mut self, stream: S) {
        self.stream = Some(BufStream::new(stream));
    }

    /// Upgrades the underlying connection to SSL/TLS
    pub fn upgrade_tls_stream(&mut self, tls_parameters: &ClientTlsParameters) -> io::Result<()> {
        match self.stream {
            Some(ref mut stream) => stream.get_mut().upgrade_tls(tls_parameters),
            None => Ok(()),
        }
    }

    /// Tells if the underlying stream is currently encrypted
    pub fn is_encrypted(&self) -> bool {
        match self.stream {
            Some(ref stream) => stream.get_ref().is_encrypted(),
            None => false,
        }
    }

    /// Set timeout
    pub fn set_timeout(&mut self, duration: Option<Duration>) -> io::Result<()> {
        match self.stream {
            Some(ref mut stream) => {
                stream.get_mut().set_read_timeout(duration)?;
                stream.get_mut().set_write_timeout(duration)?;
                Ok(())
            }
            None => Ok(()),
        }
    }

    /// Connects to the configured server
    pub fn connect<A: ToSocketAddrs>(
        &mut self,
        addr: &A,
        tls_parameters: Option<&ClientTlsParameters>,
    ) -> SmtpResult {
        // Connect should not be called when the client is already connected
        if self.stream.is_some() {
            return_err!("The connection is already established", self);
        }

        let mut addresses = addr.to_socket_addrs()?;

        let server_addr = match addresses.next() {
            Some(addr) => addr,
            None => return_err!("Could not resolve hostname", self),
        };

        debug!("connecting to {}", server_addr);

        // Try to connect
        self.set_stream(Connector::connect(&server_addr, tls_parameters)?);

        self.read_response()
    }

    /// Checks if the server is connected using the NOOP SMTP command
    #[cfg_attr(feature = "cargo-clippy", allow(wrong_self_convention))]
    pub fn is_connected(&mut self) -> bool {
        self.command(NoopCommand).is_ok()
    }

    /// Sends an AUTH command with the given mechanism, and handles challenge if needed
    pub fn auth(&mut self, mechanism: Mechanism, credentials: &Credentials) -> SmtpResult {
        // TODO
        let mut challenges = 10;
        let mut response = self.command(AuthCommand::new(mechanism, credentials.clone(), None)?)?;

        while challenges > 0 && response.has_code(334) {
            challenges -= 1;
            response = self.command(AuthCommand::new_from_response(
                mechanism,
                credentials.clone(),
                &response,
            )?)?;
        }

        if challenges == 0 {
            Err(Error::ResponseParsing("Unexpected number of challenges"))
        } else {
            Ok(response)
        }
    }

    /// Sends the message content
    pub fn message(&mut self, message: Box<Read>) -> SmtpResult {
        let mut out_buf: Vec<u8> = vec![];
        let mut codec = ClientCodec::new();

        let mut message_reader = BufReader::new(message);

        loop {
            out_buf.clear();

            let consumed = match message_reader.fill_buf() {
                Ok(bytes) => {
                    codec.encode(bytes, &mut out_buf)?;
                    bytes.len()
                }
                Err(ref err) => panic!("Failed with: {}", err),
            };
            message_reader.consume(consumed);

            if consumed == 0 {
                break;
            }

            self.write(out_buf.as_slice())?;
        }

        self.write(b"\r\n.\r\n")?;
        self.read_response()
    }

    /// Sends an SMTP command
    pub fn command<C: Display>(&mut self, command: C) -> SmtpResult {
        self.write(command.to_string().as_bytes())?;
        self.read_response()
    }

    /// Writes a string to the server
    fn write(&mut self, string: &[u8]) -> Result<(), Error> {
        if self.stream.is_none() {
            return Err(From::from("Connection closed"));
        }

        self.stream.as_mut().unwrap().write_all(string)?;
        self.stream.as_mut().unwrap().flush()?;

        debug!(
            "Wrote: {}",
            escape_crlf(String::from_utf8_lossy(string).as_ref())
        );
        Ok(())
    }

    /// Gets the SMTP response
    fn read_response(&mut self) -> SmtpResult {
        let mut raw_response = String::new();
        let mut response = raw_response.parse::<Response>();

        while response.is_err() {
            if response.as_ref().err().unwrap() != &NomErrorKind::Complete {
                break;
            }
            // TODO read more than one line
            let read_count = self.stream.as_mut().unwrap().read_line(&mut raw_response)?;

            // EOF is reached
            if read_count == 0 {
                break;
            }

            response = raw_response.parse::<Response>();
        }

        debug!("Read: {}", escape_crlf(raw_response.as_ref()));

        let final_response = response?;

        if final_response.is_positive() {
            Ok(final_response)
        } else {
            Err(From::from(final_response))
        }
    }
}

#[cfg(test)]
mod test {
    use super::{escape_crlf, ClientCodec};

    #[test]
    fn test_codec() {
        let mut codec = ClientCodec::new();
        let mut buf: Vec<u8> = vec![];

        assert!(codec.encode(b"test\r\n", &mut buf).is_ok());
        assert!(codec.encode(b".\r\n", &mut buf).is_ok());
        assert!(codec.encode(b"\r\ntest", &mut buf).is_ok());
        assert!(codec.encode(b"te\r\n.\r\nst", &mut buf).is_ok());
        assert!(codec.encode(b"test", &mut buf).is_ok());
        assert!(codec.encode(b"test.", &mut buf).is_ok());
        assert!(codec.encode(b"test\n", &mut buf).is_ok());
        assert!(codec.encode(b".test\n", &mut buf).is_ok());
        assert!(codec.encode(b"test", &mut buf).is_ok());
        assert_eq!(
            String::from_utf8(buf).unwrap(),
            "test\r\n..\r\n\r\ntestte\r\n..\r\nsttesttest.test\n.test\ntest"
        );
    }

    #[test]
    fn test_escape_crlf() {
        assert_eq!(escape_crlf("\r\n"), "<CRLF>");
        assert_eq!(escape_crlf("EHLO my_name\r\n"), "EHLO my_name<CRLF>");
        assert_eq!(
            escape_crlf("EHLO my_name\r\nSIZE 42\r\n"),
            "EHLO my_name<CRLF>SIZE 42<CRLF>"
        );
    }
}
<|endoftext|>


<commit_before>use std::{fmt, iter::FromIterator, sync::Arc};

use hir::{ExpandResult, MacroFile};
use ide_db::base_db::{
    salsa::debug::{DebugQueryTable, TableEntry},
    CrateId, FileId, FileTextQuery, SourceDatabase, SourceRootId,
};
use ide_db::{
    symbol_index::{LibrarySymbolsQuery, SymbolIndex},
    RootDatabase,
};
use itertools::Itertools;
use profile::{memory_usage, Bytes};
use rustc_hash::FxHashMap;
use stdx::format_to;
use syntax::{ast, Parse, SyntaxNode};

fn syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats {
    ide_db::base_db::ParseQuery.in_db(db).entries::<SyntaxTreeStats>()
}
fn macro_syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats {
    hir::db::ParseMacroExpansionQuery.in_db(db).entries::<SyntaxTreeStats>()
}

// Feature: Status
//
// Shows internal statistic about memory usage of rust-analyzer.
//
// |===
// | Editor  | Action Name
//
// | VS Code | **Rust Analyzer: Status**
// |===
// image::https://user-images.githubusercontent.com/48062697/113065584-05f34500-91b1-11eb-98cc-5c196f76be7f.gif[]
pub(crate) fn status(db: &RootDatabase, file_id: Option<FileId>) -> String {
    let mut buf = String::new();
    let count = profile::countme::get_all();
    format_to!(buf, "{}\n", FileTextQuery.in_db(db).entries::<FilesStats>());
    format_to!(buf, "{}\n", LibrarySymbolsQuery.in_db(db).entries::<LibrarySymbolsStats>());
    format_to!(buf, "{}\n", syntax_tree_stats(db));
    format_to!(buf, "{} (Macros)\n", macro_syntax_tree_stats(db));
    format_to!(buf, "{} Total\n", memory_usage());
    format_to!(
        buf,
        "\nCounts:\n{}",
        if count.to_string().contains("all counts are zero") {
            String::from("All counts are zero\n")
        } else {
            count.to_string()
        }
    );

    if let Some(file_id) = file_id {
        format_to!(buf, "\nFile info:\n");
        let krate = crate::parent_module::crate_for(db, file_id).pop();
        match krate {
            Some(krate) => {
                let crate_graph = db.crate_graph();
                let display_crate = |krate: CrateId| match &crate_graph[krate].display_name {
                    Some(it) => format!("{}({:?})", it, krate),
                    None => format!("{:?}", krate),
                };
                format_to!(buf, "crate: {}\n", display_crate(krate));
                let deps = crate_graph[krate]
                    .dependencies
                    .iter()
                    .map(|dep| format!("{}={:?}", dep.name, dep.crate_id))
                    .format(", ");
                format_to!(buf, "deps: {}\n", deps);
            }
            None => format_to!(buf, "does not belong to any crate"),
        }
    }

    buf
}

#[derive(Default)]
struct FilesStats {
    total: usize,
    size: Bytes,
}

impl fmt::Display for FilesStats {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{} ({}) files", self.total, self.size)
    }
}

impl FromIterator<TableEntry<FileId, Arc<String>>> for FilesStats {
    fn from_iter<T>(iter: T) -> FilesStats
    where
        T: IntoIterator<Item = TableEntry<FileId, Arc<String>>>,
    {
        let mut res = FilesStats::default();
        for entry in iter {
            res.total += 1;
            res.size += entry.value.unwrap().len();
        }
        res
    }
}

#[derive(Default)]
pub(crate) struct SyntaxTreeStats {
    total: usize,
    pub(crate) retained: usize,
}

impl fmt::Display for SyntaxTreeStats {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{} trees, {} retained", self.total, self.retained)
    }
}

impl FromIterator<TableEntry<FileId, Parse<ast::SourceFile>>> for SyntaxTreeStats {
    fn from_iter<T>(iter: T) -> SyntaxTreeStats
    where
        T: IntoIterator<Item = TableEntry<FileId, Parse<ast::SourceFile>>>,
    {
        let mut res = SyntaxTreeStats::default();
        for entry in iter {
            res.total += 1;
            res.retained += entry.value.is_some() as usize;
        }
        res
    }
}

impl<M> FromIterator<TableEntry<MacroFile, ExpandResult<Option<(Parse<SyntaxNode>, M)>>>>
    for SyntaxTreeStats
{
    fn from_iter<T>(iter: T) -> SyntaxTreeStats
    where
        T: IntoIterator<Item = TableEntry<MacroFile, ExpandResult<Option<(Parse<SyntaxNode>, M)>>>>,
    {
        let mut res = SyntaxTreeStats::default();
        for entry in iter {
            res.total += 1;
            res.retained += entry.value.is_some() as usize;
        }
        res
    }
}

#[derive(Default)]
struct LibrarySymbolsStats {
    total: usize,
    size: Bytes,
}

impl fmt::Display for LibrarySymbolsStats {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{} ({}) index symbols", self.total, self.size)
    }
}

impl FromIterator<TableEntry<(), Arc<FxHashMap<SourceRootId, SymbolIndex>>>>
    for LibrarySymbolsStats
{
    fn from_iter<T>(iter: T) -> LibrarySymbolsStats
    where
        T: IntoIterator<Item = TableEntry<(), Arc<FxHashMap<SourceRootId, SymbolIndex>>>>,
    {
        let mut res = LibrarySymbolsStats::default();
        for entry in iter {
            let value = entry.value.unwrap();
            for symbols in value.values() {
                res.total += symbols.len();
                res.size += symbols.memory_size();
            }
        }
        res
    }
}
<commit_msg>remove incorrect double blank new lines<commit_after>use std::{fmt, iter::FromIterator, sync::Arc};

use hir::{ExpandResult, MacroFile};
use ide_db::base_db::{
    salsa::debug::{DebugQueryTable, TableEntry},
    CrateId, FileId, FileTextQuery, SourceDatabase, SourceRootId,
};
use ide_db::{
    symbol_index::{LibrarySymbolsQuery, SymbolIndex},
    RootDatabase,
};
use itertools::Itertools;
use profile::{memory_usage, Bytes};
use rustc_hash::FxHashMap;
use stdx::format_to;
use syntax::{ast, Parse, SyntaxNode};

fn syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats {
    ide_db::base_db::ParseQuery.in_db(db).entries::<SyntaxTreeStats>()
}
fn macro_syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats {
    hir::db::ParseMacroExpansionQuery.in_db(db).entries::<SyntaxTreeStats>()
}

// Feature: Status
//
// Shows internal statistic about memory usage of rust-analyzer.
//
// |===
// | Editor  | Action Name
//
// | VS Code | **Rust Analyzer: Status**
// |===
// image::https://user-images.githubusercontent.com/48062697/113065584-05f34500-91b1-11eb-98cc-5c196f76be7f.gif[]
pub(crate) fn status(db: &RootDatabase, file_id: Option<FileId>) -> String {
    let mut buf = String::new();
    let count = profile::countme::get_all();
    format_to!(buf, "{}\n", FileTextQuery.in_db(db).entries::<FilesStats>());
    format_to!(buf, "{}\n", LibrarySymbolsQuery.in_db(db).entries::<LibrarySymbolsStats>());
    format_to!(buf, "{}\n", syntax_tree_stats(db));
    format_to!(buf, "{} (Macros)\n", macro_syntax_tree_stats(db));
    format_to!(buf, "{} Total\n", memory_usage());
    format_to!(
        buf,
        "\nCounts:\n{}",
        if count.to_string().contains("all counts are zero") {
            String::from("All counts are zero\n")
        } else {
            count.to_string()
        }
    );

    if let Some(file_id) = file_id {
        format_to!(buf, "\nFile info:\n");
        let krate = crate::parent_module::crate_for(db, file_id).pop();
        match krate {
            Some(krate) => {
                let crate_graph = db.crate_graph();
                let display_crate = |krate: CrateId| match &crate_graph[krate].display_name {
                    Some(it) => format!("{}({:?})", it, krate),
                    None => format!("{:?}", krate),
                };
                format_to!(buf, "crate: {}\n", display_crate(krate));
                let deps = crate_graph[krate]
                    .dependencies
                    .iter()
                    .map(|dep| format!("{}={:?}", dep.name, dep.crate_id))
                    .format(", ");
                format_to!(buf, "deps: {}\n", deps);
            }
            None => format_to!(buf, "does not belong to any crate"),
        }
    }

    buf.trim().to_string()
}

#[derive(Default)]
struct FilesStats {
    total: usize,
    size: Bytes,
}

impl fmt::Display for FilesStats {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{} ({}) files", self.total, self.size)
    }
}

impl FromIterator<TableEntry<FileId, Arc<String>>> for FilesStats {
    fn from_iter<T>(iter: T) -> FilesStats
    where
        T: IntoIterator<Item = TableEntry<FileId, Arc<String>>>,
    {
        let mut res = FilesStats::default();
        for entry in iter {
            res.total += 1;
            res.size += entry.value.unwrap().len();
        }
        res
    }
}

#[derive(Default)]
pub(crate) struct SyntaxTreeStats {
    total: usize,
    pub(crate) retained: usize,
}

impl fmt::Display for SyntaxTreeStats {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{} trees, {} retained", self.total, self.retained)
    }
}

impl FromIterator<TableEntry<FileId, Parse<ast::SourceFile>>> for SyntaxTreeStats {
    fn from_iter<T>(iter: T) -> SyntaxTreeStats
    where
        T: IntoIterator<Item = TableEntry<FileId, Parse<ast::SourceFile>>>,
    {
        let mut res = SyntaxTreeStats::default();
        for entry in iter {
            res.total += 1;
            res.retained += entry.value.is_some() as usize;
        }
        res
    }
}

impl<M> FromIterator<TableEntry<MacroFile, ExpandResult<Option<(Parse<SyntaxNode>, M)>>>>
    for SyntaxTreeStats
{
    fn from_iter<T>(iter: T) -> SyntaxTreeStats
    where
        T: IntoIterator<Item = TableEntry<MacroFile, ExpandResult<Option<(Parse<SyntaxNode>, M)>>>>,
    {
        let mut res = SyntaxTreeStats::default();
        for entry in iter {
            res.total += 1;
            res.retained += entry.value.is_some() as usize;
        }
        res
    }
}

#[derive(Default)]
struct LibrarySymbolsStats {
    total: usize,
    size: Bytes,
}

impl fmt::Display for LibrarySymbolsStats {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{} ({}) index symbols", self.total, self.size)
    }
}

impl FromIterator<TableEntry<(), Arc<FxHashMap<SourceRootId, SymbolIndex>>>>
    for LibrarySymbolsStats
{
    fn from_iter<T>(iter: T) -> LibrarySymbolsStats
    where
        T: IntoIterator<Item = TableEntry<(), Arc<FxHashMap<SourceRootId, SymbolIndex>>>>,
    {
        let mut res = LibrarySymbolsStats::default();
        for entry in iter {
            let value = entry.value.unwrap();
            for symbols in value.values() {
                res.total += symbols.len();
                res.size += symbols.memory_size();
            }
        }
        res
    }
}
<|endoftext|>


<commit_before>extern crate cc;
extern crate regex;

fn main() {
    build::main()
}

#[cfg(feature = "docs-only")]
mod build {
    pub fn main() {}
}

#[cfg(not(feature = "docs-only"))]
mod build {
    use std::process::Command;
    use std::env;
    use std::fs;
    use std::path::Path;
    use regex::Regex;

    pub fn main() {
        let out_dir = env::var("OUT_DIR").unwrap();
        let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();

        let out_dir = Path::new(&out_dir);
        let native_from = Path::new(&crate_dir).join("native");
        let native_to = Path::new(&out_dir).join("native");

        // 1. Copy the native runtime library into the build directory.
        copy_native_library(&native_from, &native_to);

        // 2. Build the object file from source using node-gyp.
        build_object_file(&native_to);

        // 3. Link the library from the object file using gcc.
        link_library(&native_to);

        // 4. Copy native build artifacts
        copy_build_artifacts(&native_to, &out_dir);

        // Rebuild if any of these environment variables change
        println!("cargo:rerun-if-env-changed=npm_config_target");
        println!("cargo:rerun-if-env-changed=npm_config_arch");
        println!("cargo:rerun-if-env-changed=npm_config_target_arch");
    }

    fn copy_files(dir_from: impl AsRef<Path>, dir_to: impl AsRef<Path>) {
        for entry in fs::read_dir(dir_from.as_ref()).unwrap() {
            let entry = entry.unwrap();

            if entry.file_type().unwrap().is_dir() {
                continue;
            }

            let file_name = entry.file_name();

            let from = dir_from.as_ref().join(&file_name);
            let to = dir_to.as_ref().join(&file_name);

            fs::copy(from, to).unwrap();
        }
    }

    fn copy_native_library(native_from: impl AsRef<Path>, native_to: impl AsRef<Path>) {
        let native_from = native_from.as_ref();
        let native_to = native_to.as_ref();

        let src_from = native_from.join("src");
        let src_to = native_to.join("src");

        fs::create_dir_all(&src_to).unwrap();

        copy_files(&native_from, &native_to);
        copy_files(&src_from, &src_to);
    }

    #[cfg(unix)]
    fn npm(cwd: &Path) -> Command {
        let mut cmd = Command::new("npm");
        cmd.current_dir(cwd);
        cmd
    }

    #[cfg(windows)]
    fn npm(cwd: &Path) -> Command {
        let mut cmd = Command::new("cmd.exe");
        cmd.args(&["/C", "npm"]);
        cmd.current_dir(cwd);
        cmd
    }

    // The node-gyp build output includes platform information in a string
    // that looks like:
    //
    //     gyp verb architecture ia32
    fn parse_node_arch(node_gyp_output: &str) -> String {
        let version_regex = Regex::new(r"gyp verb architecture (?P<arch>ia32|x64|arm|arm64)").unwrap();
        let captures = version_regex.captures(&node_gyp_output).unwrap();
        String::from(&captures["arch"])
    }

    // The node-gyp output includes the root directory of shared resources
    // for the Node installation in a string that looks like:
    //
    //     '-Dnode_root_dir=C:\\Users\\dherman\\.node-gyp\\8.3.0'
    fn parse_node_root_dir(node_gyp_output: &str) -> &str {
        let node_root_dir_flag_pattern = "'-Dnode_root_dir=";
        let node_root_dir_start_index = node_gyp_output
            .find(node_root_dir_flag_pattern)
            .map(|i| i + node_root_dir_flag_pattern.len())
            .expect("Couldn't find node_root_dir in node-gyp output.");
        let node_root_dir_end_index = node_gyp_output[node_root_dir_start_index..].find("'").unwrap() + node_root_dir_start_index;
        &node_gyp_output[node_root_dir_start_index..node_root_dir_end_index]
    }

    // The node-gyp output includes the name of the shared Node library file.
    // In NPM versions <= v5.0.3, this was just the filename by itself, e.g.:
    //
    //     '-Dnode_lib_file=node.lib'
    //
    // In NPM versions >= v5.3.0, this was a templated absolute path with a
    // reference to a gyp variable, e.g.:
    //
    //     '-Dnode_lib_file=C:\\Users\\dherman\\.node-gyp\\8.3.0\\<(target_arch)\\node.lib'
    //
    // Either way, we simply extract the value here. The `neon-build` crate
    // processes it further.
    fn parse_node_lib_file(node_gyp_output: &str) -> &str {
        let node_lib_file_flag_pattern = "'-Dnode_lib_file=";
        let node_lib_file_start_index = node_gyp_output
            .find(node_lib_file_flag_pattern)
            .map(|i| i + node_lib_file_flag_pattern.len())
            .expect("Couldn't find node_lib_file in node-gyp output.");
        let node_lib_file_end_index = node_gyp_output[node_lib_file_start_index..].find("'").unwrap() + node_lib_file_start_index;
        &node_gyp_output[node_lib_file_start_index..node_lib_file_end_index]
    }

    fn build_object_file(native_dir: &Path) {
        if cfg!(windows) {
            // Downcase all the npm environment variables to ensure they are read by node-gyp.
            for (key, value) in env::vars() {
                if key.starts_with("NPM_CONFIG") {
                    env::remove_var(&key);
                    env::set_var(key.to_lowercase(), value);
                }
            }
        }

        // Ensure that all package.json dependencies and dev dependencies are installed.
        npm(native_dir).args(&["install", "--silent"]).status().ok().expect("Failed to run \"npm install\" for neon-sys!");

        // Run `node-gyp configure` in verbose mode to read node_root_dir on Windows.
        let output = npm(native_dir)
            .args(&["run", if debug() { "configure-debug" } else { "configure-release" }])
            .output()
            .expect("Failed to run \"node-gyp configure\" for neon-sys!");

        if !output.status.success() {
            panic!(format!(
                "Failed to run \"node-gyp configure\" for neon-sys!\n Out: {}\n Err: {}",
                String::from_utf8_lossy(&output.stdout),
                String::from_utf8_lossy(&output.stderr)
            ));
        }

        if cfg!(windows) {
            let node_gyp_output = String::from_utf8_lossy(&output.stderr);
            println!("cargo:node_root_dir={}", parse_node_root_dir(&node_gyp_output));
            println!("cargo:node_lib_file={}", parse_node_lib_file(&node_gyp_output));
        }

        // Run `node-gyp build`.
        let build_output = npm(native_dir)
            .args(&["run", if debug() { "build-debug" } else { "build-release" }])
            .output()
            .ok()
            .expect("Failed to run \"node-gyp build\" for neon-sys!");

        let node_gyp_build_output = String::from_utf8_lossy(&build_output.stderr);
        println!("cargo:node_arch={}", parse_node_arch(&node_gyp_build_output));
    }

    // Link the built object file into a static library.
    fn link_library(native_dir: &Path) {
        let configuration = if debug() { "Debug" } else { "Release" };

        let object_path = if cfg!(unix) {
            native_dir
                .join("build")
                .join(configuration)
                .join("obj.target")
                .join("neon")
                .join("src")
                .join("neon.o")
        } else {
            let neon_dir = native_dir
                .join("build")
                .join(configuration)
                .join("obj")
                .join("neon");
            let object_path = neon_dir.join("src").join("neon.obj");
            if object_path.exists() {
                object_path
            } else {
                neon_dir.join("neon.obj")
            }
        };

        cc::Build::new().cpp(true).object(object_path).compile("libneon.a");
    }

    #[cfg(unix)]
    fn copy_build_artifacts(_native_dir: &Path, _out_dir: &Path) {}

    #[cfg(windows)]
    fn copy_build_artifacts(native_dir: &Path, out_dir: &Path) {
        let configuration = if debug() { "Debug" } else { "Release" };
        let win_delay_file = "win_delay_load_hook.obj";
        let win_delay_dest = out_dir.join(win_delay_file);
        let win_delay_source = native_dir
            .join("build")
            .join(configuration)
            .join("obj")
            .join("neon")
            .join(win_delay_file);

        // Win delay hook is only needed for electron, warn instead of crash if not found
        if let Err(err) = fs::copy(win_delay_source, win_delay_dest) {
            if err.kind() == std::io::ErrorKind::NotFound {
                eprintln!("warning: {} could not be found", win_delay_file);
            } else {
                panic!("{:?}", err);
            }
        }
    }

    fn debug() -> bool {
        match env::var("DEBUG") {
            Ok(s) => s == "true",
            Err(_) => false
        }
    }
}
<commit_msg>fix(neon-build): Fix incorrect panic mesasge<commit_after>extern crate cc;
extern crate regex;

fn main() {
    build::main()
}

#[cfg(feature = "docs-only")]
mod build {
    pub fn main() {}
}

#[cfg(not(feature = "docs-only"))]
mod build {
    use std::process::Command;
    use std::env;
    use std::fs;
    use std::path::Path;
    use regex::Regex;

    pub fn main() {
        let out_dir = env::var("OUT_DIR").unwrap();
        let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();

        let out_dir = Path::new(&out_dir);
        let native_from = Path::new(&crate_dir).join("native");
        let native_to = Path::new(&out_dir).join("native");

        // 1. Copy the native runtime library into the build directory.
        copy_native_library(&native_from, &native_to);

        // 2. Build the object file from source using node-gyp.
        build_object_file(&native_to);

        // 3. Link the library from the object file using gcc.
        link_library(&native_to);

        // 4. Copy native build artifacts
        copy_build_artifacts(&native_to, &out_dir);

        // Rebuild if any of these environment variables change
        println!("cargo:rerun-if-env-changed=npm_config_target");
        println!("cargo:rerun-if-env-changed=npm_config_arch");
        println!("cargo:rerun-if-env-changed=npm_config_target_arch");
    }

    fn copy_files(dir_from: impl AsRef<Path>, dir_to: impl AsRef<Path>) {
        for entry in fs::read_dir(dir_from.as_ref()).unwrap() {
            let entry = entry.unwrap();

            if entry.file_type().unwrap().is_dir() {
                continue;
            }

            let file_name = entry.file_name();

            let from = dir_from.as_ref().join(&file_name);
            let to = dir_to.as_ref().join(&file_name);

            fs::copy(from, to).unwrap();
        }
    }

    fn copy_native_library(native_from: impl AsRef<Path>, native_to: impl AsRef<Path>) {
        let native_from = native_from.as_ref();
        let native_to = native_to.as_ref();

        let src_from = native_from.join("src");
        let src_to = native_to.join("src");

        fs::create_dir_all(&src_to).unwrap();

        copy_files(&native_from, &native_to);
        copy_files(&src_from, &src_to);
    }

    #[cfg(unix)]
    fn npm(cwd: &Path) -> Command {
        let mut cmd = Command::new("npm");
        cmd.current_dir(cwd);
        cmd
    }

    #[cfg(windows)]
    fn npm(cwd: &Path) -> Command {
        let mut cmd = Command::new("cmd.exe");
        cmd.args(&["/C", "npm"]);
        cmd.current_dir(cwd);
        cmd
    }

    // The node-gyp build output includes platform information in a string
    // that looks like:
    //
    //     gyp verb architecture ia32
    fn parse_node_arch(node_gyp_output: &str) -> String {
        let version_regex = Regex::new(r"gyp verb architecture (?P<arch>ia32|x64|arm|arm64)").unwrap();
        let captures = version_regex.captures(&node_gyp_output).unwrap();
        String::from(&captures["arch"])
    }

    // The node-gyp output includes the root directory of shared resources
    // for the Node installation in a string that looks like:
    //
    //     '-Dnode_root_dir=C:\\Users\\dherman\\.node-gyp\\8.3.0'
    fn parse_node_root_dir(node_gyp_output: &str) -> &str {
        let node_root_dir_flag_pattern = "'-Dnode_root_dir=";
        let node_root_dir_start_index = node_gyp_output
            .find(node_root_dir_flag_pattern)
            .map(|i| i + node_root_dir_flag_pattern.len())
            .expect("Couldn't find node_root_dir in node-gyp output.");
        let node_root_dir_end_index = node_gyp_output[node_root_dir_start_index..].find("'").unwrap() + node_root_dir_start_index;
        &node_gyp_output[node_root_dir_start_index..node_root_dir_end_index]
    }

    // The node-gyp output includes the name of the shared Node library file.
    // In NPM versions <= v5.0.3, this was just the filename by itself, e.g.:
    //
    //     '-Dnode_lib_file=node.lib'
    //
    // In NPM versions >= v5.3.0, this was a templated absolute path with a
    // reference to a gyp variable, e.g.:
    //
    //     '-Dnode_lib_file=C:\\Users\\dherman\\.node-gyp\\8.3.0\\<(target_arch)\\node.lib'
    //
    // Either way, we simply extract the value here. The `neon-build` crate
    // processes it further.
    fn parse_node_lib_file(node_gyp_output: &str) -> &str {
        let node_lib_file_flag_pattern = "'-Dnode_lib_file=";
        let node_lib_file_start_index = node_gyp_output
            .find(node_lib_file_flag_pattern)
            .map(|i| i + node_lib_file_flag_pattern.len())
            .expect("Couldn't find node_lib_file in node-gyp output.");
        let node_lib_file_end_index = node_gyp_output[node_lib_file_start_index..].find("'").unwrap() + node_lib_file_start_index;
        &node_gyp_output[node_lib_file_start_index..node_lib_file_end_index]
    }

    fn build_object_file(native_dir: &Path) {
        if cfg!(windows) {
            // Downcase all the npm environment variables to ensure they are read by node-gyp.
            for (key, value) in env::vars() {
                if key.starts_with("NPM_CONFIG") {
                    env::remove_var(&key);
                    env::set_var(key.to_lowercase(), value);
                }
            }
        }

        // Ensure that all package.json dependencies and dev dependencies are installed.
        npm(native_dir).args(&["install", "--silent"]).status().ok().expect("Failed to run \"npm install\" for neon-sys!");

        // Run `node-gyp configure` in verbose mode to read node_root_dir on Windows.
        let output = npm(native_dir)
            .args(&["run", if debug() { "configure-debug" } else { "configure-release" }])
            .output()
            .expect("Failed to run \"node-gyp configure\" for neon-sys!");

        if !output.status.success() {
            panic!(
                "Failed to run \"node-gyp configure\" for neon-sys!\n Out: {}\n Err: {}",
                String::from_utf8_lossy(&output.stdout),
                String::from_utf8_lossy(&output.stderr)
            );
        }

        if cfg!(windows) {
            let node_gyp_output = String::from_utf8_lossy(&output.stderr);
            println!("cargo:node_root_dir={}", parse_node_root_dir(&node_gyp_output));
            println!("cargo:node_lib_file={}", parse_node_lib_file(&node_gyp_output));
        }

        // Run `node-gyp build`.
        let build_output = npm(native_dir)
            .args(&["run", if debug() { "build-debug" } else { "build-release" }])
            .output()
            .ok()
            .expect("Failed to run \"node-gyp build\" for neon-sys!");

        let node_gyp_build_output = String::from_utf8_lossy(&build_output.stderr);
        println!("cargo:node_arch={}", parse_node_arch(&node_gyp_build_output));
    }

    // Link the built object file into a static library.
    fn link_library(native_dir: &Path) {
        let configuration = if debug() { "Debug" } else { "Release" };

        let object_path = if cfg!(unix) {
            native_dir
                .join("build")
                .join(configuration)
                .join("obj.target")
                .join("neon")
                .join("src")
                .join("neon.o")
        } else {
            let neon_dir = native_dir
                .join("build")
                .join(configuration)
                .join("obj")
                .join("neon");
            let object_path = neon_dir.join("src").join("neon.obj");
            if object_path.exists() {
                object_path
            } else {
                neon_dir.join("neon.obj")
            }
        };

        cc::Build::new().cpp(true).object(object_path).compile("libneon.a");
    }

    #[cfg(unix)]
    fn copy_build_artifacts(_native_dir: &Path, _out_dir: &Path) {}

    #[cfg(windows)]
    fn copy_build_artifacts(native_dir: &Path, out_dir: &Path) {
        let configuration = if debug() { "Debug" } else { "Release" };
        let win_delay_file = "win_delay_load_hook.obj";
        let win_delay_dest = out_dir.join(win_delay_file);
        let win_delay_source = native_dir
            .join("build")
            .join(configuration)
            .join("obj")
            .join("neon")
            .join(win_delay_file);

        // Win delay hook is only needed for electron, warn instead of crash if not found
        if let Err(err) = fs::copy(win_delay_source, win_delay_dest) {
            if err.kind() == std::io::ErrorKind::NotFound {
                eprintln!("warning: {} could not be found", win_delay_file);
            } else {
                panic!("{:?}", err);
            }
        }
    }

    fn debug() -> bool {
        match env::var("DEBUG") {
            Ok(s) => s == "true",
            Err(_) => false
        }
    }
}
<|endoftext|>


<commit_before>
pub const SUBJECT: &'static str = "sub";
pub const AUDIENCE: &'static str = "aud";
pub const ISSUER: &'static str = "iss";<commit_msg>add comments for claims module<commit_after>//! Credential Claims module.
//!
//! Contains constants used as keys into the [AwsCredentials](../struct.AwsCredentials.html) claims map
//! returned by the STS client's federated assume role APIs.

/// Key used in the claims map for the `Subject` claim.
///
/// The `Subject` is the unique user identifier that is returned by the identity provider.
/// For SAML this is the `NameID` element in the `Subject` element of the SAML assertion.
/// For OpenID Connect this field contains the value returned by the identity provider
/// as the token's `sub` claim.
pub const SUBJECT: &'static str = "sub";

/// Key used in the claims map for the `Audience` claim.
///
/// The intended audience (also known as client ID) of the web identity token.
/// This is traditionally the client identifier issued to the application that requested the web identity token.
/// For OpenID Connect this field contains the value of the `aud` claim.
/// For SAML this is the value of the `Recipient` attribute of the `SubjectConfirmationData`
/// element of the SAML assertion.
pub const AUDIENCE: &'static str = "aud";

/// Key used in the claims map for the `Issuer` claim.
///
/// For OpenID Connect ID Tokens this contains the value of the `iss` field.
/// For OAuth 2.0 access tokens, this contains the value of the `ProviderId` parameter
/// that was passed in the `AssumeRoleWithWebIdentity` request.
/// For SAML this is the value of the Issuer element of the SAML assertion.
pub const ISSUER: &'static str = "iss";<|endoftext|>


<commit_before>//! Low-level bindings to libm

#![cfg(target_os = "linux")]

extern crate linux_api;

use linux_api::{c_double, c_float,
                c_long, c_longlong};

#[link(name = "m")] //For -lm
extern {

    ///Rounds to an integer value in c_double format
    ///
    ///If you want an integer format, use lrint instead
    pub fn nearbyint(x: c_double) -> c_double;

    ///Rounds to an integer value in c_float format
    ///
    ///If you want an integer format, use lrintf instead
    pub fn nearbyintf(x: c_float) -> c_float;

    ///Rounds to an integer value in c_double format
    ///
    ///If you want an integer format, use lrint instead
    pub fn rint(x: c_double) -> c_double;

    ///Rounds to an integer value in c_float format
    ///
    ///If you want an integer format, use lrintf instead
    pub fn rintf(x: c_float) -> c_float;

    ///Rounds a c_double to the nearest c_long
    pub fn lrint(x: c_double) -> c_long;

    ///Rounds a c_float to the nearest c_long
    pub fn lrintf(x: c_float) -> c_long;

    ///Rounds a c_double to the nearest c_longlong
    pub fn llrint(x: c_double) -> c_longlong;

    ///Rounds a c_float to the nearest c_longlong
    pub fn llrintf(x: c_float) -> c_longlong;

}

#[cfg(test)]
#[allow(unused_assignments)] // Unsafe functions
mod test {

    extern crate linux_api;

    use linux_api::{c_long, c_longlong};

    use super::*;

    #[test]
    fn test_rint() {

        let value = 246.246f64;

        let mut result = 0f64;

        unsafe { result = rint(value); }

        assert_eq!(246.0f64, result);
    }

    #[test]
    fn test_rintf() {

        let value = 2543637.536f32;

        let mut result = 0f32;

        unsafe { result = rintf(value); }

        assert_eq!(2543638.0f32, result);
    }

    #[test]
    fn test_nearbyint() {

        let value = 246.246f64;

        let mut result = 0f64;

        unsafe { result = nearbyint(value); }

        assert_eq!(246.0f64, result);
    }

    #[test]
    fn test_nearbyintf() {

        let value = 2543637.536f32;

        let mut result = 0f32;

        unsafe { result = nearbyintf(value); }

        assert_eq!(2543638.0f32, result);
    }

    #[test]
    fn test_lrint() {

        let value = 2464326.432f64;

        let mut result: c_long = 0;

        unsafe { result = lrint(value); }

        assert_eq!(2464326, result);

    }

    #[test]
    fn test_lrintf() {

        let value = 2464326.432f32;

        let mut result: c_long = 0;

        unsafe { result = lrintf(value); }

        assert_eq!(2464326, result);

    }

    #[test]
    fn test_llrint() {

        let value = 46873283884.432f64;

        let mut result: c_longlong = 0;

        unsafe { result = llrint(value); }

        assert_eq!(46873283884, result);

    }

    #[test]
    fn test_llrintf() {

        let value = 4687328.9732f32;

        let mut result: c_longlong = 0;

        unsafe { result = llrintf(value); }

        assert_eq!(4687329, result);

    }

}
<commit_msg>Add remainder and remainderf<commit_after>//! Low-level bindings to libm

#![cfg(target_os = "linux")]

extern crate linux_api;

use linux_api::{c_double, c_float,
                c_long, c_longlong};

#[link(name = "m")] //For -lm
extern {

    ///Rounds to an integer value in c_double format
    ///
    ///If you want an integer format, use lrint instead
    pub fn nearbyint(x: c_double) -> c_double;

    ///Rounds to an integer value in c_float format
    ///
    ///If you want an integer format, use lrintf instead
    pub fn nearbyintf(x: c_float) -> c_float;

    ///Rounds to an integer value in c_double format
    ///
    ///If you want an integer format, use lrint instead
    pub fn rint(x: c_double) -> c_double;

    ///Rounds to an integer value in c_float format
    ///
    ///If you want an integer format, use lrintf instead
    pub fn rintf(x: c_float) -> c_float;

    ///Rounds a c_double to the nearest c_long
    pub fn lrint(x: c_double) -> c_long;

    ///Rounds a c_float to the nearest c_long
    pub fn lrintf(x: c_float) -> c_long;

    ///Rounds a c_double to the nearest c_longlong
    pub fn llrint(x: c_double) -> c_longlong;

    ///Rounds a c_float to the nearest c_longlong
    pub fn llrintf(x: c_float) -> c_longlong;

    ///Returns the floating-point remainder of numer / denom
    pub fn remainder(numer: c_double, denom: c_double) -> c_double;

    ///Returns the floating-point remainder of numer / denom
    pub fn remainderf(number: c_float, denom: c_float) -> c_float;

}

#[cfg(test)]
#[allow(unused_assignments)] // Unsafe functions
mod test {

    extern crate linux_api;

    use linux_api::{c_long, c_longlong};

    use super::*;

    #[test]
    fn test_rint() {

        let value = 246.246f64;

        let mut result = 0f64;

        unsafe { result = rint(value); }

        assert_eq!(246.0f64, result);
    }

    #[test]
    fn test_rintf() {

        let value = 2543637.536f32;

        let mut result = 0f32;

        unsafe { result = rintf(value); }

        assert_eq!(2543638.0f32, result);
    }

    #[test]
    fn test_nearbyint() {

        let value = 246.246f64;

        let mut result = 0f64;

        unsafe { result = nearbyint(value); }

        assert_eq!(246.0f64, result);
    }

    #[test]
    fn test_nearbyintf() {

        let value = 2543637.536f32;

        let mut result = 0f32;

        unsafe { result = nearbyintf(value); }

        assert_eq!(2543638.0f32, result);
    }

    #[test]
    fn test_lrint() {

        let value = 2464326.432f64;

        let mut result: c_long = 0;

        unsafe { result = lrint(value); }

        assert_eq!(2464326, result);

    }

    #[test]
    fn test_lrintf() {

        let value = 2464326.432f32;

        let mut result: c_long = 0;

        unsafe { result = lrintf(value); }

        assert_eq!(2464326, result);

    }

    #[test]
    fn test_llrint() {

        let value = 46873283884.432f64;

        let mut result: c_longlong = 0;

        unsafe { result = llrint(value); }

        assert_eq!(46873283884, result);

    }

    #[test]
    fn test_llrintf() {

        let value = 4687328.9732f32;

        let mut result: c_longlong = 0;

        unsafe { result = llrintf(value); }

        assert_eq!(4687329, result);

    }

}
<|endoftext|>