<commit_before>//! DNS data.

pub use self::charstr::{CharStr, CharStrError};
pub use self::compose::{ComposeBytes, ComposeBuf};
pub use self::error::{ComposeError, ComposeResult, ParseError, ParseResult,
                      FromStrError, FromStrResult};
pub use self::iana::{Class, Opcode, Rcode, RRType};
pub use self::message::{Message, MessageBuf, MessageBuilder};
pub use self::name::{DName, DNameSlice, DNameBuf, PackedDName};
pub use self::nest::Nest;
pub use self::octets::Octets;
pub use self::parse::{ParseBytes};
pub use self::question::Question;
pub use self::rdata::{GenericRecordData, RecordData};
pub use self::record::Record;

pub mod charstr;
pub mod compose;
pub mod error;
pub mod header;
pub mod iana;
pub mod message;
pub mod name;
pub mod nest;
pub mod octets;
pub mod parse;
pub mod question;
pub mod rdata;
pub mod record;
mod u8;

<commit_msg>Add some introduction to the bits module.<commit_after>//! DNS data.
//!
//! This module provides types for working with DNS data and parsing and
//! composing wire-format DNS messages.
//!
//! There are types for the most basic building blocks of DNS data, `DName`
//! for domain names, `CharStr` for character strings, and `Octets` for
//! arbitrary binary data. These types are cow-like, that is, they can
//! contain both borrowed or owned data. Using borrowed data avoids copying
//! when parsing messages, using owned data makes it easy to create these
//! types out of the blue, for instance when converting from zonefile data.
//! In addition, domain names know a third variant: packed. This variant
//! is created when parsing compressed domain names from a message. In order
//! to avoid allocations, compressed names are only unpacked when they are
//! actually needed. See the `name` module for more details.
//!
//! From those basic types, composite types are defined: `Question` for
//! the questions of a query, `Record` for resource records. The data of
//! resource records is defined in terms of a trait `RecordData` over which
//! records are generic. This module only defines the trait and a generic
//! type usable for all record types `GenericRecordData`. Types for concrete
//! record data are defined in the `domain::rdata` module instead.
//!
//! Both parsing and parsing happen on bytes buffers. While in theory they
//! could have been built on top of `Read` and `Write`, doing so on top of
//! buffers seemed more efficient or at least a hell of a lot more simple.
//! Luckily, unless you want to implement your own record data types, you
//! are unlikely to have to concern yourself with the details of either.
//!
//! Instead, the types `Message` and `MessageBuilder` are there to make
//! parsing and constructing DNS messages easy. A `Message` takes the
//! binary data of a DNS message and allows iterating over its four
//! sections to look at the questions and resource records. Similarly,
//! a `MessageBuilder` takes a bytes vector (or creates one for you) and
//! has functionality to step-by-step build the sections of the message.

pub use self::charstr::{CharStr, CharStrError};
pub use self::compose::{ComposeBytes, ComposeBuf};
pub use self::error::{ComposeError, ComposeResult, ParseError, ParseResult,
                      FromStrError, FromStrResult};
pub use self::iana::{Class, Opcode, Rcode, RRType};
pub use self::message::{Message, MessageBuf, MessageBuilder};
pub use self::name::{DName, DNameSlice, DNameBuf, PackedDName};
pub use self::nest::Nest;
pub use self::octets::Octets;
pub use self::parse::{ParseBytes};
pub use self::question::Question;
pub use self::rdata::{GenericRecordData, RecordData};
pub use self::record::Record;

pub mod charstr;
pub mod compose;
pub mod error;
pub mod header;
pub mod iana;
pub mod message;
pub mod name;
pub mod nest;
pub mod octets;
pub mod parse;
pub mod question;
pub mod rdata;
pub mod record;
mod u8;

<|endoftext|>


<commit_before>use serde_json::from_reader;
use std::collections::HashMap;
use std::fs::File;
use std::path::Path;

use compositing::Node;
use resource::{Load, LoadError, Result, ResCache};

/// Time.
pub type Time = f64;

pub struct Clip<'a, 'b> where 'a: 'b {
  gen_node: Box<Fn(Time) -> Node<'a> + 'b>
}

impl<'a, 'b> Clip<'a, 'b> {
  pub fn new<F>(f: F) -> Self where F: 'b + Fn(Time) -> Node<'a> {
    Clip {
      gen_node: Box::new(f)
    }
  }
}

/// A cut is an object that slices a `Clip` at an *input time* and *output time*. It is instantiated
/// in a `Track` at a given *instance time*.
#[derive(Clone)]
pub struct Cut<'a, 'b, 'c> where 'a: 'b, 'b: 'c {
  pub in_time: Time,
  pub out_time: Time,
  pub inst_time: Time,
  pub clip: &'c Clip<'a, 'b>
}

impl<'a, 'b, 'c> Cut<'a, 'b, 'c> where 'a: 'b, 'b: 'c {
  pub fn new(in_time: Time, out_time: Time, inst_time: Time, clip: &'c Clip<'a, 'b>) -> Self {
    assert!(in_time <= out_time);

    Cut {
      in_time: in_time,
      out_time: out_time,
      inst_time: inst_time,
      clip: clip
    }
  }

  /// Duration of the cut.
  pub fn dur(&self) -> Time {
    self.out_time - self.in_time
  }
}

/// A track gathers `Cut`s and its purpose is to be used inside a `Timeline`.
#[derive(Clone)]
pub struct Track<'a, 'b, 'c> where 'a: 'b, 'b: 'c {
  cuts: Vec<Cut<'a, 'b, 'c>>
}

impl<'a, 'b, 'c> Track<'a, 'b, 'c> where 'a: 'b, 'b: 'c {
  pub fn new() -> Self {
    Track {
      cuts: Vec::new()
    }
  }

  pub fn add_cut(&mut self, cut: Cut<'a, 'b, 'c>) {
    self.cuts.push(cut);
  }
}

impl<'a, 'b, 'c, 'd> From<&'d [Cut<'a, 'b, 'c>]> for Track<'a, 'b, 'c> {
  fn from(cuts: &'d [Cut<'a, 'b, 'c>]) -> Self {
    Track {
      cuts: cuts.to_vec()
    }
  }
}

/// A timeline gathers tracks used to build up the visual aspect of the demo.
#[derive(Clone)]
pub struct Timeline<'a, 'b, 'c> where 'a: 'b, 'b: 'c {
  tracks: Vec<Track<'a, 'b, 'c>>,
}

impl<'a, 'b, 'c> Timeline<'a, 'b, 'c> where 'a: 'b, 'b: 'c {
  pub fn new() -> Self {
    Timeline {
      tracks: Vec::new(),
    }
  }

  /// Turn a TimelineManifest into a Timeline by providing a mapping between clips’ names and real
  /// clips.
  pub fn from_manifest(manifest: &TimelineManifest, mapping: &HashMap<String, &'c Clip<'a, 'b>>) -> Self {
    let mut timeline = Self::new();

    for track_manifest in &manifest.tracks {
      let mut track = Track::new();

      for cut_manifest in &track_manifest.cuts {
        let in_time = cut_manifest.in_time;
        let out_time = cut_manifest.out_time;
        let inst_time = cut_manifest.inst_time;

        if let Some(clip) = mapping.get(&cut_manifest.clip).cloned() {
          track.add_cut(Cut::new(in_time, out_time, inst_time, clip));
        } else {
          warn!("the clip {:?} doesn’t exist", cut_manifest.clip);
        }
      }

      timeline.add_track(track);
    }

    timeline
  }

  pub fn add_track(&mut self, track: Track<'a, 'b, 'c>) {
    self.tracks.push(track);
  }

  pub fn play(&self, t: Time) -> Vec<Node<'a>> {
    let mut active_nodes = Vec::new();

    for track in &self.tracks {
      for cut in &track.cuts {
        if cut.inst_time <= t && t <= cut.inst_time + cut.dur() {
          active_nodes.push((cut.clip.gen_node)(t));
        }
      }
    }

    active_nodes
  }
}

impl<'a, 'b, 'c, 'd> From<&'d [Track<'a, 'b, 'c>]> for Timeline<'a, 'b, 'c> {
  fn from(tracks: &'d [Track<'a, 'b, 'c>]) -> Self {
    Timeline {
      tracks: tracks.to_vec(),
    }
  }
}

#[derive(Debug, Deserialize, PartialEq, Serialize)]
pub struct TimelineManifest {
  pub tracks: Vec<TrackManifest>
}

impl Load for TimelineManifest {
  type Args = ();

  const TY_STR: &'static str = "edit";

  fn load<P>(path: P, _: &mut ResCache, _: Self::Args) -> Result<Self> where P: AsRef<Path> {
    let path = path.as_ref();

    info!("loading timeline: {:?}", path);

    let file = File::open(path).map_err(|e| LoadError::FileNotFound(path.to_path_buf(), format!("{:?}", e)))?;
    from_reader(file).map_err(|e| LoadError::ParseFailed(format!("{:?}", e)))
  }
}

#[derive(Debug, Deserialize, PartialEq, Serialize)]
pub struct TrackManifest {
  pub cuts: Vec<CutManifest>
}

#[derive(Debug, Deserialize, PartialEq, Serialize)]
pub struct CutManifest {
  pub in_time: Time,
  pub out_time: Time,
  pub inst_time: Time,
  pub clip: String
}

/// A transition is a fold of `Node`s down to a single `Node`.
pub struct Transition<'a> {
  fold: Box<Fn(Vec<Node>) -> Node + 'a>
}

impl<'a> Transition<'a> {
  pub fn new<F>(f: F) -> Self where F: 'a + Fn(Vec<Node>) -> Node {
    Transition {
      fold: Box::new(f)
    }
  }
}
<commit_msg>Added overlaps to Timeline.<commit_after>use serde_json::from_reader;
use std::collections::HashMap;
use std::fs::File;
use std::path::Path;

use compositing::Node;
use resource::{Load, LoadError, Result, ResCache};

/// Time.
pub type Time = f64;

pub struct Clip<'a, 'b> where 'a: 'b {
  gen_node: Box<Fn(Time) -> Node<'a> + 'b>
}

impl<'a, 'b> Clip<'a, 'b> {
  pub fn new<F>(f: F) -> Self where F: 'b + Fn(Time) -> Node<'a> {
    Clip {
      gen_node: Box::new(f)
    }
  }
}

/// A cut is an object that slices a `Clip` at an *input time* and *output time*. It is instantiated
/// in a `Track` at a given *instance time*.
#[derive(Clone)]
pub struct Cut<'a, 'b, 'c> where 'a: 'b, 'b: 'c {
  pub in_time: Time,
  pub out_time: Time,
  pub inst_time: Time,
  pub clip: &'c Clip<'a, 'b>
}

impl<'a, 'b, 'c> Cut<'a, 'b, 'c> where 'a: 'b, 'b: 'c {
  pub fn new(in_time: Time, out_time: Time, inst_time: Time, clip: &'c Clip<'a, 'b>) -> Self {
    assert!(in_time <= out_time);

    Cut {
      in_time: in_time,
      out_time: out_time,
      inst_time: inst_time,
      clip: clip
    }
  }

  /// Duration of the cut.
  pub fn dur(&self) -> Time {
    self.out_time - self.in_time
  }
}

/// A track gathers `Cut`s and its purpose is to be used inside a `Timeline`.
#[derive(Clone)]
pub struct Track<'a, 'b, 'c> where 'a: 'b, 'b: 'c {
  cuts: Vec<Cut<'a, 'b, 'c>>
}

impl<'a, 'b, 'c> Track<'a, 'b, 'c> where 'a: 'b, 'b: 'c {
  pub fn new() -> Self {
    Track {
      cuts: Vec::new()
    }
  }

  pub fn add_cut(&mut self, cut: Cut<'a, 'b, 'c>) {
    self.cuts.push(cut);
  }
}

impl<'a, 'b, 'c, 'd> From<&'d [Cut<'a, 'b, 'c>]> for Track<'a, 'b, 'c> {
  fn from(cuts: &'d [Cut<'a, 'b, 'c>]) -> Self {
    Track {
      cuts: cuts.to_vec()
    }
  }
}

/// A timeline gathers tracks used to build up the visual aspect of the demo.
pub struct Timeline<'a, 'b, 'c> where 'a: 'b, 'b: 'c {
  tracks: Vec<Track<'a, 'b, 'c>>,
  overlaps: Vec<Overlap<'a>>
}

impl<'a, 'b, 'c> Timeline<'a, 'b, 'c> where 'a: 'b, 'b: 'c {
  pub fn new() -> Self {
    Timeline {
      tracks: Vec::new(),
      overlaps: Vec::new()
    }
  }

  /// Turn a TimelineManifest into a Timeline by providing a mapping between clips’ names and real
  /// clips.
  pub fn from_manifest(manifest: &TimelineManifest, mapping: &HashMap<String, &'c Clip<'a, 'b>>) -> Self {
    let mut timeline = Self::new();

    for track_manifest in &manifest.tracks {
      let mut track = Track::new();

      for cut_manifest in &track_manifest.cuts {
        let in_time = cut_manifest.in_time;
        let out_time = cut_manifest.out_time;
        let inst_time = cut_manifest.inst_time;

        if let Some(clip) = mapping.get(&cut_manifest.clip).cloned() {
          track.add_cut(Cut::new(in_time, out_time, inst_time, clip));
        } else {
          warn!("the clip {:?} doesn’t exist", cut_manifest.clip);
        }
      }

      timeline.add_track(track);
    }

    timeline
  }

  pub fn add_track(&mut self, track: Track<'a, 'b, 'c>) {
    self.tracks.push(track);
  }

  pub fn add_overlap(&mut self, overlap: Overlap<'a>) {
    self.overlaps.push(overlap)
  }

  pub fn play(&self, t: Time) -> Option<Node<'a>> {
    let mut active_nodes = Vec::new();

    // populate the active nodes
    for track in &self.tracks {
      for cut in &track.cuts {
        if cut.inst_time <= t && t <= cut.inst_time + cut.dur() {
          active_nodes.push((cut.clip.gen_node)(t));
        }
      }
    }

    // apply overlap if needed
    match active_nodes.len() {
      0 => None,
      1 => active_nodes.pop(), // pop() is already Option<_>
      _ => {
        // we need to seek for an overlap here because we have strictly more than one node in hands
        self.find_overlap(t).map(|overlap| {
          (overlap.fold)(active_nodes)
        })
      }
    }
  }

  /// Find an active overlap at the given time.
  fn find_overlap(&self, t: Time) -> Option<&Overlap<'a>> {
    self.overlaps.iter().find(|x| x.inst_time <= t && t <= x.inst_time + x.dur)
  }
}

#[derive(Debug, Deserialize, PartialEq, Serialize)]
pub struct TimelineManifest {
  pub tracks: Vec<TrackManifest>
}

impl Load for TimelineManifest {
  type Args = ();

  const TY_STR: &'static str = "edit";

  fn load<P>(path: P, _: &mut ResCache, _: Self::Args) -> Result<Self> where P: AsRef<Path> {
    let path = path.as_ref();

    info!("loading timeline: {:?}", path);

    let file = File::open(path).map_err(|e| LoadError::FileNotFound(path.to_path_buf(), format!("{:?}", e)))?;
    from_reader(file).map_err(|e| LoadError::ParseFailed(format!("{:?}", e)))
  }
}

#[derive(Debug, Deserialize, PartialEq, Serialize)]
pub struct TrackManifest {
  pub cuts: Vec<CutManifest>
}

#[derive(Debug, Deserialize, PartialEq, Serialize)]
pub struct CutManifest {
  pub in_time: Time,
  pub out_time: Time,
  pub inst_time: Time,
  pub clip: String
}

/// An overlap is a fold of `Node`s down to a single `Node`. It’s used whenever two cuts overlap and
/// need to be merged into a single one. It can be used for styling effect or transitions.
pub struct Overlap<'a> {
  pub inst_time: Time,
  pub dur: Time,
  pub fold: Box<Fn(Vec<Node>) -> Node + 'a>,
}

impl<'a> Overlap<'a> {
  pub fn new<F>(inst_time: Time, dur: Time, f: F) -> Self where F: 'a + Fn(Vec<Node>) -> Node {
    Overlap {
      inst_time: inst_time,
      dur: dur,
      fold: Box::new(f)
    }
  }
}
<|endoftext|>


<commit_before>/*
 * Built-in method definitions for scheme
 *
 * Done:
 * +, -, *, / (works on lists of numbers)
 * =, >, <, >=, <= (works on list of numbers)
 * not (works on single argument)
 * list (works on any arguments)
 * list?, null?, symbol? (works on single argument)
 * cons, car, cdr, append
 * equal?
 *
 * Coming:
 * eq?
 *
 *    {'+':op.add, '-':op.sub, '*':op.mul, '/':op.div, 'not':op.not_,
       '>':op.gt, '<':op.lt, '>=':op.ge, '<=':op.le, '=':op.eq,
       'equal?':op.eq, 'eq?':op.is_, 'length':len, 'cons':lambda x,y:[x]+y,
       'car':lambda x:x[0],'cdr':lambda x:x[1:], 'append':op.add,
       'list':lambda *x:list(x), 'list?': lambda x:isa(x,list),
       'null?':lambda x:x==[], 'symbol?':lambda x: isa(x, Symbol)})
 *
 */

macro_rules! math_function {
    ($function:ident $identity:expr) => {
        pub fn $function( args:~[Expression], _:@Environment) -> Expression {
            match args {
                [] => $identity,
                [head] => vec::foldl($identity, ~[head], |x, y| {x.$function(y)}),
                [head, ..tail] => vec::foldl(head, tail, |x, y| {x.$function(y)})
            }
        }
    }
}

math_function!(add Int(0))
math_function!(sub Int(0))
math_function!(mul Int(1))
math_function!(div Int(1))

pub fn equals( args:~[Expression], _:@Environment) -> Expression {
    for args.tail().each() |&expr| {
        if expr != args.head() {
            return Bool(false);
        }
    }
    return Bool(true);
}

pub fn not( args:~[Expression], _:@Environment) -> Expression {
    if args.len() > 1 {
        fail fmt!("Built-in function 'not' takes only one argument. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    return Bool(!args[0].to_bool());
}

pub fn car( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 1 {
        fail fmt!("Built-in function 'car' takes only one argument. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match copy args[0] {
        List(list) => list.head(),
        _ => fail fmt!("Built-in function 'car' requires a list argument. It was called with %s", args[0].to_str())
    }
}

pub fn cdr( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 1 {
        fail fmt!("Built-in function 'cdr' takes only one argument. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match copy args[0] {
        List(list) => List(list.tail()),
        _ => fail fmt!("Built-in function 'cdr' requires a list argument. It was called with %s", args[0].to_str())
    }
}

pub fn cons( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 2 {
        fail fmt!("Built-in function 'cons' takes two arguments. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match copy args[1] {
        List(list) => List( ~[args[0]] + list ),
        x => List( ~[args[0]] + ~[x] )
    }
}

pub fn append( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 2 {
        fail fmt!("Built-in function 'append' takes two arguments. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match copy args[0] {
        List(list1) => {
            match copy args[1] {
                List(list) => List( list1 + list ),
                x => List( list1 + ~[x] )
            }
        }
        _ => fail fmt!("Built-in function 'append' requires a list as the first arguments. It was called with %s", List(args).to_str())
    }
}

pub fn length( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 1 {
        fail fmt!("Built-in function 'length' takes only one argument. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match copy args[0] {
        List(list) => Int(list.len() as int),
        _ => fail fmt!("Built-in function 'append' requires a list argument. It was called with %s", List(args).to_str())
    }
}

pub fn equal_( args:~[Expression], _:@Environment ) -> Expression {
    if args.len() != 2 {
        fail fmt!("Built-in function 'equal?' takes two arguments. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    Bool(args[0] == args[1])
}

pub fn symbol_( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 1 {
        fail fmt!("Built-in function 'symbol?' takes only one argument. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match args[0] {
        Symbol(_) => Bool(true),
        _ => Bool(false)
    }
}

pub fn list_( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 1 {
        fail fmt!("Built-in function 'list?' takes only one argument. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match args[0] {
        List(_) => Bool(true),
        _ => Bool(false)
    }
}

pub fn null_( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 1 {
        fail fmt!("Built-in function 'null?' takes only one argument. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match copy args[0] {
        List(list) => Bool(list.len() == 0),
        _ => Bool(false)
    }
}

pub fn list( args:~[Expression], _:@Environment) -> Expression {
    List(args)
}

pub fn builtins() -> ~[(~str,~fn(~[Expression], @Environment) -> Expression)] {
    ~[ (~"+", add), (~"-", sub), (~"*", mul), (~"/", div),
       (~"=", equals), (~"not", not),
       (~"car", car), (~"cdr", cdr),
       (~"cons", cons), (~"append", append),
       (~"list", list), (~"length", length),
       (~"equal?", equal_),
       (~"symbol?", symbol_),
       (~"list?", list_),
       (~"null?", null_)
    ]
}
<commit_msg>Extract test for count of args in builtins<commit_after>/*
 * Built-in method definitions for scheme
 *
 * Done:
 * +, -, *, / (works on lists of numbers)
 * =, >, <, >=, <= (works on list of numbers)
 * not (works on single argument)
 * list (works on any arguments)
 * list?, null?, symbol? (works on single argument)
 * cons, car, cdr, append
 * equal?
 *
 * Coming:
 * eq?
 *
 *    {'+':op.add, '-':op.sub, '*':op.mul, '/':op.div, 'not':op.not_,
       '>':op.gt, '<':op.lt, '>=':op.ge, '<=':op.le, '=':op.eq,
       'equal?':op.eq, 'eq?':op.is_, 'length':len, 'cons':lambda x,y:[x]+y,
       'car':lambda x:x[0],'cdr':lambda x:x[1:], 'append':op.add,
       'list':lambda *x:list(x), 'list?': lambda x:isa(x,list),
       'null?':lambda x:x==[], 'symbol?':lambda x: isa(x, Symbol)})
 *
 */

macro_rules! math_function {
    ($function:ident $identity:expr) => {
        pub fn $function( args:~[Expression], _:@Environment) -> Expression {
            match args {
                [] => $identity,
                [head] => vec::foldl($identity, ~[head], |x, y| {x.$function(y)}),
                [head, ..tail] => vec::foldl(head, tail, |x, y| {x.$function(y)})
            }
        }
    }
}

math_function!(add Int(0))
math_function!(sub Int(0))
math_function!(mul Int(1))
math_function!(div Int(1))

pub fn equals( args:~[Expression], _:@Environment) -> Expression {
    for args.tail().each() |&expr| {
        if expr != args.head() {
            return Bool(false);
        }
    }
    return Bool(true);
}

pub fn assert_number_of_args( function:~str, min:uint, max:uint, args:~[Expression] ) {
    if args.len() > max || args.len() < min {
        if max == min {
            fail fmt!("Built-in function '%s' takes only %u argument%s. It was called with %u '%s'", function, max, if max==1 {~""} else {~"s"}, args.len(), List(args).to_str());
        } else {
            fail fmt!("Built-in function '%s' takes between %u and %u arguments. It was called with %u '%s'", function, min, max, args.len(), List(args).to_str());
        }
    }
}

pub fn not( args:~[Expression], _:@Environment) -> Expression {
    assert_number_of_args( ~"not", 1, 1, copy args );

    return Bool(!args[0].to_bool());
}

pub fn car( args:~[Expression], _:@Environment) -> Expression {
    assert_number_of_args( ~"car", 1, 1, copy args );

    match copy args[0] {
        List(list) => list.head(),
        _ => fail fmt!("Built-in function 'car' requires a list argument. It was called with %s", args[0].to_str())
    }
}

pub fn cdr( args:~[Expression], _:@Environment) -> Expression {
    assert_number_of_args( ~"cdr", 1, 1, copy args );

    match copy args[0] {
        List(list) => List(list.tail()),
        _ => fail fmt!("Built-in function 'cdr' requires a list argument. It was called with %s", args[0].to_str())
    }
}

pub fn cons( args:~[Expression], _:@Environment) -> Expression {
    assert_number_of_args( ~"cons", 2, 2, copy args );

    match copy args[1] {
        List(list) => List( ~[args[0]] + list ),
        x => List( ~[args[0]] + ~[x] )
    }
}

pub fn append( args:~[Expression], _:@Environment) -> Expression {
    assert_number_of_args( ~"append", 2, 2, copy args );

    match copy args[0] {
        List(list1) => {
            match copy args[1] {
                List(list) => List( list1 + list ),
                x => List( list1 + ~[x] )
            }
        }
        _ => fail fmt!("Built-in function 'append' requires a list as the first arguments. It was called with %s", List(args).to_str())
    }
}

pub fn length( args:~[Expression], _:@Environment) -> Expression {
    assert_number_of_args( ~"length", 1, 1, copy args );

    match copy args[0] {
        List(list) => Int(list.len() as int),
        _ => fail fmt!("Built-in function 'append' requires a list argument. It was called with %s", List(args).to_str())
    }
}

pub fn equal_( args:~[Expression], _:@Environment ) -> Expression {
    assert_number_of_args( ~"equal?", 2, 2, copy args );

    Bool(args[0] == args[1])
}

pub fn symbol_( args:~[Expression], _:@Environment) -> Expression {
    assert_number_of_args( ~"symbol?", 1, 1, copy args );

    match args[0] {
        Symbol(_) => Bool(true),
        _ => Bool(false)
    }
}

pub fn list_( args:~[Expression], _:@Environment) -> Expression {
    assert_number_of_args( ~"list?", 1, 1, copy args );

    match args[0] {
        List(_) => Bool(true),
        _ => Bool(false)
    }
}

pub fn null_( args:~[Expression], _:@Environment) -> Expression {
    assert_number_of_args( ~"null?", 1, 1, copy args );

    match copy args[0] {
        List(list) => Bool(list.len() == 0),
        _ => Bool(false)
    }
}

pub fn list( args:~[Expression], _:@Environment) -> Expression {
    List(args)
}

pub fn builtins() -> ~[(~str,~fn(~[Expression], @Environment) -> Expression)] {
    ~[ (~"+", add), (~"-", sub), (~"*", mul), (~"/", div),
       (~"=", equals), (~"not", not),
       (~"car", car), (~"cdr", cdr),
       (~"cons", cons), (~"append", append),
       (~"list", list), (~"length", length),
       (~"equal?", equal_),
       (~"symbol?", symbol_),
       (~"list?", list_),
       (~"null?", null_)
    ]
}
<|endoftext|>


<commit_before>//! Main evaluator loop and setting up the initial stack frame.

use std::ffi::OsStr;

use rand::rngs::StdRng;
use rand::SeedableRng;

use rustc_hir::def_id::DefId;
use rustc::ty::layout::{LayoutOf, Size};
use rustc::ty::{self, TyCtxt};

use crate::*;

/// Configuration needed to spawn a Miri instance.
#[derive(Clone)]
pub struct MiriConfig {
    /// Determine if validity checking and Stacked Borrows are enabled.
    pub validate: bool,
    /// Determines if communication with the host environment is enabled.
    pub communicate: bool,
    /// Determines if memory leaks should be ignored.
    pub ignore_leaks: bool,
    /// Environment variables that should always be isolated from the host.
    pub excluded_env_vars: Vec<String>,
    /// Command-line arguments passed to the interpreted program.
    pub args: Vec<String>,
    /// The seed to use when non-determinism or randomness are required (e.g. ptr-to-int cast, `getrandom()`).
    pub seed: Option<u64>,
    /// The stacked borrow id to report about
    pub tracked_pointer_tag: Option<PtrId>,
}

/// Details of premature program termination.
pub enum TerminationInfo {
    Exit(i64),
    PoppedTrackedPointerTag(Item),
    Abort,
}

/// Returns a freshly created `InterpCx`, along with an `MPlaceTy` representing
/// the location where the return value of the `start` lang item will be
/// written to.
/// Public because this is also used by `priroda`.
pub fn create_ecx<'mir, 'tcx: 'mir>(
    tcx: TyCtxt<'tcx>,
    main_id: DefId,
    config: MiriConfig,
) -> InterpResult<'tcx, (InterpCx<'mir, 'tcx, Evaluator<'tcx>>, MPlaceTy<'tcx, Tag>)> {
    let mut ecx = InterpCx::new(
        tcx.at(rustc_span::source_map::DUMMY_SP),
        ty::ParamEnv::reveal_all(),
        Evaluator::new(config.communicate),
        MemoryExtra::new(
            StdRng::seed_from_u64(config.seed.unwrap_or(0)),
            config.validate,
            config.tracked_pointer_tag,
        ),
    );
    // Complete initialization.
    EnvVars::init(&mut ecx, config.excluded_env_vars);

    // Setup first stack-frame
    let main_instance = ty::Instance::mono(tcx, main_id);
    let main_mir = ecx.load_mir(main_instance.def, None)?;
    if main_mir.arg_count != 0 {
        bug!("main function must not take any arguments");
    }

    let start_id = tcx.lang_items().start_fn().unwrap();
    let main_ret_ty = tcx.fn_sig(main_id).output();
    let main_ret_ty = main_ret_ty.no_bound_vars().unwrap();
    let start_instance = ty::Instance::resolve(
        tcx,
        ty::ParamEnv::reveal_all(),
        start_id,
        tcx.mk_substs(::std::iter::once(ty::subst::GenericArg::from(main_ret_ty))),
    )
    .unwrap();

    // First argument: pointer to `main()`.
    let main_ptr = ecx.memory.create_fn_alloc(FnVal::Instance(main_instance));
    // Second argument (argc): length of `config.args`.
    let argc = Scalar::from_uint(config.args.len() as u128, ecx.pointer_size());
    // Third argument (`argv`): created from `config.args`.
    let argv = {
        // Put each argument in memory, collect pointers.
        let mut argvs = Vec::<Scalar<Tag>>::new();
        for arg in config.args.iter() {
            // Make space for `0` terminator.
            let size = arg.len() as u64 + 1;
            let arg_type = tcx.mk_array(tcx.types.u8, size);
            let arg_place = ecx.allocate(ecx.layout_of(arg_type)?, MiriMemoryKind::Env.into());
            ecx.write_os_str_to_c_str(OsStr::new(arg), arg_place.ptr, size)?;
            argvs.push(arg_place.ptr);
        }
        // Make an array with all these pointers, in the Miri memory.
        let argvs_layout =
            ecx.layout_of(tcx.mk_array(tcx.mk_imm_ptr(tcx.types.u8), argvs.len() as u64))?;
        let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Env.into());
        for (idx, arg) in argvs.into_iter().enumerate() {
            let place = ecx.mplace_field(argvs_place, idx as u64)?;
            ecx.write_scalar(arg, place.into())?;
        }
        ecx.memory.mark_immutable(argvs_place.ptr.assert_ptr().alloc_id)?;
        // A pointer to that place is the 3rd argument for main.
        let argv = argvs_place.ptr;
        // Store `argc` and `argv` for macOS `_NSGetArg{c,v}`.
        {
            let argc_place =
                ecx.allocate(ecx.layout_of(tcx.types.isize)?, MiriMemoryKind::Env.into());
            ecx.write_scalar(argc, argc_place.into())?;
            ecx.machine.argc = Some(argc_place.ptr);

            let argv_place = ecx.allocate(
                ecx.layout_of(tcx.mk_imm_ptr(tcx.types.unit))?,
                MiriMemoryKind::Env.into(),
            );
            ecx.write_scalar(argv, argv_place.into())?;
            ecx.machine.argv = Some(argv_place.ptr);
        }
        // Store command line as UTF-16 for Windows `GetCommandLineW`.
        {
            // Construct a command string with all the aguments.
            let mut cmd = String::new();
            for arg in config.args.iter() {
                if !cmd.is_empty() {
                    cmd.push(' ');
                }
                cmd.push_str(&*shell_escape::windows::escape(arg.as_str().into()));
            }
            // Don't forget `0` terminator.
            cmd.push(std::char::from_u32(0).unwrap());

            let cmd_utf16: Vec<u16> = cmd.encode_utf16().collect();
            let cmd_type = tcx.mk_array(tcx.types.u16, cmd_utf16.len() as u64);
            let cmd_place = ecx.allocate(ecx.layout_of(cmd_type)?, MiriMemoryKind::Env.into());
            ecx.machine.cmd_line = Some(cmd_place.ptr);
            // Store the UTF-16 string. We just allocated so we know the bounds are fine.
            let char_size = Size::from_bytes(2);
            for (idx, &c) in cmd_utf16.iter().enumerate() {
                let place = ecx.mplace_field(cmd_place, idx as u64)?;
                ecx.write_scalar(Scalar::from_uint(c, char_size), place.into())?;
            }
        }
        argv
    };

    // Return place (in static memory so that it does not count as leak).
    let ret_place = ecx.allocate(ecx.layout_of(tcx.types.isize)?, MiriMemoryKind::Env.into());
    // Call start function.
    ecx.call_function(
        start_instance,
        &[main_ptr.into(), argc.into(), argv.into()],
        Some(ret_place.into()),
        StackPopCleanup::None { cleanup: true },
    )?;

    // Set the last_error to 0
    let errno_layout = ecx.layout_of(tcx.types.u32)?;
    let errno_place = ecx.allocate(errno_layout, MiriMemoryKind::Env.into());
    ecx.write_scalar(Scalar::from_u32(0), errno_place.into())?;
    ecx.machine.last_error = Some(errno_place);

    Ok((ecx, ret_place))
}

/// Evaluates the main function specified by `main_id`.
/// Returns `Some(return_code)` if program executed completed.
/// Returns `None` if an evaluation error occured.
pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> Option<i64> {
    // FIXME: We always ignore leaks on some platforms where we do not
    // correctly implement TLS destructors.
    let target_os = tcx.sess.target.target.target_os.to_lowercase();
    let ignore_leaks = config.ignore_leaks || target_os == "windows" || target_os == "macos";

    let (mut ecx, ret_place) = match create_ecx(tcx, main_id, config) {
        Ok(v) => v,
        Err(mut err) => {
            err.print_backtrace();
            panic!("Miri initialziation error: {}", err.kind)
        }
    };

    // Perform the main execution.
    let res: InterpResult<'_, i64> = (|| {
        ecx.run()?;
        // Read the return code pointer *before* we run TLS destructors, to assert
        // that it was written to by the time that `start` lang item returned.
        let return_code = ecx.read_scalar(ret_place.into())?.not_undef()?.to_machine_isize(&ecx)?;
        ecx.run_tls_dtors()?;
        Ok(return_code)
    })();

    // Process the result.
    match res {
        Ok(return_code) => {
            if !ignore_leaks {
                let leaks = ecx.memory.leak_report();
                if leaks != 0 {
                    tcx.sess.err("the evaluated program leaked memory");
                    // Ignore the provided return code - let the reported error
                    // determine the return code.
                    return None;
                }
            }
            return Some(return_code);
        }
        Err(mut e) => {
            // Special treatment for some error kinds
            let msg = match e.kind {
                InterpError::MachineStop(ref info) => {
                    let info = info
                        .downcast_ref::<TerminationInfo>()
                        .expect("invalid MachineStop payload");
                    match info {
                        TerminationInfo::Exit(code) => return Some(*code),
                        TerminationInfo::PoppedTrackedPointerTag(item) =>
                            format!("popped tracked tag for item {:?}", item),
                        TerminationInfo::Abort =>
                            format!("the evaluated program aborted execution"),
                    }
                }
                err_unsup!(NoMirFor(..)) => format!(
                    "{}. Did you set `MIRI_SYSROOT` to a Miri-enabled sysroot? You can prepare one with `cargo miri setup`.",
                    e
                ),
                InterpError::InvalidProgram(_) =>
                    bug!("This error should be impossible in Miri: {}", e),
                _ => e.to_string(),
            };
            e.print_backtrace();
            if let Some(frame) = ecx.stack().last() {
                let span = frame.current_source_info().unwrap().span;

                let msg = format!("Miri evaluation error: {}", msg);
                let mut err = ecx.tcx.sess.struct_span_err(span, msg.as_str());
                let frames = ecx.generate_stacktrace(None);
                err.span_label(span, msg);
                // We iterate with indices because we need to look at the next frame (the caller).
                for idx in 0..frames.len() {
                    let frame_info = &frames[idx];
                    let call_site_is_local = frames
                        .get(idx + 1)
                        .map_or(false, |caller_info| caller_info.instance.def_id().is_local());
                    if call_site_is_local {
                        err.span_note(frame_info.call_site, &frame_info.to_string());
                    } else {
                        err.note(&frame_info.to_string());
                    }
                }
                err.emit();
            } else {
                ecx.tcx.sess.err(&msg);
            }

            for (i, frame) in ecx.stack().iter().enumerate() {
                trace!("-------------------");
                trace!("Frame {}", i);
                trace!("    return: {:?}", frame.return_place.map(|p| *p));
                for (i, local) in frame.locals.iter().enumerate() {
                    trace!("    local {}: {:?}", i, local.value);
                }
            }
            // Let the reported error determine the return code.
            return None;
        }
    }
}
<commit_msg>Split error reporting from main eval function<commit_after>//! Main evaluator loop and setting up the initial stack frame.

use std::ffi::OsStr;

use rand::rngs::StdRng;
use rand::SeedableRng;

use rustc_hir::def_id::DefId;
use rustc::ty::layout::{LayoutOf, Size};
use rustc::ty::{self, TyCtxt};
use rustc_mir::interpret::InterpErrorInfo;

use crate::*;

/// Configuration needed to spawn a Miri instance.
#[derive(Clone)]
pub struct MiriConfig {
    /// Determine if validity checking and Stacked Borrows are enabled.
    pub validate: bool,
    /// Determines if communication with the host environment is enabled.
    pub communicate: bool,
    /// Determines if memory leaks should be ignored.
    pub ignore_leaks: bool,
    /// Environment variables that should always be isolated from the host.
    pub excluded_env_vars: Vec<String>,
    /// Command-line arguments passed to the interpreted program.
    pub args: Vec<String>,
    /// The seed to use when non-determinism or randomness are required (e.g. ptr-to-int cast, `getrandom()`).
    pub seed: Option<u64>,
    /// The stacked borrow id to report about
    pub tracked_pointer_tag: Option<PtrId>,
}

/// Details of premature program termination.
pub enum TerminationInfo {
    Exit(i64),
    PoppedTrackedPointerTag(Item),
    Abort,
}

/// Returns a freshly created `InterpCx`, along with an `MPlaceTy` representing
/// the location where the return value of the `start` lang item will be
/// written to.
/// Public because this is also used by `priroda`.
pub fn create_ecx<'mir, 'tcx: 'mir>(
    tcx: TyCtxt<'tcx>,
    main_id: DefId,
    config: MiriConfig,
) -> InterpResult<'tcx, (InterpCx<'mir, 'tcx, Evaluator<'tcx>>, MPlaceTy<'tcx, Tag>)> {
    let mut ecx = InterpCx::new(
        tcx.at(rustc_span::source_map::DUMMY_SP),
        ty::ParamEnv::reveal_all(),
        Evaluator::new(config.communicate),
        MemoryExtra::new(
            StdRng::seed_from_u64(config.seed.unwrap_or(0)),
            config.validate,
            config.tracked_pointer_tag,
        ),
    );
    // Complete initialization.
    EnvVars::init(&mut ecx, config.excluded_env_vars);

    // Setup first stack-frame
    let main_instance = ty::Instance::mono(tcx, main_id);
    let main_mir = ecx.load_mir(main_instance.def, None)?;
    if main_mir.arg_count != 0 {
        bug!("main function must not take any arguments");
    }

    let start_id = tcx.lang_items().start_fn().unwrap();
    let main_ret_ty = tcx.fn_sig(main_id).output();
    let main_ret_ty = main_ret_ty.no_bound_vars().unwrap();
    let start_instance = ty::Instance::resolve(
        tcx,
        ty::ParamEnv::reveal_all(),
        start_id,
        tcx.mk_substs(::std::iter::once(ty::subst::GenericArg::from(main_ret_ty))),
    )
    .unwrap();

    // First argument: pointer to `main()`.
    let main_ptr = ecx.memory.create_fn_alloc(FnVal::Instance(main_instance));
    // Second argument (argc): length of `config.args`.
    let argc = Scalar::from_uint(config.args.len() as u128, ecx.pointer_size());
    // Third argument (`argv`): created from `config.args`.
    let argv = {
        // Put each argument in memory, collect pointers.
        let mut argvs = Vec::<Scalar<Tag>>::new();
        for arg in config.args.iter() {
            // Make space for `0` terminator.
            let size = arg.len() as u64 + 1;
            let arg_type = tcx.mk_array(tcx.types.u8, size);
            let arg_place = ecx.allocate(ecx.layout_of(arg_type)?, MiriMemoryKind::Env.into());
            ecx.write_os_str_to_c_str(OsStr::new(arg), arg_place.ptr, size)?;
            argvs.push(arg_place.ptr);
        }
        // Make an array with all these pointers, in the Miri memory.
        let argvs_layout =
            ecx.layout_of(tcx.mk_array(tcx.mk_imm_ptr(tcx.types.u8), argvs.len() as u64))?;
        let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Env.into());
        for (idx, arg) in argvs.into_iter().enumerate() {
            let place = ecx.mplace_field(argvs_place, idx as u64)?;
            ecx.write_scalar(arg, place.into())?;
        }
        ecx.memory.mark_immutable(argvs_place.ptr.assert_ptr().alloc_id)?;
        // A pointer to that place is the 3rd argument for main.
        let argv = argvs_place.ptr;
        // Store `argc` and `argv` for macOS `_NSGetArg{c,v}`.
        {
            let argc_place =
                ecx.allocate(ecx.layout_of(tcx.types.isize)?, MiriMemoryKind::Env.into());
            ecx.write_scalar(argc, argc_place.into())?;
            ecx.machine.argc = Some(argc_place.ptr);

            let argv_place = ecx.allocate(
                ecx.layout_of(tcx.mk_imm_ptr(tcx.types.unit))?,
                MiriMemoryKind::Env.into(),
            );
            ecx.write_scalar(argv, argv_place.into())?;
            ecx.machine.argv = Some(argv_place.ptr);
        }
        // Store command line as UTF-16 for Windows `GetCommandLineW`.
        {
            // Construct a command string with all the aguments.
            let mut cmd = String::new();
            for arg in config.args.iter() {
                if !cmd.is_empty() {
                    cmd.push(' ');
                }
                cmd.push_str(&*shell_escape::windows::escape(arg.as_str().into()));
            }
            // Don't forget `0` terminator.
            cmd.push(std::char::from_u32(0).unwrap());

            let cmd_utf16: Vec<u16> = cmd.encode_utf16().collect();
            let cmd_type = tcx.mk_array(tcx.types.u16, cmd_utf16.len() as u64);
            let cmd_place = ecx.allocate(ecx.layout_of(cmd_type)?, MiriMemoryKind::Env.into());
            ecx.machine.cmd_line = Some(cmd_place.ptr);
            // Store the UTF-16 string. We just allocated so we know the bounds are fine.
            let char_size = Size::from_bytes(2);
            for (idx, &c) in cmd_utf16.iter().enumerate() {
                let place = ecx.mplace_field(cmd_place, idx as u64)?;
                ecx.write_scalar(Scalar::from_uint(c, char_size), place.into())?;
            }
        }
        argv
    };

    // Return place (in static memory so that it does not count as leak).
    let ret_place = ecx.allocate(ecx.layout_of(tcx.types.isize)?, MiriMemoryKind::Env.into());
    // Call start function.
    ecx.call_function(
        start_instance,
        &[main_ptr.into(), argc.into(), argv.into()],
        Some(ret_place.into()),
        StackPopCleanup::None { cleanup: true },
    )?;

    // Set the last_error to 0
    let errno_layout = ecx.layout_of(tcx.types.u32)?;
    let errno_place = ecx.allocate(errno_layout, MiriMemoryKind::Env.into());
    ecx.write_scalar(Scalar::from_u32(0), errno_place.into())?;
    ecx.machine.last_error = Some(errno_place);

    Ok((ecx, ret_place))
}

/// Evaluates the main function specified by `main_id`.
/// Returns `Some(return_code)` if program executed completed.
/// Returns `None` if an evaluation error occured.
pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> Option<i64> {
    // FIXME: We always ignore leaks on some platforms where we do not
    // correctly implement TLS destructors.
    let target_os = tcx.sess.target.target.target_os.to_lowercase();
    let ignore_leaks = config.ignore_leaks || target_os == "windows" || target_os == "macos";

    let (mut ecx, ret_place) = match create_ecx(tcx, main_id, config) {
        Ok(v) => v,
        Err(mut err) => {
            err.print_backtrace();
            panic!("Miri initialziation error: {}", err.kind)
        }
    };

    // Perform the main execution.
    let res: InterpResult<'_, i64> = (|| {
        ecx.run()?;
        // Read the return code pointer *before* we run TLS destructors, to assert
        // that it was written to by the time that `start` lang item returned.
        let return_code = ecx.read_scalar(ret_place.into())?.not_undef()?.to_machine_isize(&ecx)?;
        ecx.run_tls_dtors()?;
        Ok(return_code)
    })();

    // Process the result.
    match res {
        Ok(return_code) => {
            if !ignore_leaks {
                let leaks = ecx.memory.leak_report();
                if leaks != 0 {
                    tcx.sess.err("the evaluated program leaked memory");
                    // Ignore the provided return code - let the reported error
                    // determine the return code.
                    return None;
                }
            }
            return Some(return_code);
        }
        Err(e) => report_err(&ecx, e),
    }
}

fn report_err<'tcx, 'mir>(
    ecx: &InterpCx<'mir, 'tcx, Evaluator<'tcx>>,
    mut e: InterpErrorInfo<'tcx>,
) -> Option<i64> {
    // Special treatment for some error kinds
    let msg = match e.kind {
        InterpError::MachineStop(ref info) => {
            let info = info.downcast_ref::<TerminationInfo>().expect("invalid MachineStop payload");
            match info {
                TerminationInfo::Exit(code) => return Some(*code),
                TerminationInfo::PoppedTrackedPointerTag(item) =>
                    format!("popped tracked tag for item {:?}", item),
                TerminationInfo::Abort => format!("the evaluated program aborted execution"),
            }
        }
        err_unsup!(NoMirFor(..)) => format!(
            "{}. Did you set `MIRI_SYSROOT` to a Miri-enabled sysroot? You can prepare one with `cargo miri setup`.",
            e
        ),
        InterpError::InvalidProgram(_) => bug!("This error should be impossible in Miri: {}", e),
        _ => e.to_string(),
    };
    e.print_backtrace();
    if let Some(frame) = ecx.stack().last() {
        let span = frame.current_source_info().unwrap().span;

        let msg = format!("Miri evaluation error: {}", msg);
        let mut err = ecx.tcx.sess.struct_span_err(span, msg.as_str());
        let frames = ecx.generate_stacktrace(None);
        err.span_label(span, msg);
        // We iterate with indices because we need to look at the next frame (the caller).
        for idx in 0..frames.len() {
            let frame_info = &frames[idx];
            let call_site_is_local = frames
                .get(idx + 1)
                .map_or(false, |caller_info| caller_info.instance.def_id().is_local());
            if call_site_is_local {
                err.span_note(frame_info.call_site, &frame_info.to_string());
            } else {
                err.note(&frame_info.to_string());
            }
        }
        err.emit();
    } else {
        ecx.tcx.sess.err(&msg);
    }

    for (i, frame) in ecx.stack().iter().enumerate() {
        trace!("-------------------");
        trace!("Frame {}", i);
        trace!("    return: {:?}", frame.return_place.map(|p| *p));
        for (i, local) in frame.locals.iter().enumerate() {
            trace!("    local {}: {:?}", i, local.value);
        }
    }
    // Let the reported error determine the return code.
    return None;
}
<|endoftext|>


<commit_before>use ast::{Expr, ConstExpr, BlockExpr, LocalExpr, GetConstFieldExpr, GetFieldExpr, CallExpr, WhileLoopExpr, IfExpr, SwitchExpr, ObjectDeclExpr, ArrayDeclExpr, FunctionDeclExpr, NumOpExpr, BitOpExpr, ConstructExpr, ReturnExpr, ThrowExpr, AssignExpr};
use ast::{CNum, CInt, CString, CBool, CRegExp, CNull, CUndefined};
use ast::{OpSub, OpAdd, OpMul, OpDiv, OpMod};
use ast::{BitAnd, BitOr, BitXor, BitShl, BitShr};
use js::value::{Value, VNull, VUndefined, VNumber, VString, VObject, VBoolean, VFunction, ResultValue};
use js::object::ObjectData;
use js::function::{RegularFunc, RegularFunction};
use js::{console, math, object, array, function, json};
use collections::treemap::TreeMap;
use std::vec::Vec;
use std::f64;
use std::gc::Gc;
use std::cell::RefCell;
/// An execution engine
pub trait Executor {
	/// Makes a new execution engine
	fn new() -> ~Self;
	/// Sets a global variable
	fn set_global(&mut self, name:~str, val:Value) -> Value;
	/// Gets a global variable
	fn get_global(&self, name:~str) -> Value;
	/// Make a new scope
	fn make_scope(&mut self) -> Gc<RefCell<ObjectData>>;
	/// Destroy the current scope
	fn destroy_scope(&mut self) -> ();
	/// Runs the expression
	fn run(&mut self, expr:&Expr) -> ResultValue;
}
/// An intepreter
pub struct Interpreter {
	/// An object representing the global variables
	global: Value,
	/// The scopes
	scopes: Vec<Gc<RefCell<ObjectData>>>,
}
impl Executor for Interpreter {
	fn new() -> ~Interpreter {
		let mut globals : ObjectData = TreeMap::new();
		globals.swap(~"NaN", Gc::new(VNumber(f64::NAN)));
		globals.swap(~"Infinity", Gc::new(VNumber(f64::INFINITY)));
		globals.swap(~"console", console::_create());
		globals.swap(~"Math", math::_create());
		globals.swap(~"Object", object::_create());
		globals.swap(~"Array", array::_create());
		globals.swap(~"Function", function::_create());
		globals.swap(~"JSON", json::_create());
		return ~Interpreter {global: Gc::new(VObject(RefCell::new(globals))), scopes: Vec::new()};
	}
	fn set_global(&mut self, name:~str, val:Value) -> Value {
		self.global.borrow().set_field(name, val)
	}
	fn get_global(&self, name:~str) -> Value {
		self.global.borrow().get_field(name)
	}
	fn make_scope(&mut self) -> Gc<RefCell<ObjectData>> {
		let mut data = TreeMap::new();
		let value = Gc::new(RefCell::new(data));
		self.scopes.push(value.clone());
		value
	}
	fn destroy_scope(&mut self) -> () {
		self.scopes.pop();
	}
	fn run(&mut self, expr:&Expr) -> ResultValue {
		match *expr {
			ConstExpr(CNull) => Ok(Gc::new(VNull)),
			ConstExpr(CUndefined) => Ok(Gc::new(VUndefined)),
			ConstExpr(CNum(num)) => Ok(Gc::new(VNumber(num))),
			ConstExpr(CInt(num)) => Ok(Gc::new(VNumber(num as f64))),
			ConstExpr(CString(ref str)) => Ok(Gc::new(VString(str.to_owned()))),
			ConstExpr(CBool(val)) => Ok(Gc::new(VBoolean(val))),
			ConstExpr(CRegExp(ref reg, _, _)) => Ok(Gc::new(VBoolean(true))),
			BlockExpr(ref es) => {
				let mut obj = Gc::new(VNull);
				for e in es.iter() {
					let val = try!(self.run(*e));
					if e == es.last().unwrap() {
						obj = val;
					}
				}
				Ok(obj)
			},
			LocalExpr(ref name) => {
				let mut value = Gc::new(VUndefined);
				for scope in self.scopes.iter().rev() {
					match scope.borrow().borrow().find(name) {
						Some(v) => {
							value = v.clone();
							break;
						}
						None => ()
					}
				}
				Ok(if value.borrow() == &VUndefined {
					self.global.borrow().get_field(name.clone())
				} else {
					value
				})
			},
			GetConstFieldExpr(ref obj, ref field) => {
				let val_obj = try!(self.run(*obj));
				Ok(val_obj.borrow().get_field(field.clone()))
			},
			GetFieldExpr(ref obj, ref field) => {
				let val_obj = try!(self.run(*obj));
				let val_field = try!(self.run(*field));
				Ok(val_obj.borrow().get_field(val_field.borrow().to_str()))
			},
			CallExpr(ref callee, ref args) => {
				let mut this = self.global.clone();
				let func = try!(self.run(callee.clone()));
				let mut v_args = Vec::with_capacity(args.len());
				for arg in args.iter() {
					v_args.push(try!(self.run(*arg)));
				}
				Ok(match *func.borrow() {
					VFunction(ref func) => {
						func.borrow().call(self, this, Gc::new(VNull), v_args).unwrap()
					},
					_ => Gc::new(VUndefined)
				})
			},
			WhileLoopExpr(ref cond, ref expr) => {
				let mut result = Gc::new(VUndefined);
				while try!(self.run(*cond)).borrow().is_true() {
					result = try!(self.run(*expr));
				}
				Ok(result)
			},
			IfExpr(ref cond, ref expr, None) => {
				Ok(if try!(self.run(*cond)).borrow().is_true() {
					try!(self.run(*expr))
				} else {
					Gc::new(VUndefined)
				})
			},
			IfExpr(ref cond, ref expr, Some(ref else_e)) => {
				Ok(if try!(self.run(*cond)).borrow().is_true() {
					try!(self.run(*expr))
				} else {
					try!(self.run(*else_e))
				})
			},
			SwitchExpr(ref val_e, ref vals, ref default) => {
				let val = try!(self.run(*val_e)).borrow().clone();
				let mut result = Gc::new(VNull);
				let mut matched = false;
				for tup in vals.iter() {
					let tup:&(~Expr, Vec<~Expr>) = tup;
					match *tup {
						(ref cond, ref block) if(val == *try!(self.run(*cond)).borrow()) => {
							matched = true;
							let last_expr = block.last().unwrap();
							for expr in block.iter() {
								let e_result = try!(self.run(*expr));
								if expr == last_expr {
									result = e_result;
								}
							}
						},
						_ => ()
					}
				}
				if !matched && default.is_some() {
					result = try!(self.run(*default.as_ref().unwrap()));
				}
				Ok(result)
			},
			ObjectDeclExpr(ref map) => {
				let mut obj = TreeMap::new();
				for (key, val) in map.iter() {
					obj.insert(key.clone(), try!(self.run(val.clone())));
				}
				obj.swap(~"__proto__", self.get_global(~"Object").borrow().get_field(~"prototype"));
				Ok(Gc::new(VObject(RefCell::new(obj))))
			},
			ArrayDeclExpr(ref arr) => {
				let mut arr_map = TreeMap::new();
				let mut index = 0;
				for val in arr.iter() {
					let val = try!(self.run(val.clone()));
					arr_map.insert(index.to_str(), val);
					index += 1;
				}
				arr_map.insert(~"__proto__", self.get_global(~"Array").borrow().get_field(~"prototype"));
				Ok(Gc::new(VObject(RefCell::new(arr_map))))
			},
			FunctionDeclExpr(ref name, ref args, ref expr) => {
				let function = RegularFunc(RegularFunction::new(*expr.clone(), args.clone()));
				let val = Gc::new(VFunction(RefCell::new(function)));
				if name.is_some() {
					self.global.borrow().set_field(name.clone().unwrap(), val);
				}
				Ok(val)
			},
			NumOpExpr(ref op, ref a, ref b) => {
				let v_a = try!(self.run(*a)).borrow().clone();
				let v_b = try!(self.run(*b)).borrow().clone();
				Ok(Gc::new(match *op {
					OpAdd => v_a + v_b,
					OpSub => v_a - v_b,
					OpMul => v_a * v_b,
					OpDiv => v_a / v_b,
					OpMod => v_a % v_b
				}))
			},
			BitOpExpr(ref op, ref a, ref b) => {
				let v_a = try!(self.run(*a)).borrow().clone();
				let v_b = try!(self.run(*b)).borrow().clone();
				Ok(Gc::new(match *op {
					BitAnd => v_a & v_b,
					BitOr => v_a | v_b,
					BitXor => v_a ^ v_b,
					BitShl => v_a << v_b,
					BitShr => v_a >> v_b
				}))
			},
			ConstructExpr(ref callee, ref args) => {
				let func = try!(self.run(callee.clone()));
				let mut v_args = Vec::with_capacity(args.len());
				for arg in args.iter() {
					v_args.push(try!(self.run(*arg)));
				}
				let this = Gc::new(VObject(RefCell::new(TreeMap::new())));
				this.borrow().set_field(~"__proto__", func.borrow().get_field(~"prototype"));
				Ok(match *func.borrow() {
					VFunction(ref func) => {
						func.borrow().call(self, this, Gc::new(VNull), v_args).unwrap();
						this
					},
					_ => Gc::new(VUndefined)
				})
			},
			ReturnExpr(ref ret) => {
				match *ret {
					Some(ref v) =>
						self.run(v.clone()),
					None => Ok(Gc::new(VUndefined))
				}
			},
			ThrowExpr(ref ex) => Err(try!(self.run(*ex))),
			AssignExpr(ref ref_e, ref val_e) => {
				let val = try!(self.run(*val_e));
				match **ref_e {
					LocalExpr(ref name) => {
						self.global.borrow().set_field(name.clone(), val);
					},
					GetConstFieldExpr(ref obj, ref field) => {
						let val_obj = try!(self.run(*obj));
						val_obj.borrow().set_field(field.clone(), val);
					},
					_ => ()
				}
				Ok(val)
			}
		}
	}
}<commit_msg>Implement support for this in interpreter<commit_after>use ast::{Expr, ConstExpr, BlockExpr, LocalExpr, GetConstFieldExpr, GetFieldExpr, CallExpr, WhileLoopExpr, IfExpr, SwitchExpr, ObjectDeclExpr, ArrayDeclExpr, FunctionDeclExpr, NumOpExpr, BitOpExpr, ConstructExpr, ReturnExpr, ThrowExpr, AssignExpr};
use ast::{CNum, CInt, CString, CBool, CRegExp, CNull, CUndefined};
use ast::{OpSub, OpAdd, OpMul, OpDiv, OpMod};
use ast::{BitAnd, BitOr, BitXor, BitShl, BitShr};
use js::value::{Value, VNull, VUndefined, VNumber, VString, VObject, VBoolean, VFunction, ResultValue};
use js::object::ObjectData;
use js::function::{RegularFunc, RegularFunction};
use js::{console, math, object, array, function, json};
use collections::treemap::TreeMap;
use std::vec::Vec;
use std::f64;
use std::gc::Gc;
use std::cell::RefCell;
/// An execution engine
pub trait Executor {
	/// Makes a new execution engine
	fn new() -> ~Self;
	/// Sets a global variable
	fn set_global(&mut self, name:~str, val:Value) -> Value;
	/// Gets a global variable
	fn get_global(&self, name:~str) -> Value;
	/// Make a new scope
	fn make_scope(&mut self) -> Gc<RefCell<ObjectData>>;
	/// Destroy the current scope
	fn destroy_scope(&mut self) -> ();
	/// Runs the expression
	fn run(&mut self, expr:&Expr) -> ResultValue;
}
/// An intepreter
pub struct Interpreter {
	/// An object representing the global variables
	global: Value,
	/// The scopes
	scopes: Vec<Gc<RefCell<ObjectData>>>,
}
impl Executor for Interpreter {
	fn new() -> ~Interpreter {
		let mut globals : ObjectData = TreeMap::new();
		globals.swap(~"NaN", Gc::new(VNumber(f64::NAN)));
		globals.swap(~"Infinity", Gc::new(VNumber(f64::INFINITY)));
		globals.swap(~"console", console::_create());
		globals.swap(~"Math", math::_create());
		globals.swap(~"Object", object::_create());
		globals.swap(~"Array", array::_create());
		globals.swap(~"Function", function::_create());
		globals.swap(~"JSON", json::_create());
		return ~Interpreter {global: Gc::new(VObject(RefCell::new(globals))), scopes: Vec::new()};
	}
	fn set_global(&mut self, name:~str, val:Value) -> Value {
		self.global.borrow().set_field(name, val)
	}
	fn get_global(&self, name:~str) -> Value {
		self.global.borrow().get_field(name)
	}
	fn make_scope(&mut self) -> Gc<RefCell<ObjectData>> {
		let mut data = TreeMap::new();
		let value = Gc::new(RefCell::new(data));
		self.scopes.push(value.clone());
		value
	}
	fn destroy_scope(&mut self) -> () {
		self.scopes.pop();
	}
	fn run(&mut self, expr:&Expr) -> ResultValue {
		match *expr {
			ConstExpr(CNull) => Ok(Gc::new(VNull)),
			ConstExpr(CUndefined) => Ok(Gc::new(VUndefined)),
			ConstExpr(CNum(num)) => Ok(Gc::new(VNumber(num))),
			ConstExpr(CInt(num)) => Ok(Gc::new(VNumber(num as f64))),
			ConstExpr(CString(ref str)) => Ok(Gc::new(VString(str.to_owned()))),
			ConstExpr(CBool(val)) => Ok(Gc::new(VBoolean(val))),
			ConstExpr(CRegExp(ref reg, _, _)) => Ok(Gc::new(VBoolean(true))),
			BlockExpr(ref es) => {
				let mut obj = Gc::new(VNull);
				for e in es.iter() {
					let val = try!(self.run(*e));
					if e == es.last().unwrap() {
						obj = val;
					}
				}
				Ok(obj)
			},
			LocalExpr(ref name) => {
				let mut value = Gc::new(VUndefined);
				for scope in self.scopes.iter().rev() {
					match scope.borrow().borrow().find(name) {
						Some(v) => {
							value = v.clone();
							break;
						}
						None => ()
					}
				}
				Ok(if value.borrow() == &VUndefined {
					self.global.borrow().get_field(name.clone())
				} else {
					value
				})
			},
			GetConstFieldExpr(ref obj, ref field) => {
				let val_obj = try!(self.run(*obj));
				Ok(val_obj.borrow().get_field(field.clone()))
			},
			GetFieldExpr(ref obj, ref field) => {
				let val_obj = try!(self.run(*obj));
				let val_field = try!(self.run(*field));
				Ok(val_obj.borrow().get_field(val_field.borrow().to_str()))
			},
			CallExpr(ref callee, ref args) => {
				let (this, func) = match **callee {
					GetConstFieldExpr(ref obj, ref field) => {
						let obj = try!(self.run(*obj));
						(obj, obj.borrow().get_field(field.clone()))
					},
					GetFieldExpr(ref obj, ref field) => {
						let obj = try!(self.run(*obj));
						let field = try!(self.run(*field));
						(obj, obj.borrow().get_field(field.borrow().to_str()))
					},
					_ => (self.global.clone(), try!(self.run(callee.clone())))
				};
				let mut v_args = Vec::with_capacity(args.len());
				for arg in args.iter() {
					v_args.push(try!(self.run(*arg)));
				}
				Ok(match *func.borrow() {
					VFunction(ref func) => {
						func.borrow().call(self, this, Gc::new(VNull), v_args).unwrap()
					},
					_ => Gc::new(VUndefined)
				})
			},
			WhileLoopExpr(ref cond, ref expr) => {
				let mut result = Gc::new(VUndefined);
				while try!(self.run(*cond)).borrow().is_true() {
					result = try!(self.run(*expr));
				}
				Ok(result)
			},
			IfExpr(ref cond, ref expr, None) => {
				Ok(if try!(self.run(*cond)).borrow().is_true() {
					try!(self.run(*expr))
				} else {
					Gc::new(VUndefined)
				})
			},
			IfExpr(ref cond, ref expr, Some(ref else_e)) => {
				Ok(if try!(self.run(*cond)).borrow().is_true() {
					try!(self.run(*expr))
				} else {
					try!(self.run(*else_e))
				})
			},
			SwitchExpr(ref val_e, ref vals, ref default) => {
				let val = try!(self.run(*val_e)).borrow().clone();
				let mut result = Gc::new(VNull);
				let mut matched = false;
				for tup in vals.iter() {
					let tup:&(~Expr, Vec<~Expr>) = tup;
					match *tup {
						(ref cond, ref block) if(val == *try!(self.run(*cond)).borrow()) => {
							matched = true;
							let last_expr = block.last().unwrap();
							for expr in block.iter() {
								let e_result = try!(self.run(*expr));
								if expr == last_expr {
									result = e_result;
								}
							}
						},
						_ => ()
					}
				}
				if !matched && default.is_some() {
					result = try!(self.run(*default.as_ref().unwrap()));
				}
				Ok(result)
			},
			ObjectDeclExpr(ref map) => {
				let mut obj = TreeMap::new();
				for (key, val) in map.iter() {
					obj.insert(key.clone(), try!(self.run(val.clone())));
				}
				obj.swap(~"__proto__", self.get_global(~"Object").borrow().get_field(~"prototype"));
				Ok(Gc::new(VObject(RefCell::new(obj))))
			},
			ArrayDeclExpr(ref arr) => {
				let mut arr_map = TreeMap::new();
				let mut index = 0;
				for val in arr.iter() {
					let val = try!(self.run(val.clone()));
					arr_map.insert(index.to_str(), val);
					index += 1;
				}
				arr_map.insert(~"__proto__", self.get_global(~"Array").borrow().get_field(~"prototype"));
				Ok(Gc::new(VObject(RefCell::new(arr_map))))
			},
			FunctionDeclExpr(ref name, ref args, ref expr) => {
				let function = RegularFunc(RegularFunction::new(*expr.clone(), args.clone()));
				let val = Gc::new(VFunction(RefCell::new(function)));
				if name.is_some() {
					self.global.borrow().set_field(name.clone().unwrap(), val);
				}
				Ok(val)
			},
			NumOpExpr(ref op, ref a, ref b) => {
				let v_a = try!(self.run(*a)).borrow().clone();
				let v_b = try!(self.run(*b)).borrow().clone();
				Ok(Gc::new(match *op {
					OpAdd => v_a + v_b,
					OpSub => v_a - v_b,
					OpMul => v_a * v_b,
					OpDiv => v_a / v_b,
					OpMod => v_a % v_b
				}))
			},
			BitOpExpr(ref op, ref a, ref b) => {
				let v_a = try!(self.run(*a)).borrow().clone();
				let v_b = try!(self.run(*b)).borrow().clone();
				Ok(Gc::new(match *op {
					BitAnd => v_a & v_b,
					BitOr => v_a | v_b,
					BitXor => v_a ^ v_b,
					BitShl => v_a << v_b,
					BitShr => v_a >> v_b
				}))
			},
			ConstructExpr(ref callee, ref args) => {
				let func = try!(self.run(callee.clone()));
				let mut v_args = Vec::with_capacity(args.len());
				for arg in args.iter() {
					v_args.push(try!(self.run(*arg)));
				}
				let this = Gc::new(VObject(RefCell::new(TreeMap::new())));
				this.borrow().set_field(~"__proto__", func.borrow().get_field(~"prototype"));
				Ok(match *func.borrow() {
					VFunction(ref func) => {
						func.borrow().call(self, this, Gc::new(VNull), v_args).unwrap();
						this
					},
					_ => Gc::new(VUndefined)
				})
			},
			ReturnExpr(ref ret) => {
				match *ret {
					Some(ref v) =>
						self.run(v.clone()),
					None => Ok(Gc::new(VUndefined))
				}
			},
			ThrowExpr(ref ex) => Err(try!(self.run(*ex))),
			AssignExpr(ref ref_e, ref val_e) => {
				let val = try!(self.run(*val_e));
				match **ref_e {
					LocalExpr(ref name) => {
						self.global.borrow().set_field(name.clone(), val);
					},
					GetConstFieldExpr(ref obj, ref field) => {
						let val_obj = try!(self.run(*obj));
						val_obj.borrow().set_field(field.clone(), val);
					},
					_ => ()
				}
				Ok(val)
			}
		}
	}
}<|endoftext|>


<commit_before>/// The `CheckDigitAlgorithm` trait is used to specify the functionality of a checksum function
/// that uses a check digit for error detection.
pub trait CheckDigitAlgorithm {
    /// Computes the checksum for the provided number.
    fn checksum(&self, num: u64) -> u8;

    /// Computes the check digit for the provided number.
    fn calculate_check_digit(&self, num: u64) -> u8;

    /// Tests if the provided number, which must be suffixed with a check digit, is erroneous.
    fn is_valid(&self, num: u64) -> bool;
}

/// Luhn check digit algorithm.
pub struct LuhnAlgorithm {}

impl LuhnAlgorithm {
    /// Performs the summation of digits in a number as specified by the Luhn algorithm.
    fn digit_sum(num: u64) -> u32 {
        let mut num_pre_div = num;
        let mut num_post_div;
        let mut sum = 0u32;
        let mut i = 0u8;
        // Scan digits from right to left
        loop {
            num_post_div = num_pre_div / 10;
            i += 1;
            let digit = num_pre_div - num_post_div * 10;
            if i % 2 == 0 {
                // Even indexed digits are doubled and adjusted if greater than 9
                let mut second_digit = digit * 2;
                if second_digit > 9 {
                    second_digit = second_digit - 9;
                }
                sum += second_digit as u32;
            } else {
                // Odd indexed digits are treated as-is
                sum += digit as u32;
            }
            if num_post_div == 0 {
                break;
            }
            num_pre_div = num_post_div;
        }
        sum
    }
}

impl CheckDigitAlgorithm for LuhnAlgorithm {
    /// Computes the Luhn checksum for the provided number.
    ///
    /// # Examples
    ///
    /// Provide the function with an identification number.
    ///
    /// ```
    /// use checksum::CheckDigitAlgorithm;
    /// let acct_num = 79927398713;
    /// let algo = checksum::LuhnAlgorithm {};
    /// let checksum = algo.checksum(acct_num);
    /// assert_eq!(checksum, 0);
    /// if checksum != 0 {
    ///     println!("Account number has been corrupted!");
    /// }
    /// ```
    fn checksum(&self, num: u64) -> u8 {
        (LuhnAlgorithm::digit_sum(num) % 10) as u8
    }

    /// Computes the Luhn check digit for the provided number.
    ///
    /// # Examples
    ///
    /// Provide the function with an identification number.
    ///
    /// ```
    /// use checksum::CheckDigitAlgorithm;
    /// let acct_num = 7992739871;
    /// let algo = checksum::LuhnAlgorithm {};
    /// let checksum = algo.calculate_check_digit(acct_num);
    /// assert_eq!(checksum, 3);
    /// ```
    fn calculate_check_digit(&self, num: u64) -> u8 {
        (LuhnAlgorithm::digit_sum(num * 10) * 9 % 10) as u8
    }

    /// Verifies the check digit using the Luhn algorithm.
    ///
    /// # Examples
    ///
    /// Provide the function with an identification number.
    ///
    /// ```
    /// use checksum::CheckDigitAlgorithm;
    /// let acct_num = 79927398713;
    /// let algo = checksum::LuhnAlgorithm {};
    /// let is_valid = algo.is_valid(acct_num);
    /// assert_eq!(is_valid, true);
    /// if is_valid {
    ///     println!("Account number is valid!");
    /// } else {
    ///     println!("Account number is NOT valid!");
    /// }
    /// ```
    fn is_valid(&self, num: u64) -> bool {
        self.checksum(num) == 0
    }
}

const DIHEDRAL_D5: [[u8; 10]; 10] = [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
                                     [1, 2, 3, 4, 0, 6, 7, 8, 9, 5],
                                     [2, 3, 4, 0, 1, 7, 8, 9, 5, 6],
                                     [3, 4, 0, 1, 2, 8, 9, 5, 6, 7],
                                     [4, 0, 1, 2, 3, 9, 5, 6, 7, 8],
                                     [5, 9, 8, 7, 6, 0, 4, 3, 2, 1],
                                     [6, 5, 9, 8, 7, 1, 0, 4, 3, 2],
                                     [7, 6, 5, 9, 8, 2, 1, 0, 4, 3],
                                     [8, 7, 6, 5, 9, 3, 2, 1, 0, 4],
                                     [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]];

const INV_DIHEDRAL_D5: [u8; 10] = [0, 4, 3, 2, 1, 5, 6, 7, 8, 9];

const VERHOEFF_P_TABLE: [[u8; 10]; 8] = [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
                                         [1, 5, 7, 6, 2, 8, 3, 0, 9, 4],
                                         [5, 8, 0, 3, 7, 9, 6, 1, 4, 2],
                                         [8, 9, 1, 6, 0, 4, 3, 5, 2, 7],
                                         [9, 4, 5, 3, 1, 2, 6, 8, 7, 0],
                                         [4, 2, 8, 6, 5, 7, 3, 9, 0, 1],
                                         [2, 7, 9, 3, 8, 0, 6, 4, 1, 5],
                                         [7, 0, 4, 6, 9, 1, 3, 2, 5, 8]];

/// Computes the Verhoeff checksum for the provided number.
///
/// # Examples
///
/// Generate a checksum for 236:
///
/// ```
/// let num = 2363;
/// let check_digit = checksum::verhoeff_checksum(num);
/// assert_eq!(check_digit, 0);
/// ```
pub fn verhoeff_checksum(num: u64) -> u8 {
    let mut num_pre_div = num;
    let mut num_post_div;
    let mut i = 0u8;
    let mut c = 0u8;
    loop {
        num_post_div = num_pre_div / 10;
        let digit = num_pre_div - num_post_div * 10;
        c = DIHEDRAL_D5[c as usize][VERHOEFF_P_TABLE[(i % 8) as usize][digit as usize] as usize];
        i += 1;
        if num_post_div == 0 {
            break;
        }
        num_pre_div = num_post_div;
    }
    c
}

/// Computes the Verhoeff check digit for the provided number.
///
/// # Examples
///
/// Generate a check digit for 236:
///
/// ```
/// let num = 236;
/// let check_digit = checksum::verhoeff_calculate_check_digit(num);
/// assert_eq!(check_digit, 3);
/// ```
pub fn verhoeff_calculate_check_digit(num: u64) -> u8 {
    let c = verhoeff_checksum(num * 10);
    INV_DIHEDRAL_D5[c as usize]
}

/// Uses the Verhoeff checksum formula for error detection.
///
/// # Examples
///
/// Validate the check digit 2363.
///
/// ```
/// let num = 2363;
/// let is_valid = checksum::verhoeff_is_valid(num);
/// assert_eq!(is_valid, true);
/// ```
pub fn verhoeff_is_valid(num: u64) -> bool {
    verhoeff_checksum(num) == 0
}
<commit_msg>Add description of Luhn algorithm<commit_after>/// The `CheckDigitAlgorithm` trait is used to specify the functionality of a checksum function
/// that uses a check digit for error detection.
pub trait CheckDigitAlgorithm {
    /// Computes the checksum for the provided number.
    fn checksum(&self, num: u64) -> u8;

    /// Computes the check digit for the provided number.
    fn calculate_check_digit(&self, num: u64) -> u8;

    /// Tests if the provided number, which must be suffixed with a check digit, is erroneous.
    fn is_valid(&self, num: u64) -> bool;
}

/// Luhn check digit algorithm.
///
/// The Luhn algorithm will detect any single-digit error, as well as **almost** all transpositions
/// of adjacent digits. It will **not**, however, detect transposition of the two-digit sequence
/// *09* to *90* (or vice versa). It will detect 7 of the 10 possible twin errors (it will not
/// detect *22* <-> *55*, *33* <-> *66*, or *44* <-> *77*).
pub struct LuhnAlgorithm {}

impl LuhnAlgorithm {
    /// Performs the summation of digits in a number as specified by the Luhn algorithm.
    fn digit_sum(num: u64) -> u32 {
        let mut num_pre_div = num;
        let mut num_post_div;
        let mut sum = 0u32;
        let mut i = 0u8;
        // Scan digits from right to left
        loop {
            num_post_div = num_pre_div / 10;
            i += 1;
            let digit = num_pre_div - num_post_div * 10;
            if i % 2 == 0 {
                // Even indexed digits are doubled and adjusted if greater than 9
                let mut second_digit = digit * 2;
                if second_digit > 9 {
                    second_digit = second_digit - 9;
                }
                sum += second_digit as u32;
            } else {
                // Odd indexed digits are treated as-is
                sum += digit as u32;
            }
            if num_post_div == 0 {
                break;
            }
            num_pre_div = num_post_div;
        }
        sum
    }
}

impl CheckDigitAlgorithm for LuhnAlgorithm {
    /// Computes the Luhn checksum for the provided number.
    ///
    /// # Examples
    ///
    /// Provide the function with an identification number.
    ///
    /// ```
    /// use checksum::CheckDigitAlgorithm;
    /// let acct_num = 79927398713;
    /// let algo = checksum::LuhnAlgorithm {};
    /// let checksum = algo.checksum(acct_num);
    /// assert_eq!(checksum, 0);
    /// if checksum != 0 {
    ///     println!("Account number has been corrupted!");
    /// }
    /// ```
    fn checksum(&self, num: u64) -> u8 {
        (LuhnAlgorithm::digit_sum(num) % 10) as u8
    }

    /// Computes the Luhn check digit for the provided number.
    ///
    /// # Examples
    ///
    /// Provide the function with an identification number.
    ///
    /// ```
    /// use checksum::CheckDigitAlgorithm;
    /// let acct_num = 7992739871;
    /// let algo = checksum::LuhnAlgorithm {};
    /// let checksum = algo.calculate_check_digit(acct_num);
    /// assert_eq!(checksum, 3);
    /// ```
    fn calculate_check_digit(&self, num: u64) -> u8 {
        (LuhnAlgorithm::digit_sum(num * 10) * 9 % 10) as u8
    }

    /// Verifies the check digit using the Luhn algorithm.
    ///
    /// # Examples
    ///
    /// Provide the function with an identification number.
    ///
    /// ```
    /// use checksum::CheckDigitAlgorithm;
    /// let acct_num = 79927398713;
    /// let algo = checksum::LuhnAlgorithm {};
    /// let is_valid = algo.is_valid(acct_num);
    /// assert_eq!(is_valid, true);
    /// if is_valid {
    ///     println!("Account number is valid!");
    /// } else {
    ///     println!("Account number is NOT valid!");
    /// }
    /// ```
    fn is_valid(&self, num: u64) -> bool {
        self.checksum(num) == 0
    }
}

const DIHEDRAL_D5: [[u8; 10]; 10] = [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
                                     [1, 2, 3, 4, 0, 6, 7, 8, 9, 5],
                                     [2, 3, 4, 0, 1, 7, 8, 9, 5, 6],
                                     [3, 4, 0, 1, 2, 8, 9, 5, 6, 7],
                                     [4, 0, 1, 2, 3, 9, 5, 6, 7, 8],
                                     [5, 9, 8, 7, 6, 0, 4, 3, 2, 1],
                                     [6, 5, 9, 8, 7, 1, 0, 4, 3, 2],
                                     [7, 6, 5, 9, 8, 2, 1, 0, 4, 3],
                                     [8, 7, 6, 5, 9, 3, 2, 1, 0, 4],
                                     [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]];

const INV_DIHEDRAL_D5: [u8; 10] = [0, 4, 3, 2, 1, 5, 6, 7, 8, 9];

const VERHOEFF_P_TABLE: [[u8; 10]; 8] = [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
                                         [1, 5, 7, 6, 2, 8, 3, 0, 9, 4],
                                         [5, 8, 0, 3, 7, 9, 6, 1, 4, 2],
                                         [8, 9, 1, 6, 0, 4, 3, 5, 2, 7],
                                         [9, 4, 5, 3, 1, 2, 6, 8, 7, 0],
                                         [4, 2, 8, 6, 5, 7, 3, 9, 0, 1],
                                         [2, 7, 9, 3, 8, 0, 6, 4, 1, 5],
                                         [7, 0, 4, 6, 9, 1, 3, 2, 5, 8]];

/// Computes the Verhoeff checksum for the provided number.
///
/// # Examples
///
/// Generate a checksum for 236:
///
/// ```
/// let num = 2363;
/// let check_digit = checksum::verhoeff_checksum(num);
/// assert_eq!(check_digit, 0);
/// ```
pub fn verhoeff_checksum(num: u64) -> u8 {
    let mut num_pre_div = num;
    let mut num_post_div;
    let mut i = 0u8;
    let mut c = 0u8;
    loop {
        num_post_div = num_pre_div / 10;
        let digit = num_pre_div - num_post_div * 10;
        c = DIHEDRAL_D5[c as usize][VERHOEFF_P_TABLE[(i % 8) as usize][digit as usize] as usize];
        i += 1;
        if num_post_div == 0 {
            break;
        }
        num_pre_div = num_post_div;
    }
    c
}

/// Computes the Verhoeff check digit for the provided number.
///
/// # Examples
///
/// Generate a check digit for 236:
///
/// ```
/// let num = 236;
/// let check_digit = checksum::verhoeff_calculate_check_digit(num);
/// assert_eq!(check_digit, 3);
/// ```
pub fn verhoeff_calculate_check_digit(num: u64) -> u8 {
    let c = verhoeff_checksum(num * 10);
    INV_DIHEDRAL_D5[c as usize]
}

/// Uses the Verhoeff checksum formula for error detection.
///
/// # Examples
///
/// Validate the check digit 2363.
///
/// ```
/// let num = 2363;
/// let is_valid = checksum::verhoeff_is_valid(num);
/// assert_eq!(is_valid, true);
/// ```
pub fn verhoeff_is_valid(num: u64) -> bool {
    verhoeff_checksum(num) == 0
}
<|endoftext|>


<commit_before>//! Functions for computing properties of the terminal grid

use std::collections::{vec_deque, VecDeque};
use std::ops::{Index, IndexMut, Deref, DerefMut};
use std::slice::{Iter, IterMut};

use term::Cursor;
use ::Rgb;

/// Calculate the number of cells for an axis
pub fn num_cells_axis(cell_width: u32, cell_sep: i32, screen_width: u32) -> u32 {
    println!("num_cells_axis(cell_width: {}, cell_sep: {}, screen_width: {}",
             cell_width, cell_sep, screen_width);
    ((screen_width as i32 - cell_sep) as f64 / (cell_width as i32 + cell_sep) as f64) as u32
}

#[derive(Clone, Debug)]
pub struct Cell {
    pub c: char,
    pub fg: Rgb,
    pub bg: Rgb,
    pub flags: CellFlags,
}

bitflags! {
    pub flags CellFlags: u32 {
        const INVERSE   = 0b00000001,
        const BOLD      = 0b00000010,
        const ITALIC    = 0b00000100,
        const UNDERLINE = 0b00001000,
    }
}

impl Cell {
    pub fn new(c: char) -> Cell {
        Cell {
            c: c.into(),
            bg: Default::default(),
            fg: Default::default(),
            flags: CellFlags::empty(),
        }
    }
}

/// Represents the terminal display contents
#[derive(Clone)]
pub struct Grid {
    /// Rows in the grid. Each row holds a list of cells corresponding to the columns in that row.
    raw: VecDeque<Row>,

    /// Number of columns
    cols: usize,

    /// Number of rows.
    ///
    /// Invariant: rows is equivalent to cells.len()
    rows: usize,
}

impl Grid {
    pub fn new(rows: usize, cols: usize) -> Grid {
        let mut raw = VecDeque::with_capacity(rows);
        for _ in 0..rows {
            raw.push_back(Row::new(cols));
        }

        Grid {
            raw: raw,
            cols: cols,
            rows: rows,
        }
    }

    pub fn rows(&self) -> vec_deque::Iter<Row> {
        self.raw.iter()
    }

    pub fn rows_mut(&mut self) -> vec_deque::IterMut<Row> {
        self.raw.iter_mut()
    }

    pub fn num_rows(&self) -> usize {
        self.rows
    }

    pub fn num_cols(&self) -> usize {
        self.cols
    }

    pub fn feed(&mut self) {
        // do the borrowck dance
        let row = self.raw.pop_front().unwrap();
        self.raw.push_back(row);
    }

    pub fn unfeed(&mut self) {
        // do the borrowck dance
        let row = self.raw.pop_back().unwrap();
        self.raw.push_front(row);
    }

    pub fn clear(&mut self) {
        for row in self.raw.iter_mut() {
            for cell in row.iter_mut() {
                cell.c = ' ';
            }
        }
    }
}

impl Index<usize> for Grid {
    type Output = Row;

    #[inline]
    fn index<'a>(&'a self, index: usize) -> &'a Row {
        &self.raw[index]
    }
}

impl IndexMut<usize> for Grid {
    #[inline]
    fn index_mut<'a>(&'a mut self, index: usize) -> &'a mut Row {
        &mut self.raw[index]
    }
}

impl Index<Cursor> for Grid {
    type Output = Cell;

    #[inline]
    fn index<'a>(&'a self, cursor: Cursor) -> &'a Cell {
        &self.raw[cursor.y as usize][cursor.x as usize]
    }
}

impl IndexMut<Cursor> for Grid {
    #[inline]
    fn index_mut<'a>(&'a mut self, cursor: Cursor) -> &'a mut Cell {
        &mut self.raw[cursor.y as usize][cursor.x as usize]
    }
}

/// A row in the grid
#[derive(Debug, Clone)]
pub struct Row(Vec<Cell>);

impl Row {
    pub fn new(columns: usize) -> Row {
        Row(vec![Cell::new(' '); columns])
    }

    pub fn cells(&self) -> Iter<Cell> {
        self.0.iter()
    }

    pub fn cells_mut(&mut self) -> IterMut<Cell> {
        self.0.iter_mut()
    }
}

impl Deref for Row {
    type Target = Vec<Cell>;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl DerefMut for Row {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}

impl Index<usize> for Row {
    type Output = Cell;

    #[inline]
    fn index<'a>(&'a self, index: usize) -> &'a Cell {
        &self.0[index]
    }
}

impl IndexMut<usize> for Row {
    #[inline]
    fn index_mut<'a>(&'a mut self, index: usize) -> &'a mut Cell {
        &mut self.0[index]
    }
}
<commit_msg>Tweak some Grid methods<commit_after>//! Functions for computing properties of the terminal grid

use std::collections::{vec_deque, VecDeque};
use std::ops::{Index, IndexMut, Deref, DerefMut};
use std::slice::{Iter, IterMut};

use term::Cursor;
use ::Rgb;

/// Calculate the number of cells for an axis
pub fn num_cells_axis(cell_width: u32, cell_sep: i32, screen_width: u32) -> u32 {
    println!("num_cells_axis(cell_width: {}, cell_sep: {}, screen_width: {}",
             cell_width, cell_sep, screen_width);
    ((screen_width as i32 - cell_sep) as f64 / (cell_width as i32 + cell_sep) as f64) as u32
}

#[derive(Clone, Debug)]
pub struct Cell {
    pub c: char,
    pub fg: Rgb,
    pub bg: Rgb,
    pub flags: CellFlags,
}

bitflags! {
    pub flags CellFlags: u32 {
        const INVERSE   = 0b00000001,
        const BOLD      = 0b00000010,
        const ITALIC    = 0b00000100,
        const UNDERLINE = 0b00001000,
    }
}

impl Cell {
    pub fn new(c: char) -> Cell {
        Cell {
            c: c.into(),
            bg: Default::default(),
            fg: Default::default(),
            flags: CellFlags::empty(),
        }
    }
}

/// Represents the terminal display contents
#[derive(Clone)]
pub struct Grid {
    /// Rows in the grid. Each row holds a list of cells corresponding to the columns in that row.
    raw: VecDeque<Row>,

    /// Number of columns
    cols: usize,

    /// Number of rows.
    ///
    /// Invariant: rows is equivalent to cells.len()
    rows: usize,
}

impl Grid {
    pub fn new(rows: usize, cols: usize) -> Grid {
        let mut raw = VecDeque::with_capacity(rows);
        for _ in 0..rows {
            raw.push_back(Row::new(cols));
        }

        Grid {
            raw: raw,
            cols: cols,
            rows: rows,
        }
    }

    #[inline]
    pub fn rows(&self) -> vec_deque::Iter<Row> {
        self.raw.iter()
    }

    #[inline]
    pub fn rows_mut(&mut self) -> vec_deque::IterMut<Row> {
        self.raw.iter_mut()
    }

    #[inline]
    pub fn num_rows(&self) -> usize {
        self.raw.len()
    }

    #[inline]
    pub fn num_cols(&self) -> usize {
        self.raw[0].len()
    }

    pub fn feed(&mut self) {
        // do the borrowck dance
        let row = self.raw.pop_front().unwrap();
        self.raw.push_back(row);
    }

    pub fn unfeed(&mut self) {
        // do the borrowck dance
        let row = self.raw.pop_back().unwrap();
        self.raw.push_front(row);
    }

    pub fn clear(&mut self) {
        for row in self.raw.iter_mut() {
            for cell in row.iter_mut() {
                cell.c = ' ';
            }
        }
    }
}

impl Index<usize> for Grid {
    type Output = Row;

    #[inline]
    fn index<'a>(&'a self, index: usize) -> &'a Row {
        &self.raw[index]
    }
}

impl IndexMut<usize> for Grid {
    #[inline]
    fn index_mut<'a>(&'a mut self, index: usize) -> &'a mut Row {
        &mut self.raw[index]
    }
}

impl Index<Cursor> for Grid {
    type Output = Cell;

    #[inline]
    fn index<'a>(&'a self, cursor: Cursor) -> &'a Cell {
        &self.raw[cursor.y as usize][cursor.x as usize]
    }
}

impl IndexMut<Cursor> for Grid {
    #[inline]
    fn index_mut<'a>(&'a mut self, cursor: Cursor) -> &'a mut Cell {
        &mut self.raw[cursor.y as usize][cursor.x as usize]
    }
}

/// A row in the grid
#[derive(Debug, Clone)]
pub struct Row(Vec<Cell>);

impl Row {
    pub fn new(columns: usize) -> Row {
        Row(vec![Cell::new(' '); columns])
    }

    pub fn cells(&self) -> Iter<Cell> {
        self.0.iter()
    }

    pub fn cells_mut(&mut self) -> IterMut<Cell> {
        self.0.iter_mut()
    }
}

impl Deref for Row {
    type Target = Vec<Cell>;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl DerefMut for Row {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}

impl Index<usize> for Row {
    type Output = Cell;

    #[inline]
    fn index<'a>(&'a self, index: usize) -> &'a Cell {
        &self.0[index]
    }
}

impl IndexMut<usize> for Row {
    #[inline]
    fn index_mut<'a>(&'a mut self, index: usize) -> &'a mut Cell {
        &mut self.0[index]
    }
}
<|endoftext|>


<commit_before>use parser::Block;
use parser::ListItem;
use parser::Block::{Header, Paragraph, Blockquote, Hr, CodeBlock, UnorderedList, Raw};
use parser::Span;
use parser::Span::{Break, Text, Emphasis, Strong, Code, Link, Image};

// takes a number of elements and returns their collective text as a slug
fn slugify(elements: &[Span]) -> String {
    let mut ret = String::new();

    for el in elements {
        let next = match *el {
            Break => "".to_owned(),
            Text(ref text) |
            Link(ref text, _, _) |
            Image(ref text, _, _) |
            Code(ref text) => text.trim().replace(" ", "_").to_lowercase().to_owned(),
            Strong(ref content) | Emphasis(ref content) => slugify(content),
        };
        if !ret.is_empty() {
            ret.push('_');
        }
        ret.push_str(&next);
    }

    ret
}

pub fn to_html(blocks: &[Block]) -> String {
    let mut ret = String::new();
    for block in blocks.iter() {
        let next = match *block {
            Header(ref elements, level) => format_header(elements, level),
            Paragraph(ref elements) => format_paragraph(elements),
            Blockquote(ref elements) => format_blockquote(elements),
            CodeBlock(ref lang, ref elements) => format_codeblock(lang, elements),
            UnorderedList(ref elements) => format_unordered_list(elements),
            Raw(ref elements) => elements.to_owned(),
            Hr => format!("
"),
        };
        ret.push_str(&next)
    }
    ret = ret.trim().to_owned();
    ret.push('\n');
    ret
}

fn format_spans(elements: &[Span]) -> String {
    let mut ret = String::new();
    for element in elements.iter() {
        let next = match *element {
            Break => format!("
"),
            Text(ref text) => format!("{}", &escape(text)),
            Code(ref text) => format!("{}", &escape(text)),
            Link(ref text, ref url, None) =>
                format!("{}", &escape(url), &escape(text)),
            Link(ref text, ref url, Some(ref title)) => format!("{}",
                                                                &escape(url),
                                                                &escape(title),
                                                                &escape(text)),
            Image(ref text, ref url, None) =>
                format!("", &escape(url), &escape(text)),
            Image(ref text, ref url, Some(ref title)) =>
                format!("",
                        &escape(url),
                        &escape(title),
                        &escape(text)),
            Emphasis(ref content) => format!("{}", format_spans(content)),
            Strong(ref content) => format!("{}", format_spans(content)),
        };
        ret.push_str(&next)
    }
    ret
}

fn escape(text: &str) -> String {
    text.replace("&", "&")
        .replace("<", "<")
        .replace("\"", """)
        .replace("'", "’")
        .replace(">", ">")
}

fn format_unordered_list(elements: &[ListItem]) -> String {
    let mut ret = String::new();
    for list_item in elements {
        let mut content = String::new();
        match *list_item {
            ListItem::Simple(ref els) => {
                content.push_str(&format_spans(els))
            }
            ListItem::Paragraph(ref paragraphs) => {
                content.push_str(&format!("\n{}", to_html(paragraphs)))
            }
        }

        ret.push_str(&format!("\n
{}
\n", content))
    }
    format!("
{}
\n\n", ret)
}

fn format_codeblock(language: &Option<String>,elements: &str) -> String {
    if language.is_none() {
        format!("
{}
\n\n", &escape(elements))
    } else {
        format!("
{}
\n\n", &escape(language.as_ref().unwrap()), &escape(elements))
    }
}

fn format_blockquote(elements: &[Block]) -> String {
    format!("
\n{}
\n\n", to_html(elements))
}

fn format_paragraph(elements: &[Span]) -> String {
    format!("
{}
\n\n", format_spans(elements))
}

fn format_header(elements: &[Span], level: usize) -> String {
    format!("<h{} id='{}'>{}</h{}>\n\n",
            level,
            slugify(elements),
            format_spans(elements),
            level)
}
<commit_msg>Fix code tag having `lanuage-` class<commit_after>use parser::Block;
use parser::ListItem;
use parser::Block::{Header, Paragraph, Blockquote, Hr, CodeBlock, UnorderedList, Raw};
use parser::Span;
use parser::Span::{Break, Text, Emphasis, Strong, Code, Link, Image};

// takes a number of elements and returns their collective text as a slug
fn slugify(elements: &[Span]) -> String {
    let mut ret = String::new();

    for el in elements {
        let next = match *el {
            Break => "".to_owned(),
            Text(ref text) |
            Link(ref text, _, _) |
            Image(ref text, _, _) |
            Code(ref text) => text.trim().replace(" ", "_").to_lowercase().to_owned(),
            Strong(ref content) | Emphasis(ref content) => slugify(content),
        };
        if !ret.is_empty() {
            ret.push('_');
        }
        ret.push_str(&next);
    }

    ret
}

pub fn to_html(blocks: &[Block]) -> String {
    let mut ret = String::new();
    for block in blocks.iter() {
        let next = match *block {
            Header(ref elements, level) => format_header(elements, level),
            Paragraph(ref elements) => format_paragraph(elements),
            Blockquote(ref elements) => format_blockquote(elements),
            CodeBlock(ref lang, ref elements) => format_codeblock(lang, elements),
            UnorderedList(ref elements) => format_unordered_list(elements),
            Raw(ref elements) => elements.to_owned(),
            Hr => format!("
"),
        };
        ret.push_str(&next)
    }
    ret = ret.trim().to_owned();
    ret.push('\n');
    ret
}

fn format_spans(elements: &[Span]) -> String {
    let mut ret = String::new();
    for element in elements.iter() {
        let next = match *element {
            Break => format!("
"),
            Text(ref text) => format!("{}", &escape(text)),
            Code(ref text) => format!("{}", &escape(text)),
            Link(ref text, ref url, None) =>
                format!("{}", &escape(url), &escape(text)),
            Link(ref text, ref url, Some(ref title)) => format!("{}",
                                                                &escape(url),
                                                                &escape(title),
                                                                &escape(text)),
            Image(ref text, ref url, None) =>
                format!("", &escape(url), &escape(text)),
            Image(ref text, ref url, Some(ref title)) =>
                format!("",
                        &escape(url),
                        &escape(title),
                        &escape(text)),
            Emphasis(ref content) => format!("{}", format_spans(content)),
            Strong(ref content) => format!("{}", format_spans(content)),
        };
        ret.push_str(&next)
    }
    ret
}

fn escape(text: &str) -> String {
    text.replace("&", "&")
        .replace("<", "<")
        .replace("\"", """)
        .replace("'", "’")
        .replace(">", ">")
}

fn format_unordered_list(elements: &[ListItem]) -> String {
    let mut ret = String::new();
    for list_item in elements {
        let mut content = String::new();
        match *list_item {
            ListItem::Simple(ref els) => {
                content.push_str(&format_spans(els))
            }
            ListItem::Paragraph(ref paragraphs) => {
                content.push_str(&format!("\n{}", to_html(paragraphs)))
            }
        }

        ret.push_str(&format!("\n
{}
\n", content))
    }
    format!("
{}
\n\n", ret)
}

fn format_codeblock(lang: &Option<String>,elements: &str) -> String {
    if lang.is_none() || (lang.is_some() && lang.as_ref().unwrap().is_empty()) {
        format!("
{}
\n\n", &escape(elements))
    } else {
        format!("
{}
\n\n", &escape(lang.as_ref().unwrap()), &escape(elements))
    }
}

fn format_blockquote(elements: &[Block]) -> String {
    format!("
\n{}
\n\n", to_html(elements))
}

fn format_paragraph(elements: &[Span]) -> String {
    format!("
{}
\n\n", format_spans(elements))
}

fn format_header(elements: &[Span], level: usize) -> String {
    format!("<h{} id='{}'>{}</h{}>\n\n",
            level,
            slugify(elements),
            format_spans(elements),
            level)
}
<|endoftext|>