<commit_before>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

#[allow(unused_variables)]
pub mod storeid {
    use std::path::PathBuf;

    use ruru::{Class, Object, AnyObject, Boolean, RString, NilClass};

    use libimagstore::storeid::StoreId;

    wrappable_struct!(StoreId, StoreIdWrapper, STOREID_WRAPPER);
    class!(RStoreId);

    methods!(
        RStoreId,
        itself,

        fn r_storeid_new(base: RString, id: RString) -> AnyObject {
            let base = match base.map(|b| b.to_string()).map(PathBuf::from) {
                Ok(base) => base,
                Err(e) => {
                    // TODO: Exception!
                    error!("Building StoreId object failed: {:?}", e);
                    return AnyObject::from(NilClass::new().value());
                },
            };

            let id = match id.map(|id| id.to_string()).map(PathBuf::from) {
                Ok(id) => id,
                Err(e) => {
                    // TODO: Exception!
                    error!("Building StoreId object failed: {:?}", e);
                    return AnyObject::from(NilClass::new().value());
                },
            };

            match StoreId::new(Some(base), id) {
                Ok(sid) => Class::from_existing("RStoreId").wrap_data(sid, &*STOREID_WRAPPER),
                Err(e) => {
                    // TODO: Exception!
                    error!("Building StoreId object failed: {:?}", e);
                    return AnyObject::from(NilClass::new().value());
                },
            }
        }

        fn r_storeid_new_baseless(id: RString) -> AnyObject {
            let id = match id.map(|id| id.to_string()).map(PathBuf::from) {
                Ok(id) => id,
                Err(e) => {
                    // TODO: Exception!
                    error!("Building StoreId object failed: {:?}", e);
                    return AnyObject::from(NilClass::new().value());
                },
            };

            match StoreId::new(None, id) {
                Ok(sid) => Class::from_existing("RStoreId").wrap_data(sid, &*STOREID_WRAPPER),
                Err(e) => {
                    // TODO: Exception!
                    error!("Building StoreId object failed: {:?}", e);
                    return AnyObject::from(NilClass::new().value());
                },
            }
        }

        fn r_storeid_without_base() -> RStoreId {
            let withoutbase : StoreId = itself.get_data(&*STOREID_WRAPPER).clone().without_base();
            Class::from_existing("RStoreId").wrap_data(withoutbase, &*STOREID_WRAPPER)
        }

        fn r_storeid_with_base(base: RString) -> AnyObject {
            let base : PathBuf = match base.map(|b| b.to_string()).map(PathBuf::from) {
                Ok(pb) => pb,
                Err(e) => {
                    // TODO: Exception!
                    error!("Error: {:?}", e);
                    return AnyObject::from(NilClass::new().value());
                },
            };
            let withoutbase : StoreId = itself.get_data(&*STOREID_WRAPPER).clone().with_base(base);
            Class::from_existing("RStoreId").wrap_data(withoutbase, &*STOREID_WRAPPER)
        }

        fn r_storeid_into_pathbuf() -> AnyObject {
            itself.get_data(&*STOREID_WRAPPER)
                .clone()
                .into_pathbuf()
                // TODO: No unwraps
                .map(|pb| pb.to_str().map(String::from).unwrap())
                .as_ref()
                .map(|s| AnyObject::from(RString::new(s).value()))
                // TODO: Exception!
                .unwrap_or(AnyObject::from(NilClass::new().value()))
        }

        fn r_storeid_exists() -> Boolean {
            Boolean::new(itself.get_data(&*STOREID_WRAPPER).exists())
        }

        fn r_storeid_to_str() -> AnyObject {
            itself.get_data(&*STOREID_WRAPPER)
                .to_str()
                .as_ref()
                .map(|s| AnyObject::from(RString::new(s).value()))
                // TODO: Exception!
                .unwrap_or(AnyObject::from(NilClass::new().value()))
        }

        fn r_storeid_local() -> RString {
            let local = itself.get_data(&*STOREID_WRAPPER).local();
            let local = local.to_str().unwrap(); // TODO: No unwraps
            RString::new(local)
        }

    );

    pub fn setup() -> Class {
        let mut class = Class::new("RStoreId", None);
        class.define(|itself| {
            itself.def_self("new"          , r_storeid_new);
            itself.def_self("new_baseless" , r_storeid_new_baseless);

            itself.def("without_base"      , r_storeid_without_base);
            itself.def("with_base"         , r_storeid_with_base);
            itself.def("into_pathbuf"      , r_storeid_into_pathbuf);
            itself.def("exists"            , r_storeid_exists);
            itself.def("to_str"            , r_storeid_to_str);
            itself.def("local"             , r_storeid_local);
        });
        class
    }

}
<commit_msg>Add store::entry::RFileLockEntry<commit_after>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

#[allow(unused_variables)]
pub mod storeid {
    use std::path::PathBuf;

    use ruru::{Class, Object, AnyObject, Boolean, RString, NilClass};

    use libimagstore::storeid::StoreId;

    wrappable_struct!(StoreId, StoreIdWrapper, STOREID_WRAPPER);
    class!(RStoreId);

    methods!(
        RStoreId,
        itself,

        fn r_storeid_new(base: RString, id: RString) -> AnyObject {
            let base = match base.map(|b| b.to_string()).map(PathBuf::from) {
                Ok(base) => base,
                Err(e) => {
                    // TODO: Exception!
                    error!("Building StoreId object failed: {:?}", e);
                    return AnyObject::from(NilClass::new().value());
                },
            };

            let id = match id.map(|id| id.to_string()).map(PathBuf::from) {
                Ok(id) => id,
                Err(e) => {
                    // TODO: Exception!
                    error!("Building StoreId object failed: {:?}", e);
                    return AnyObject::from(NilClass::new().value());
                },
            };

            match StoreId::new(Some(base), id) {
                Ok(sid) => Class::from_existing("RStoreId").wrap_data(sid, &*STOREID_WRAPPER),
                Err(e) => {
                    // TODO: Exception!
                    error!("Building StoreId object failed: {:?}", e);
                    return AnyObject::from(NilClass::new().value());
                },
            }
        }

        fn r_storeid_new_baseless(id: RString) -> AnyObject {
            let id = match id.map(|id| id.to_string()).map(PathBuf::from) {
                Ok(id) => id,
                Err(e) => {
                    // TODO: Exception!
                    error!("Building StoreId object failed: {:?}", e);
                    return AnyObject::from(NilClass::new().value());
                },
            };

            match StoreId::new(None, id) {
                Ok(sid) => Class::from_existing("RStoreId").wrap_data(sid, &*STOREID_WRAPPER),
                Err(e) => {
                    // TODO: Exception!
                    error!("Building StoreId object failed: {:?}", e);
                    return AnyObject::from(NilClass::new().value());
                },
            }
        }

        fn r_storeid_without_base() -> RStoreId {
            let withoutbase : StoreId = itself.get_data(&*STOREID_WRAPPER).clone().without_base();
            Class::from_existing("RStoreId").wrap_data(withoutbase, &*STOREID_WRAPPER)
        }

        fn r_storeid_with_base(base: RString) -> AnyObject {
            let base : PathBuf = match base.map(|b| b.to_string()).map(PathBuf::from) {
                Ok(pb) => pb,
                Err(e) => {
                    // TODO: Exception!
                    error!("Error: {:?}", e);
                    return AnyObject::from(NilClass::new().value());
                },
            };
            let withoutbase : StoreId = itself.get_data(&*STOREID_WRAPPER).clone().with_base(base);
            Class::from_existing("RStoreId").wrap_data(withoutbase, &*STOREID_WRAPPER)
        }

        fn r_storeid_into_pathbuf() -> AnyObject {
            itself.get_data(&*STOREID_WRAPPER)
                .clone()
                .into_pathbuf()
                // TODO: No unwraps
                .map(|pb| pb.to_str().map(String::from).unwrap())
                .as_ref()
                .map(|s| AnyObject::from(RString::new(s).value()))
                // TODO: Exception!
                .unwrap_or(AnyObject::from(NilClass::new().value()))
        }

        fn r_storeid_exists() -> Boolean {
            Boolean::new(itself.get_data(&*STOREID_WRAPPER).exists())
        }

        fn r_storeid_to_str() -> AnyObject {
            itself.get_data(&*STOREID_WRAPPER)
                .to_str()
                .as_ref()
                .map(|s| AnyObject::from(RString::new(s).value()))
                // TODO: Exception!
                .unwrap_or(AnyObject::from(NilClass::new().value()))
        }

        fn r_storeid_local() -> RString {
            let local = itself.get_data(&*STOREID_WRAPPER).local();
            let local = local.to_str().unwrap(); // TODO: No unwraps
            RString::new(local)
        }

    );

    pub fn setup() -> Class {
        let mut class = Class::new("RStoreId", None);
        class.define(|itself| {
            itself.def_self("new"          , r_storeid_new);
            itself.def_self("new_baseless" , r_storeid_new_baseless);

            itself.def("without_base"      , r_storeid_without_base);
            itself.def("with_base"         , r_storeid_with_base);
            itself.def("into_pathbuf"      , r_storeid_into_pathbuf);
            itself.def("exists"            , r_storeid_exists);
            itself.def("to_str"            , r_storeid_to_str);
            itself.def("local"             , r_storeid_local);
        });
        class
    }

}

#[allow(unused_variables)]
pub mod store {
    pub mod entry {
        use std::collections::BTreeMap;
        use std::error::Error;
        use std::ops::Deref;
        use std::ops::DerefMut;

        use ruru::{Class, Object, Array, Hash, Fixnum, Float, Symbol, AnyObject, Boolean, RString, VM};

        use libimagstore::store::FileLockEntry as FLE;
        use libimagstore::store::EntryHeader;
        use libimagstore::store::EntryContent;
        use libimagstore::store::Entry;

        pub struct FLECustomWrapper(Box<FLE<'static>>);

        impl Deref for FLECustomWrapper {
            type Target = Box<FLE<'static>>;

            fn deref(&self) -> &Self::Target {
                &self.0
            }
        }

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

        wrappable_struct!(FLECustomWrapper, FileLockEntryWrapper, FLE_WRAPPER);
        class!(RFileLockEntry);

        wrappable_struct!(EntryHeader, EntryHeaderWrapper, ENTRY_HEADER_WRAPPER);
        class!(REntryHeader);
        methods!(
            REntryHeader,
            itself,

            fn r_entry_header_new() -> AnyObject {
                Class::from_existing("REntryHeader")
                    .wrap_data(EntryHeader::new(), &*ENTRY_HEADER_WRAPPER)
            }

            fn r_entry_header_insert(spec: RString, obj: AnyObject) -> Boolean {
                use toml::Value;
                use ruru::types::ValueType;

                fn do_insert(eh: &mut EntryHeader, spec: &str, v: Value) -> Boolean {
                    match eh.insert(spec, v) {
                        Ok(b) => Boolean::new(b),
                        Err(e) => {
                            VM::raise(Class::from_existing("RuntimeError"), e.description());
                            return Boolean::new(false);
                        }
                    }
                }

                fn to_value(obj: AnyObject) -> Result<Value, ()> {
                    match obj.value().ty() {
                        ValueType::Fixnum =>
                            Ok(Value::Integer(obj.try_convert_to::<Fixnum>().unwrap().to_i64())),

                        ValueType::Float =>
                            Ok(Value::Float(obj.try_convert_to::<Float>().unwrap().to_f64())),

                        ValueType::RString =>
                            Ok(Value::String(obj.try_convert_to::<RString>().unwrap().to_string())),

                        ValueType::Symbol =>
                            Ok(Value::String(obj.try_convert_to::<Symbol>().unwrap().to_string())),

                        _ => Err(()),
                    }
                }

                if let Err(ref error) = spec { // raise exception if "spec" is not a String
                    VM::raise(error.to_exception(), error.description());
                    return Boolean::new(false);
                }

                let spec = spec.unwrap().to_string(); // safe because of check above.
                let obj = obj.unwrap(); // possibly not safe... TODO
                match obj.value().ty() {
                    ValueType::Fixnum => {
                        let i = obj.try_convert_to::<Fixnum>().unwrap().to_i64();
                        do_insert(itself.get_data(&*ENTRY_HEADER_WRAPPER), &spec, Value::Integer(i))
                    }

                    ValueType::Float => {
                        let f = obj.try_convert_to::<Float>().unwrap().to_f64();
                        do_insert(itself.get_data(&*ENTRY_HEADER_WRAPPER), &spec, Value::Float(f))
                    }

                    ValueType::RString => {
                        let s = obj.try_convert_to::<RString>().unwrap().to_string();
                        do_insert(itself.get_data(&*ENTRY_HEADER_WRAPPER), &spec, Value::String(s))
                    }

                    ValueType::Symbol => {
                        let s = obj.try_convert_to::<Symbol>().unwrap().to_string();
                        do_insert(itself.get_data(&*ENTRY_HEADER_WRAPPER), &spec, Value::String(s))
                    }

                    ValueType::Array => {
                        let vals = obj.try_convert_to::<Array>()
                            .unwrap()
                            .into_iter()
                            .map(to_value)
                            .map(|el| {
                                let e_class = Class::from_existing("ArgumentError");
                                let err = "Arrays can only hold 'Fixnum', 'Float', 'String' or 'Symbol' in this API";
                                el.map_err(|_| VM::raise(e_class, err))
                            })
                            .filter_map(|e| e.ok())
                            .collect::<Vec<Value>>();

                        do_insert(itself.get_data(&*ENTRY_HEADER_WRAPPER), &spec, Value::Array(vals))
                    }

                    ValueType::Hash => {
                        let mut btm = BTreeMap::new();
                        obj.try_convert_to::<Hash>()
                            .unwrap()
                            .each(|key, value| {
                                let key = match key.value().ty() {
                                    ValueType::RString => obj.try_convert_to::<RString>().unwrap().to_string(),
                                    ValueType::Symbol  => obj.try_convert_to::<Symbol>().unwrap().to_string(),
                                    _ => {
                                        let e_class = Class::from_existing("ArgumentError");
                                        let err = "Hash must have 'String' or 'Symbol' as Key";
                                        VM::raise(e_class, err);
                                        return; // from closure
                                    }
                                };
                                let value = match to_value(value) {
                                    Err(e) => {
                                        let e_class = Class::from_existing("ArgumentError");
                                        let err = "Hash must have 'Fixnum', 'Float', 'String' or 'Symbol' as value in this API";
                                        VM::raise(e_class, err);
                                        return; // from closure
                                    }
                                    Ok(v) => v,
                                };

                                btm.insert(key, value);
                            });

                        do_insert(itself.get_data(&*ENTRY_HEADER_WRAPPER), &spec, Value::Table(btm))
                    }

                    ValueType::Nil => {
                        VM::raise(Class::from_existing("ArgumentError"), "Unexpected Argument 'nil'");
                        return Boolean::new(false);
                    }

                    _ => {
                        VM::raise(Class::from_existing("ArgumentError"), "Unexpected Argument Type");
                        return Boolean::new(false);
                    }
                }

            }

        );

        wrappable_struct!(EntryContent, EntryContentWrapper, ENTRY_CONTENT_WRAPPER);
        class!(REntryContent);

        wrappable_struct!(Entry, EntryWrapper, ENTRY_WRAPPER);
        class!(REntry);

        pub fn setup_filelockentry() -> Class {
            let mut class = Class::new("RFileLockEntry", None);
            class
        }

        pub fn setup_entryheader() -> Class {
            let mut class = Class::new("REntryHeader", None);
            class
        }

        pub fn setup_entrycontent() -> Class {
            let string = Class::from_existing("String");
            let mut class = Class::new("REntryContent", Some(&string));
            class
        }
    }

}

<|endoftext|>


<commit_before>use std::error::Error;
use std::clone::Clone;
use std::fmt::Error as FmtError;
use std::fmt::{Display, Formatter};

/// Enum of Error Types, as of now we have two:
/// * ConversionError: for Errors concerning conversion failures from task_hookrs::task::Task to
/// libimagtodo::task::Task. unused.
/// * StoreError: For Errors thrown by functions of the Store/structs relates to the Store
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum TodoErrorKind {
    ConversionError,
    StoreError,
}

/// Maps a TodoErrorKind to a String
fn todo_error_type_as_str(e: &TodoErrorKind) -> &'static str {
    match e {
        &TodoErrorKind::ConversionError     => "Conversion Error",
        &TodoErrorKind::StoreError          => "Store Error",
    }
}

impl Display for TodoErrorKind {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
        try!(write!(fmt, "{}", todo_error_type_as_str(self)));
        Ok(())
    }
}

/// Error struct for the imag-todo module
#[derive(Debug)]
pub struct TodoError {
    err_type : TodoErrorKind,
    cause : Option<Box<Error>>,
}

impl TodoError {
    /// Creates a new TodoError, with TodoErrorKind errtype and an optional cause
    pub fn new(errtype : TodoErrorKind, cause : Option<Box<Error>>) -> TodoError {
        TodoError {
            err_type : errtype,
            cause : cause,
        }
    }
    /// Returns the error type (TodoErrorKind)
    pub fn err_type(&self) -> TodoErrorKind {
        self.err_type.clone()
    }
}

impl Display for TodoError {
    fn fmt(&self, fmt : &mut Formatter) -> Result<(), FmtError> {
        try!(write!(fmt, "[{}]", todo_error_type_as_str(&self.err_type.clone())));
        Ok(())
    }
}

impl Error for TodoError {
    fn description(&self) -> &str {
        todo_error_type_as_str(&self.err_type.clone())
    }
    fn cause(&self) -> Option<&Error> {
        self.cause.as_ref().map(|e| &**e)
    }
}
<commit_msg>Rewrite error module<commit_after>generate_error_module!(
    generate_error_types!(TodoError, TodoErrorKind,
        ConversionError     => "Conversion Error",
        StoreError          => "Store Error",
        ImportError         => "Error importing"
    );
);

pub use self::error::TodoError;
pub use self::error::TodoErrorKind;
pub use self::error::MapErrInto;

<|endoftext|>


<commit_before>#![feature(collections)]
#![feature(io)]
#![feature(os)]
#![feature(path)]

extern crate document;

use std::cmp::min;
use std::old_io::{File,BufferedWriter,stdio};

use document::parser::Parser;

fn pretty_error(xml: &str, position: usize) -> &str {
    let s = &xml[position..];
    let l = s.chars().count();
    s.slice_chars(0, min(l, 15))
}

fn process_input<R>(input: R)
    where R: Reader
{
    let mut input = input;
    let data = match input.read_to_string() {
        Ok(x) => x,
        Err(x) => panic!("Can't read: {}", x),
    };

    let p = Parser::new();

    let package = match p.parse(&data) {
        Ok(d) => d,
        Err(point) => panic!("Unable to parse: {}", pretty_error(&data, point)),
    };

    let mut out = BufferedWriter::new(stdio::stdout_raw());

    {
        let d = package.as_document();
        document::writer::format_document(&d, &mut out).ok().expect("I can't output");
    }
}

#[allow(dead_code)]
fn main() {
    let mut args = std::os::args();

    let filename = args.remove(1);

    if filename == "-" {
        process_input(stdio::stdin_raw());
    } else {
        process_input(File::open(&Path::new(filename)))
    }
}
<commit_msg>Update for new command-line argument access<commit_after>#![feature(collections)]
#![feature(io)]
#![feature(os)]
#![feature(env)]
#![feature(path)]

extern crate document;

use std::env;
use std::cmp::min;
use std::old_io::{File,BufferedWriter,stdio};

use document::parser::Parser;

fn pretty_error(xml: &str, position: usize) -> &str {
    let s = &xml[position..];
    let l = s.chars().count();
    s.slice_chars(0, min(l, 15))
}

fn process_input<R>(input: R)
    where R: Reader
{
    let mut input = input;
    let data = match input.read_to_string() {
        Ok(x) => x,
        Err(x) => panic!("Can't read: {}", x),
    };

    let p = Parser::new();

    let package = match p.parse(&data) {
        Ok(d) => d,
        Err(point) => panic!("Unable to parse: {}", pretty_error(&data, point)),
    };

    let mut out = BufferedWriter::new(stdio::stdout_raw());

    {
        let d = package.as_document();
        document::writer::format_document(&d, &mut out).ok().expect("I can't output");
    }
}

#[allow(dead_code)]
fn main() {
    let args: Result<Vec<_>, _> = env::args().map(|a| a.into_string()).collect();
    let mut args = args.unwrap();

    let filename = args.remove(1);

    if filename == "-" {
        process_input(stdio::stdin_raw());
    } else {
        process_input(File::open(&Path::new(filename)))
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::io::{File, FileNotFound};
use std::str;

use parser::{Parser, Token};
use super::Context;

/// `Compiler` is a object that compiles a string into a `Vec<Token>`.
pub struct Compiler<T> {
    ctx: Context,
    reader: T,
    partials: HashMap<String, Vec<Token>>,
    otag: String,
    ctag: String,
}

impl<T: Iterator<char>> Compiler<T> {
    /// Construct a default compiler.
    pub fn new(ctx: Context, reader: T) -> Compiler<T> {
        Compiler {
            ctx: ctx,
            reader: reader,
            partials: HashMap::new(),
            otag: "{{".to_string(),
            ctag: "}}".to_string(),
        }
    }

    /// Construct a default compiler.
    pub fn new_with(
        ctx: Context,
        reader: T,
        partials: HashMap<String, Vec<Token>>,
        otag: String,
        ctag: String
    ) -> Compiler<T> {
        Compiler {
            ctx: ctx,
            reader: reader,
            partials: partials,
            otag: otag,
            ctag: ctag,
        }
    }

    /// Compiles a template into a series of tokens.
    pub fn compile(mut self) -> (Vec<Token>, HashMap<String, Vec<Token>>) {
        let (tokens, partials) = {
            let parser = Parser::new(&mut self.reader, self.otag.as_slice(), self.ctag.as_slice());
            parser.parse()
        };

        // Compile the partials if we haven't done so already.
        for name in partials.move_iter() {
            let path = self.ctx.template_path.join(name + "." + self.ctx.template_extension);

            if !self.partials.contains_key(&name) {
                // Insert a placeholder so we don't recurse off to infinity.
                self.partials.insert(name.to_string(), Vec::new());

                match File::open(&path).read_to_end() {
                    Ok(contents) => {
                        let string = match str::from_utf8(contents.as_slice()) {
                            Some(string) => string.to_string(),
                            None => { fail!("Failed to parse file as UTF-8"); }
                        };

                        let compiler = Compiler {
                            ctx: self.ctx.clone(),
                            reader: string.as_slice().chars(),
                            partials: self.partials.clone(),
                            otag: "{{".to_string(),
                            ctag: "}}".to_string(),
                        };

                        let (tokens, _) = compiler.compile();

                        self.partials.insert(name, tokens);
                    },
                    Err(e) => {
                        // Ignore missing files.
                        if e.kind == FileNotFound {
                            debug!("failed to read file {}", path.display());
                        } else {
                            fail!("error reading file: {}", e);
                        }
                    }
                }
            }
        }

        let Compiler { partials, .. } = self;

        (tokens, partials)
    }
}

#[cfg(test)]
mod tests {
    use parser::{Token, Text, ETag, UTag, Section, IncompleteSection, Partial};
    use super::Compiler;
    use super::super::Context;

    fn compile_str(template: &str) -> Vec<Token> {
        let ctx = Context::new(Path::new("."));
        let (tokens, _) = Compiler::new(ctx, template.chars()).compile();
        tokens
    }

    fn token_to_str(token: &Token) -> String {
        match *token {
            // recursive enums crash %?
            Section(ref name,
                    inverted,
                    ref children,
                    ref otag,
                    ref osection,
                    ref src,
                    ref tag,
                    ref ctag) => {
                let name = name.iter().map(|e| format!("{}", *e)).collect::<Vec<String>>();
                let children = children.iter().map(|x| token_to_str(x)).collect::<Vec<String>>();
                format!("Section(vec!({}), {}, vec!({}), {}, {}, {}, {}, {})",
                        name.connect(", "),
                        inverted,
                        children.connect(", "),
                        otag,
                        osection,
                        src,
                        tag,
                        ctag)
            }
            ETag(ref name, ref tag) => {
                let name = name.iter().map(|e| format!("{}", *e)).collect::<Vec<String>>();
                format!("ETag(vec!({}), {})", name.connect(", "), *tag)
            }
            UTag(ref name, ref tag) => {
                let name = name.iter().map(|e| format!("{}", *e)).collect::<Vec<String>>();
                format!("UTag(vec!({}), {})", name.connect(", "), *tag)
            }
            IncompleteSection(ref name, ref inverted, ref osection, ref newlined) => {
                let name = name.iter().map(|e| format!("{}", *e)).collect::<Vec<String>>();
                format!("IncompleteSection(vec!({}), {}, {}, {})",
                        name.connect(", "),
                        *inverted,
                        *osection,
                        *newlined)
            }
            _ => {
                format!("{}", token)
            }
        }
    }

    fn check_tokens(actual: Vec<Token>, expected: &[Token]) {
        // TODO: equality is currently broken for enums
        let actual: Vec<String> = actual.iter().map(token_to_str).collect();
        let expected = expected.iter().map(token_to_str).collect();

        assert_eq!(actual, expected);
    }

    #[test]
    fn test_compile_texts() {
        check_tokens(compile_str("hello world"), [
            Text("hello world".to_string())
        ]);
        check_tokens(compile_str("hello {world"), [
            Text("hello {world".to_string())
        ]);
        check_tokens(compile_str("hello world}"), [
            Text("hello world}".to_string())
        ]);
        check_tokens(compile_str("hello world}}"), [
            Text("hello world}}".to_string())
        ]);
    }

    #[test]
    fn test_compile_etags() {
        check_tokens(compile_str("{{ name }}"), [
            ETag(vec!("name".to_string()), "{{ name }}".to_string())
        ]);

        check_tokens(compile_str("before {{name}} after"), [
            Text("before ".to_string()),
            ETag(vec!("name".to_string()), "{{name}}".to_string()),
            Text(" after".to_string())
        ]);

        check_tokens(compile_str("before {{name}}"), [
            Text("before ".to_string()),
            ETag(vec!("name".to_string()), "{{name}}".to_string())
        ]);

        check_tokens(compile_str("{{name}} after"), [
            ETag(vec!("name".to_string()), "{{name}}".to_string()),
            Text(" after".to_string())
        ]);
    }

    #[test]
    fn test_compile_utags() {
        check_tokens(compile_str("{{{name}}}"), [
            UTag(vec!("name".to_string()), "{{{name}}}".to_string())
        ]);

        check_tokens(compile_str("before {{{name}}} after"), [
            Text("before ".to_string()),
            UTag(vec!("name".to_string()), "{{{name}}}".to_string()),
            Text(" after".to_string())
        ]);

        check_tokens(compile_str("before {{{name}}}"), [
            Text("before ".to_string()),
            UTag(vec!("name".to_string()), "{{{name}}}".to_string())
        ]);

        check_tokens(compile_str("{{{name}}} after"), [
            UTag(vec!("name".to_string()), "{{{name}}}".to_string()),
            Text(" after".to_string())
        ]);
    }

    #[test]
    fn test_compile_sections() {
        check_tokens(compile_str("{{# name}}{{/name}}"), [
            Section(
                vec!("name".to_string()),
                false,
                Vec::new(),
                "{{".to_string(),
                "{{# name}}".to_string(),
                "".to_string(),
                "{{/name}}".to_string(),
                "}}".to_string()
            )
        ]);

        check_tokens(compile_str("before {{^name}}{{/name}} after"), [
            Text("before ".to_string()),
            Section(
                vec!("name".to_string()),
                true,
                Vec::new(),
                "{{".to_string(),
                "{{^name}}".to_string(),
                "".to_string(),
                "{{/name}}".to_string(),
                "}}".to_string()
            ),
            Text(" after".to_string())
        ]);

        check_tokens(compile_str("before {{#name}}{{/name}}"), [
            Text("before ".to_string()),
            Section(
                vec!("name".to_string()),
                false,
                Vec::new(),
                "{{".to_string(),
                "{{#name}}".to_string(),
                "".to_string(),
                "{{/name}}".to_string(),
                "}}".to_string()
            )
        ]);

        check_tokens(compile_str("{{#name}}{{/name}} after"), [
            Section(
                vec!("name".to_string()),
                false,
                Vec::new(),
                "{{".to_string(),
                "{{#name}}".to_string(),
                "".to_string(),
                "{{/name}}".to_string(),
                "}}".to_string()
            ),
            Text(" after".to_string())
        ]);

        check_tokens(compile_str(
                "before {{#a}} 1 {{^b}} 2 {{/b}} {{/a}} after"), [
            Text("before ".to_string()),
            Section(
                vec!("a".to_string()),
                false,
                vec!(
                    Text(" 1 ".to_string()),
                    Section(
                        vec!("b".to_string()),
                        true,
                        vec!(Text(" 2 ".to_string())),
                        "{{".to_string(),
                        "{{^b}}".to_string(),
                        " 2 ".to_string(),
                        "{{/b}}".to_string(),
                        "}}".to_string()
                    ),
                    Text(" ".to_string())
                ),
                "{{".to_string(),
                "{{#a}}".to_string(),
                " 1 {{^b}} 2 {{/b}} ".to_string(),
                "{{/a}}".to_string(),
                "}}".to_string()
            ),
            Text(" after".to_string())
        ]);
    }

    #[test]
    fn test_compile_partials() {
        check_tokens(compile_str("{{> test}}"), [
            Partial("test".to_string(), "".to_string(), "{{> test}}".to_string())
        ]);

        check_tokens(compile_str("before {{>test}} after"), [
            Text("before ".to_string()),
            Partial("test".to_string(), "".to_string(), "{{>test}}".to_string()),
            Text(" after".to_string())
        ]);

        check_tokens(compile_str("before {{> test}}"), [
            Text("before ".to_string()),
            Partial("test".to_string(), "".to_string(), "{{> test}}".to_string())
        ]);

        check_tokens(compile_str("{{>test}} after"), [
            Partial("test".to_string(), "".to_string(), "{{>test}}".to_string()),
            Text(" after".to_string())
        ]);
    }

    #[test]
    fn test_compile_delimiters() {
        check_tokens(compile_str("before {{=<% %>=}}<%name%> after"), [
            Text("before ".to_string()),
            ETag(vec!("name".to_string()), "<%name%>".to_string()),
            Text(" after".to_string())
        ]);
    }
}
<commit_msg>Use into_iter instead of move_iter.<commit_after>use std::collections::HashMap;
use std::io::{File, FileNotFound};
use std::str;

use parser::{Parser, Token};
use super::Context;

/// `Compiler` is a object that compiles a string into a `Vec<Token>`.
pub struct Compiler<T> {
    ctx: Context,
    reader: T,
    partials: HashMap<String, Vec<Token>>,
    otag: String,
    ctag: String,
}

impl<T: Iterator<char>> Compiler<T> {
    /// Construct a default compiler.
    pub fn new(ctx: Context, reader: T) -> Compiler<T> {
        Compiler {
            ctx: ctx,
            reader: reader,
            partials: HashMap::new(),
            otag: "{{".to_string(),
            ctag: "}}".to_string(),
        }
    }

    /// Construct a default compiler.
    pub fn new_with(
        ctx: Context,
        reader: T,
        partials: HashMap<String, Vec<Token>>,
        otag: String,
        ctag: String
    ) -> Compiler<T> {
        Compiler {
            ctx: ctx,
            reader: reader,
            partials: partials,
            otag: otag,
            ctag: ctag,
        }
    }

    /// Compiles a template into a series of tokens.
    pub fn compile(mut self) -> (Vec<Token>, HashMap<String, Vec<Token>>) {
        let (tokens, partials) = {
            let parser = Parser::new(&mut self.reader, self.otag.as_slice(), self.ctag.as_slice());
            parser.parse()
        };

        // Compile the partials if we haven't done so already.
        for name in partials.into_iter() {
            let path = self.ctx.template_path.join(name + "." + self.ctx.template_extension);

            if !self.partials.contains_key(&name) {
                // Insert a placeholder so we don't recurse off to infinity.
                self.partials.insert(name.to_string(), Vec::new());

                match File::open(&path).read_to_end() {
                    Ok(contents) => {
                        let string = match str::from_utf8(contents.as_slice()) {
                            Some(string) => string.to_string(),
                            None => { fail!("Failed to parse file as UTF-8"); }
                        };

                        let compiler = Compiler {
                            ctx: self.ctx.clone(),
                            reader: string.as_slice().chars(),
                            partials: self.partials.clone(),
                            otag: "{{".to_string(),
                            ctag: "}}".to_string(),
                        };

                        let (tokens, _) = compiler.compile();

                        self.partials.insert(name, tokens);
                    },
                    Err(e) => {
                        // Ignore missing files.
                        if e.kind == FileNotFound {
                            debug!("failed to read file {}", path.display());
                        } else {
                            fail!("error reading file: {}", e);
                        }
                    }
                }
            }
        }

        let Compiler { partials, .. } = self;

        (tokens, partials)
    }
}

#[cfg(test)]
mod tests {
    use parser::{Token, Text, ETag, UTag, Section, IncompleteSection, Partial};
    use super::Compiler;
    use super::super::Context;

    fn compile_str(template: &str) -> Vec<Token> {
        let ctx = Context::new(Path::new("."));
        let (tokens, _) = Compiler::new(ctx, template.chars()).compile();
        tokens
    }

    fn token_to_str(token: &Token) -> String {
        match *token {
            // recursive enums crash %?
            Section(ref name,
                    inverted,
                    ref children,
                    ref otag,
                    ref osection,
                    ref src,
                    ref tag,
                    ref ctag) => {
                let name = name.iter().map(|e| format!("{}", *e)).collect::<Vec<String>>();
                let children = children.iter().map(|x| token_to_str(x)).collect::<Vec<String>>();
                format!("Section(vec!({}), {}, vec!({}), {}, {}, {}, {}, {})",
                        name.connect(", "),
                        inverted,
                        children.connect(", "),
                        otag,
                        osection,
                        src,
                        tag,
                        ctag)
            }
            ETag(ref name, ref tag) => {
                let name = name.iter().map(|e| format!("{}", *e)).collect::<Vec<String>>();
                format!("ETag(vec!({}), {})", name.connect(", "), *tag)
            }
            UTag(ref name, ref tag) => {
                let name = name.iter().map(|e| format!("{}", *e)).collect::<Vec<String>>();
                format!("UTag(vec!({}), {})", name.connect(", "), *tag)
            }
            IncompleteSection(ref name, ref inverted, ref osection, ref newlined) => {
                let name = name.iter().map(|e| format!("{}", *e)).collect::<Vec<String>>();
                format!("IncompleteSection(vec!({}), {}, {}, {})",
                        name.connect(", "),
                        *inverted,
                        *osection,
                        *newlined)
            }
            _ => {
                format!("{}", token)
            }
        }
    }

    fn check_tokens(actual: Vec<Token>, expected: &[Token]) {
        // TODO: equality is currently broken for enums
        let actual: Vec<String> = actual.iter().map(token_to_str).collect();
        let expected = expected.iter().map(token_to_str).collect();

        assert_eq!(actual, expected);
    }

    #[test]
    fn test_compile_texts() {
        check_tokens(compile_str("hello world"), [
            Text("hello world".to_string())
        ]);
        check_tokens(compile_str("hello {world"), [
            Text("hello {world".to_string())
        ]);
        check_tokens(compile_str("hello world}"), [
            Text("hello world}".to_string())
        ]);
        check_tokens(compile_str("hello world}}"), [
            Text("hello world}}".to_string())
        ]);
    }

    #[test]
    fn test_compile_etags() {
        check_tokens(compile_str("{{ name }}"), [
            ETag(vec!("name".to_string()), "{{ name }}".to_string())
        ]);

        check_tokens(compile_str("before {{name}} after"), [
            Text("before ".to_string()),
            ETag(vec!("name".to_string()), "{{name}}".to_string()),
            Text(" after".to_string())
        ]);

        check_tokens(compile_str("before {{name}}"), [
            Text("before ".to_string()),
            ETag(vec!("name".to_string()), "{{name}}".to_string())
        ]);

        check_tokens(compile_str("{{name}} after"), [
            ETag(vec!("name".to_string()), "{{name}}".to_string()),
            Text(" after".to_string())
        ]);
    }

    #[test]
    fn test_compile_utags() {
        check_tokens(compile_str("{{{name}}}"), [
            UTag(vec!("name".to_string()), "{{{name}}}".to_string())
        ]);

        check_tokens(compile_str("before {{{name}}} after"), [
            Text("before ".to_string()),
            UTag(vec!("name".to_string()), "{{{name}}}".to_string()),
            Text(" after".to_string())
        ]);

        check_tokens(compile_str("before {{{name}}}"), [
            Text("before ".to_string()),
            UTag(vec!("name".to_string()), "{{{name}}}".to_string())
        ]);

        check_tokens(compile_str("{{{name}}} after"), [
            UTag(vec!("name".to_string()), "{{{name}}}".to_string()),
            Text(" after".to_string())
        ]);
    }

    #[test]
    fn test_compile_sections() {
        check_tokens(compile_str("{{# name}}{{/name}}"), [
            Section(
                vec!("name".to_string()),
                false,
                Vec::new(),
                "{{".to_string(),
                "{{# name}}".to_string(),
                "".to_string(),
                "{{/name}}".to_string(),
                "}}".to_string()
            )
        ]);

        check_tokens(compile_str("before {{^name}}{{/name}} after"), [
            Text("before ".to_string()),
            Section(
                vec!("name".to_string()),
                true,
                Vec::new(),
                "{{".to_string(),
                "{{^name}}".to_string(),
                "".to_string(),
                "{{/name}}".to_string(),
                "}}".to_string()
            ),
            Text(" after".to_string())
        ]);

        check_tokens(compile_str("before {{#name}}{{/name}}"), [
            Text("before ".to_string()),
            Section(
                vec!("name".to_string()),
                false,
                Vec::new(),
                "{{".to_string(),
                "{{#name}}".to_string(),
                "".to_string(),
                "{{/name}}".to_string(),
                "}}".to_string()
            )
        ]);

        check_tokens(compile_str("{{#name}}{{/name}} after"), [
            Section(
                vec!("name".to_string()),
                false,
                Vec::new(),
                "{{".to_string(),
                "{{#name}}".to_string(),
                "".to_string(),
                "{{/name}}".to_string(),
                "}}".to_string()
            ),
            Text(" after".to_string())
        ]);

        check_tokens(compile_str(
                "before {{#a}} 1 {{^b}} 2 {{/b}} {{/a}} after"), [
            Text("before ".to_string()),
            Section(
                vec!("a".to_string()),
                false,
                vec!(
                    Text(" 1 ".to_string()),
                    Section(
                        vec!("b".to_string()),
                        true,
                        vec!(Text(" 2 ".to_string())),
                        "{{".to_string(),
                        "{{^b}}".to_string(),
                        " 2 ".to_string(),
                        "{{/b}}".to_string(),
                        "}}".to_string()
                    ),
                    Text(" ".to_string())
                ),
                "{{".to_string(),
                "{{#a}}".to_string(),
                " 1 {{^b}} 2 {{/b}} ".to_string(),
                "{{/a}}".to_string(),
                "}}".to_string()
            ),
            Text(" after".to_string())
        ]);
    }

    #[test]
    fn test_compile_partials() {
        check_tokens(compile_str("{{> test}}"), [
            Partial("test".to_string(), "".to_string(), "{{> test}}".to_string())
        ]);

        check_tokens(compile_str("before {{>test}} after"), [
            Text("before ".to_string()),
            Partial("test".to_string(), "".to_string(), "{{>test}}".to_string()),
            Text(" after".to_string())
        ]);

        check_tokens(compile_str("before {{> test}}"), [
            Text("before ".to_string()),
            Partial("test".to_string(), "".to_string(), "{{> test}}".to_string())
        ]);

        check_tokens(compile_str("{{>test}} after"), [
            Partial("test".to_string(), "".to_string(), "{{>test}}".to_string()),
            Text(" after".to_string())
        ]);
    }

    #[test]
    fn test_compile_delimiters() {
        check_tokens(compile_str("before {{=<% %>=}}<%name%> after"), [
            Text("before ".to_string()),
            ETag(vec!("name".to_string()), "<%name%>".to_string()),
            Text(" after".to_string())
        ]);
    }
}
<|endoftext|>


<commit_before>//! Compound data types.

#![allow(non_snake_case)]

use std::collections::HashMap;
use std::mem;

use Result;
use band::{Band, Value};
use primitive::*;

macro_rules! itemize(
    ($code:item) => ($code);
);

macro_rules! compound(
    ($structure:ident { $($field:ident ($($kind:tt)+) $(|$this:ident| $body:block)*,)+ }) => (
        declare!($structure { $($field $($kind)+,)+ });
        implement!($structure { $($field ($($kind)+) $(|$this| $body)*,)+ });
    );
);

macro_rules! declare(
    ($structure:ident { $($field:ident $kind:ty,)+ }) => (
        itemize! {
            #[derive(Debug, Default)]
            pub struct $structure { $(pub $field: $kind,)+ }
        }
    );
);

macro_rules! implement(
    ($structure:ident { $($field:ident ($($kind:tt)+) $(|$this:ident| $body:block)*,)+ }) => (
        impl Value for $structure {
            fn read<T: Band>(band: &mut T) -> Result<Self> {
                let mut value = $structure::default();
                $(value.$field = read!($structure, value, band, [$($kind)+] $(|$this| $body)*);)+
                Ok(value)
            }
        }
    );
);

macro_rules! read(
    ($structure:ident, $this:ident, $band:ident, [$kind:ty] |$that:ident| $body:block) => ({
        #[inline(always)]
        fn count($that: &$structure) -> Result<usize> $body
        let count = try!(count(&$this));
        let mut values = Vec::with_capacity(count);
        for _ in 0..count {
            values.push(try!(Value::read($band)));
        }
        values
    });
    ($structure:ident, $this:ident, $band:ident, [$kind:ty]) => ({
        try!(Value::read($band))
    });
);

compound!(OffsetTable {
    version       (Fixed ),
    numTables     (USHORT),
    searchRange   (USHORT),
    entrySelector (USHORT),
    rangeShift    (USHORT),
});

compound!(TableRecord {
    tag      (ULONG),
    checkSum (ULONG),
    offset   (ULONG),
    length   (ULONG),
});

compound!(CharMappingHeader {
    version   (USHORT),
    numTables (USHORT),
});

compound!(EncodingRecord {
    platformID (USHORT),
    encodingID (USHORT),
    offset     (ULONG ),
});

pub enum CharMapping {
    Format4(CharMappingFormat4),
    Format6(CharMappingFormat6),
}

compound!(CharMappingFormat4 {
    format        (USHORT     ),
    length        (USHORT     ),
    language      (USHORT     ),
    segCountX2    (USHORT     ),
    searchRange   (USHORT     ),
    entrySelector (USHORT     ),
    rangeShift    (USHORT     ),
    endCode       (Vec<USHORT>) |this| { Ok(this.segments()) },
    reservedPad   (USHORT     ),
    startCode     (Vec<USHORT>) |this| { Ok(this.segments()) },
    idDelta       (Vec<SHORT> ) |this| { Ok(this.segments()) },
    idRangeOffset (Vec<USHORT>) |this| { Ok(this.segments()) },
    glyphIdArray  (Vec<USHORT>) |this| { this.payload() },
});

compound!(CharMappingFormat6 {
    format       (USHORT     ),
    length       (USHORT     ),
    language     (USHORT     ),
    firstCode    (USHORT     ),
    entryCount   (USHORT     ),
    glyphIdArray (Vec<USHORT>) |this| { Ok(this.entryCount as usize) },
});

compound!(FontHeader {
    version            (Fixed       ),
    fontRevision       (Fixed       ),
    checkSumAdjustment (ULONG       ),
    magicNumber        (ULONG       ),
    flags              (USHORT      ),
    unitsPerEm         (USHORT      ),
    created            (LONGDATETIME),
    modified           (LONGDATETIME),
    xMin               (SHORT       ),
    yMin               (SHORT       ),
    xMax               (SHORT       ),
    yMax               (SHORT       ),
    macStyle           (USHORT      ),
    lowestRecPPEM      (USHORT      ),
    fontDirectionHint  (SHORT       ),
    indexToLocFormat   (SHORT       ),
    glyphDataFormat    (SHORT       ),
});

pub enum MaxProfile {
    Version05(MaxProfileVersion05),
    Version10(MaxProfileVersion10),
}

compound!(MaxProfileVersion05 {
    version   (Fixed ),
    numGlyphs (USHORT),
});

compound!(MaxProfileVersion10 {
    version               (Fixed ),
    numGlyphs             (USHORT),
    maxPoints             (USHORT),
    maxContours           (USHORT),
    maxCompositePoints    (USHORT),
    maxCompositeContours  (USHORT),
    maxZones              (USHORT),
    maxTwilightPoints     (USHORT),
    maxStorage            (USHORT),
    maxFunctionDefs       (USHORT),
    maxInstructionDefs    (USHORT),
    maxStackElements      (USHORT),
    maxSizeOfInstructions (USHORT),
    maxComponentElements  (USHORT),
    maxComponentDepth     (USHORT),
});

impl TableRecord {
    #[doc(hidden)]
    pub fn check<T, F>(&self, band: &mut T, process: F) -> Result<bool>
        where T: Band, F: Fn(usize, ULONG) -> ULONG
    {
        let length = {
            let size = mem::size_of::<ULONG>();
            ((self.length as usize + size - 1) & !(size - 1)) / size
        };
        band.stay(|band| {
            try!(band.jump(self.offset as u64));
            let mut checksum: u64 = 0;
            for i in 0..length {
                checksum += process(i, try!(Value::read(band))) as u64;
            }
            Ok(self.checkSum == checksum as u32)
        })
    }
}

impl CharMappingFormat4 {
    pub fn mapping(&self) -> HashMap<USHORT, USHORT> {
        let segments = self.segments();

        let mut map = HashMap::new();
        for i in 0..(segments - 1) {
            let startCode = self.startCode[i];
            let idDelta = self.idDelta[i];
            let idRangeOffset = self.idRangeOffset[i];
            for j in startCode..(self.endCode[i] + 1) {
                let index = if idRangeOffset > 0 {
                    let offset = (idRangeOffset / 2 + (j - startCode)) - (segments - i) as USHORT;
                    self.glyphIdArray[offset as usize]
                } else {
                    (idDelta + j as SHORT) as USHORT
                };
                map.insert(j, index);
            }
        }

        map
    }

    fn payload(&self) -> Result<usize> {
        let segments = self.segments();

        if segments == 0 {
            raise!("a character-to-glyph mapping has no segments");
        }
        if self.startCode[segments - 1] != 0xFFFF || self.endCode[segments - 1] != 0xFFFF {
            raise!("a character-to-glyph mapping is malformed");
        }

        let mut count = 0;
        for i in 0..(segments - 1) {
            let startCode = self.startCode[i];
            let idRangeOffset = self.idRangeOffset[i];
            for j in startCode..(self.endCode[i] + 1) {
                if idRangeOffset > 0 {
                    let offset = (idRangeOffset / 2 + (j - startCode)) - (segments - i) as USHORT;
                    if offset >= count {
                        count = offset + 1;
                    }
                }
            }
        }

        Ok(count as usize)
    }

    #[inline]
    fn segments(&self) -> usize {
        self.segCountX2 as usize / 2
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn table_record_check() {
        use compound::TableRecord;
        use std::io::Cursor;

        macro_rules! check(
            ($length:expr, $checksum:expr, $data:expr) => ({
                let data: &[u8] = $data;
                let mut reader = Cursor::new(data);
                let table = TableRecord {
                    length: $length,
                    checkSum: $checksum,
                    .. TableRecord::default()
                };
                table.check(&mut reader, |_, chunk| chunk).unwrap()
            })
        );

        assert!(!check!(3 * 4, 1 + 2 + 4, &[0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3]));
        assert!( check!(3 * 4, 1 + 2 + 3, &[0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3]));
    }
}
<commit_msg>Get rid of Version and Fromat from type names<commit_after>//! Compound data types.

#![allow(non_snake_case)]

use std::collections::HashMap;
use std::mem;

use Result;
use band::{Band, Value};
use primitive::*;

macro_rules! itemize(
    ($code:item) => ($code);
);

macro_rules! compound(
    ($structure:ident { $($field:ident ($($kind:tt)+) $(|$this:ident| $body:block)*,)+ }) => (
        declare!($structure { $($field $($kind)+,)+ });
        implement!($structure { $($field ($($kind)+) $(|$this| $body)*,)+ });
    );
);

macro_rules! declare(
    ($structure:ident { $($field:ident $kind:ty,)+ }) => (
        itemize! {
            #[derive(Debug, Default)]
            pub struct $structure { $(pub $field: $kind,)+ }
        }
    );
);

macro_rules! implement(
    ($structure:ident { $($field:ident ($($kind:tt)+) $(|$this:ident| $body:block)*,)+ }) => (
        impl Value for $structure {
            fn read<T: Band>(band: &mut T) -> Result<Self> {
                let mut value = $structure::default();
                $(value.$field = read!($structure, value, band, [$($kind)+] $(|$this| $body)*);)+
                Ok(value)
            }
        }
    );
);

macro_rules! read(
    ($structure:ident, $this:ident, $band:ident, [$kind:ty] |$that:ident| $body:block) => ({
        #[inline(always)]
        fn count($that: &$structure) -> Result<usize> $body
        let count = try!(count(&$this));
        let mut values = Vec::with_capacity(count);
        for _ in 0..count {
            values.push(try!(Value::read($band)));
        }
        values
    });
    ($structure:ident, $this:ident, $band:ident, [$kind:ty]) => ({
        try!(Value::read($band))
    });
);

compound!(OffsetTable {
    version       (Fixed ),
    numTables     (USHORT),
    searchRange   (USHORT),
    entrySelector (USHORT),
    rangeShift    (USHORT),
});

compound!(TableRecord {
    tag      (ULONG),
    checkSum (ULONG),
    offset   (ULONG),
    length   (ULONG),
});

compound!(CharMappingHeader {
    version   (USHORT),
    numTables (USHORT),
});

compound!(EncodingRecord {
    platformID (USHORT),
    encodingID (USHORT),
    offset     (ULONG ),
});

pub enum CharMapping {
    Format4(CharMapping4),
    Format6(CharMapping6),
}

compound!(CharMapping4 {
    format        (USHORT     ),
    length        (USHORT     ),
    language      (USHORT     ),
    segCountX2    (USHORT     ),
    searchRange   (USHORT     ),
    entrySelector (USHORT     ),
    rangeShift    (USHORT     ),
    endCode       (Vec<USHORT>) |this| { Ok(this.segments()) },
    reservedPad   (USHORT     ),
    startCode     (Vec<USHORT>) |this| { Ok(this.segments()) },
    idDelta       (Vec<SHORT> ) |this| { Ok(this.segments()) },
    idRangeOffset (Vec<USHORT>) |this| { Ok(this.segments()) },
    glyphIdArray  (Vec<USHORT>) |this| { this.payload() },
});

compound!(CharMapping6 {
    format       (USHORT     ),
    length       (USHORT     ),
    language     (USHORT     ),
    firstCode    (USHORT     ),
    entryCount   (USHORT     ),
    glyphIdArray (Vec<USHORT>) |this| { Ok(this.entryCount as usize) },
});

compound!(FontHeader {
    version            (Fixed       ),
    fontRevision       (Fixed       ),
    checkSumAdjustment (ULONG       ),
    magicNumber        (ULONG       ),
    flags              (USHORT      ),
    unitsPerEm         (USHORT      ),
    created            (LONGDATETIME),
    modified           (LONGDATETIME),
    xMin               (SHORT       ),
    yMin               (SHORT       ),
    xMax               (SHORT       ),
    yMax               (SHORT       ),
    macStyle           (USHORT      ),
    lowestRecPPEM      (USHORT      ),
    fontDirectionHint  (SHORT       ),
    indexToLocFormat   (SHORT       ),
    glyphDataFormat    (SHORT       ),
});

pub enum MaxProfile {
    Version05(MaxProfile05),
    Version10(MaxProfile10),
}

compound!(MaxProfile05 {
    version   (Fixed ),
    numGlyphs (USHORT),
});

compound!(MaxProfile10 {
    version               (Fixed ),
    numGlyphs             (USHORT),
    maxPoints             (USHORT),
    maxContours           (USHORT),
    maxCompositePoints    (USHORT),
    maxCompositeContours  (USHORT),
    maxZones              (USHORT),
    maxTwilightPoints     (USHORT),
    maxStorage            (USHORT),
    maxFunctionDefs       (USHORT),
    maxInstructionDefs    (USHORT),
    maxStackElements      (USHORT),
    maxSizeOfInstructions (USHORT),
    maxComponentElements  (USHORT),
    maxComponentDepth     (USHORT),
});

impl TableRecord {
    #[doc(hidden)]
    pub fn check<T, F>(&self, band: &mut T, process: F) -> Result<bool>
        where T: Band, F: Fn(usize, ULONG) -> ULONG
    {
        let length = {
            let size = mem::size_of::<ULONG>();
            ((self.length as usize + size - 1) & !(size - 1)) / size
        };
        band.stay(|band| {
            try!(band.jump(self.offset as u64));
            let mut checksum: u64 = 0;
            for i in 0..length {
                checksum += process(i, try!(Value::read(band))) as u64;
            }
            Ok(self.checkSum == checksum as u32)
        })
    }
}

impl CharMapping4 {
    pub fn mapping(&self) -> HashMap<USHORT, USHORT> {
        let segments = self.segments();

        let mut map = HashMap::new();
        for i in 0..(segments - 1) {
            let startCode = self.startCode[i];
            let idDelta = self.idDelta[i];
            let idRangeOffset = self.idRangeOffset[i];
            for j in startCode..(self.endCode[i] + 1) {
                let index = if idRangeOffset > 0 {
                    let offset = (idRangeOffset / 2 + (j - startCode)) - (segments - i) as USHORT;
                    self.glyphIdArray[offset as usize]
                } else {
                    (idDelta + j as SHORT) as USHORT
                };
                map.insert(j, index);
            }
        }

        map
    }

    fn payload(&self) -> Result<usize> {
        let segments = self.segments();

        if segments == 0 {
            raise!("a character-to-glyph mapping has no segments");
        }
        if self.startCode[segments - 1] != 0xFFFF || self.endCode[segments - 1] != 0xFFFF {
            raise!("a character-to-glyph mapping is malformed");
        }

        let mut count = 0;
        for i in 0..(segments - 1) {
            let startCode = self.startCode[i];
            let idRangeOffset = self.idRangeOffset[i];
            for j in startCode..(self.endCode[i] + 1) {
                if idRangeOffset > 0 {
                    let offset = (idRangeOffset / 2 + (j - startCode)) - (segments - i) as USHORT;
                    if offset >= count {
                        count = offset + 1;
                    }
                }
            }
        }

        Ok(count as usize)
    }

    #[inline]
    fn segments(&self) -> usize {
        self.segCountX2 as usize / 2
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn table_record_check() {
        use compound::TableRecord;
        use std::io::Cursor;

        macro_rules! check(
            ($length:expr, $checksum:expr, $data:expr) => ({
                let data: &[u8] = $data;
                let mut reader = Cursor::new(data);
                let table = TableRecord {
                    length: $length,
                    checkSum: $checksum,
                    .. TableRecord::default()
                };
                table.check(&mut reader, |_, chunk| chunk).unwrap()
            })
        );

        assert!(!check!(3 * 4, 1 + 2 + 4, &[0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3]));
        assert!( check!(3 * 4, 1 + 2 + 3, &[0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3]));
    }
}
<|endoftext|>


<commit_before>use std::borrow::Cow;

use rustc::mir::interpret::{
    read_target_uint, AllocId, AllocKind, Allocation, ConstValue, EvalResult, GlobalId, Scalar,
};
use rustc::ty::{Const, LazyConst};
use rustc_mir::interpret::{
    EvalContext, MPlaceTy, Machine, Memory, MemoryKind, OpTy, PlaceTy, Pointer, StackPopCleanup,
};

use cranelift_module::*;

use crate::prelude::*;

#[derive(Default)]
pub struct ConstantCx {
    todo: HashSet<TodoItem>,
    done: HashSet<DataId>,
}

#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
enum TodoItem {
    Alloc(AllocId),
    Static(DefId),
}

impl ConstantCx {
    pub fn finalize<'a, 'tcx: 'a, B: Backend>(
        mut self,
        tcx: TyCtxt<'a, 'tcx, 'tcx>,
        module: &mut Module<B>,
    ) {
        //println!("todo {:?}", self.todo);
        define_all_allocs(tcx, module, &mut self);
        //println!("done {:?}", self.done);
        self.done.clear();
    }
}

pub fn codegen_static<'a, 'tcx: 'a>(ccx: &mut ConstantCx, def_id: DefId) {
    ccx.todo.insert(TodoItem::Static(def_id));
}

pub fn codegen_static_ref<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    static_: &Static<'tcx>,
) -> CPlace<'tcx> {
    let data_id = data_id_for_static(fx.tcx, fx.module, static_.def_id, Linkage::Import);
    cplace_for_dataid(fx, static_.ty, data_id)
}

pub fn trans_promoted<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    promoted: Promoted,
) -> CPlace<'tcx> {
    let const_ = fx
        .tcx
        .const_eval(ParamEnv::reveal_all().and(GlobalId {
            instance: fx.instance,
            promoted: Some(promoted),
        }))
        .unwrap();

    trans_const_place(fx, const_)
}

pub fn trans_constant<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    constant: &Constant<'tcx>,
) -> CValue<'tcx> {
    let const_ = fx.monomorphize(&constant.literal);
    let const_ = force_eval_const(fx, const_);
    trans_const_value(fx, const_)
}

pub fn force_eval_const<'a, 'tcx: 'a>(
    fx: &FunctionCx<'a, 'tcx, impl Backend>,
    const_: &'tcx LazyConst<'tcx>,
) -> Const<'tcx> {
    match *const_ {
        LazyConst::Unevaluated(def_id, ref substs) => {
            let param_env = ParamEnv::reveal_all();
            let instance = Instance::resolve(fx.tcx, param_env, def_id, substs).unwrap();
            let cid = GlobalId {
                instance,
                promoted: None,
            };
            fx.tcx.const_eval(param_env.and(cid)).unwrap()
        }
        LazyConst::Evaluated(const_) => const_,
    }
}

fn trans_const_value<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    const_: Const<'tcx>,
) -> CValue<'tcx> {
    let ty = fx.monomorphize(&const_.ty);
    let layout = fx.layout_of(ty);
    match ty.sty {
        ty::Bool => {
            let bits = const_.val.try_to_bits(layout.size).unwrap();
            CValue::const_val(fx, ty, bits as u64 as i64)
        }
        ty::Uint(_) => {
            let bits = const_.val.try_to_bits(layout.size).unwrap();
            CValue::const_val(fx, ty, bits as u64 as i64)
        }
        ty::Int(_) => {
            let bits = const_.val.try_to_bits(layout.size).unwrap();
            CValue::const_val(fx, ty, bits as i128 as i64)
        }
        ty::FnDef(def_id, substs) => {
            let func_ref = fx.get_function_ref(
                Instance::resolve(fx.tcx, ParamEnv::reveal_all(), def_id, substs).unwrap(),
            );
            let func_addr = fx.bcx.ins().func_addr(fx.pointer_type, func_ref);
            CValue::ByVal(func_addr, layout)
        }
        _ => trans_const_place(fx, const_).to_cvalue(fx),
    }
}

fn trans_const_place<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    const_: Const<'tcx>,
) -> CPlace<'tcx> {
    // Adapted from https://github.com/rust-lang/rust/pull/53671/files#diff-e0b58bb6712edaa8595ad7237542c958L551
    let result = || -> EvalResult<'tcx, &'tcx Allocation> {
        let mut ecx = EvalContext::new(
            fx.tcx.at(DUMMY_SP),
            ty::ParamEnv::reveal_all(),
            TransPlaceInterpreter,
        );
        ecx.push_stack_frame(
            fx.instance,
            DUMMY_SP,
            fx.mir,
            None,
            StackPopCleanup::None { cleanup: false },
        )
        .unwrap();
        let op = ecx.eval_operand(
            &Operand::Constant(Box::new(Constant {
                span: DUMMY_SP,
                ty: const_.ty,
                user_ty: None,
                literal: fx.tcx.intern_lazy_const(LazyConst::Evaluated(const_)),
            })),
            None,
        )?;
        let ptr = ecx.allocate(op.layout, MemoryKind::Stack);
        ecx.copy_op(op, ptr.into())?;
        let alloc = ecx.memory().get(ptr.to_ptr()?.alloc_id)?;
        Ok(fx.tcx.intern_const_alloc(alloc.clone()))
    };
    let alloc = result().expect("unable to convert ConstValue to Allocation");

    //println!("const value: {:?} allocation: {:?}", value, alloc);
    let alloc_id = fx.tcx.alloc_map.lock().allocate(alloc);
    fx.constants.todo.insert(TodoItem::Alloc(alloc_id));
    let data_id = data_id_for_alloc_id(fx.module, alloc_id);
    cplace_for_dataid(fx, const_.ty, data_id)
}

fn data_id_for_alloc_id<B: Backend>(module: &mut Module<B>, alloc_id: AllocId) -> DataId {
    module
        .declare_data(&format!("__alloc_{}", alloc_id.0), Linkage::Local, false)
        .unwrap()
}

fn data_id_for_static<'a, 'tcx: 'a, B: Backend>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    module: &mut Module<B>,
    def_id: DefId,
    linkage: Linkage,
) -> DataId {
    let symbol_name = tcx.symbol_name(Instance::mono(tcx, def_id)).as_str();
    let is_mutable = if let ::rustc::hir::Mutability::MutMutable = tcx.is_static(def_id).unwrap() {
        true
    } else {
        !tcx.type_of(def_id)
            .is_freeze(tcx, ParamEnv::reveal_all(), DUMMY_SP)
    };
    module
        .declare_data(&*symbol_name, linkage, is_mutable)
        .unwrap()
}

fn cplace_for_dataid<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    ty: Ty<'tcx>,
    data_id: DataId,
) -> CPlace<'tcx> {
    let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
    let global_ptr = fx.bcx.ins().global_value(fx.pointer_type, local_data_id);
    let layout = fx.layout_of(fx.monomorphize(&ty));
    assert!(!layout.is_unsized(), "unsized statics aren't supported");
    CPlace::Addr(global_ptr, None, layout)
}

fn define_all_allocs<'a, 'tcx: 'a, B: Backend + 'a>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    module: &mut Module<B>,
    cx: &mut ConstantCx,
) {
    let memory = Memory::<TransPlaceInterpreter>::new(tcx.at(DUMMY_SP));

    while let Some(todo_item) = pop_set(&mut cx.todo) {
        let (data_id, alloc) = match todo_item {
            TodoItem::Alloc(alloc_id) => {
                //println!("alloc_id {}", alloc_id);
                let data_id = data_id_for_alloc_id(module, alloc_id);
                let alloc = memory.get(alloc_id).unwrap();
                (data_id, alloc)
            }
            TodoItem::Static(def_id) => {
                //println!("static {:?}", def_id);
                let instance = ty::Instance::mono(tcx, def_id);
                let cid = GlobalId {
                    instance,
                    promoted: None,
                };
                let const_ = tcx.const_eval(ParamEnv::reveal_all().and(cid)).unwrap();

                let alloc = match const_.val {
                    ConstValue::ByRef(_alloc_id, alloc, n) if n.bytes() == 0 => alloc,
                    _ => bug!("static const eval returned {:#?}", const_),
                };

                let data_id = data_id_for_static(tcx, module, def_id, Linkage::Export);
                (data_id, alloc)
            }
        };

        //("data_id {}", data_id);
        if cx.done.contains(&data_id) {
            continue;
        }

        let mut data_ctx = DataContext::new();

        data_ctx.define(alloc.bytes.to_vec().into_boxed_slice());

        for &(offset, (_tag, reloc)) in alloc.relocations.iter() {
            let reloc_offset = {
                let endianness = tcx.data_layout.endian;
                let offset = offset.bytes() as usize;
                let ptr_size = tcx.data_layout.pointer_size;
                let bytes = &alloc.bytes[offset..offset + ptr_size.bytes() as usize];
                read_target_uint(endianness, bytes).unwrap()
            };

            let data_id = match tcx.alloc_map.lock().get(reloc).unwrap() {
                AllocKind::Function(instance) => {
                    let func_id = crate::abi::import_function(tcx, module, instance);
                    let local_func_id = module.declare_func_in_data(func_id, &mut data_ctx);
                    data_ctx.write_function_addr(reloc_offset as u32, local_func_id);
                    continue;
                }
                AllocKind::Memory(_) => {
                    cx.todo.insert(TodoItem::Alloc(reloc));
                    data_id_for_alloc_id(module, reloc)
                }
                AllocKind::Static(def_id) => {
                    cx.todo.insert(TodoItem::Static(def_id));
                    data_id_for_static(tcx, module, def_id, Linkage::Import)
                }
            };

            let global_value = module.declare_data_in_data(data_id, &mut data_ctx);
            data_ctx.write_data_addr(reloc_offset as u32, global_value, 0);
        }

        module.define_data(data_id, &data_ctx).unwrap();
        cx.done.insert(data_id);
    }

    assert!(cx.todo.is_empty(), "{:?}", cx.todo);
}

fn pop_set<T: Copy + Eq + ::std::hash::Hash>(set: &mut HashSet<T>) -> Option<T> {
    if let Some(elem) = set.iter().next().map(|elem| *elem) {
        set.remove(&elem);
        Some(elem)
    } else {
        None
    }
}

struct TransPlaceInterpreter;

impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for TransPlaceInterpreter {
    type MemoryKinds = !;
    type PointerTag = ();
    type AllocExtra = ();
    type MemoryExtra = ();
    type FrameExtra = ();
    type MemoryMap = FxHashMap<AllocId, (MemoryKind<!>, Allocation<()>)>;
    const STATIC_KIND: Option<!> = None;

    fn enforce_validity(_: &EvalContext<'a, 'mir, 'tcx, Self>) -> bool {
        false
    }

    fn before_terminator(_: &mut EvalContext<'a, 'mir, 'tcx, Self>) -> EvalResult<'tcx> {
        panic!();
    }

    fn find_fn(
        _: &mut EvalContext<'a, 'mir, 'tcx, Self>,
        _: Instance<'tcx>,
        _: &[OpTy<'tcx>],
        _: Option<PlaceTy<'tcx>>,
        _: Option<BasicBlock>,
    ) -> EvalResult<'tcx, Option<&'mir Mir<'tcx>>> {
        panic!();
    }

    fn call_intrinsic(
        _: &mut EvalContext<'a, 'mir, 'tcx, Self>,
        _: Instance<'tcx>,
        _: &[OpTy<'tcx>],
        _: PlaceTy<'tcx>,
    ) -> EvalResult<'tcx> {
        panic!();
    }

    fn find_foreign_static(
        _: DefId,
        _: ::rustc::ty::query::TyCtxtAt<'a, 'tcx, 'tcx>,
        _: &(),
    ) -> EvalResult<'tcx, Cow<'tcx, Allocation>> {
        panic!();
    }

    fn ptr_op(
        _: &EvalContext<'a, 'mir, 'tcx, Self>,
        _: mir::BinOp,
        _: Scalar,
        _: TyLayout<'tcx>,
        _: Scalar,
        _: TyLayout<'tcx>,
    ) -> EvalResult<'tcx, (Scalar, bool)> {
        panic!();
    }

    fn box_alloc(_: &mut EvalContext<'a, 'mir, 'tcx, Self>, _: PlaceTy<'tcx>) -> EvalResult<'tcx> {
        panic!();
    }

    fn tag_dereference(
        _: &EvalContext<'a, 'mir, 'tcx, Self>,
        _: MPlaceTy<'tcx>,
        _: Option<::rustc::hir::Mutability>,
    ) -> EvalResult<'tcx, Scalar> {
        panic!();
    }

    fn adjust_static_allocation<'alloc>(
        alloc: &'alloc Allocation,
        _: &(),
    ) -> Cow<'alloc, Allocation> {
        Cow::Borrowed(alloc)
    }

    fn tag_new_allocation(
        _: &mut EvalContext<'a, 'mir, 'tcx, Self>,
        ptr: Pointer,
        _: MemoryKind<!>,
    ) -> Pointer {
        ptr
    }

    fn stack_push(_: &mut EvalContext<'a, 'mir, 'tcx, Self>) -> EvalResult<'tcx>{
        Ok(())
    }

    fn stack_pop(_: &mut EvalContext<'a, 'mir, 'tcx, Self>, _: ()) -> EvalResult<'tcx> {
        Ok(())
    }
}
<commit_msg>Fix offset addend mixup<commit_after>use std::borrow::Cow;

use rustc::mir::interpret::{
    read_target_uint, AllocId, AllocKind, Allocation, ConstValue, EvalResult, GlobalId, Scalar,
};
use rustc::ty::{Const, LazyConst};
use rustc_mir::interpret::{
    EvalContext, MPlaceTy, Machine, Memory, MemoryKind, OpTy, PlaceTy, Pointer, StackPopCleanup,
};

use cranelift_module::*;

use crate::prelude::*;

#[derive(Default)]
pub struct ConstantCx {
    todo: HashSet<TodoItem>,
    done: HashSet<DataId>,
}

#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
enum TodoItem {
    Alloc(AllocId),
    Static(DefId),
}

impl ConstantCx {
    pub fn finalize<'a, 'tcx: 'a, B: Backend>(
        mut self,
        tcx: TyCtxt<'a, 'tcx, 'tcx>,
        module: &mut Module<B>,
    ) {
        //println!("todo {:?}", self.todo);
        define_all_allocs(tcx, module, &mut self);
        //println!("done {:?}", self.done);
        self.done.clear();
    }
}

pub fn codegen_static<'a, 'tcx: 'a>(ccx: &mut ConstantCx, def_id: DefId) {
    ccx.todo.insert(TodoItem::Static(def_id));
}

pub fn codegen_static_ref<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    static_: &Static<'tcx>,
) -> CPlace<'tcx> {
    let data_id = data_id_for_static(fx.tcx, fx.module, static_.def_id, Linkage::Import);
    cplace_for_dataid(fx, static_.ty, data_id)
}

pub fn trans_promoted<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    promoted: Promoted,
) -> CPlace<'tcx> {
    let const_ = fx
        .tcx
        .const_eval(ParamEnv::reveal_all().and(GlobalId {
            instance: fx.instance,
            promoted: Some(promoted),
        }))
        .unwrap();

    trans_const_place(fx, const_)
}

pub fn trans_constant<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    constant: &Constant<'tcx>,
) -> CValue<'tcx> {
    let const_ = fx.monomorphize(&constant.literal);
    let const_ = force_eval_const(fx, const_);
    trans_const_value(fx, const_)
}

pub fn force_eval_const<'a, 'tcx: 'a>(
    fx: &FunctionCx<'a, 'tcx, impl Backend>,
    const_: &'tcx LazyConst<'tcx>,
) -> Const<'tcx> {
    match *const_ {
        LazyConst::Unevaluated(def_id, ref substs) => {
            let param_env = ParamEnv::reveal_all();
            let instance = Instance::resolve(fx.tcx, param_env, def_id, substs).unwrap();
            let cid = GlobalId {
                instance,
                promoted: None,
            };
            fx.tcx.const_eval(param_env.and(cid)).unwrap()
        }
        LazyConst::Evaluated(const_) => const_,
    }
}

fn trans_const_value<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    const_: Const<'tcx>,
) -> CValue<'tcx> {
    let ty = fx.monomorphize(&const_.ty);
    let layout = fx.layout_of(ty);
    match ty.sty {
        ty::Bool => {
            let bits = const_.val.try_to_bits(layout.size).unwrap();
            CValue::const_val(fx, ty, bits as u64 as i64)
        }
        ty::Uint(_) => {
            let bits = const_.val.try_to_bits(layout.size).unwrap();
            CValue::const_val(fx, ty, bits as u64 as i64)
        }
        ty::Int(_) => {
            let bits = const_.val.try_to_bits(layout.size).unwrap();
            CValue::const_val(fx, ty, bits as i128 as i64)
        }
        ty::FnDef(def_id, substs) => {
            let func_ref = fx.get_function_ref(
                Instance::resolve(fx.tcx, ParamEnv::reveal_all(), def_id, substs).unwrap(),
            );
            let func_addr = fx.bcx.ins().func_addr(fx.pointer_type, func_ref);
            CValue::ByVal(func_addr, layout)
        }
        _ => trans_const_place(fx, const_).to_cvalue(fx),
    }
}

fn trans_const_place<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    const_: Const<'tcx>,
) -> CPlace<'tcx> {
    // Adapted from https://github.com/rust-lang/rust/pull/53671/files#diff-e0b58bb6712edaa8595ad7237542c958L551
    let result = || -> EvalResult<'tcx, &'tcx Allocation> {
        let mut ecx = EvalContext::new(
            fx.tcx.at(DUMMY_SP),
            ty::ParamEnv::reveal_all(),
            TransPlaceInterpreter,
        );
        ecx.push_stack_frame(
            fx.instance,
            DUMMY_SP,
            fx.mir,
            None,
            StackPopCleanup::None { cleanup: false },
        )
        .unwrap();
        let op = ecx.eval_operand(
            &Operand::Constant(Box::new(Constant {
                span: DUMMY_SP,
                ty: const_.ty,
                user_ty: None,
                literal: fx.tcx.intern_lazy_const(LazyConst::Evaluated(const_)),
            })),
            None,
        )?;
        let ptr = ecx.allocate(op.layout, MemoryKind::Stack);
        ecx.copy_op(op, ptr.into())?;
        let alloc = ecx.memory().get(ptr.to_ptr()?.alloc_id)?;
        Ok(fx.tcx.intern_const_alloc(alloc.clone()))
    };
    let alloc = result().expect("unable to convert ConstValue to Allocation");

    //println!("const value: {:?} allocation: {:?}", value, alloc);
    let alloc_id = fx.tcx.alloc_map.lock().allocate(alloc);
    fx.constants.todo.insert(TodoItem::Alloc(alloc_id));
    let data_id = data_id_for_alloc_id(fx.module, alloc_id);
    cplace_for_dataid(fx, const_.ty, data_id)
}

fn data_id_for_alloc_id<B: Backend>(module: &mut Module<B>, alloc_id: AllocId) -> DataId {
    module
        .declare_data(&format!("__alloc_{}", alloc_id.0), Linkage::Local, false)
        .unwrap()
}

fn data_id_for_static<'a, 'tcx: 'a, B: Backend>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    module: &mut Module<B>,
    def_id: DefId,
    linkage: Linkage,
) -> DataId {
    let symbol_name = tcx.symbol_name(Instance::mono(tcx, def_id)).as_str();
    let is_mutable = if let ::rustc::hir::Mutability::MutMutable = tcx.is_static(def_id).unwrap() {
        true
    } else {
        !tcx.type_of(def_id)
            .is_freeze(tcx, ParamEnv::reveal_all(), DUMMY_SP)
    };
    module
        .declare_data(&*symbol_name, linkage, is_mutable)
        .unwrap()
}

fn cplace_for_dataid<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    ty: Ty<'tcx>,
    data_id: DataId,
) -> CPlace<'tcx> {
    let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
    let global_ptr = fx.bcx.ins().global_value(fx.pointer_type, local_data_id);
    let layout = fx.layout_of(fx.monomorphize(&ty));
    assert!(!layout.is_unsized(), "unsized statics aren't supported");
    CPlace::Addr(global_ptr, None, layout)
}

fn define_all_allocs<'a, 'tcx: 'a, B: Backend + 'a>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    module: &mut Module<B>,
    cx: &mut ConstantCx,
) {
    let memory = Memory::<TransPlaceInterpreter>::new(tcx.at(DUMMY_SP));

    while let Some(todo_item) = pop_set(&mut cx.todo) {
        let (data_id, alloc) = match todo_item {
            TodoItem::Alloc(alloc_id) => {
                //println!("alloc_id {}", alloc_id);
                let data_id = data_id_for_alloc_id(module, alloc_id);
                let alloc = memory.get(alloc_id).unwrap();
                (data_id, alloc)
            }
            TodoItem::Static(def_id) => {
                //println!("static {:?}", def_id);
                let instance = ty::Instance::mono(tcx, def_id);
                let cid = GlobalId {
                    instance,
                    promoted: None,
                };
                let const_ = tcx.const_eval(ParamEnv::reveal_all().and(cid)).unwrap();

                let alloc = match const_.val {
                    ConstValue::ByRef(_alloc_id, alloc, n) if n.bytes() == 0 => alloc,
                    _ => bug!("static const eval returned {:#?}", const_),
                };

                let data_id = data_id_for_static(tcx, module, def_id, Linkage::Export);
                (data_id, alloc)
            }
        };

        //("data_id {}", data_id);
        if cx.done.contains(&data_id) {
            continue;
        }

        let mut data_ctx = DataContext::new();

        data_ctx.define(alloc.bytes.to_vec().into_boxed_slice());

        for &(offset, (_tag, reloc)) in alloc.relocations.iter() {
            let addend = {
                let endianness = tcx.data_layout.endian;
                let offset = offset.bytes() as usize;
                let ptr_size = tcx.data_layout.pointer_size;
                let bytes = &alloc.bytes[offset..offset + ptr_size.bytes() as usize];
                read_target_uint(endianness, bytes).unwrap()
            };

            let data_id = match tcx.alloc_map.lock().get(reloc).unwrap() {
                AllocKind::Function(instance) => {
                    assert_eq!(addend, 0);
                    let func_id = crate::abi::import_function(tcx, module, instance);
                    let local_func_id = module.declare_func_in_data(func_id, &mut data_ctx);
                    data_ctx.write_function_addr(offset.bytes() as u32, local_func_id);
                    continue;
                }
                AllocKind::Memory(_) => {
                    cx.todo.insert(TodoItem::Alloc(reloc));
                    data_id_for_alloc_id(module, reloc)
                }
                AllocKind::Static(def_id) => {
                    cx.todo.insert(TodoItem::Static(def_id));
                    data_id_for_static(tcx, module, def_id, Linkage::Import)
                }
            };

            let global_value = module.declare_data_in_data(data_id, &mut data_ctx);
            data_ctx.write_data_addr(offset.bytes() as u32, global_value, addend as i64);
        }

        module.define_data(data_id, &data_ctx).unwrap();
        cx.done.insert(data_id);
    }

    assert!(cx.todo.is_empty(), "{:?}", cx.todo);
}

fn pop_set<T: Copy + Eq + ::std::hash::Hash>(set: &mut HashSet<T>) -> Option<T> {
    if let Some(elem) = set.iter().next().map(|elem| *elem) {
        set.remove(&elem);
        Some(elem)
    } else {
        None
    }
}

struct TransPlaceInterpreter;

impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for TransPlaceInterpreter {
    type MemoryKinds = !;
    type PointerTag = ();
    type AllocExtra = ();
    type MemoryExtra = ();
    type FrameExtra = ();
    type MemoryMap = FxHashMap<AllocId, (MemoryKind<!>, Allocation<()>)>;
    const STATIC_KIND: Option<!> = None;

    fn enforce_validity(_: &EvalContext<'a, 'mir, 'tcx, Self>) -> bool {
        false
    }

    fn before_terminator(_: &mut EvalContext<'a, 'mir, 'tcx, Self>) -> EvalResult<'tcx> {
        panic!();
    }

    fn find_fn(
        _: &mut EvalContext<'a, 'mir, 'tcx, Self>,
        _: Instance<'tcx>,
        _: &[OpTy<'tcx>],
        _: Option<PlaceTy<'tcx>>,
        _: Option<BasicBlock>,
    ) -> EvalResult<'tcx, Option<&'mir Mir<'tcx>>> {
        panic!();
    }

    fn call_intrinsic(
        _: &mut EvalContext<'a, 'mir, 'tcx, Self>,
        _: Instance<'tcx>,
        _: &[OpTy<'tcx>],
        _: PlaceTy<'tcx>,
    ) -> EvalResult<'tcx> {
        panic!();
    }

    fn find_foreign_static(
        _: DefId,
        _: ::rustc::ty::query::TyCtxtAt<'a, 'tcx, 'tcx>,
        _: &(),
    ) -> EvalResult<'tcx, Cow<'tcx, Allocation>> {
        panic!();
    }

    fn ptr_op(
        _: &EvalContext<'a, 'mir, 'tcx, Self>,
        _: mir::BinOp,
        _: Scalar,
        _: TyLayout<'tcx>,
        _: Scalar,
        _: TyLayout<'tcx>,
    ) -> EvalResult<'tcx, (Scalar, bool)> {
        panic!();
    }

    fn box_alloc(_: &mut EvalContext<'a, 'mir, 'tcx, Self>, _: PlaceTy<'tcx>) -> EvalResult<'tcx> {
        panic!();
    }

    fn tag_dereference(
        _: &EvalContext<'a, 'mir, 'tcx, Self>,
        _: MPlaceTy<'tcx>,
        _: Option<::rustc::hir::Mutability>,
    ) -> EvalResult<'tcx, Scalar> {
        panic!();
    }

    fn adjust_static_allocation<'alloc>(
        alloc: &'alloc Allocation,
        _: &(),
    ) -> Cow<'alloc, Allocation> {
        Cow::Borrowed(alloc)
    }

    fn tag_new_allocation(
        _: &mut EvalContext<'a, 'mir, 'tcx, Self>,
        ptr: Pointer,
        _: MemoryKind<!>,
    ) -> Pointer {
        ptr
    }

    fn stack_push(_: &mut EvalContext<'a, 'mir, 'tcx, Self>) -> EvalResult<'tcx>{
        Ok(())
    }

    fn stack_pop(_: &mut EvalContext<'a, 'mir, 'tcx, Self>, _: ()) -> EvalResult<'tcx> {
        Ok(())
    }
}
<|endoftext|>


<commit_before>//! Implements some common utilities for the examples

use std::io;
use std::io::BufferedReader;
use lua;

pub fn repl(L: &mut lua::State) {
    let mut stdin = BufferedReader::new(io::stdin());
    let stdout = &mut io::stdout() as &mut io::Writer;
    let stderr = &mut io::stderr() as &mut io::Writer;
    loop {
        L.settop(0); // clear the stack
        write!(stdout, "> ");
        stdout.flush();
        let line = stdin.read_line();
        let mut line = if line.is_some() { line.unwrap() } else { break };
        if line.starts_with("=") {
            line = format!("return {}", line.slice_from(1));
        }
        match L.loadbuffer(line, "=stdin") {
            Ok(_) => (),
            Err(err) => { writeln!(stderr, "{}", err.to_str()); continue; }
        }
        match L.pcall(0, lua::MULTRET, 0) {
            Ok(_) => (),
            Err(_) => {
                match L.tostring(-1) {
                    Some(msg) => writeln!(stderr, "{}", msg),
                    None => writeln!(stderr, "(error object is not a string)")
                }
            }
        }
        if L.gettop() > 0 {
            L.getglobal("print");
            L.insert(1);
            let nargs = L.gettop()-1;
            match L.pcall(nargs, 0, 0) {
                Ok(_) => (),
                Err(_) => {
                    writeln!(stderr, "error calling 'print' ({})",
                             L.tostring(-1).unwrap_or_default());
                    continue;
                }
            }
        }
    }
}
<commit_msg>Update for removal of io::io_error<commit_after>//! Implements some common utilities for the examples

use std::io;
use std::io::BufferedReader;
use lua;

pub fn repl(L: &mut lua::State) {
    let mut stdin = BufferedReader::new(io::stdin());
    let stdout = &mut io::stdout() as &mut io::Writer;
    let stderr = &mut io::stderr() as &mut io::Writer;
    loop {
        L.settop(0); // clear the stack
        let _ = write!(stdout, "> ");
        let _ = stdout.flush();
        let mut line = match stdin.read_line() {
            Ok(line) => line,
            Err(_) => break
        };
        if line.starts_with("=") {
            line = format!("return {}", line.slice_from(1));
        }
        match L.loadbuffer(line, "=stdin") {
            Ok(_) => (),
            Err(err) => { let _ = writeln!(stderr, "{}", err.to_str()); continue; }
        }
        match L.pcall(0, lua::MULTRET, 0) {
            Ok(_) => (),
            Err(_) => {
                match L.tostring(-1) {
                    Some(msg) => { let _ = writeln!(stderr, "{}", msg); }
                    None => { let _ = writeln!(stderr, "(error object is not a string)"); }
                }
            }
        }
        if L.gettop() > 0 {
            L.getglobal("print");
            L.insert(1);
            let nargs = L.gettop()-1;
            match L.pcall(nargs, 0, 0) {
                Ok(_) => (),
                Err(_) => {
                    let _ = writeln!(stderr, "error calling 'print' ({})",
                                     L.tostring(-1).unwrap_or_default());
                    continue;
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>// Claxon -- A FLAC decoding library in Rust
// Copyright 2015 Ruud van Asseldonk
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// A copy of the License has been included in the root of the repository.

extern crate claxon;
extern crate hound;

use claxon::{Block, FlacReader};
use hound::{WavSpec, WavWriter};
use std::env;
use std::path::Path;

fn decode_file(fname: &Path) {
    let mut reader = FlacReader::open(fname).expect("failed to open FLAC stream");

    // TODO: Write fallback for other sample widths and channel numbers.
    assert!(reader.streaminfo().bits_per_sample == 16);
    assert!(reader.streaminfo().channels == 2);

    let spec = WavSpec {
        // TODO: u8 for channels, is that weird? Would u32 be better?
        channels: reader.streaminfo().channels as u16,
        sample_rate: reader.streaminfo().sample_rate,
        // TODO: again, would u32 be better, even if the range is smaller?
        bits_per_sample: reader.streaminfo().bits_per_sample as u16,
        sample_format: hound::SampleFormat::Int,
    };

    let fname_wav = fname.with_extension("wav");
    let mut wav_writer = WavWriter::create(fname_wav, spec).expect("failed to create wav file");

    let mut frame_reader = reader.blocks();
    let mut block = Block::empty();
    loop {
        // Read a single frame. Recycle the buffer from the previous frame to
        // avoid allocations as much as possible.
        match frame_reader.read_next_or_eof(block.into_buffer()) {
            Ok(Some(next_block)) => block = next_block,
            Ok(None) => break, // EOF.
            Err(error) => panic!("{}", error),
        }

        let mut sample_writer = wav_writer.get_i16_writer(block.duration() * 2);

        // Write the samples in the block to the wav file, channels interleaved.
        for (left, right) in block.stereo_samples() {
            // The `stereo_samples()` iterator does not yield more samples
            // than the duration of the block, so we never write more
            // samples to the writer than requested, hence using the
            // unchecked functions is safe here.
            unsafe {
                sample_writer.write_sample_unchecked(left);
                sample_writer.write_sample_unchecked(right);
            }
        }

        sample_writer.flush().expect("failed to write samples to wav file");
    }

    wav_writer.finalize().expect("failed to finalize wav file");
}

fn main() {
    let mut no_args = true;

    for fname in env::args().skip(1) {
        no_args = false;

        print!("{}", fname);
        decode_file(&Path::new(&fname));
        println!(": done");
    }

    if no_args {
        println!("no files to decode");
    }
}
<commit_msg>Improved documentation in decode example<commit_after>// Claxon -- A FLAC decoding library in Rust
// Copyright 2015 Ruud van Asseldonk
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// A copy of the License has been included in the root of the repository.

// This file implements a decoder, like the reference `flac -d`. It is fast, but
// being fast requires dealing with a few details of the FLAC format. There is
// also a simpler example, `decode_simple`, which is less verbose.

extern crate claxon;
extern crate hound;

use claxon::{Block, FlacReader};
use hound::{WavSpec, WavWriter};
use std::env;
use std::path::Path;

fn decode_file(fname: &Path) {
    let mut reader = FlacReader::open(fname).expect("failed to open FLAC stream");

    // TODO: Write fallback for other sample widths and channel numbers.
    assert!(reader.streaminfo().bits_per_sample == 16);
    assert!(reader.streaminfo().channels == 2);

    let spec = WavSpec {
        channels: reader.streaminfo().channels as u16,
        sample_rate: reader.streaminfo().sample_rate,
        bits_per_sample: reader.streaminfo().bits_per_sample as u16,
        sample_format: hound::SampleFormat::Int,
    };

    let fname_wav = fname.with_extension("wav");
    let mut wav_writer = WavWriter::create(fname_wav, spec).expect("failed to create wav file");

    let mut frame_reader = reader.blocks();
    let mut block = Block::empty();
    loop {
        // Read a single frame. Recycle the buffer from the previous frame to
        // avoid allocations as much as possible.
        match frame_reader.read_next_or_eof(block.into_buffer()) {
            Ok(Some(next_block)) => block = next_block,
            Ok(None) => break, // EOF.
            Err(error) => panic!("{}", error),
        }

        let mut sample_writer = wav_writer.get_i16_writer(block.duration() * 2);

        // Write the samples in the block to the wav file, channels interleaved.
        for (left, right) in block.stereo_samples() {
            // The `stereo_samples()` iterator does not yield more samples
            // than the duration of the block, so we never write more
            // samples to the writer than requested, hence using the
            // unchecked functions is safe here.
            unsafe {
                sample_writer.write_sample_unchecked(left);
                sample_writer.write_sample_unchecked(right);
            }
        }

        sample_writer.flush().expect("failed to write samples to wav file");
    }

    wav_writer.finalize().expect("failed to finalize wav file");
}

fn main() {
    let mut no_args = true;

    for fname in env::args().skip(1) {
        no_args = false;

        print!("{}", fname);
        decode_file(&Path::new(&fname));
        println!(": done");
    }

    if no_args {
        println!("no files to decode");
    }
}
<|endoftext|>


<commit_before>//! An example showing off the usage of `Deserialize` to automatically decode
//! TOML into a Rust `struct`
//!
//! Note that this works similarly with `serde` as well.

#![deny(warnings)]

extern crate toml;
#[macro_use]
extern crate serde_derive;

/// This is what we're going to decode into. Each field is optional, meaning
/// that it doesn't have to be present in TOML.
#[derive(Debug, Deserialize)]
struct Config {
    global_string: Option<String>,
    global_integer: Option<u64>,
    server: Option<ServerConfig>,
    peers: Option<Vec<PeerConfig>>,
}

/// Sub-structs are decoded from tables, so this will decode from the `[server]`
/// table.
///
/// Again, each field is optional, meaning they don't have to be present.
#[derive(Debug, Deserialize)]
struct ServerConfig {
    ip: Option<String>,
    port: Option<u64>,
}

#[derive(Debug, Deserialize)]
struct PeerConfig {
    ip: Option<String>,
    port: Option<u64>,
}

fn main() {
    let toml_str = r#"
        global_string = "test"
        global_integer = 5

        [server]
        ip = "127.0.0.1"
        port = 80

        [[peers]]
        ip = "127.0.0.1"
        port = 8080

        [[peers]]
        ip = "127.0.0.1"
    "#;

    let decoded: Config = toml::from_str(toml_str).unwrap();
    println!("{:#?}", decoded);
}
<commit_msg>Add `extern crate serde` to examples/decode.rs<commit_after>//! An example showing off the usage of `Deserialize` to automatically decode
//! TOML into a Rust `struct`

#![deny(warnings)]

extern crate toml;
extern crate serde;
#[macro_use]
extern crate serde_derive;

/// This is what we're going to decode into. Each field is optional, meaning
/// that it doesn't have to be present in TOML.
#[derive(Debug, Deserialize)]
struct Config {
    global_string: Option<String>,
    global_integer: Option<u64>,
    server: Option<ServerConfig>,
    peers: Option<Vec<PeerConfig>>,
}

/// Sub-structs are decoded from tables, so this will decode from the `[server]`
/// table.
///
/// Again, each field is optional, meaning they don't have to be present.
#[derive(Debug, Deserialize)]
struct ServerConfig {
    ip: Option<String>,
    port: Option<u64>,
}

#[derive(Debug, Deserialize)]
struct PeerConfig {
    ip: Option<String>,
    port: Option<u64>,
}

fn main() {
    let toml_str = r#"
        global_string = "test"
        global_integer = 5

        [server]
        ip = "127.0.0.1"
        port = 80

        [[peers]]
        ip = "127.0.0.1"
        port = 8080

        [[peers]]
        ip = "127.0.0.1"
    "#;

    let decoded: Config = toml::from_str(toml_str).unwrap();
    println!("{:#?}", decoded);
}
<|endoftext|>