<commit_before>extern crate structopt;

mod calculate;
mod measure;

use crate::calculate::Calculation;
use std::fmt::Display;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;
use std::process::exit;
use structopt::StructOpt;

#[derive(Clone, Debug, StructOpt)]
#[structopt(name = "performance", about = "performance regression testing runner")]
enum Opt {
    #[structopt(name = "measure")]
    Measure {
        #[structopt(parse(from_os_str))]
        #[structopt(short)]
        projects_dir: PathBuf,
        #[structopt(short)]
        branch_name: String,
    },
    #[structopt(name = "calculate")]
    Calculate {
        #[structopt(parse(from_os_str))]
        #[structopt(short)]
        results_dir: PathBuf,
    },
}

fn gracefully_exit_or<A, B, E: Display>(f: &dyn Fn(A) -> B, r: Result<A, E>) -> B {
    match r {
        Err(e) => {
            println!("{}", e);
            exit(1)
        },
        Ok(x) => f(x),
    }
}

// This is where all the printing, exiting, and error displaying
// should happen. Module functions should only return values.
fn main() {
    match Opt::from_args() {

        Opt::Measure { projects_dir, branch_name } => {
            let statuses = gracefully_exit_or(
                &|x| x,
                measure::measure(&projects_dir, &branch_name)
            );

            for status in statuses {
                match status.code() {
                    None => (),
                    Some(0) => (),
                    // if any child command exited with a non zero status code, exit with the same one here.
                    Some(nonzero) => {
                        println!("a child process exited with a nonzero status code.");
                        exit(nonzero)
                    },
                }
            }
        },

        Opt::Calculate { results_dir } => {
            let calculations = gracefully_exit_or(
                &|x| x,
                calculate::regressions(&results_dir)
            );

            // print calculations to stdout
            println!(":: All Calculations ::\n");
            for c in &calculations {
                println!("{:#?}\n", c);
            }
            println!("");

            // write calculations to file so it can be downloaded as an artifact
            let json_calcs = serde_json::to_string(&calculations)
                .expect("failed to serialize calculations to json");

            let outfile = &mut results_dir.into_os_string();
            outfile.push("/final_calculations.json");

            let mut f = File::create(outfile).expect("Unable to create file");
            f.write_all(json_calcs.as_bytes()).expect("unable to write data");

            // filter for regressions
            let regressions: Vec<Calculation> = calculations
                .into_iter()
                .filter(|c| c.regression)
                .collect();

            // exit with non zero exit code if there are regressions
            match regressions[..] {
                [] => println!("congrats! no regressions :)"),
                _ => {
                    println!(":: Regressions Found ::\n");
                    for r in regressions {
                        println!("{:#?}", r);
                    }
                    println!("");
                    exit(1)
                }
            }
        },

    }
}
<commit_msg>minor print change<commit_after>extern crate structopt;

mod calculate;
mod measure;

use crate::calculate::Calculation;
use std::fmt::Display;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;
use std::process::exit;
use structopt::StructOpt;

#[derive(Clone, Debug, StructOpt)]
#[structopt(name = "performance", about = "performance regression testing runner")]
enum Opt {
    #[structopt(name = "measure")]
    Measure {
        #[structopt(parse(from_os_str))]
        #[structopt(short)]
        projects_dir: PathBuf,
        #[structopt(short)]
        branch_name: String,
    },
    #[structopt(name = "calculate")]
    Calculate {
        #[structopt(parse(from_os_str))]
        #[structopt(short)]
        results_dir: PathBuf,
    },
}

fn gracefully_exit_or<A, B, E: Display>(f: &dyn Fn(A) -> B, r: Result<A, E>) -> B {
    match r {
        Err(e) => {
            println!("{}", e);
            exit(1)
        },
        Ok(x) => f(x),
    }
}

// This is where all the printing, exiting, and error displaying
// should happen. Module functions should only return values.
fn main() {
    match Opt::from_args() {

        Opt::Measure { projects_dir, branch_name } => {
            let statuses = gracefully_exit_or(
                &|x| x,
                measure::measure(&projects_dir, &branch_name)
            );

            for status in statuses {
                match status.code() {
                    None => (),
                    Some(0) => (),
                    // if any child command exited with a non zero status code, exit with the same one here.
                    Some(nonzero) => {
                        println!("a child process exited with a nonzero status code.");
                        exit(nonzero)
                    },
                }
            }
        },

        Opt::Calculate { results_dir } => {
            let calculations = gracefully_exit_or(
                &|x| x,
                calculate::regressions(&results_dir)
            );

            // print calculations to stdout
            println!(":: All Calculations ::\n");
            for c in &calculations {
                println!("{:#?}\n", c);
            }
            println!("");

            // write calculations to file so it can be downloaded as an artifact
            let json_calcs = serde_json::to_string(&calculations)
                .expect("failed to serialize calculations to json");

            let outfile = &mut results_dir.into_os_string();
            outfile.push("/final_calculations.json");

            let mut f = File::create(outfile).expect("Unable to create file");
            f.write_all(json_calcs.as_bytes()).expect("unable to write data");

            // filter for regressions
            let regressions: Vec<Calculation> = calculations
                .into_iter()
                .filter(|c| c.regression)
                .collect();

            // exit with non zero exit code if there are regressions
            match regressions[..] {
                [] => println!("congrats! no regressions :)"),
                _ => {
                    println!(":: Regressions Found ::\n");
                    println!("");
                    for r in regressions {
                        println!("{:#?}\n", r);
                    }
                    println!("");
                    exit(1)
                }
            }
        },

    }
}
<|endoftext|>


<commit_before>use quote;
use syn;
use proc_macro2::Span;

use diagnostic_shim::*;
use field::*;
use meta::*;
use model::*;
use util::*;

pub fn derive(item: syn::DeriveInput) -> Result<quote::Tokens, Diagnostic> {
    let treat_none_as_null = MetaItem::with_name(&item.attrs, "changeset_options")
        .map(|meta| {
            meta.warn_if_other_options(&["treat_none_as_null"]);
            meta.nested_item("treat_none_as_null")
                .map(|m| m.expect_bool_value())
        })
        .unwrap_or(Ok(false))?;
    let model = Model::from_item(&item)?;
    let struct_name = &model.name;
    let table_name = model.table_name();

    let (_, ty_generics, where_clause) = item.generics.split_for_impl();
    let mut impl_generics = item.generics.clone();
    impl_generics.params.push(parse_quote!('update));
    let (impl_generics, _, _) = impl_generics.split_for_impl();

    let fields_for_update = model
        .fields()
        .iter()
        .filter(|f| !model.primary_key_names.contains(&f.column_name()))
        .collect::<Vec<_>>();
    let changeset_ty = fields_for_update
        .iter()
        .map(|field| field_changeset_ty(field, table_name, treat_none_as_null));
    let changeset_expr = fields_for_update
        .iter()
        .map(|field| field_changeset_expr(field, table_name, treat_none_as_null));

    if fields_for_update.is_empty() {
        Span::call_site()
            .error(
                "Deriving `AsChangeset` on a structure that only contains the primary key isn't supported."
            )
            .help("If you want to change the primary key of a row, you should do so with `.set(table::id.eq(new_id))`.")
            .note("`#[derive(AsChangeset)]` never changes the primary key of a row.")
            .emit();
    }

    Ok(wrap_in_dummy_mod(
        model.dummy_mod_name("as_changeset"),
        quote!(
            use self::diesel::query_builder::AsChangeset;
            use self::diesel::prelude::*;

            impl #impl_generics AsChangeset for &'update #struct_name #ty_generics
            #where_clause
            {
                type Target = #table_name::table;
                type Changeset = <(#(#changeset_ty,)*) as AsChangeset>::Changeset;

                fn as_changeset(self) -> Self::Changeset {
                    (#(#changeset_expr,)*).as_changeset()
                }
            }
        ),
    ))
}

fn field_changeset_ty(
    field: &Field,
    table_name: syn::Ident,
    treat_none_as_null: bool,
) -> syn::Type {
    let column_name = field.column_name();
    if !treat_none_as_null && is_option_ty(&field.ty) {
        let field_ty = inner_of_option_ty(&field.ty);
        parse_quote!(std::option::Option<diesel::dsl::Eq<#table_name::#column_name, &'update #field_ty>>)
    } else {
        let field_ty = &field.ty;
        parse_quote!(diesel::dsl::Eq<#table_name::#column_name, &'update #field_ty>)
    }
}

fn field_changeset_expr(
    field: &Field,
    table_name: syn::Ident,
    treat_none_as_null: bool,
) -> syn::Expr {
    let field_access = field.name.access();
    let column_name = field.column_name();
    if !treat_none_as_null && is_option_ty(&field.ty) {
        parse_quote!(self#field_access.as_ref().map(|x| #table_name::#column_name.eq(x)))
    } else {
        parse_quote!(#table_name::#column_name.eq(&self#field_access))
    }
}
<commit_msg>Derive `AsChangeset` also for the plain struct, similar to `Insertable`<commit_after>use quote;
use syn;
use proc_macro2::Span;

use diagnostic_shim::*;
use field::*;
use meta::*;
use model::*;
use util::*;

pub fn derive(item: syn::DeriveInput) -> Result<quote::Tokens, Diagnostic> {
    let treat_none_as_null = MetaItem::with_name(&item.attrs, "changeset_options")
        .map(|meta| {
            meta.warn_if_other_options(&["treat_none_as_null"]);
            meta.nested_item("treat_none_as_null")
                .map(|m| m.expect_bool_value())
        })
        .unwrap_or(Ok(false))?;
    let model = Model::from_item(&item)?;
    let struct_name = &model.name;
    let table_name = model.table_name();

    let (_, ty_generics, where_clause) = item.generics.split_for_impl();
    let mut impl_generics = item.generics.clone();
    impl_generics.params.push(parse_quote!('update));
    let (impl_generics, _, _) = impl_generics.split_for_impl();

    let fields_for_update = model
        .fields()
        .iter()
        .filter(|f| !model.primary_key_names.contains(&f.column_name()))
        .collect::<Vec<_>>();
    let ref_changeset_ty = fields_for_update.iter().map(|field| {
        field_changeset_ty(
            field,
            table_name,
            treat_none_as_null,
            Some(quote!(&'update)),
        )
    });
    let ref_changeset_expr = fields_for_update
        .iter()
        .map(|field| field_changeset_expr(field, table_name, treat_none_as_null, Some(quote!(&))));
    let direct_changeset_ty = fields_for_update
        .iter()
        .map(|field| field_changeset_ty(field, table_name, treat_none_as_null, None));
    let direct_changeset_expr = fields_for_update
        .iter()
        .map(|field| field_changeset_expr(field, table_name, treat_none_as_null, None));

    if fields_for_update.is_empty() {
        Span::call_site()
            .error(
                "Deriving `AsChangeset` on a structure that only contains the primary key isn't supported."
            )
            .help("If you want to change the primary key of a row, you should do so with `.set(table::id.eq(new_id))`.")
            .note("`#[derive(AsChangeset)]` never changes the primary key of a row.")
            .emit();
    }

    Ok(wrap_in_dummy_mod(
        model.dummy_mod_name("as_changeset"),
        quote!(
            use self::diesel::query_builder::AsChangeset;
            use self::diesel::prelude::*;

            impl #impl_generics AsChangeset for &'update #struct_name #ty_generics
            #where_clause
            {
                type Target = #table_name::table;
                type Changeset = <(#(#ref_changeset_ty,)*) as AsChangeset>::Changeset;

                fn as_changeset(self) -> Self::Changeset {
                    (#(#ref_changeset_expr,)*).as_changeset()
                }
            }

            impl #impl_generics AsChangeset for #struct_name #ty_generics
            #where_clause
            {
                type Target = #table_name::table;
                type Changeset = <(#(#direct_changeset_ty,)*) as AsChangeset>::Changeset;

                fn as_changeset(self) -> Self::Changeset {
                    (#(#direct_changeset_expr,)*).as_changeset()
                }
            }
        ),
    ))
}

fn field_changeset_ty(
    field: &Field,
    table_name: syn::Ident,
    treat_none_as_null: bool,
    lifetime: Option<quote::Tokens>,
) -> syn::Type {
    let column_name = field.column_name();
    if !treat_none_as_null && is_option_ty(&field.ty) {
        let field_ty = inner_of_option_ty(&field.ty);
        parse_quote!(std::option::Option<diesel::dsl::Eq<#table_name::#column_name, #lifetime #field_ty>>)
    } else {
        let field_ty = &field.ty;
        parse_quote!(diesel::dsl::Eq<#table_name::#column_name, #lifetime #field_ty>)
    }
}

fn field_changeset_expr(
    field: &Field,
    table_name: syn::Ident,
    treat_none_as_null: bool,
    lifetime: Option<quote::Tokens>,
) -> syn::Expr {
    let field_access = field.name.access();
    let column_name = field.column_name();
    if !treat_none_as_null && is_option_ty(&field.ty) {
        if lifetime.is_some() {
            parse_quote!(self#field_access.as_ref().map(|x| #table_name::#column_name.eq(x)))
        } else {
            parse_quote!(self#field_access.map(|x| #table_name::#column_name.eq(x)))
        }
    } else {
        parse_quote!(#table_name::#column_name.eq(#lifetime self#field_access))
    }
}
<|endoftext|>


<commit_before>
#[deriving(Clone, PartialEq)]
pub enum ExprAst {
    Int(IntNode),
    Str(StrNode),
    Bool(BoolNode),
    Pair(PairNode),
    Symbol(SymbolNode),
    Char(CharNode),
    Proc(ProcNode),
    CompProc(CompProcNode),
    Nil
}

pub trait Ast {
    fn print(&self);
}

impl Ast for ExprAst {
    fn print(&self) {
        match *self {
            ExprAst::Int(ref ast) => ast.print(),
            ExprAst::Str(ref ast) => ast.print(),
            ExprAst::Bool(ref ast) => ast.print(),
            ExprAst::Pair(ref ast) => ast.print(),
            ExprAst::Symbol(ref ast) => ast.print(),
            ExprAst::Char(ref ast) => ast.print(),
            ExprAst::Proc(ref ast) => ast.print(),
            ExprAst::CompProc(ref ast) => ast.print(),
            ExprAst::Nil => println!("nil")
        }
    }
}

macro_rules! is_ast_type {
    ($func_name:ident, $type_name:ident) => (impl ExprAst {
        pub fn $func_name(&self) -> bool {
            match *self {
                ExprAst::$type_name(_) => true,
                _ => false
            }
        }})
}

is_ast_type!(is_char, Char);
is_ast_type!(is_pair, Pair);
is_ast_type!(is_int, Int);
is_ast_type!(is_symbol, Symbol);
is_ast_type!(is_string, Str);
is_ast_type!(is_proc, Proc);
is_ast_type!(is_bool, Bool);

macro_rules! is_type {
    ($func_name:ident, $type_str:expr) => (impl ExprAst {
        pub fn $func_name(&self) -> bool {
            return self.is_tagged(ExprAst::Symbol(SymbolNode::new($type_str)));
        }
    })
}

is_type!(is_quote, "quote");
is_type!(is_def, "def");
is_type!(is_and, "and");
is_type!(is_or, "or");
is_type!(is_if, "if");
is_type!(is_assign, "set!");
is_type!(is_lambda, "lambda");
is_type!(is_cond, "cond");
is_type!(is_let, "let");
is_type!(is_begin, "begin");

#[allow(dead_code)]
impl ExprAst {
    pub fn is_true(&self) -> bool {
        return self.as_bool();
    }

    pub fn is_false(&self) -> bool {
        return !self.as_bool();
    }

    pub fn is_empty(&self) -> bool {
        match *self {
            ExprAst::Nil => true,
            _ => false
        }
    }

    pub fn as_bool(&self) -> bool {
        match *self {
            ExprAst::Bool(ref ast) => ast.value,
            _ => panic!("error type: expect BoolNode")
        }
    }

    pub fn as_int(&self) -> int {
        match *self {
            ExprAst::Int(ref ast) => ast.value,
            _ => panic!("error type: expect IntNode")
        }
    }

    pub fn as_str(&self) -> String {
        match *self {
            ExprAst::Str(ref ast) => ast.value.clone(),
            _ => panic!("error type: expect StrNode")
        }
    }

    pub fn as_char(&self) -> char {
        match *self {
            ExprAst::Char(ref ast) => ast.value,
            _ => panic!("error type: expect CharNode")
        }
    }

    pub fn car(&self) -> ExprAst {
        match *self {
            ExprAst::Pair(ref ast) => ast.pair[0].clone(),
            _ => panic!("error type: expect PairNode")
        }
    }

    pub fn cdr(&self) -> ExprAst {
        match *self {
            ExprAst::Pair(ref ast) => ast.pair[1].clone(),
            _ => panic!("error type: expect PairNode")
        }
    }

    pub fn is_last(&self) -> bool {
        assert!(self.is_pair());
        return self.cdr().is_empty();
    }

    pub fn is_self(&self) -> bool {
        match *self {
            ExprAst::Bool(_) => true,
            ExprAst::Int(_) => true,
            ExprAst::Char(_) => true,
            ExprAst::Str(_) => true,
            _ => false
        }
    }

    pub fn def_var(&self) -> ExprAst {
        assert!(self.is_def());
        if self.cdr().car().is_symbol() {
            self.cdr().car()
        } else {
            self.cdr().car().car()
        }
    }

    pub fn def_val(&self) -> ExprAst {
        assert!(self.is_def());
        if self.cdr().car().is_symbol() {
            self.cdr().cdr().car()
        } else {
            //proc
            ExprAst::Symbol(SymbolNode::new("OK"))
        }
    }

    fn is_tagged(&self, tag: ExprAst) -> bool {
        if self.is_pair() {
            let car = self.car();
            return car.is_symbol() && car == tag;
        }
        return false;
    }
}

#[deriving(Clone, PartialEq, Eq)]
pub struct IntNode {
    value: int
}

#[allow(dead_code)]
impl IntNode {
    pub fn new(val: int) -> IntNode {
        IntNode{ value: val}
    }
}

impl Ast for IntNode {
    fn print(&self) {
        println!("IntNode: {}", self.value);
    }
}

#[deriving(Clone, PartialEq)]
pub struct StrNode {
    value: String
}

impl Ast for StrNode {
    fn print(&self) {
        println!("StrNode: {}", self.value);
    }
}

#[allow(dead_code)]
impl StrNode {
    pub fn new(val: &str) -> StrNode {
        StrNode{ value: val.to_string()}
    }
}

#[deriving(Clone, PartialEq)]
pub struct BoolNode {
    value: bool
}

#[allow(dead_code)]
impl BoolNode {
    pub fn new(val: bool) -> BoolNode {
        BoolNode{ value: val}
    }
}

impl Ast for BoolNode {
    fn print(&self) {
        println!("BoolNode: {}", self.value);
    }
}

#[deriving(Clone, PartialEq)]
pub struct PairNode{
    pair: Vec<ExprAst>,
}

#[allow(dead_code)]
impl PairNode {
    pub fn new(car: ExprAst, cdr: ExprAst) -> PairNode {
        PairNode {
            pair: vec![car, cdr]
        }
    }
}

impl Ast for PairNode {
    fn print(&self) {
        println!("PairNode (");
        self.pair[0].print();
        self.pair[1].print();
        println!(")");
    }
}

#[deriving(Clone, PartialEq)]
pub struct SymbolNode {
    value: String
}

impl Ast for SymbolNode {
    fn print(&self) {
        println!("SymbolNode: {}", self.value);
    }
}

#[allow(dead_code)]
impl SymbolNode {
    pub fn new(val: &str) -> SymbolNode {
        SymbolNode {
            value: val.to_string()
        }
    }
}

#[deriving(Clone, PartialEq)]
pub struct CharNode {
    value: char
}

impl Ast for CharNode {
    fn print(&self) {
        println!("CharNode: {}", self.value);
    }
}

#[allow(dead_code)]
impl CharNode {
    pub fn new(val: char) -> CharNode {
        CharNode {
            value: val
        }
    }
}

#[deriving(Clone)]
struct ProcFunc(fn(ExprAst) -> ExprAst);

impl PartialEq for ProcFunc {
    fn eq(&self, o: &ProcFunc) -> bool {
        let _o: *const() = unsafe { ::std::mem::transmute(o)};
        let _s: *const() = unsafe { ::std::mem::transmute(self)};
        _s == _o
    }
    fn ne(&self, o: &ProcFunc) -> bool {
        !self.eq(o)
    }
}

#[deriving(Clone, PartialEq)]
pub struct ProcNode {
    value: String,
    func: ProcFunc
}

impl ProcNode {
    pub fn new(obj: fn(ExprAst)-> ExprAst) -> ProcNode {
        ProcNode {
            value: "proc".to_string(),
            func: ProcFunc(obj)
        }
    }
}

impl Ast for ProcNode {
    fn print(&self) {
        println!("ProcNode: {}", self.value);
    }
}

#[deriving(Clone, PartialEq)]
pub struct CompProcNode {
    pub params: Box<ExprAst>,
    pub body:   Box<ExprAst>,
    pub env:    Box<ExprAst>
}

impl Ast for CompProcNode {
    fn print(&self) {
        println!("CompProcNode: ");
        self.params.print();
        self.body.print();
        self.env.print();
    }
}

#[test]
fn test_ast_int() {
    let int_node = ExprAst::Int(IntNode::new(3));
    assert!(int_node.as_int() == 3);
}

#[test]
#[should_fail]
fn test_ast_int_fail() {
    let str_node = ExprAst::Str(StrNode::new("hello"));
    assert!(str_node.as_int() == 3);
}

#[test]
fn test_ast_bool() {
    let bool_node = ExprAst::Bool(BoolNode::new(false));
    assert!(bool_node.as_bool() == false);
}

#[test]
#[should_fail]
fn test_ast_bool_fail() {
    let int_node = ExprAst::Int(IntNode::new(3));
    assert!(int_node.as_bool() == false);
}

#[test]
fn test_ast_char() {
    let char_node = ExprAst::Char(CharNode::new('a'));
    assert!(char_node.as_char() == 'a');
}

#[test]
#[should_fail]
fn test_ast_char_fail() {
    let int_node = ExprAst::Int(IntNode::new(1));
    assert!(int_node.as_char() == 'a');
    assert!(int_node.is_self());
}

#[test]
fn test_ast_str() {
    let str_node = ExprAst::Str(StrNode::new("hello"));
    assert!(str_node.as_str() == "hello");
    assert!(str_node.is_self());
}

#[test]
#[should_fail]
fn test_ast_str_fail() {
    let int_node = ExprAst::Int(IntNode::new(3));
    assert!(int_node.as_str() == "3");
    assert!(int_node.is_self());
}

#[test]
fn test_ast_pair() {
    let int_node = ExprAst::Int(IntNode::new(3));
    int_node.print();
    let str_node = ExprAst::Str(StrNode::new("hello"));
    str_node.print();
    let pair_node = ExprAst::Pair(PairNode::new(int_node, str_node));
    let car_node = pair_node.car();
    let cdr_node = pair_node.cdr();
    assert!(car_node.as_int() == 3);
    assert!(cdr_node.as_str() == "hello");
    assert!(!pair_node.is_self());
}

#[test]
fn test_ast_symbol() {
    let sym_node = ExprAst::Symbol(SymbolNode::new("sym"));
    assert!(sym_node.is_symbol());
    assert!(!sym_node.is_self());
}

#[test]
#[should_fail]
fn test_ast_pair_fail() {
    let int_node = ExprAst::Int(IntNode::new(3));
    let car_node = int_node.car();
    assert!(car_node.as_int() == 3);
}

#[test]
fn test_ast_emptylist() {
    let empty_node = ExprAst::Nil;
    assert!(empty_node.is_empty());
    assert!(!empty_node.is_self());
}

#[test]
#[should_fail]
fn test_ast_emptylist_fail() {
    let empty_node = ExprAst::Int(IntNode::new(3));
    assert!(empty_node.is_empty());
    assert!(empty_node.is_quote());
}

#[test]
fn test_ast_is_set() {
    macro_rules! test_case {
        ($str_name:expr) => {
            {let node = ExprAst::Pair(PairNode::new(
                ExprAst::Symbol(SymbolNode::new($str_name)),
                ExprAst::Int(IntNode::new(3))));
            node}
        }
    }
    assert!(test_case!("let").is_let());
    assert!(test_case!("if").is_if());
    assert!(test_case!("lambda").is_lambda());
    assert!(test_case!("cond").is_cond());
    assert!(test_case!("set!").is_assign());
    assert!(test_case!("cond").is_cond());
    assert!(test_case!("begin").is_begin());
}
<commit_msg>cleanup<commit_after>
#[deriving(Clone, PartialEq)]
pub enum ExprAst {
    Int(IntNode),
    Str(StrNode),
    Bool(BoolNode),
    Pair(PairNode),
    Symbol(SymbolNode),
    Char(CharNode),
    Proc(ProcNode),
    CompProc(CompProcNode),
    Nil
}

pub trait Ast {
    fn print(&self);
}

impl Ast for ExprAst {
    fn print(&self) {
        match *self {
            ExprAst::Int(ref ast) => ast.print(),
            ExprAst::Str(ref ast) => ast.print(),
            ExprAst::Bool(ref ast) => ast.print(),
            ExprAst::Pair(ref ast) => ast.print(),
            ExprAst::Symbol(ref ast) => ast.print(),
            ExprAst::Char(ref ast) => ast.print(),
            ExprAst::Proc(ref ast) => ast.print(),
            ExprAst::CompProc(ref ast) => ast.print(),
            ExprAst::Nil => println!("nil")
        }
    }
}

macro_rules! is_ast_type {
    ($func_name:ident, $type_name:ident) => (impl ExprAst {
        pub fn $func_name(&self) -> bool {
            match *self {
                ExprAst::$type_name(_) => true,
                _ => false
            }
        }})
}

is_ast_type!(is_char, Char);
is_ast_type!(is_pair, Pair);
is_ast_type!(is_int, Int);
is_ast_type!(is_symbol, Symbol);
is_ast_type!(is_string, Str);
is_ast_type!(is_proc, Proc);
is_ast_type!(is_bool, Bool);

macro_rules! is_type {
    ($func_name:ident, $type_str:expr) => (impl ExprAst {
        pub fn $func_name(&self) -> bool {
            return self.is_tagged(ExprAst::Symbol(SymbolNode::new($type_str)));
        }
    })
}

is_type!(is_quote, "quote");
is_type!(is_def, "def");
is_type!(is_and, "and");
is_type!(is_or, "or");
is_type!(is_if, "if");
is_type!(is_assign, "set!");
is_type!(is_lambda, "lambda");
is_type!(is_cond, "cond");
is_type!(is_let, "let");
is_type!(is_begin, "begin");

#[allow(dead_code)]
impl ExprAst {
    pub fn is_true(&self) -> bool {
        return self.as_bool();
    }

    pub fn is_false(&self) -> bool {
        return !self.as_bool();
    }

    pub fn is_empty(&self) -> bool {
        match *self {
            ExprAst::Nil => true,
            _ => false
        }
    }

    pub fn as_bool(&self) -> bool {
        match *self {
            ExprAst::Bool(ref ast) => ast.value,
            _ => panic!("error type: expect BoolNode")
        }
    }

    pub fn as_int(&self) -> int {
        match *self {
            ExprAst::Int(ref ast) => ast.value,
            _ => panic!("error type: expect IntNode")
        }
    }

    pub fn as_str(&self) -> String {
        match *self {
            ExprAst::Str(ref ast) => ast.value.clone(),
            _ => panic!("error type: expect StrNode")
        }
    }

    pub fn as_char(&self) -> char {
        match *self {
            ExprAst::Char(ref ast) => ast.value,
            _ => panic!("error type: expect CharNode")
        }
    }

    pub fn car(&self) -> ExprAst {
        match *self {
            ExprAst::Pair(ref ast) => ast.pair[0].clone(),
            _ => panic!("error type: expect PairNode")
        }
    }

    pub fn cdr(&self) -> ExprAst {
        match *self {
            ExprAst::Pair(ref ast) => ast.pair[1].clone(),
            _ => panic!("error type: expect PairNode")
        }
    }

    pub fn is_last(&self) -> bool {
        assert!(self.is_pair());
        return self.cdr().is_empty();
    }

    pub fn is_self(&self) -> bool {
        match *self {
            ExprAst::Bool(_) => true,
            ExprAst::Int(_) => true,
            ExprAst::Char(_) => true,
            ExprAst::Str(_) => true,
            _ => false
        }
    }

    pub fn def_var(&self) -> ExprAst {
        assert!(self.is_def());
        if self.cdr().car().is_symbol() {
            self.cdr().car()
        } else {
            self.cdr().car().car()
        }
    }

    pub fn def_val(&self) -> ExprAst {
        assert!(self.is_def());
        if self.cdr().car().is_symbol() {
            self.cdr().cdr().car()
        } else {
            //proc
            ExprAst::Symbol(SymbolNode::new("OK"))
        }
    }

    fn is_tagged(&self, tag: ExprAst) -> bool {
        if self.is_pair() {
            let car = self.car();
            return car.is_symbol() && car == tag;
        }
        return false;
    }
}

#[deriving(Clone, PartialEq, Eq)]
pub struct IntNode {
    value: int
}

#[allow(dead_code)]
impl IntNode {
    pub fn new(val: int) -> IntNode {
        IntNode{ value: val}
    }
}

impl Ast for IntNode {
    fn print(&self) {
        println!("IntNode: {}", self.value);
    }
}

#[deriving(Clone, PartialEq)]
pub struct StrNode {
    value: String
}

impl Ast for StrNode {
    fn print(&self) {
        println!("StrNode: {}", self.value);
    }
}

#[allow(dead_code)]
impl StrNode {
    pub fn new(val: &str) -> StrNode {
        StrNode{ value: val.to_string()}
    }
}

#[deriving(Clone, PartialEq)]
pub struct BoolNode {
    value: bool
}

#[allow(dead_code)]
impl BoolNode {
    pub fn new(val: bool) -> BoolNode {
        BoolNode{ value: val}
    }
}

impl Ast for BoolNode {
    fn print(&self) {
        println!("BoolNode: {}", self.value);
    }
}

#[deriving(Clone, PartialEq)]
pub struct PairNode{
    pair: Vec<ExprAst>,
}

#[allow(dead_code)]
impl PairNode {
    pub fn new(car: ExprAst, cdr: ExprAst) -> PairNode {
        PairNode {
            pair: vec![car, cdr]
        }
    }
}

impl Ast for PairNode {
    fn print(&self) {
        println!("PairNode (");
        self.pair[0].print();
        self.pair[1].print();
        println!(")");
    }
}

#[deriving(Clone, PartialEq)]
pub struct SymbolNode {
    value: String
}

impl Ast for SymbolNode {
    fn print(&self) {
        println!("SymbolNode: {}", self.value);
    }
}

#[allow(dead_code)]
impl SymbolNode {
    pub fn new(val: &str) -> SymbolNode {
        SymbolNode {
            value: val.to_string()
        }
    }
}

#[deriving(Clone, PartialEq)]
pub struct CharNode {
    value: char
}

impl Ast for CharNode {
    fn print(&self) {
        println!("CharNode: {}", self.value);
    }
}

#[allow(dead_code)]
impl CharNode {
    pub fn new(val: char) -> CharNode {
        CharNode {
            value: val
        }
    }
}

#[deriving(Clone)]
struct ProcFunc(fn(ExprAst) -> ExprAst);

impl PartialEq for ProcFunc {
    fn eq(&self, o: &ProcFunc) -> bool {
        let _o: *const() = unsafe { ::std::mem::transmute(o)};
        let _s: *const() = unsafe { ::std::mem::transmute(self)};
        _s == _o
    }
    fn ne(&self, o: &ProcFunc) -> bool {
        !self.eq(o)
    }
}

#[deriving(Clone, PartialEq)]
pub struct ProcNode {
    value: String,
    func: ProcFunc
}

impl ProcNode {
    pub fn new(obj: fn(ExprAst)-> ExprAst) -> ProcNode {
        ProcNode {
            value: "proc".to_string(),
            func: ProcFunc(obj)
        }
    }
}

impl Ast for ProcNode {
    fn print(&self) {
        println!("ProcNode: {}", self.value);
    }
}

#[deriving(Clone, PartialEq)]
pub struct CompProcNode {
    pub params: Box<ExprAst>,
    pub body:   Box<ExprAst>,
    pub env:    Box<ExprAst>
}

impl Ast for CompProcNode {
    fn print(&self) {
        println!("CompProcNode: ");
        self.params.print();
        self.body.print();
        self.env.print();
    }
}

#[test]
fn test_ast_int() {
    let int_node = ExprAst::Int(IntNode::new(3));
    assert!(int_node.as_int() == 3);
}

#[test]
#[should_fail]
fn test_ast_int_fail() {
    let str_node = ExprAst::Str(StrNode::new("hello"));
    assert!(str_node.as_int() == 3);
}

#[test]
fn test_ast_bool() {
    let bool_node = ExprAst::Bool(BoolNode::new(false));
    assert!(bool_node.as_bool() == false);
}

#[test]
#[should_fail]
fn test_ast_bool_fail() {
    let int_node = ExprAst::Int(IntNode::new(3));
    assert!(int_node.as_bool() == false);
}

#[test]
fn test_ast_char() {
    let char_node = ExprAst::Char(CharNode::new('a'));
    assert!(char_node.as_char() == 'a');
}

#[test]
#[should_fail]
fn test_ast_char_fail() {
    let int_node = ExprAst::Int(IntNode::new(1));
    assert!(int_node.as_char() == 'a');
    assert!(int_node.is_self());
}

#[test]
fn test_ast_str() {
    let str_node = ExprAst::Str(StrNode::new("hello"));
    assert!(str_node.as_str() == "hello");
    assert!(str_node.is_self());
}

#[test]
#[should_fail]
fn test_ast_str_fail() {
    let int_node = ExprAst::Int(IntNode::new(3));
    assert!(int_node.as_str() == "3");
    assert!(int_node.is_self());
}

#[test]
fn test_ast_pair() {
    let int_node = ExprAst::Int(IntNode::new(3));
    int_node.print();
    let str_node = ExprAst::Str(StrNode::new("hello"));
    str_node.print();
    let pair_node = ExprAst::Pair(PairNode::new(int_node, str_node));
    let car_node = pair_node.car();
    let cdr_node = pair_node.cdr();
    assert!(car_node.as_int() == 3);
    assert!(cdr_node.as_str() == "hello");
    assert!(!pair_node.is_self());
}

#[test]
fn test_ast_symbol() {
    let sym_node = ExprAst::Symbol(SymbolNode::new("sym"));
    assert!(sym_node.is_symbol());
    assert!(!sym_node.is_self());
}

#[test]
#[should_fail]
fn test_ast_pair_fail() {
    let int_node = ExprAst::Int(IntNode::new(3));
    let car_node = int_node.car();
    assert!(car_node.as_int() == 3);
}

#[test]
fn test_ast_empty() {
    let empty_node = ExprAst::Nil;
    assert!(empty_node.is_empty());
    assert!(!empty_node.is_self());
}

#[test]
#[should_fail]
fn test_ast_empty_fail() {
    let empty_node = ExprAst::Int(IntNode::new(3));
    assert!(empty_node.is_empty());
    assert!(empty_node.is_quote());
}

#[test]
fn test_ast_is_set() {
    macro_rules! test_case {
        ($str_name:expr) => {
            {let node = ExprAst::Pair(PairNode::new(
                ExprAst::Symbol(SymbolNode::new($str_name)),
                ExprAst::Int(IntNode::new(3))));
            node}
        }
    }
    assert!(test_case!("let").is_let());
    assert!(test_case!("if").is_if());
    assert!(test_case!("lambda").is_lambda());
    assert!(test_case!("cond").is_cond());
    assert!(test_case!("set!").is_assign());
    assert!(test_case!("cond").is_cond());
    assert!(test_case!("begin").is_begin());
}
<|endoftext|>


<commit_before>use types::*;
use types::flags::*;
use types::generation::*;
use types::parsing::*;

use cookie_factory::GenError;

pub mod metadata {
    use super::*;

    pub const NAME:          &'static str   = "{{protocol.name}}";
    pub const MAJOR_VERSION: ShortShortUInt = {{protocol.major_version}};
    pub const MINOR_VERSION: ShortShortUInt = {{protocol.minor_version}};
    pub const REVISION:      ShortShortUInt = {{protocol.revision}};
    pub const PORT:          LongUInt       = {{protocol.port}};
    pub const COPYRIGHT:     &'static str   = r#"{{copyright}}"#;
}

pub mod constants {
    use super::*;

    {{#each protocol.constants as |constant| ~}}
    pub const {{sanitize_name constant.name}}: {{constant.type}} = {{constant.value}};
    {{/each ~}}
}

pub enum AMQPError {
    Soft(AMQPSoftError),
    Hard(AMQPHardError),
}

impl AMQPError {
    pub fn get_id(&self) -> ShortUInt {
        match *self {
            AMQPError::Soft(ref s) => s.get_id(),
            AMQPError::Hard(ref h) => h.get_id(),
        }
    }

    pub fn from_id(id: ShortUInt) -> Option<AMQPError> {
        AMQPSoftError::from_id(id).map(|e| AMQPError::Soft(e)).or_else(|| AMQPHardError::from_id(id).map(|e| AMQPError::Hard(e)))
    }
}

pub enum AMQPSoftError {
    {{#each protocol.soft_errors as |constant| ~}}
    {{camel constant.name}},
    {{/each ~}}
}

impl AMQPSoftError {
    pub fn get_id(&self) -> ShortUInt {
        match *self {
            {{#each protocol.soft_errors as |constant| ~}}
            AMQPSoftError::{{camel constant.name}} => {{constant.value}},
            {{/each ~}}
        }
    }

    pub fn from_id(id: ShortUInt) -> Option<AMQPSoftError> {
        match id {
            {{#each protocol.soft_errors as |constant| ~}}
            {{constant.value}} => Some(AMQPSoftError::{{camel constant.name}}),
            {{/each ~}}
            _                  => None,
        }
    }
}

pub enum AMQPHardError {
    {{#each protocol.hard_errors as |constant| ~}}
    {{camel constant.name}},
    {{/each ~}}
}

impl AMQPHardError {
    pub fn get_id(&self) -> ShortUInt {
        match *self {
            {{#each protocol.hard_errors as |constant| ~}}
            AMQPHardError::{{camel constant.name}} => {{constant.value}},
            {{/each ~}}
        }
    }

    pub fn from_id(id: ShortUInt) -> Option<AMQPHardError> {
        match id {
            {{#each protocol.hard_errors as |constant| ~}}
            {{constant.value}} => Some(AMQPHardError::{{camel constant.name}}),
            {{/each ~}}
            _                  => None,
        }
    }
}

{{#each protocol.classes as |class| ~}}
use self::{{snake class.name}}::parse_{{snake class.name}};
{{/each ~}}

named!(pub parse_class<AMQPClass>, switch!(parse_id,
    {{#each protocol.classes as |class| ~}}
    {{class.id}} => map!(call!(parse_{{snake class.name}}), AMQPClass::{{camel class.name}}) {{#unless @last ~}}|{{/unless ~}}
    {{/each ~}}
));

pub fn gen_class<'a>(input: (&'a mut [u8], usize), class: &AMQPClass) -> Result<(&'a mut [u8], usize), GenError> {
    match *class {
        {{#each protocol.classes as |class| ~}}
        AMQPClass::{{camel class.name}}(ref {{snake class.name}}) => {{snake class.name}}::gen_{{snake class.name}}(input, {{snake class.name}}),
        {{/each ~}}
    }
}

#[derive(Clone, Debug, PartialEq)]
pub enum AMQPClass {
    {{#each protocol.classes as |class| ~}}
    {{camel class.name}}({{snake class.name}}::AMQPMethod),
    {{/each ~}}
}

{{#each protocol.classes as |class|}}
pub mod {{snake class.name}} {
    use super::*;

    named!(pub parse_{{snake class.name}}<{{snake class.name}}::AMQPMethod>, switch!(parse_id,
        {{#each class.methods as |method| ~}}
        {{method.id}} => map!(call!(parse_{{snake method.name}}), AMQPMethod::{{camel method.name}}) {{#unless @last ~}}|{{/unless ~}}
        {{/each ~}}
    ));

    pub fn gen_{{snake class.name}}<'a>(input: (&'a mut [u8], usize), method: &AMQPMethod) -> Result<(&'a mut [u8], usize), GenError> {
        match *method {
            {{#each class.methods as |method| ~}}
            AMQPMethod::{{camel method.name}}(ref {{snake method.name}}) => {
                do_gen!(input,
                    gen_id(&{{class.id}}) >>
                    gen_{{snake method.name}}({{snake method.name}})
                )
            },
            {{/each ~}}
        }
    }

    #[derive(Clone, Debug, PartialEq)]
    pub enum AMQPMethod {
        {{#each class.methods as |method| ~}}
        {{camel method.name}}({{camel method.name}}),
        {{/each ~}}
    }

    {{#each class.methods as |method|}}
    #[derive(Clone, Debug, PartialEq)]
    pub struct {{camel method.name}} {
        {{#each_argument method.arguments as |argument| ~}}
        {{#if argument_is_value ~}}
        pub {{snake argument.name}}: {{argument.type}},
        {{else}}
        {{#each_flag argument as |flag| ~}}
        pub {{snake flag.name}}: Boolean,
        {{/each_flag ~}}
        {{/if ~}}
        {{/each_argument ~}}
    }

    named!(pub parse_{{snake method.name}}<{{camel method.name}}>, do_parse!(
        {{#each_argument method.arguments as |argument| ~}}
        {{#if argument_is_value ~}}
        {{snake argument.name}}: parse_{{snake_type argument.type}} >>
        {{else}}
        /* FIXME: support multiple flags structs? */
        flags: apply!(parse_flags, &vec![
            {{#each_flag argument as |flag| ~}}
            "{{flag.name}}",
            {{/each_flag ~}}
        ]) >>
        {{/if ~}}
        {{/each_argument ~}}
        ({{camel method.name}} {
            {{#each_argument method.arguments as |argument| ~}}
            {{#if argument_is_value ~}}
            {{snake argument.name}}: {{snake argument.name}},
            {{else}}
            {{#each_flag argument as |flag| ~}}
            {{snake flag.name}}: flags.get_flag("{{snake flag.name}}").unwrap_or({{flag.default_value}}),
            {{/each_flag ~}}
            {{/if ~}}
            {{/each_argument ~}}
        })
    ));

    pub fn gen_{{snake method.name}}<'a>(input: (&'a mut [u8], usize), {{#if method.has_arguments ~}}method{{else}}_{{/if ~}}: &{{camel method.name}}) -> Result<(&'a mut [u8],usize), GenError> {
        {{#if method.has_flags ~}}
        /* FIXME: support multiple flags structs? */
        let mut flags = AMQPFlags::new();
        {{#each_argument method.arguments as |argument| ~}}
        {{#unless argument_is_value ~}}
        {{#each_flag argument as |flag| ~}}
        flags.add_flag("{{snake flag.name}}".to_string(), method.{{snake flag.name}});
        {{/each_flag ~}}
        {{/unless ~}}
        {{/each_argument ~}}
        {{/if ~}}
        do_gen!(input,
            gen_id(&{{method.id}})
            {{#each_argument method.arguments as |argument| ~}}
            {{#if argument_is_value ~}}
            >> gen_{{snake_type argument.type}}(&method.{{snake argument.name}})
            {{else}}
            >> gen_flags(&flags)
            {{/if ~}}
            {{/each_argument ~}}
        )
    }
    {{/each ~}}
}
{{/each ~}}
<commit_msg>protocol: add class properties<commit_after>use types::*;
use types::flags::*;
use types::generation::*;
use types::parsing::*;

use cookie_factory::GenError;

pub mod metadata {
    use super::*;

    pub const NAME:          &'static str   = "{{protocol.name}}";
    pub const MAJOR_VERSION: ShortShortUInt = {{protocol.major_version}};
    pub const MINOR_VERSION: ShortShortUInt = {{protocol.minor_version}};
    pub const REVISION:      ShortShortUInt = {{protocol.revision}};
    pub const PORT:          LongUInt       = {{protocol.port}};
    pub const COPYRIGHT:     &'static str   = r#"{{copyright}}"#;
}

pub mod constants {
    use super::*;

    {{#each protocol.constants as |constant| ~}}
    pub const {{sanitize_name constant.name}}: {{constant.type}} = {{constant.value}};
    {{/each ~}}
}

pub enum AMQPError {
    Soft(AMQPSoftError),
    Hard(AMQPHardError),
}

impl AMQPError {
    pub fn get_id(&self) -> ShortUInt {
        match *self {
            AMQPError::Soft(ref s) => s.get_id(),
            AMQPError::Hard(ref h) => h.get_id(),
        }
    }

    pub fn from_id(id: ShortUInt) -> Option<AMQPError> {
        AMQPSoftError::from_id(id).map(|e| AMQPError::Soft(e)).or_else(|| AMQPHardError::from_id(id).map(|e| AMQPError::Hard(e)))
    }
}

pub enum AMQPSoftError {
    {{#each protocol.soft_errors as |constant| ~}}
    {{camel constant.name}},
    {{/each ~}}
}

impl AMQPSoftError {
    pub fn get_id(&self) -> ShortUInt {
        match *self {
            {{#each protocol.soft_errors as |constant| ~}}
            AMQPSoftError::{{camel constant.name}} => {{constant.value}},
            {{/each ~}}
        }
    }

    pub fn from_id(id: ShortUInt) -> Option<AMQPSoftError> {
        match id {
            {{#each protocol.soft_errors as |constant| ~}}
            {{constant.value}} => Some(AMQPSoftError::{{camel constant.name}}),
            {{/each ~}}
            _                  => None,
        }
    }
}

pub enum AMQPHardError {
    {{#each protocol.hard_errors as |constant| ~}}
    {{camel constant.name}},
    {{/each ~}}
}

impl AMQPHardError {
    pub fn get_id(&self) -> ShortUInt {
        match *self {
            {{#each protocol.hard_errors as |constant| ~}}
            AMQPHardError::{{camel constant.name}} => {{constant.value}},
            {{/each ~}}
        }
    }

    pub fn from_id(id: ShortUInt) -> Option<AMQPHardError> {
        match id {
            {{#each protocol.hard_errors as |constant| ~}}
            {{constant.value}} => Some(AMQPHardError::{{camel constant.name}}),
            {{/each ~}}
            _                  => None,
        }
    }
}

{{#each protocol.classes as |class| ~}}
use self::{{snake class.name}}::parse_{{snake class.name}};
{{/each ~}}

named!(pub parse_class<AMQPClass>, switch!(parse_id,
    {{#each protocol.classes as |class| ~}}
    {{class.id}} => map!(call!(parse_{{snake class.name}}), AMQPClass::{{camel class.name}}) {{#unless @last ~}}|{{/unless ~}}
    {{/each ~}}
));

pub fn gen_class<'a>(input: (&'a mut [u8], usize), class: &AMQPClass) -> Result<(&'a mut [u8], usize), GenError> {
    match *class {
        {{#each protocol.classes as |class| ~}}
        AMQPClass::{{camel class.name}}(ref {{snake class.name}}) => {{snake class.name}}::gen_{{snake class.name}}(input, {{snake class.name}}),
        {{/each ~}}
    }
}

#[derive(Clone, Debug, PartialEq)]
pub enum AMQPClass {
    {{#each protocol.classes as |class| ~}}
    {{camel class.name}}({{snake class.name}}::AMQPMethod),
    {{/each ~}}
}

{{#each protocol.classes as |class|}}
pub mod {{snake class.name}} {
    use super::*;

    named!(pub parse_{{snake class.name}}<{{snake class.name}}::AMQPMethod>, switch!(parse_id,
        {{#each class.methods as |method| ~}}
        {{method.id}} => map!(call!(parse_{{snake method.name}}), AMQPMethod::{{camel method.name}}) {{#unless @last ~}}|{{/unless ~}}
        {{/each ~}}
    ));

    pub fn gen_{{snake class.name}}<'a>(input: (&'a mut [u8], usize), method: &AMQPMethod) -> Result<(&'a mut [u8], usize), GenError> {
        match *method {
            {{#each class.methods as |method| ~}}
            AMQPMethod::{{camel method.name}}(ref {{snake method.name}}) => {
                do_gen!(input,
                    gen_id(&{{class.id}}) >>
                    gen_{{snake method.name}}({{snake method.name}})
                )
            },
            {{/each ~}}
        }
    }

    #[derive(Clone, Debug, PartialEq)]
    pub enum AMQPMethod {
        {{#each class.methods as |method| ~}}
        {{camel method.name}}({{camel method.name}}),
        {{/each ~}}
    }

    {{#each class.methods as |method|}}
    #[derive(Clone, Debug, PartialEq)]
    pub struct {{camel method.name}} {
        {{#each_argument method.arguments as |argument| ~}}
        {{#if argument_is_value ~}}
        pub {{snake argument.name}}: {{argument.type}},
        {{else}}
        {{#each_flag argument as |flag| ~}}
        pub {{snake flag.name}}: Boolean,
        {{/each_flag ~}}
        {{/if ~}}
        {{/each_argument ~}}
    }

    named!(pub parse_{{snake method.name}}<{{camel method.name}}>, do_parse!(
        {{#each_argument method.arguments as |argument| ~}}
        {{#if argument_is_value ~}}
        {{snake argument.name}}: parse_{{snake_type argument.type}} >>
        {{else}}
        /* FIXME: support multiple flags structs? */
        flags: apply!(parse_flags, &vec![
            {{#each_flag argument as |flag| ~}}
            "{{flag.name}}",
            {{/each_flag ~}}
        ]) >>
        {{/if ~}}
        {{/each_argument ~}}
        ({{camel method.name}} {
            {{#each_argument method.arguments as |argument| ~}}
            {{#if argument_is_value ~}}
            {{snake argument.name}}: {{snake argument.name}},
            {{else}}
            {{#each_flag argument as |flag| ~}}
            {{snake flag.name}}: flags.get_flag("{{snake flag.name}}").unwrap_or({{flag.default_value}}),
            {{/each_flag ~}}
            {{/if ~}}
            {{/each_argument ~}}
        })
    ));

    pub fn gen_{{snake method.name}}<'a>(input: (&'a mut [u8], usize), {{#if method.has_arguments ~}}method{{else}}_{{/if ~}}: &{{camel method.name}}) -> Result<(&'a mut [u8],usize), GenError> {
        {{#if method.has_flags ~}}
        /* FIXME: support multiple flags structs? */
        let mut flags = AMQPFlags::new();
        {{#each_argument method.arguments as |argument| ~}}
        {{#unless argument_is_value ~}}
        {{#each_flag argument as |flag| ~}}
        flags.add_flag("{{snake flag.name}}".to_string(), method.{{snake flag.name}});
        {{/each_flag ~}}
        {{/unless ~}}
        {{/each_argument ~}}
        {{/if ~}}
        do_gen!(input,
            gen_id(&{{method.id}})
            {{#each_argument method.arguments as |argument| ~}}
            {{#if argument_is_value ~}}
            >> gen_{{snake_type argument.type}}(&method.{{snake argument.name}})
            {{else}}
            >> gen_flags(&flags)
            {{/if ~}}
            {{/each_argument ~}}
        )
    }
    {{/each ~}}
    {{#if class.has_properties ~}}
    pub enum AMQPProperty {
        {{#each class.properties as |property| ~}}
        {{camel property.name}}({{property.type}}),
        {{/each ~}}
    } /* TODO: add bitmask */
    {{/if ~}}
}
{{/each ~}}
<|endoftext|>


<commit_before>use item_state::ItemState;
use bar_builder::{
    UpdateStream,
};
use std::rc::Rc;
use xcb::{
    Connection,
    Rectangle,
    Window,
};
use futures::stream::{Merge, MergedItem};
use futures::{Future, Stream};
use xcb_event_stream::XcbEventStream;
use error::*;
use std::error::Error;
use xcb;
use component::Slot;

type UpdateAndEventStream = Merge<UpdateStream, XcbEventStream>;

pub struct Bar {
    pub center_items: Vec<ItemState>,
    pub conn: Rc<Connection>,
    pub foreground: u32,
    pub geometry: Rectangle,
    pub item_positions: Vec<(u16, u16)>,
    pub left_items: Vec<ItemState>,
    pub right_items: Vec<ItemState>,
    pub stream: Option<UpdateAndEventStream>,
    pub window: Window,
}

impl Bar {
    fn get_stream(&mut self) -> UpdateAndEventStream {
        ::std::mem::replace(&mut self.stream, None).unwrap()
    }

    pub fn run(mut self) -> Box<Future<Item=(), Error=()>> {
        let future = self.get_stream()
            .map_err(|e| ::error::Error::with_chain(e, ErrorKind::ItemError))
            .for_each(move |item| -> Result<()> {
                let (_, update) = match item {
                    MergedItem::First(update) => (None, Some(update)),
                    MergedItem::Second(event) => (Some(event), None),
                    MergedItem::Both(update, event) => (Some(event), Some(update)),
                };

                if let Some(update) = update {
                    let size_changed;
                    let width;

                    {
                        let slot_items = match update.slot {
                            Slot::Left => &mut self.left_items,
                            Slot::Center => &mut self.center_items,
                            Slot::Right => &mut self.right_items,
                        };
                        slot_items[update.index].update(update.value)?;

                        width = slot_items[update.index].get_content_width();
                        size_changed = self.item_positions[update.id].1 != width;
                    }

                    match update.slot {
                        Slot::Center => self.redraw_center()?,
                        Slot::Left => self.redraw_left(size_changed, update.index)?,
                        Slot::Right => self.redraw_right(size_changed, update.index)?,
                    }
                }
                Ok(())
            })
            .map_err(|err| {
                println!("Error occurred: {}", err);
                let mut cause = err.cause();
                while let Some(err) = cause {
                    println!("  Caused by: {}", err);
                    cause = err.cause();
                }
            });

        Box::new(future)
    }

    fn redraw_center(&mut self) -> Result<()> {
        let width_all: u16 = self.center_items.iter()
            .map(|item| item.get_content_width())
            .sum();

        let mut pos = (self.geometry.width())/2-width_all/2;

        for item in self.center_items.iter() {
            self.item_positions[item.get_id()].0 = pos;
            self.draw_item(item, pos)?;
            self.item_positions[item.get_id()].1 = item.get_content_width();
            pos += item.get_content_width();
        }

        Ok(())
    }

    fn redraw_right(&mut self, size_changed: bool, index: usize) -> Result<()> {
        let mut pos = self.geometry.width();

        for n in 0..self.right_items.len() {
            let item = &self.right_items[self.right_items.len()-n-1];

            pos -= item.get_content_width();

            if n < self.right_items.len()-index-1 {
                continue;
            }

            if size_changed {
                let mut bg_start = pos;
                let mut bg_end = pos + item.get_content_width();

                if n == self.right_items.len()-1 {
                    let old_start = self.item_positions[item.get_id()].0 as u16;
                    if old_start < bg_start {
                        bg_start = old_start;
                    }
                }

                self.paint_bg(bg_start, bg_end)?;
            }

            self.item_positions[item.get_id()].0 = pos;
            self.item_positions[item.get_id()].1 = item.get_content_width();
            self.draw_item(item, pos)?;

            if !size_changed {
                break;
            }
        }

        Ok(())
    }

    fn redraw_left(&mut self, size_changed: bool, index: usize) -> Result<()> {
        let mut pos = 0;

        for n in 0..self.left_items.len() {
            let item = &self.left_items[n];

            if n < index {
                continue;
            }

            if size_changed {
                let mut bg_start = pos;
                let mut bg_end = pos + item.get_content_width();

                if n == self.left_items.len()-1 {
                    let old_end = self.item_positions[item.get_id()].0 +
                        self.item_positions[item.get_id()].1;
                    if bg_end < old_end {
                        bg_end = old_end;
                    }
                }

                self.paint_bg(bg_start, bg_end)?;
            }

            self.item_positions[item.get_id()].0 = pos;
            self.item_positions[item.get_id()].1 = item.get_content_width();
            self.draw_item(item, pos)?;

            if !size_changed {
                break;
            }
        }

        Ok(())
    }

    fn draw_item(&self, item: &ItemState, pos: u16) -> Result<()> {
        if !item.is_ready() {
            return Ok(());
        }

        try_xcb!(xcb::copy_area_checked, "failed to copy pixmap",
            &self.conn,
            item.get_pixmap(),
            self.window,
            self.foreground,
            0, 0,
            pos as i16, 0,
            item.get_content_width() as u16,
            self.geometry.height());

        Ok(())
    }

    fn paint_bg(&self, a: u16, b: u16) -> Result<()> {
        try_xcb!(xcb::poly_fill_rectangle, "failed to draw background",
            &self.conn,
            self.window,
            self.foreground,
            &[Rectangle::new(a as i16, 0, b-a, self.geometry.height())]);

        Ok(())
    }
}
<commit_msg>Add documentation for `Bar`.<commit_after>use item_state::ItemState;
use bar_builder::{
    UpdateStream,
};
use std::rc::Rc;
use xcb::{
    Connection,
    Rectangle,
    Window,
};
use futures::stream::{Merge, MergedItem};
use futures::{Future, Stream};
use xcb_event_stream::XcbEventStream;
use error::*;
use std::error::Error;
use xcb;
use component::Slot;

type UpdateAndEventStream = Merge<UpdateStream, XcbEventStream>;

/// Struct that contains everything needed to run the bar.
pub struct Bar {
    pub center_items: Vec<ItemState>,
    pub conn: Rc<Connection>,
    pub foreground: u32,
    pub geometry: Rectangle,
    pub item_positions: Vec<(u16, u16)>,
    pub left_items: Vec<ItemState>,
    pub right_items: Vec<ItemState>,
    pub stream: Option<UpdateAndEventStream>,
    pub window: Window,
}

impl Bar {
    /// Returns `self.stream` without borrowing or consuming `self`.
    /// Panics if called twice.
    fn get_stream(&mut self) -> UpdateAndEventStream {
        ::std::mem::replace(&mut self.stream, None).unwrap()
    }

    /// Launch and run the bar.
    pub fn run(mut self) -> Box<Future<Item=(), Error=()>> {
        let future = self.get_stream()
            .map_err(|e| ::error::Error::with_chain(e, ErrorKind::ItemError))
            .for_each(move |item| -> Result<()> {
                let (_, update) = match item {
                    MergedItem::First(update) => (None, Some(update)),
                    MergedItem::Second(event) => (Some(event), None),
                    MergedItem::Both(update, event) => (Some(event), Some(update)),
                };

                if let Some(update) = update {
                    let size_changed;

                    // Figure out if the component has chanaged
                    // it's size since the last update.
                    // TODO: Move to a function
                    {
                        let slot_items = match update.slot {
                            Slot::Left => &mut self.left_items,
                            Slot::Center => &mut self.center_items,
                            Slot::Right => &mut self.right_items,
                        };
                        slot_items[update.index].update(update.value)?;

                        let width = slot_items[update.index].get_content_width();
                        size_changed = self.item_positions[update.id].1 != width;
                    }

                    // Redraw only neccessary stuff
                    match update.slot {
                        Slot::Center => self.redraw_center()?,
                        Slot::Left => self.redraw_left(size_changed, update.index)?,
                        Slot::Right => self.redraw_right(size_changed, update.index)?,
                    }
                }
                Ok(())
            })
            .map_err(|err| {
                println!("Error occurred: {}", err);
                let mut cause = err.cause();
                while let Some(err) = cause {
                    println!("  Caused by: {}", err);
                    cause = err.cause();
                }
            });

        Box::new(future)
    }

    /// Redraws components in the center slot.
    /// Unforunately centering means that all components
    /// must be redrawn if even one of them changes size.
    fn redraw_center(&mut self) -> Result<()> {
        let width_all: u16 = self.center_items.iter()
            .map(|item| item.get_content_width())
            .sum();

        let mut pos = (self.geometry.width())/2-width_all/2;

        for item in self.center_items.iter() {
            self.item_positions[item.get_id()].0 = pos;
            self.draw_item(item, pos)?;
            self.item_positions[item.get_id()].1 = item.get_content_width();
            pos += item.get_content_width();
        }

        Ok(())
    }

    /// Pretty much the same as `self.redraw_left` but with `left` replaced with `right`.
    /// The order in which the items are gone through is reversed.
    fn redraw_right(&mut self, size_changed: bool, index: usize) -> Result<()> {
        let mut pos = self.geometry.width();

        for n in 0..self.right_items.len() {
            let item = &self.right_items[self.right_items.len()-n-1];

            pos -= item.get_content_width();

            if n < self.right_items.len()-index-1 {
                continue;
            }

            if size_changed {
                let mut bg_start = pos;
                let mut bg_end = pos + item.get_content_width();

                if n == self.right_items.len()-1 {
                    let old_start = self.item_positions[item.get_id()].0 as u16;
                    if old_start < bg_start {
                        bg_start = old_start;
                    }
                }

                self.paint_bg(bg_start, bg_end)?;
            }

            self.item_positions[item.get_id()].0 = pos;
            self.item_positions[item.get_id()].1 = item.get_content_width();
            self.draw_item(item, pos)?;

            if !size_changed {
                break;
            }
        }

        Ok(())
    }

    /// Redraw only needed items in the right slot.
    /// Symmetric to `self.redraw_left`.
    ///
    /// If the component hasn't changed it's size, it doesn't affect
    /// any other components and we can get away with just painting
    /// the one component.
    ///
    /// However if the component has changed it's size, we must also
    /// redraw every component on the right of it. If the item has shrunk
    /// we must also repaint the exposed background.
    fn redraw_left(&mut self, size_changed: bool, index: usize) -> Result<()> {
        let mut pos = 0;

        for n in 0..self.left_items.len() {
            let item = &self.left_items[n];

            if n < index {
                continue;
            }

            if size_changed {
                let mut bg_start = pos;
                let mut bg_end = pos + item.get_content_width();

                if n == self.left_items.len()-1 {
                    let old_end = self.item_positions[item.get_id()].0 +
                        self.item_positions[item.get_id()].1;
                    if bg_end < old_end {
                        bg_end = old_end;
                    }
                }

                self.paint_bg(bg_start, bg_end)?;
            }

            self.item_positions[item.get_id()].0 = pos;
            self.item_positions[item.get_id()].1 = item.get_content_width();
            self.draw_item(item, pos)?;

            if !size_changed {
                break;
            }
        }

        Ok(())
    }

    /// Copies the item's pixmap to the window.
    fn draw_item(&self, item: &ItemState, pos: u16) -> Result<()> {
        if !item.is_ready() {
            return Ok(());
        }

        try_xcb!(xcb::copy_area_checked, "failed to copy pixmap",
            &self.conn,
            item.get_pixmap(),
            self.window,
            self.foreground,
            0, 0,
            pos as i16, 0,
            item.get_content_width() as u16,
            self.geometry.height());

        Ok(())
    }

    /// Draws the background starting at point a on the x-axis until point b.
    fn paint_bg(&self, a: u16, b: u16) -> Result<()> {
        try_xcb!(xcb::poly_fill_rectangle, "failed to draw background",
            &self.conn,
            self.window,
            self.foreground,
            &[Rectangle::new(a as i16, 0, b-a, self.geometry.height())]);

        Ok(())
    }
}
<|endoftext|>


<commit_before>use std::fs::read_to_string;

use buildpack::{
    eyre,
    libcnb::{
        self,
        build::{BuildContext, BuildResult, BuildResultBuilder},
        data::build_plan::BuildPlan,
        detect::{DetectContext, DetectResult, DetectResultBuilder},
        generic::{GenericMetadata, GenericPlatform},
        Buildpack,
    },
    tracing, BuildpackTrait,
};
use sources::Sources;

pub struct SourcesBuildpack;

impl BuildpackTrait for SourcesBuildpack {
    fn toml() -> &'static str {
        include_str!("../buildpack.toml")
    }
}

const PROJECT_JSON: &str = "project.json";

impl Buildpack for SourcesBuildpack {
    type Platform = GenericPlatform;
    type Metadata = GenericMetadata;
    type Error = eyre::Report;

    fn detect(&self, context: DetectContext<Self>) -> libcnb::Result<DetectResult, Self::Error> {
        let sources = read_to_string(PROJECT_JSON)
            .ok()
            .and_then(|json| serde_json::from_str::<serde_json::Value>(&json).ok())
            .and_then(|project| project.get("sources").cloned())
            .and_then(|sources| serde_json::from_value::<Sources>(sources).ok());

        if let Some(sources) = sources {
            tracing::warn!("Importing project sources");
            sources
                .import_sync(&context.app_dir)
                .map_err(libcnb::Error::BuildpackError)?;

            // Although this buildpack does not do anything in the build phase we
            // add to the build plan mainly for documentation / debugging purposes
            let (require, provide) =
                Self::require_and_provide("sources", PROJECT_JSON, "Import project sources", None);
            let mut build_plan = BuildPlan::new();
            build_plan.requires = vec![require];
            build_plan.provides = vec![provide];
            return DetectResultBuilder::pass().build_plan(build_plan).build();
        }

        DetectResultBuilder::fail().build()
    }

    fn build(&self, _context: BuildContext<Self>) -> libcnb::Result<BuildResult, Self::Error> {
        BuildResultBuilder::new().build()
    }
}
<commit_msg>chore(Sources buildpack): Change log level to `info`<commit_after>use std::fs::read_to_string;

use buildpack::{
    eyre,
    libcnb::{
        self,
        build::{BuildContext, BuildResult, BuildResultBuilder},
        data::build_plan::BuildPlan,
        detect::{DetectContext, DetectResult, DetectResultBuilder},
        generic::{GenericMetadata, GenericPlatform},
        Buildpack,
    },
    tracing, BuildpackTrait,
};
use sources::Sources;

pub struct SourcesBuildpack;

impl BuildpackTrait for SourcesBuildpack {
    fn toml() -> &'static str {
        include_str!("../buildpack.toml")
    }
}

const PROJECT_JSON: &str = "project.json";

impl Buildpack for SourcesBuildpack {
    type Platform = GenericPlatform;
    type Metadata = GenericMetadata;
    type Error = eyre::Report;

    fn detect(&self, context: DetectContext<Self>) -> libcnb::Result<DetectResult, Self::Error> {
        let sources = read_to_string(PROJECT_JSON)
            .ok()
            .and_then(|json| serde_json::from_str::<serde_json::Value>(&json).ok())
            .and_then(|project| project.get("sources").cloned())
            .and_then(|sources| serde_json::from_value::<Sources>(sources).ok());

        if let Some(sources) = sources {
            tracing::info!("Importing project sources");
            sources
                .import_sync(&context.app_dir)
                .map_err(libcnb::Error::BuildpackError)?;

            // Although this buildpack does not do anything in the build phase we
            // add to the build plan mainly for documentation / debugging purposes
            let (require, provide) =
                Self::require_and_provide("sources", PROJECT_JSON, "Import project sources", None);
            let mut build_plan = BuildPlan::new();
            build_plan.requires = vec![require];
            build_plan.provides = vec![provide];
            return DetectResultBuilder::pass().build_plan(build_plan).build();
        }

        DetectResultBuilder::fail().build()
    }

    fn build(&self, _context: BuildContext<Self>) -> libcnb::Result<BuildResult, Self::Error> {
        BuildResultBuilder::new().build()
    }
}
<|endoftext|>


<commit_before>//! Similar to https://github.com/retep998/wio-rs/blob/44093f7db8/src/com.rs , but can be null

use std::fmt;
use std::ops;
use std::ptr;
use winapi::Interface;
use winapi::ctypes::c_void;
use winapi::shared::guiddef::GUID;
use winapi::shared::winerror::HRESULT;
use winapi::shared::winerror::SUCCEEDED;
use winapi::um::unknwnbase::IUnknown;

pub type HResult<T> = Result<T, HResultError>;

/// An error code returned by a Windows API.
pub struct HResultError(HRESULT);

impl fmt::Debug for HResultError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "0x{:08X}", self.0 as u32)
    }
}

impl From<HRESULT> for HResultError {
    fn from(h: HRESULT) -> Self {
        HResultError(h)
    }
}

pub trait ToResult: Sized {
    fn to_result(self) -> HResult<()>;
}

impl ToResult for HRESULT {
    fn to_result(self) -> HResult<()> {
        if SUCCEEDED(self) {
            Ok(())
        } else {
            Err(HResultError(self))
        }
    }
}

pub fn as_ptr<T>(x: &T) -> *mut T {
    x as *const T as _
}

/// Forked from https://github.com/retep998/wio-rs/blob/44093f7db8/src/com.rs
#[derive(PartialEq, Debug)]
pub struct ComPtr<T>(*mut T) where T: Interface;

impl<T> ComPtr<T> where T: Interface {
    /// Creates a `ComPtr` to wrap a raw pointer.
    /// It takes ownership over the pointer which means it does __not__ call `AddRef`.
    /// `T` __must__ be a COM interface that inherits from `IUnknown`.
    pub unsafe fn from_raw(ptr: *mut T) -> ComPtr<T> {
        assert!(!ptr.is_null());
        ComPtr(ptr)
    }

    /// For use with APIs that take an interface UUID and
    /// "return" a new COM object through a `*mut *mut c_void` out-parameter.
    pub unsafe fn new_with_uuid<F>(f: F) -> HResult<Self>
        where F: FnOnce(&GUID, *mut *mut c_void) -> HRESULT
    {
        Self::new_with(|ptr| f(&T::uuidof(), ptr as _))
    }

    /// For use with APIs that "return" a new COM object through a `*mut *mut T` out-parameter.
    pub unsafe fn new_with<F>(f: F) -> HResult<Self>
        where F: FnOnce(*mut *mut T) -> HRESULT
    {
        let mut ptr = ptr::null_mut();
        let status = f(&mut ptr);
        if SUCCEEDED(status) {
            Ok(ComPtr::from_raw(ptr))
        } else {
            if !ptr.is_null() {
                let ptr = ptr as *mut IUnknown;
                (*ptr).Release();
            }
            Err(HResultError(status))
        }
    }

    pub fn as_raw(&self) -> *mut T {
        self.0
    }

    fn as_unknown(&self) -> &IUnknown {
        unsafe {
            &*(self.0 as *mut IUnknown)
        }
    }

    /// Performs QueryInterface fun.
    pub fn cast<U>(&self) -> HResult<ComPtr<U>> where U: Interface {
        unsafe {
            let mut obj = ptr::null_mut();
            self.as_unknown().QueryInterface(&U::uuidof(), &mut obj).to_result()?;
            Ok(ComPtr::from_raw(obj as *mut U))
        }
    }
}

impl<T> ops::Deref for ComPtr<T> where T: Interface {
    type Target = T;
    fn deref(&self) -> &T {
        unsafe { &*self.0 }
    }
}

impl<T> Clone for ComPtr<T> where T: Interface {
    fn clone(&self) -> Self {
        unsafe {
            self.as_unknown().AddRef();
            ComPtr(self.0)
        }
    }
}

impl<T> Drop for ComPtr<T> where T: Interface {
    fn drop(&mut self) {
        unsafe {
            self.as_unknown().Release();
        }
    }
}
<commit_msg>Rewrite ComPtr::cast in terms of new_with_uuid<commit_after>//! Similar to https://github.com/retep998/wio-rs/blob/44093f7db8/src/com.rs , but can be null

use std::fmt;
use std::ops;
use std::ptr;
use winapi::Interface;
use winapi::ctypes::c_void;
use winapi::shared::guiddef::GUID;
use winapi::shared::winerror::HRESULT;
use winapi::shared::winerror::SUCCEEDED;
use winapi::um::unknwnbase::IUnknown;

pub type HResult<T> = Result<T, HResultError>;

/// An error code returned by a Windows API.
pub struct HResultError(HRESULT);

impl fmt::Debug for HResultError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "0x{:08X}", self.0 as u32)
    }
}

impl From<HRESULT> for HResultError {
    fn from(h: HRESULT) -> Self {
        HResultError(h)
    }
}

pub trait ToResult: Sized {
    fn to_result(self) -> HResult<()>;
}

impl ToResult for HRESULT {
    fn to_result(self) -> HResult<()> {
        if SUCCEEDED(self) {
            Ok(())
        } else {
            Err(HResultError(self))
        }
    }
}

pub fn as_ptr<T>(x: &T) -> *mut T {
    x as *const T as _
}

/// Forked from https://github.com/retep998/wio-rs/blob/44093f7db8/src/com.rs
#[derive(PartialEq, Debug)]
pub struct ComPtr<T>(*mut T) where T: Interface;

impl<T> ComPtr<T> where T: Interface {
    /// Creates a `ComPtr` to wrap a raw pointer.
    /// It takes ownership over the pointer which means it does __not__ call `AddRef`.
    /// `T` __must__ be a COM interface that inherits from `IUnknown`.
    pub unsafe fn from_raw(ptr: *mut T) -> ComPtr<T> {
        assert!(!ptr.is_null());
        ComPtr(ptr)
    }

    /// For use with APIs that take an interface UUID and
    /// "return" a new COM object through a `*mut *mut c_void` out-parameter.
    pub unsafe fn new_with_uuid<F>(f: F) -> HResult<Self>
        where F: FnOnce(&GUID, *mut *mut c_void) -> HRESULT
    {
        Self::new_with(|ptr| f(&T::uuidof(), ptr as _))
    }

    /// For use with APIs that "return" a new COM object through a `*mut *mut T` out-parameter.
    pub unsafe fn new_with<F>(f: F) -> HResult<Self>
        where F: FnOnce(*mut *mut T) -> HRESULT
    {
        let mut ptr = ptr::null_mut();
        let status = f(&mut ptr);
        if SUCCEEDED(status) {
            Ok(ComPtr::from_raw(ptr))
        } else {
            if !ptr.is_null() {
                let ptr = ptr as *mut IUnknown;
                (*ptr).Release();
            }
            Err(HResultError(status))
        }
    }

    pub fn as_raw(&self) -> *mut T {
        self.0
    }

    fn as_unknown(&self) -> &IUnknown {
        unsafe {
            &*(self.0 as *mut IUnknown)
        }
    }

    /// Performs QueryInterface fun.
    pub fn cast<U>(&self) -> HResult<ComPtr<U>> where U: Interface {
        unsafe {
            ComPtr::<U>::new_with_uuid(|uuid, ptr| self.as_unknown().QueryInterface(uuid, ptr))
        }
    }
}

impl<T> ops::Deref for ComPtr<T> where T: Interface {
    type Target = T;
    fn deref(&self) -> &T {
        unsafe { &*self.0 }
    }
}

impl<T> Clone for ComPtr<T> where T: Interface {
    fn clone(&self) -> Self {
        unsafe {
            self.as_unknown().AddRef();
            ComPtr(self.0)
        }
    }
}

impl<T> Drop for ComPtr<T> where T: Interface {
    fn drop(&mut self) {
        unsafe {
            self.as_unknown().Release();
        }
    }
}
<|endoftext|>


<commit_before>use clap::ArgMatches;
use std::io::{Read, Write};
use std::net;

use super::Error;

pub fn terminal_agent(matches: &ArgMatches) -> Result<(), Error> {
    let data;
    #[cfg(unix)]
    {
        unsafe {
            let ptr = libc::ttyname(1);
            assert!(!ptr.is_null());
            data = std::ffi::CStr::from_ptr(ptr).to_str()?;
        }
    }
    #[cfg(windows)]
    {
        data = std::process::id();
    }

    let port: u16 = matches.value_of("port").unwrap().parse().unwrap();
    let addr = net::SocketAddr::new(net::Ipv4Addr::new(127, 0, 0, 1).into(), port);
    let mut stream = net::TcpStream::connect(addr)?;
    write!(stream, "{}", data)?;

    clear_screen();

    stream.shutdown(net::Shutdown::Write)?;
    // Wait for the other end to close connection (which will be maintained till the end of
    // the debug session; this prevents terminal shell from stealing debuggee's input form stdin).
    for b in stream.bytes() {
        if let Err(_) = b {
            break;
        }
    }

    // Clear out any unread input buffered in stdin, so it doesn't get read by the shell.
    purge_stdin();

    Ok(())
}

fn clear_screen() {
    let terminal = crossterm::terminal();
    drop(terminal.clear(crossterm::ClearType::All));
}

#[cfg(unix)]
fn purge_stdin() {
    use std::os::unix::io::AsRawFd;
    drop(termios::tcflush(std::io::stdin().as_raw_fd(), termios::TCIFLUSH));
}
#[cfg(windows)]
fn purge_stdin() {
    use std::os::windows::io::AsRawHandle;
    unsafe {
        winapi::um::wincon::FlushConsoleInputBuffer(std::io::stdin().as_raw_handle());
    }
}
<commit_msg>Windows kills half-closed connections after a timeout.<commit_after>use clap::ArgMatches;
use std::io::{Read, Write};
use std::net;

use super::Error;

pub fn terminal_agent(matches: &ArgMatches) -> Result<(), Error> {
    let data;
    #[cfg(unix)]
    {
        unsafe {
            let ptr = libc::ttyname(1);
            assert!(!ptr.is_null());
            data = std::ffi::CStr::from_ptr(ptr).to_str()?;
        }
    }
    #[cfg(windows)]
    {
        data = std::process::id();
    }

    let port: u16 = matches.value_of("port").unwrap().parse().unwrap();
    let addr = net::SocketAddr::new(net::Ipv4Addr::new(127, 0, 0, 1).into(), port);
    let mut stream = net::TcpStream::connect(addr)?;
    writeln!(stream, "{}", data)?;

    clear_screen();

    // Wait for the other end to close connection (which will be maintained till the end of
    // the debug session; this prevents terminal shell from stealing debuggee's input form stdin).
    for b in stream.bytes() {
        if let Err(_) = b {
            break;
        }
    }

    // Clear out any unread input buffered in stdin, so it doesn't get read by the shell.
    purge_stdin();

    Ok(())
}

fn clear_screen() {
    let terminal = crossterm::terminal();
    drop(terminal.clear(crossterm::ClearType::All));
}

#[cfg(unix)]
fn purge_stdin() {
    use std::os::unix::io::AsRawFd;
    drop(termios::tcflush(std::io::stdin().as_raw_fd(), termios::TCIFLUSH));
}
#[cfg(windows)]
fn purge_stdin() {
    use std::os::windows::io::AsRawHandle;
    unsafe {
        winapi::um::wincon::FlushConsoleInputBuffer(std::io::stdin().as_raw_handle());
    }
}
<|endoftext|>


<commit_before><commit_msg>feat(Complex): implement Sub<commit_after><|endoftext|>


<commit_before>//! # Plist
//!
//! A rusty plist parser.
//!
//! ## Usage
//!
//! Put this in your `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! plist = "0.5"
//! ```
//!
//! And put this in your crate root:
//!
//! ```rust
//! extern crate plist;
//! ```
//!
//! ## Examples
//!
//! ```rust
//! use plist::Value;
//!
//! let value = Value::from_file("tests/data/xml.plist").unwrap();
//!
//! match value {
//!     Value::Array(_array) => (),
//!     _ => ()
//! }
//! ```
//!
//! ```rust
//! extern crate plist;
//! # #[cfg(feature = "serde")]
//! #[macro_use]
//! extern crate serde_derive;
//!
//! # #[cfg(feature = "serde")]
//! # fn main() {
//! #[derive(Deserialize)]
//! #[serde(rename_all = "PascalCase")]
//! struct Info {
//!     author: String,
//!     height: f32,
//! }
//!
//! let info: Info = plist::from_file("tests/data/xml.plist").unwrap();
//! # }
//! #
//! # #[cfg(not(feature = "serde"))]
//! # fn main() {}
//! ```

pub mod dictionary;

#[cfg(feature = "enable_unstable_features_that_may_break_with_minor_version_bumps")]
pub mod stream;
#[cfg(not(feature = "enable_unstable_features_that_may_break_with_minor_version_bumps"))]
mod stream;

mod date;
mod error;
mod integer;
mod uid;
mod value;

pub use date::Date;
pub use dictionary::Dictionary;
pub use error::Error;
pub use integer::Integer;
pub use uid::Uid;
pub use value::Value;

// Optional serde module
#[cfg(feature = "serde")]
#[macro_use]
extern crate serde;
#[cfg(feature = "serde")]
mod de;
#[cfg(feature = "serde")]
mod ser;
#[cfg(all(
    feature = "serde",
    any(
        test,
        feature = "enable_unstable_features_that_may_break_with_minor_version_bumps"
    )
))]
pub use self::{de::Deserializer, ser::Serializer};
#[cfg(feature = "serde")]
pub use self::{
    de::{from_file, from_reader, from_reader_xml},
    ser::{to_file_binary, to_file_xml, to_writer_binary, to_writer_xml},
};

#[cfg(all(test, feature = "serde"))]
#[macro_use]
extern crate serde_derive;

#[cfg(all(test, feature = "serde"))]
mod serde_tests;

fn u64_to_usize(len_u64: u64) -> Option<usize> {
    let len = len_u64 as usize;
    if len as u64 != len_u64 {
        return None; // Too long
    }
    Some(len)
}
<commit_msg>Add another note about the `enable_unstable_features_that_may_break_with_minor_version_bumps` feature flag.<commit_after>//! # Plist
//!
//! A rusty plist parser.
//!
//! ## Usage
//!
//! Put this in your `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! plist = "0.5"
//! ```
//!
//! And put this in your crate root:
//!
//! ```rust
//! extern crate plist;
//! ```
//!
//! ## Examples
//!
//! ```rust
//! use plist::Value;
//!
//! let value = Value::from_file("tests/data/xml.plist").unwrap();
//!
//! match value {
//!     Value::Array(_array) => (),
//!     _ => ()
//! }
//! ```
//!
//! ```rust
//! extern crate plist;
//! # #[cfg(feature = "serde")]
//! #[macro_use]
//! extern crate serde_derive;
//!
//! # #[cfg(feature = "serde")]
//! # fn main() {
//! #[derive(Deserialize)]
//! #[serde(rename_all = "PascalCase")]
//! struct Info {
//!     author: String,
//!     height: f32,
//! }
//!
//! let info: Info = plist::from_file("tests/data/xml.plist").unwrap();
//! # }
//! #
//! # #[cfg(not(feature = "serde"))]
//! # fn main() {}
//! ```
//!
//! ## Unstable Features
//!
//! Many features from previous versions are now hidden behind the
//! `enable_unstable_features_that_may_break_with_minor_version_bumps` feature. These will break in
//! minor version releases after the 1.0 release. If you really really must use them you should
//! specify a tilde requirement e.g. `plist = "~1.0.3"` in you `Cargo.toml` so that the plist crate
//! is not automatically updated to version 1.1.

pub mod dictionary;

#[cfg(feature = "enable_unstable_features_that_may_break_with_minor_version_bumps")]
pub mod stream;
#[cfg(not(feature = "enable_unstable_features_that_may_break_with_minor_version_bumps"))]
mod stream;

mod date;
mod error;
mod integer;
mod uid;
mod value;

pub use date::Date;
pub use dictionary::Dictionary;
pub use error::Error;
pub use integer::Integer;
pub use uid::Uid;
pub use value::Value;

// Optional serde module
#[cfg(feature = "serde")]
#[macro_use]
extern crate serde;
#[cfg(feature = "serde")]
mod de;
#[cfg(feature = "serde")]
mod ser;
#[cfg(all(
    feature = "serde",
    any(
        test,
        feature = "enable_unstable_features_that_may_break_with_minor_version_bumps"
    )
))]
pub use self::{de::Deserializer, ser::Serializer};
#[cfg(feature = "serde")]
pub use self::{
    de::{from_file, from_reader, from_reader_xml},
    ser::{to_file_binary, to_file_xml, to_writer_binary, to_writer_xml},
};

#[cfg(all(test, feature = "serde"))]
#[macro_use]
extern crate serde_derive;

#[cfg(all(test, feature = "serde"))]
mod serde_tests;

fn u64_to_usize(len_u64: u64) -> Option<usize> {
    let len = len_u64 as usize;
    if len as u64 != len_u64 {
        return None; // Too long
    }
    Some(len)
}
<|endoftext|>


<commit_before>use std::io::{self, Write};
use std::f32::consts::PI;
use std::f32::INFINITY;
use std::ops::Neg;

#[derive(Copy, Clone, Debug)]
pub struct Position(f32, f32);

impl Position {
    pub fn origin() -> Position {
        Position(0.0, 0.0)
    }
}

#[derive(Copy, Clone, Debug)]
pub struct Degree(pub f32);

#[derive(Copy, Clone, Debug)]
pub struct Radiant(pub f32);

impl Into<Degree> for Radiant {
    fn into(self) -> Degree {
        Degree(self.0 * 180.0 / PI)
    }
}

impl Into<Degree> for f32 {
    fn into(self) -> Degree {
        Degree(self)
    }
}

impl Into<Radiant> for Degree {
    fn into(self) -> Radiant {
        Radiant(self.0 * PI / 180.0)
    }
}

#[derive(Copy, Clone, Debug)]
pub struct Distance(f32);

impl Into<Distance> for f32 {
    fn into(self) -> Distance {
        Distance(self)
    }
}

impl Neg for Distance {
    type Output = Distance;
    fn neg(self) -> Self::Output {
        Distance(-self.0)
    }
}

impl Neg for Degree {
    type Output = Degree;
    fn neg(self) -> Self::Output {
        Degree(-self.0)
    }
}

pub trait Turtle {
    /// Move turtle forward by specified `distance`.
    fn forward<T: Into<Distance>>(&mut self, distance: T);

    /// Move turtle backward by specified `distance`.
    fn backward<T: Into<Distance>>(&mut self, distance: T) {
        self.forward(-distance.into())
    }

    /// Move turtle forward by specified `distance` *without* drawing.
    fn move_forward<T: Into<Distance>>(&mut self, distance: T);

    /// Rotate around `angle`. If `angle` is positive,
    /// the turtle is turned to the left, if negative,
    /// to the right.
    fn rotate<T: Into<Degree>>(&mut self, angle: T);

    /// Turn turtle right by `angle` degree.
    fn right<T: Into<Degree>>(&mut self, angle: T) {
        self.rotate(-angle.into());
    }

    /// Turn turtle left by `angle` degree.
    fn left<T: Into<Degree>>(&mut self, angle: T) {
        self.rotate(angle.into());
    }

    /// Returns `true` if pen is down.
    fn is_pen_down(&self) -> bool;

    /// Returns `true` if pen is up.
    fn is_pen_up(&self) -> bool {
        !self.is_pen_down()
    }

    /// Put the pen down.
    fn pen_down(&mut self);

    /// Put the pen up.
    fn pen_up(&mut self);

    fn goto(&mut self, pos: Position);

    fn home(&mut self) {
        self.goto(Position::origin());
    }

    /// Push current turtle state on stack.
    fn push(&mut self);

    /// Restore previously saved turtle state.
    fn pop(&mut self);
}

#[derive(Clone)]
struct TurtleState {
    pos: Position,
    angle: Degree,
    pendown: bool,
}

pub struct Canvas {
    states: Vec<TurtleState>,
    paths: Vec<Vec<Position>>,
}

impl Canvas {
    pub fn new() -> Canvas {
        let init_pos = Position::origin();
        let init_state = TurtleState {
            pos: init_pos,
            angle: Degree(0.0), // points upwards
            pendown: true, /* start with pen down */
        };
        Canvas {
            states: vec![init_state],
            paths: vec![vec![init_pos]],
        }
    }

    #[inline]
    fn current_state_mut(&mut self) -> &mut TurtleState {
        self.states.last_mut().unwrap()
    }

    #[inline]
    fn current_state(&self) -> &TurtleState {
        self.states.last().unwrap()
    }

    #[inline]
    fn direction(&self, distance: Distance) -> (f32, f32) {
        let state = self.current_state();
        let rad: Radiant = state.angle.into();
        let (sin, cos) = rad.0.sin_cos();
        let dx = sin * distance.0;
        let dy = cos * distance.0;
        (dx, dy)
    }

    fn line_to(&mut self, dst: Position) {
        self.paths.last_mut().unwrap().push(dst);
    }

    fn move_to(&mut self, dst: Position) {
        if self.paths.is_empty() {
            self.paths.push(vec![dst]);
        } else {
            let begin_new_path = self.paths.last().unwrap().len() > 1;
            if begin_new_path {
                self.paths.push(vec![dst]);
            } else {
                // Replace first path element with current position
                self.paths.last_mut().unwrap()[0] = dst;
            }
        }
    }

    /// Saves the turtle graphic as Scalable Vector Graphic (SVG).
    pub fn save_svg<W: Write>(&self, wr: &mut W) -> io::Result<()> {
        // Determine extend of canvas
        let mut min = Position(INFINITY, INFINITY);
        let mut max = Position(-INFINITY, -INFINITY);
        for path in self.paths.iter() {
            for pt in path.iter() {
                min.0 = min.0.min(pt.0).min(pt.0);
                max.0 = max.0.max(pt.0).max(pt.0);

                min.1 = min.1.min(pt.1).min(pt.1);
                max.1 = max.1.max(pt.1).max(pt.1);
            }
        }
        let (min_width, min_height) = (100.0, 100.0);
        let width = (max.0 - min.0).abs().max(min_width);
        let height = (max.1 - min.1).abs().max(min_height);
        let border_percent = 0.1;

        let top_left = Position(min.0 - border_percent * width,
                                min.1 - border_percent * height);

        let scale = 1.0 + 2.0 * border_percent;

        try!(writeln!(wr,
                      r#"<?xml version="1.0" encoding="UTF-8"?>
                <svg xmlns="http://www.w3.org/2000/svg"
                version="1.1" baseProfile="full"
                viewBox="{} {} {} {}">"#,
                      top_left.0,
                      top_left.1,
                      scale * width,
                      scale * height));

        // use a stroke width of 0.1% of the width or height of the canvas
        let stroke_width = scale * width.max(height) / 1000.0;
        try!(writeln!(wr,
                      r#"<g stroke="black" stroke-width="{}" fill="none">"#,
                      stroke_width));

        for path in self.paths.iter() {
            if let Some((head, tail)) = path.split_first() {
                try!(write!(wr, r#"<path d="M{} {}"#, head.0, head.1));
                for pos in tail {
                    try!(write!(wr, r#" L{} {}"#, pos.0, pos.1));
                }
                try!(writeln!(wr, r#"" />"#));
            }
        }
        try!(writeln!(wr, r#"</g>"#));

        writeln!(wr, "</svg>")
    }
}

impl Turtle for Canvas {
    /// Move turtle forward by specified `distance`.
    fn forward<T: Into<Distance>>(&mut self, distance: T) {
        let (dx, dy) = self.direction(distance.into());
        let src: Position = self.current_state().pos;
        let dst = Position(src.0 + dx, src.1 + dy);
        if self.is_pen_down() {
            self.line_to(dst);
        }
        self.current_state_mut().pos = dst;
    }

    fn rotate<T: Into<Degree>>(&mut self, angle: T) {
        let angle: Degree = angle.into();
        self.current_state_mut().angle.0 += angle.0;
    }

    fn move_forward<T: Into<Distance>>(&mut self, distance: T) {
        let (dx, dy) = self.direction(distance.into());
        let src: Position = self.current_state().pos;
        let dst = Position(src.0 + dx, src.1 + dy);
        self.move_to(dst);
    }

    fn is_pen_down(&self) -> bool {
        self.current_state().pendown
    }

    /// Put the pen down.
    fn pen_down(&mut self) {
        let pos = self.current_state().pos;
        self.move_to(pos);
        self.current_state_mut().pendown = true;
    }

    /// Put the pen up.
    fn pen_up(&mut self) {
        self.current_state_mut().pendown = false;
    }

    /// Positions the turtle exactly at `position`.
    fn goto(&mut self, position: Position) {
        self.current_state_mut().pos = position;
        self.move_to(position);
    }

    /// Push current turtle state on stack.
    fn push(&mut self) {
        let state = self.current_state_mut().clone();
        self.states.push(state);
    }

    /// Restore previously saved turtle state.
    fn pop(&mut self) {
        self.states.pop();
        let pos = self.current_state().pos;
        self.move_to(pos);
    }
}
<commit_msg>SVG coordinates are top to bottom, while turtle coords are bottom to top<commit_after>use std::io::{self, Write};
use std::f32::consts::PI;
use std::f32::INFINITY;
use std::ops::Neg;

#[derive(Copy, Clone, Debug)]
pub struct Position(f32, f32);

impl Position {
    pub fn origin() -> Position {
        Position(0.0, 0.0)
    }
}

#[derive(Copy, Clone, Debug)]
pub struct Degree(pub f32);

#[derive(Copy, Clone, Debug)]
pub struct Radiant(pub f32);

impl Into<Degree> for Radiant {
    fn into(self) -> Degree {
        Degree(self.0 * 180.0 / PI)
    }
}

impl Into<Degree> for f32 {
    fn into(self) -> Degree {
        Degree(self)
    }
}

impl Into<Radiant> for Degree {
    fn into(self) -> Radiant {
        Radiant(self.0 * PI / 180.0)
    }
}

#[derive(Copy, Clone, Debug)]
pub struct Distance(f32);

impl Into<Distance> for f32 {
    fn into(self) -> Distance {
        Distance(self)
    }
}

impl Neg for Distance {
    type Output = Distance;
    fn neg(self) -> Self::Output {
        Distance(-self.0)
    }
}

impl Neg for Degree {
    type Output = Degree;
    fn neg(self) -> Self::Output {
        Degree(-self.0)
    }
}

pub trait Turtle {
    /// Move turtle forward by specified `distance`.
    fn forward<T: Into<Distance>>(&mut self, distance: T);

    /// Move turtle backward by specified `distance`.
    fn backward<T: Into<Distance>>(&mut self, distance: T) {
        self.forward(-distance.into())
    }

    /// Move turtle forward by specified `distance` *without* drawing.
    fn move_forward<T: Into<Distance>>(&mut self, distance: T);

    /// Rotate around `angle`. If `angle` is positive,
    /// the turtle is turned to the left, if negative,
    /// to the right.
    fn rotate<T: Into<Degree>>(&mut self, angle: T);

    /// Turn turtle right by `angle` degree.
    fn right<T: Into<Degree>>(&mut self, angle: T) {
        self.rotate(-angle.into());
    }

    /// Turn turtle left by `angle` degree.
    fn left<T: Into<Degree>>(&mut self, angle: T) {
        self.rotate(angle.into());
    }

    /// Returns `true` if pen is down.
    fn is_pen_down(&self) -> bool;

    /// Returns `true` if pen is up.
    fn is_pen_up(&self) -> bool {
        !self.is_pen_down()
    }

    /// Put the pen down.
    fn pen_down(&mut self);

    /// Put the pen up.
    fn pen_up(&mut self);

    fn goto(&mut self, pos: Position);

    fn home(&mut self) {
        self.goto(Position::origin());
    }

    /// Push current turtle state on stack.
    fn push(&mut self);

    /// Restore previously saved turtle state.
    fn pop(&mut self);
}

#[derive(Clone)]
struct TurtleState {
    pos: Position,
    angle: Degree,
    pendown: bool,
}

pub struct Canvas {
    states: Vec<TurtleState>,
    paths: Vec<Vec<Position>>,
}

impl Canvas {
    pub fn new() -> Canvas {
        let init_pos = Position::origin();
        let init_state = TurtleState {
            pos: init_pos,
            // The SVG coordinates are from top to bottom, while turtle coordinates are bottom to
            // top.
            angle: Degree(180.0), // points upwards
            pendown: true, /* start with pen down */
        };
        Canvas {
            states: vec![init_state],
            paths: vec![vec![init_pos]],
        }
    }

    #[inline]
    fn current_state_mut(&mut self) -> &mut TurtleState {
        self.states.last_mut().unwrap()
    }

    #[inline]
    fn current_state(&self) -> &TurtleState {
        self.states.last().unwrap()
    }

    #[inline]
    fn direction(&self, distance: Distance) -> (f32, f32) {
        let state = self.current_state();
        let rad: Radiant = state.angle.into();
        let (sin, cos) = rad.0.sin_cos();
        let dx = sin * distance.0;
        let dy = cos * distance.0;
        (dx, dy)
    }

    fn line_to(&mut self, dst: Position) {
        self.paths.last_mut().unwrap().push(dst);
    }

    fn move_to(&mut self, dst: Position) {
        if self.paths.is_empty() {
            self.paths.push(vec![dst]);
        } else {
            let begin_new_path = self.paths.last().unwrap().len() > 1;
            if begin_new_path {
                self.paths.push(vec![dst]);
            } else {
                // Replace first path element with current position
                self.paths.last_mut().unwrap()[0] = dst;
            }
        }
    }

    /// Saves the turtle graphic as Scalable Vector Graphic (SVG).
    pub fn save_svg<W: Write>(&self, wr: &mut W) -> io::Result<()> {
        // Determine extend of canvas
        let mut min = Position(INFINITY, INFINITY);
        let mut max = Position(-INFINITY, -INFINITY);
        for path in self.paths.iter() {
            for pt in path.iter() {
                min.0 = min.0.min(pt.0).min(pt.0);
                max.0 = max.0.max(pt.0).max(pt.0);

                min.1 = min.1.min(pt.1).min(pt.1);
                max.1 = max.1.max(pt.1).max(pt.1);
            }
        }
        let (min_width, min_height) = (100.0, 100.0);
        let width = (max.0 - min.0).abs().max(min_width);
        let height = (max.1 - min.1).abs().max(min_height);
        let border_percent = 0.1;

        let top_left = Position(min.0 - border_percent * width,
                                min.1 - border_percent * height);

        let scale = 1.0 + 2.0 * border_percent;

        try!(writeln!(wr,
                      r#"<?xml version="1.0" encoding="UTF-8"?>
                <svg xmlns="http://www.w3.org/2000/svg"
                version="1.1" baseProfile="full"
                viewBox="{} {} {} {}">"#,
                      top_left.0,
                      top_left.1,
                      scale * width,
                      scale * height));

        // use a stroke width of 0.1% of the width or height of the canvas
        let stroke_width = scale * width.max(height) / 1000.0;
        try!(writeln!(wr,
                      r#"<g stroke="black" stroke-width="{}" fill="none">"#,
                      stroke_width));

        for path in self.paths.iter() {
            if let Some((head, tail)) = path.split_first() {
                try!(write!(wr, r#"<path d="M{} {}"#, head.0, head.1));
                for pos in tail {
                    try!(write!(wr, r#" L{} {}"#, pos.0, pos.1));
                }
                try!(writeln!(wr, r#"" />"#));
            }
        }
        try!(writeln!(wr, r#"</g>"#));

        writeln!(wr, "</svg>")
    }
}

impl Turtle for Canvas {
    /// Move turtle forward by specified `distance`.
    fn forward<T: Into<Distance>>(&mut self, distance: T) {
        let (dx, dy) = self.direction(distance.into());
        let src: Position = self.current_state().pos;
        let dst = Position(src.0 + dx, src.1 + dy);
        if self.is_pen_down() {
            self.line_to(dst);
        }
        self.current_state_mut().pos = dst;
    }

    fn rotate<T: Into<Degree>>(&mut self, angle: T) {
        let angle: Degree = angle.into();
        self.current_state_mut().angle.0 += angle.0;
    }

    fn move_forward<T: Into<Distance>>(&mut self, distance: T) {
        let (dx, dy) = self.direction(distance.into());
        let src: Position = self.current_state().pos;
        let dst = Position(src.0 + dx, src.1 + dy);
        self.move_to(dst);
    }

    fn is_pen_down(&self) -> bool {
        self.current_state().pendown
    }

    /// Put the pen down.
    fn pen_down(&mut self) {
        let pos = self.current_state().pos;
        self.move_to(pos);
        self.current_state_mut().pendown = true;
    }

    /// Put the pen up.
    fn pen_up(&mut self) {
        self.current_state_mut().pendown = false;
    }

    /// Positions the turtle exactly at `position`.
    fn goto(&mut self, position: Position) {
        self.current_state_mut().pos = position;
        self.move_to(position);
    }

    /// Push current turtle state on stack.
    fn push(&mut self) {
        let state = self.current_state_mut().clone();
        self.states.push(state);
    }

    /// Restore previously saved turtle state.
    fn pop(&mut self) {
        self.states.pop();
        let pos = self.current_state().pos;
        self.move_to(pos);
    }
}
<|endoftext|>