<commit_before>use std::io;
use byteorder::{LittleEndian, ByteOrder};

use super::{Deserialize, Serialize, Error, Uint32};
use super::section::{
    Section, CodeSection, TypeSection, ImportSection, ExportSection, FunctionSection,
    GlobalSection, TableSection, ElementSection, DataSection, MemorySection
};
use super::name_section::NameSection;

const WASM_MAGIC_NUMBER: [u8; 4] = [0x00, 0x61, 0x73, 0x6d];

/// WebAssembly module
#[derive(Debug, Clone)]
pub struct Module {
    magic: u32,
    version: u32,
    sections: Vec<Section>,
}

impl Default for Module {
    fn default() -> Self {
        Module {
            magic: LittleEndian::read_u32(&WASM_MAGIC_NUMBER),
            version: 1,
            sections: Vec::with_capacity(16),
        }
    }
}

impl Module {
    /// New module with sections
    pub fn new(sections: Vec<Section>) -> Self {
        Module {
            sections: sections, ..Default::default()
        }
    }

    /// Destructure the module, yielding sections
    pub fn into_sections(self) -> Vec<Section> {
        self.sections
    }

    /// Version of module.
    pub fn version(&self) -> u32 { self.version }

    /// Sections list.
    /// Each known section is optional and may appear at most once.
    pub fn sections(&self) -> &[Section] {
        &self.sections
    }

    /// Sections list (mutable)
    /// Each known section is optional and may appear at most once.
    pub fn sections_mut(&mut self) -> &mut Vec<Section> {
        &mut self.sections
    }

    /// Code section, if any.
    pub fn code_section(&self) -> Option<&CodeSection> {
        for section in self.sections() {
            if let &Section::Code(ref code_section) = section { return Some(code_section); }
        }
        None
    }

    /// Types section, if any.
    pub fn type_section(&self) -> Option<&TypeSection> {
        for section in self.sections() {
            if let &Section::Type(ref type_section) = section { return Some(type_section); }
        }
        None
    }

    /// Imports section, if any.
    pub fn import_section(&self) -> Option<&ImportSection> {
        for section in self.sections() {
            if let &Section::Import(ref import_section) = section { return Some(import_section); }
        }
        None
    }

    /// Globals section, if any.
    pub fn global_section(&self) -> Option<&GlobalSection> {
        for section in self.sections() {
            if let &Section::Global(ref section) = section { return Some(section); }
        }
        None
    }

    /// Exports section, if any.
    pub fn export_section(&self) -> Option<&ExportSection> {
        for section in self.sections() {
            if let &Section::Export(ref export_section) = section { return Some(export_section); }
        }
        None
    }

    /// Table section, if any.
    pub fn table_section(&self) -> Option<&TableSection> {
        for section in self.sections() {
            if let &Section::Table(ref section) = section { return Some(section); }
        }
        None
    }

    /// Data section, if any.
    pub fn data_section(&self) -> Option<&DataSection> {
        for section in self.sections() {
            if let &Section::Data(ref section) = section { return Some(section); }
        }
        None
    }

    /// Element section, if any.
    pub fn elements_section(&self) -> Option<&ElementSection> {
        for section in self.sections() {
            if let &Section::Element(ref section) = section { return Some(section); }
        }
        None
    }

    /// Memory section, if any.
    pub fn memory_section(&self) -> Option<&MemorySection> {
        for section in self.sections() {
            if let &Section::Memory(ref section) = section { return Some(section); }
        }
        None
    }

    /// Functions signatures section, if any.
    pub fn function_section(&self) -> Option<&FunctionSection> {
        for section in self.sections() {
            if let &Section::Function(ref sect) = section { return Some(sect); }
        }
        None
    }

    /// Start section, if any.
    pub fn start_section(&self) -> Option<u32> {
        for section in self.sections() {
            if let &Section::Start(sect) = section { return Some(sect); }
        }
        None
    }

    pub fn parse_names(mut self) -> Result<Self, (Vec<(usize, Error)>, Self)> {
        let mut parse_errors = Vec::new();

        for i in 0..self.sections.len() {
            if let Some(name_section) = {
                let section = self.sections.get(i).expect("cannot fail because i in range 0..len; qed");
                if let Section::Custom(ref custom) = *section {
                    if custom.name() == "name" {
                        let mut rdr = io::Cursor::new(custom.payload());
                        let name_section = match NameSection::deserialize(&self, &mut rdr) {
                            Ok(ns) => ns,
                            Err(e) => { parse_errors.push((i, e)); continue; }
                        };
                        Some(name_section)
                    } else {
                        None
                    }
                } else { None }
            } {
                *self.sections.get_mut(i).expect("cannot fail because i in range 0..len; qed") = Section::Name(name_section);
            }
        }

        if parse_errors.len() > 0 {
            Err((parse_errors, self))
        } else {
            Ok(self)
        }
    }
}

impl Deserialize for Module {
    type Error = super::Error;

    fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
        let mut sections = Vec::new();

        let mut magic = [0u8; 4];
        reader.read(&mut magic)?;
        if magic != WASM_MAGIC_NUMBER {
            return Err(Error::InvalidMagic);
        }

        let version: u32 = Uint32::deserialize(reader)?.into();

        if version != 1 {
            return Err(Error::UnsupportedVersion(version));
        }

        loop {
            match Section::deserialize(reader) {
                Err(Error::UnexpectedEof) => { break; },
                Err(e) => { return Err(e) },
                Ok(section) => { sections.push(section); }
            }
        }

        Ok(Module {
            magic: LittleEndian::read_u32(&magic),
            version: version,
            sections: sections,
        })
    }
}

impl Serialize for Module {
    type Error = Error;

    fn serialize<W: io::Write>(self, w: &mut W) -> Result<(), Self::Error> {
        Uint32::from(self.magic).serialize(w)?;
        Uint32::from(self.version).serialize(w)?;
        for section in self.sections.into_iter() {
            section.serialize(w)?;
        }
        Ok(())
    }
}

#[derive(Debug, Copy, Clone)]
struct PeekSection<'a> {
    cursor: usize,
    region: &'a [u8],
}

impl<'a> io::Read for PeekSection<'a> {
    fn read(&mut self, buf: &mut [u8]) -> ::std::io::Result<usize> {
        let available = ::std::cmp::min(buf.len(), self.region.len() - self.cursor);
        if available < buf.len() {
            return Err(::std::io::Error::from(::std::io::ErrorKind::UnexpectedEof));
        }

        let range = self.cursor..self.cursor + buf.len();
        buf.copy_from_slice(&self.region[range]);

        self.cursor += available;
        Ok(available)
    }
}

/// Returns size of the module in the provided stream
pub fn peek_size(source: &[u8]) -> usize {
    if source.len() < 9 {
        return 0;
    }

    let mut cursor = 8;
    loop {
        let (new_cursor, section_id, section_len) = {
            let mut peek_section = PeekSection { cursor: 0, region: &source[cursor..] };
            let section_id: u8 = match super::VarUint7::deserialize(&mut peek_section) {
                Ok(res) => res.into(),
                Err(_) => { break; },
            };
            let section_len: u32 = match super::VarUint32::deserialize(&mut peek_section) {
                Ok(res) => res.into(),
                Err(_) => { break; },
            };

            (peek_section.cursor, section_id, section_len)
        };

        if section_id <= 11 && section_len > 0 {
            let next_cursor = cursor + new_cursor + section_len as usize;
            if next_cursor >= source.len() {
                break;
            }
            cursor = next_cursor;
        } else {
            break;
        }
    }

    cursor
}

#[cfg(test)]
mod integration_tests {

    use super::super::{deserialize_file, serialize, deserialize_buffer, Section};
    use super::Module;

    #[test]
    fn hello() {
        let module = deserialize_file("./res/cases/v1/hello.wasm").expect("Should be deserialized");

        assert_eq!(module.version(), 1);
        assert_eq!(module.sections().len(), 8);
    }

    #[test]
    fn serde() {
        let module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
        let buf = serialize(module).expect("serialization to succeed");

        let module_new: Module = deserialize_buffer(&buf).expect("deserialization to succeed");
        let module_old = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");

        assert_eq!(module_old.sections().len(), module_new.sections().len());
    }

    #[test]
    fn serde_type() {
        let mut module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
        module.sections_mut().retain(|x| {
            if let &Section::Type(_) = x { true } else { false }
        });

        let buf = serialize(module).expect("serialization to succeed");

        let module_new: Module = deserialize_buffer(&buf).expect("deserialization to succeed");
        let module_old = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
        assert_eq!(
            module_old.type_section().expect("type section exists").types().len(),
            module_new.type_section().expect("type section exists").types().len(),
            "There should be equal amount of types before and after serialization"
        );
    }

    #[test]
    fn serde_import() {
        let mut module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
        module.sections_mut().retain(|x| {
            if let &Section::Import(_) = x { true } else { false }
        });

        let buf = serialize(module).expect("serialization to succeed");

        let module_new: Module = deserialize_buffer(&buf).expect("deserialization to succeed");
        let module_old = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
        assert_eq!(
            module_old.import_section().expect("import section exists").entries().len(),
            module_new.import_section().expect("import section exists").entries().len(),
            "There should be equal amount of import entries before and after serialization"
        );
    }

    #[test]
    fn serde_code() {
        let mut module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
        module.sections_mut().retain(|x| {
            if let &Section::Code(_) = x { true } else { false }
        });

        let buf = serialize(module).expect("serialization to succeed");

        let module_new: Module = deserialize_buffer(&buf).expect("deserialization to succeed");
        let module_old = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
        assert_eq!(
            module_old.code_section().expect("code section exists").bodies().len(),
            module_new.code_section().expect("code section exists").bodies().len(),
            "There should be equal amount of function bodies before and after serialization"
        );
    }

    #[test]
    fn const_() {
        use super::super::Opcode::*;

        let module = deserialize_file("./res/cases/v1/const.wasm").expect("Should be deserialized");
        let func = &module.code_section().expect("Code section to exist").bodies()[0];
        assert_eq!(func.code().elements().len(), 20);

        assert_eq!(I64Const(9223372036854775807), func.code().elements()[0]);
        assert_eq!(I64Const(-9223372036854775808), func.code().elements()[1]);
        assert_eq!(I64Const(-1152894205662152753), func.code().elements()[2]);
        assert_eq!(I64Const(-8192), func.code().elements()[3]);
        assert_eq!(I32Const(1024), func.code().elements()[4]);
        assert_eq!(I32Const(2048), func.code().elements()[5]);
        assert_eq!(I32Const(4096), func.code().elements()[6]);
        assert_eq!(I32Const(8192), func.code().elements()[7]);
        assert_eq!(I32Const(16384), func.code().elements()[8]);
        assert_eq!(I32Const(32767), func.code().elements()[9]);
        assert_eq!(I32Const(-1024), func.code().elements()[10]);
        assert_eq!(I32Const(-2048), func.code().elements()[11]);
        assert_eq!(I32Const(-4096), func.code().elements()[12]);
        assert_eq!(I32Const(-8192), func.code().elements()[13]);
        assert_eq!(I32Const(-16384), func.code().elements()[14]);
        assert_eq!(I32Const(-32768), func.code().elements()[15]);
        assert_eq!(I32Const(-2147483648), func.code().elements()[16]);
        assert_eq!(I32Const(2147483647), func.code().elements()[17]);
    }

    #[test]
    fn store() {
        use super::super::Opcode::*;

        let module = deserialize_file("./res/cases/v1/offset.wasm").expect("Should be deserialized");
        let func = &module.code_section().expect("Code section to exist").bodies()[0];

        assert_eq!(func.code().elements().len(), 5);
        assert_eq!(I64Store(0, 32), func.code().elements()[2]);
    }

    #[test]
    fn peek() {
        use super::peek_size;

        let module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
        let mut buf = serialize(module).expect("serialization to succeed");

        buf.extend_from_slice(&[1, 5, 12, 17]);

        assert_eq!(peek_size(&buf), buf.len() - 4);
    }

    #[test]
    fn peek_2() {
        use super::peek_size;

        let module = deserialize_file("./res/cases/v1/offset.wasm").expect("Should be deserialized");
        let mut buf = serialize(module).expect("serialization to succeed");

        buf.extend_from_slice(&[0, 0, 0, 0, 0, 1, 5, 12, 17]);

        assert_eq!(peek_size(&buf), buf.len() - 9);
    }

    #[test]
    fn module_default_round_trip() {
        let module1 = Module::default();
        let buf = serialize(module1).expect("Serialization should succeed");

        let module2: Module = deserialize_buffer(&buf).expect("Deserialization should succeed");
        assert_eq!(Module::default().magic, module2.magic);
    }
}
<commit_msg>add doc comment<commit_after>use std::io;
use byteorder::{LittleEndian, ByteOrder};

use super::{Deserialize, Serialize, Error, Uint32};
use super::section::{
    Section, CodeSection, TypeSection, ImportSection, ExportSection, FunctionSection,
    GlobalSection, TableSection, ElementSection, DataSection, MemorySection
};
use super::name_section::NameSection;

const WASM_MAGIC_NUMBER: [u8; 4] = [0x00, 0x61, 0x73, 0x6d];

/// WebAssembly module
#[derive(Debug, Clone)]
pub struct Module {
    magic: u32,
    version: u32,
    sections: Vec<Section>,
}

impl Default for Module {
    fn default() -> Self {
        Module {
            magic: LittleEndian::read_u32(&WASM_MAGIC_NUMBER),
            version: 1,
            sections: Vec::with_capacity(16),
        }
    }
}

impl Module {
    /// New module with sections
    pub fn new(sections: Vec<Section>) -> Self {
        Module {
            sections: sections, ..Default::default()
        }
    }

    /// Destructure the module, yielding sections
    pub fn into_sections(self) -> Vec<Section> {
        self.sections
    }

    /// Version of module.
    pub fn version(&self) -> u32 { self.version }

    /// Sections list.
    /// Each known section is optional and may appear at most once.
    pub fn sections(&self) -> &[Section] {
        &self.sections
    }

    /// Sections list (mutable)
    /// Each known section is optional and may appear at most once.
    pub fn sections_mut(&mut self) -> &mut Vec<Section> {
        &mut self.sections
    }

    /// Code section, if any.
    pub fn code_section(&self) -> Option<&CodeSection> {
        for section in self.sections() {
            if let &Section::Code(ref code_section) = section { return Some(code_section); }
        }
        None
    }

    /// Types section, if any.
    pub fn type_section(&self) -> Option<&TypeSection> {
        for section in self.sections() {
            if let &Section::Type(ref type_section) = section { return Some(type_section); }
        }
        None
    }

    /// Imports section, if any.
    pub fn import_section(&self) -> Option<&ImportSection> {
        for section in self.sections() {
            if let &Section::Import(ref import_section) = section { return Some(import_section); }
        }
        None
    }

    /// Globals section, if any.
    pub fn global_section(&self) -> Option<&GlobalSection> {
        for section in self.sections() {
            if let &Section::Global(ref section) = section { return Some(section); }
        }
        None
    }

    /// Exports section, if any.
    pub fn export_section(&self) -> Option<&ExportSection> {
        for section in self.sections() {
            if let &Section::Export(ref export_section) = section { return Some(export_section); }
        }
        None
    }

    /// Table section, if any.
    pub fn table_section(&self) -> Option<&TableSection> {
        for section in self.sections() {
            if let &Section::Table(ref section) = section { return Some(section); }
        }
        None
    }

    /// Data section, if any.
    pub fn data_section(&self) -> Option<&DataSection> {
        for section in self.sections() {
            if let &Section::Data(ref section) = section { return Some(section); }
        }
        None
    }

    /// Element section, if any.
    pub fn elements_section(&self) -> Option<&ElementSection> {
        for section in self.sections() {
            if let &Section::Element(ref section) = section { return Some(section); }
        }
        None
    }

    /// Memory section, if any.
    pub fn memory_section(&self) -> Option<&MemorySection> {
        for section in self.sections() {
            if let &Section::Memory(ref section) = section { return Some(section); }
        }
        None
    }

    /// Functions signatures section, if any.
    pub fn function_section(&self) -> Option<&FunctionSection> {
        for section in self.sections() {
            if let &Section::Function(ref sect) = section { return Some(sect); }
        }
        None
    }

    /// Start section, if any.
    pub fn start_section(&self) -> Option<u32> {
        for section in self.sections() {
            if let &Section::Start(sect) = section { return Some(sect); }
        }
        None
    }

    /// Try to parse name section in place
    /// Corresponding custom section with proper header will convert to name sections
    /// If some of them will fail to be decoded, Err variant is returned with the list of
    /// (index, Error) tuples of failed sections.
    pub fn parse_names(mut self) -> Result<Self, (Vec<(usize, Error)>, Self)> {
        let mut parse_errors = Vec::new();

        for i in 0..self.sections.len() {
            if let Some(name_section) = {
                let section = self.sections.get(i).expect("cannot fail because i in range 0..len; qed");
                if let Section::Custom(ref custom) = *section {
                    if custom.name() == "name" {
                        let mut rdr = io::Cursor::new(custom.payload());
                        let name_section = match NameSection::deserialize(&self, &mut rdr) {
                            Ok(ns) => ns,
                            Err(e) => { parse_errors.push((i, e)); continue; }
                        };
                        Some(name_section)
                    } else {
                        None
                    }
                } else { None }
            } {
                *self.sections.get_mut(i).expect("cannot fail because i in range 0..len; qed") = Section::Name(name_section);
            }
        }

        if parse_errors.len() > 0 {
            Err((parse_errors, self))
        } else {
            Ok(self)
        }
    }
}

impl Deserialize for Module {
    type Error = super::Error;

    fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
        let mut sections = Vec::new();

        let mut magic = [0u8; 4];
        reader.read(&mut magic)?;
        if magic != WASM_MAGIC_NUMBER {
            return Err(Error::InvalidMagic);
        }

        let version: u32 = Uint32::deserialize(reader)?.into();

        if version != 1 {
            return Err(Error::UnsupportedVersion(version));
        }

        loop {
            match Section::deserialize(reader) {
                Err(Error::UnexpectedEof) => { break; },
                Err(e) => { return Err(e) },
                Ok(section) => { sections.push(section); }
            }
        }

        Ok(Module {
            magic: LittleEndian::read_u32(&magic),
            version: version,
            sections: sections,
        })
    }
}

impl Serialize for Module {
    type Error = Error;

    fn serialize<W: io::Write>(self, w: &mut W) -> Result<(), Self::Error> {
        Uint32::from(self.magic).serialize(w)?;
        Uint32::from(self.version).serialize(w)?;
        for section in self.sections.into_iter() {
            section.serialize(w)?;
        }
        Ok(())
    }
}

#[derive(Debug, Copy, Clone)]
struct PeekSection<'a> {
    cursor: usize,
    region: &'a [u8],
}

impl<'a> io::Read for PeekSection<'a> {
    fn read(&mut self, buf: &mut [u8]) -> ::std::io::Result<usize> {
        let available = ::std::cmp::min(buf.len(), self.region.len() - self.cursor);
        if available < buf.len() {
            return Err(::std::io::Error::from(::std::io::ErrorKind::UnexpectedEof));
        }

        let range = self.cursor..self.cursor + buf.len();
        buf.copy_from_slice(&self.region[range]);

        self.cursor += available;
        Ok(available)
    }
}

/// Returns size of the module in the provided stream
pub fn peek_size(source: &[u8]) -> usize {
    if source.len() < 9 {
        return 0;
    }

    let mut cursor = 8;
    loop {
        let (new_cursor, section_id, section_len) = {
            let mut peek_section = PeekSection { cursor: 0, region: &source[cursor..] };
            let section_id: u8 = match super::VarUint7::deserialize(&mut peek_section) {
                Ok(res) => res.into(),
                Err(_) => { break; },
            };
            let section_len: u32 = match super::VarUint32::deserialize(&mut peek_section) {
                Ok(res) => res.into(),
                Err(_) => { break; },
            };

            (peek_section.cursor, section_id, section_len)
        };

        if section_id <= 11 && section_len > 0 {
            let next_cursor = cursor + new_cursor + section_len as usize;
            if next_cursor >= source.len() {
                break;
            }
            cursor = next_cursor;
        } else {
            break;
        }
    }

    cursor
}

#[cfg(test)]
mod integration_tests {

    use super::super::{deserialize_file, serialize, deserialize_buffer, Section};
    use super::Module;

    #[test]
    fn hello() {
        let module = deserialize_file("./res/cases/v1/hello.wasm").expect("Should be deserialized");

        assert_eq!(module.version(), 1);
        assert_eq!(module.sections().len(), 8);
    }

    #[test]
    fn serde() {
        let module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
        let buf = serialize(module).expect("serialization to succeed");

        let module_new: Module = deserialize_buffer(&buf).expect("deserialization to succeed");
        let module_old = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");

        assert_eq!(module_old.sections().len(), module_new.sections().len());
    }

    #[test]
    fn serde_type() {
        let mut module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
        module.sections_mut().retain(|x| {
            if let &Section::Type(_) = x { true } else { false }
        });

        let buf = serialize(module).expect("serialization to succeed");

        let module_new: Module = deserialize_buffer(&buf).expect("deserialization to succeed");
        let module_old = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
        assert_eq!(
            module_old.type_section().expect("type section exists").types().len(),
            module_new.type_section().expect("type section exists").types().len(),
            "There should be equal amount of types before and after serialization"
        );
    }

    #[test]
    fn serde_import() {
        let mut module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
        module.sections_mut().retain(|x| {
            if let &Section::Import(_) = x { true } else { false }
        });

        let buf = serialize(module).expect("serialization to succeed");

        let module_new: Module = deserialize_buffer(&buf).expect("deserialization to succeed");
        let module_old = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
        assert_eq!(
            module_old.import_section().expect("import section exists").entries().len(),
            module_new.import_section().expect("import section exists").entries().len(),
            "There should be equal amount of import entries before and after serialization"
        );
    }

    #[test]
    fn serde_code() {
        let mut module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
        module.sections_mut().retain(|x| {
            if let &Section::Code(_) = x { true } else { false }
        });

        let buf = serialize(module).expect("serialization to succeed");

        let module_new: Module = deserialize_buffer(&buf).expect("deserialization to succeed");
        let module_old = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
        assert_eq!(
            module_old.code_section().expect("code section exists").bodies().len(),
            module_new.code_section().expect("code section exists").bodies().len(),
            "There should be equal amount of function bodies before and after serialization"
        );
    }

    #[test]
    fn const_() {
        use super::super::Opcode::*;

        let module = deserialize_file("./res/cases/v1/const.wasm").expect("Should be deserialized");
        let func = &module.code_section().expect("Code section to exist").bodies()[0];
        assert_eq!(func.code().elements().len(), 20);

        assert_eq!(I64Const(9223372036854775807), func.code().elements()[0]);
        assert_eq!(I64Const(-9223372036854775808), func.code().elements()[1]);
        assert_eq!(I64Const(-1152894205662152753), func.code().elements()[2]);
        assert_eq!(I64Const(-8192), func.code().elements()[3]);
        assert_eq!(I32Const(1024), func.code().elements()[4]);
        assert_eq!(I32Const(2048), func.code().elements()[5]);
        assert_eq!(I32Const(4096), func.code().elements()[6]);
        assert_eq!(I32Const(8192), func.code().elements()[7]);
        assert_eq!(I32Const(16384), func.code().elements()[8]);
        assert_eq!(I32Const(32767), func.code().elements()[9]);
        assert_eq!(I32Const(-1024), func.code().elements()[10]);
        assert_eq!(I32Const(-2048), func.code().elements()[11]);
        assert_eq!(I32Const(-4096), func.code().elements()[12]);
        assert_eq!(I32Const(-8192), func.code().elements()[13]);
        assert_eq!(I32Const(-16384), func.code().elements()[14]);
        assert_eq!(I32Const(-32768), func.code().elements()[15]);
        assert_eq!(I32Const(-2147483648), func.code().elements()[16]);
        assert_eq!(I32Const(2147483647), func.code().elements()[17]);
    }

    #[test]
    fn store() {
        use super::super::Opcode::*;

        let module = deserialize_file("./res/cases/v1/offset.wasm").expect("Should be deserialized");
        let func = &module.code_section().expect("Code section to exist").bodies()[0];

        assert_eq!(func.code().elements().len(), 5);
        assert_eq!(I64Store(0, 32), func.code().elements()[2]);
    }

    #[test]
    fn peek() {
        use super::peek_size;

        let module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
        let mut buf = serialize(module).expect("serialization to succeed");

        buf.extend_from_slice(&[1, 5, 12, 17]);

        assert_eq!(peek_size(&buf), buf.len() - 4);
    }

    #[test]
    fn peek_2() {
        use super::peek_size;

        let module = deserialize_file("./res/cases/v1/offset.wasm").expect("Should be deserialized");
        let mut buf = serialize(module).expect("serialization to succeed");

        buf.extend_from_slice(&[0, 0, 0, 0, 0, 1, 5, 12, 17]);

        assert_eq!(peek_size(&buf), buf.len() - 9);
    }

    #[test]
    fn module_default_round_trip() {
        let module1 = Module::default();
        let buf = serialize(module1).expect("Serialization should succeed");

        let module2: Module = deserialize_buffer(&buf).expect("Deserialization should succeed");
        assert_eq!(Module::default().magic, module2.magic);
    }
}
<|endoftext|>


<commit_before>extern crate base64;
extern crate blake2;
extern crate rand;
extern crate regex;
extern crate lithos;
extern crate ssh_keys;
extern crate sha2;
extern crate crypto;
#[macro_use] extern crate failure;
#[macro_use] extern crate structopt;

use std::fs::File;
use std::io::{Read, BufReader, BufRead, Write, stdout, stderr};
use std::path::Path;
use std::process::exit;

use blake2::{Blake2b, digest::VariableOutput, digest::Input};
use failure::{Error, ResultExt};
use regex::Regex;
use ssh_keys::{PublicKey, PrivateKey, openssh};
use structopt::StructOpt;

use lithos::nacl;

#[derive(Debug, StructOpt)]
#[structopt(name = "lithos_crypt",
            about = "An utility to encrypt secrets for lithos. \
                     It also allows to decrypt secrets for introspection if \
                     you have access for private key (only for debugging)")]
enum Options {
    #[structopt(name="encrypt")]
    Encrypt(EncryptOpt),
    #[structopt(name="decrypt")]
    Decrypt(DecryptOpt),
    #[structopt(name="check-key")]
    CheckKey(CheckKeyOpt),
}

#[derive(Debug, StructOpt)]
#[structopt(about = "Encrypt secret value to put in config")]
pub struct EncryptOpt {
    #[structopt(long="key-file", short="k", help="
        A openssh-formatted ed25519 public key to use for encryption
    ", parse(try_from_str="parse_public_key"))]
    key: PublicKey,
    #[structopt(long="data", short="d", help="data to encrypt")]
    data: String,
    #[structopt(long="namespace", short="n", help="
        secrets namespace. Only processes \"authorized\" to read this namespace
        will be able do decrypt the data.
    ", default_value="", parse(try_from_str="validate_namespace"))]
    namespace: String,
}

#[derive(Debug, StructOpt)]
#[structopt(about = "Check that the secret value is encrypted \
                     with specified public key")]
pub struct CheckKeyOpt {
    #[structopt(long="key-file", short="k", help="
        A openssh-formatted ed25519 public key to use for encryption
    ", parse(try_from_str="parse_public_key"))]
    key: PublicKey,
    #[structopt(long="data", short="d", help="data to encrypt")]
    data: String,
}

#[derive(Debug, StructOpt)]
#[structopt(about = "Decrypt secret value from config")]
pub struct DecryptOpt {
    #[structopt(long="key-file", short="i", help="
        A openssh-formatted ed25519 private key to use for decryption
    ", parse(try_from_str="parse_private_key"))]
    key: PrivateKey,
    #[structopt(long="data", short="d", help="base64-encoded data to decrypt")]
    data: String,
}

fn validate_namespace(namespace: &str) -> Result<String, Error> {
    if !Regex::new("^[a-zA-Z0-9_.-]*$").expect("valid re").is_match(namespace) {
        bail!("invalid namespace, \
            valid on should match regex `^[a-zA-Z0-9_.-]*$`");
    }
    Ok(namespace.to_string())
}

fn parse_public_key(filename: &str) -> Result<PublicKey, Error> {
    let mut buf = String::with_capacity(1024);
    File::open(filename)
        .and_then(|f| BufReader::new(f).read_line(&mut buf))
        .context(Path::new(filename).display().to_string())?;
    let key = openssh::parse_public_key(&buf)?;
    Ok(key)
}

fn parse_private_key(filename: &str) -> Result<PrivateKey, Error> {
    let mut buf = String::with_capacity(1024);
    File::open(filename)
        .and_then(|mut f| f.read_to_string(&mut buf))
        .context(Path::new(filename).display().to_string())?;
    let mut key = openssh::parse_private_key(&buf)?;
    Ok(key.pop().expect("at least one key parsed"))
}

fn b2_short_hash(data: &[u8]) -> String {
    let mut buf = [0u8; 6];
    let mut hash: Blake2b = VariableOutput::new(buf.len()).expect("blake2b");
    hash.process(data);
    hash.variable_result(&mut buf[..]).expect("blake2b");
    return base64::encode(&buf[..])
}

fn encrypt(e: EncryptOpt) -> Result<(), Error> {
    let key_bytes = match e.key {
        PublicKey::Ed25519(key) => key,
        _ => bail!("Only ed25519 keys are supported"),
    };
    let plaintext = format!("{}:{}", e.namespace, e.data);
    let cypher = nacl::crypto_box_edwards_seal(
        plaintext.as_bytes(), &key_bytes[..]);
    let mut buf = Vec::with_capacity(cypher.len() + 24);
    buf.write(&cypher).unwrap();
    let data = base64::encode(&buf);
    println!("v2:{}:{}:{}:{}",
        b2_short_hash(&key_bytes[..]),
        b2_short_hash(e.namespace.as_bytes()),
        b2_short_hash(e.data.as_bytes()),
        data);
    Ok(())
}

fn check_key(o: CheckKeyOpt) -> Result<(), Error> {
    let key_bytes = match o.key {
        PublicKey::Ed25519(key) => key,
        _ => bail!("Only ed25519 keys are supported"),
    };
    if !o.data.starts_with("v1:") {
        bail!("Only v1 secrets are supported");
    }
    let data = base64::decode(&o.data["v1:".len()..])?;
    if data.len() < 32+24 {
        bail!("data is too short");
    }
    if data[..32] != key_bytes {
        bail!("Key mismatch");
    }
    Ok(())
}

fn decrypt(e: DecryptOpt) -> Result<(), Error> {
    let key_bytes = match e.key {
        PrivateKey::Ed25519(key) => key,
        _ => bail!("Only ed25519 keys are supported"),
    };
    if !e.data.starts_with("v2:") {
        bail!("Only v2 secrets are supported");
    }
    let mut it = e.data.split(":");
    it.next(); // skip version
    let (key_hash, ns_hash, secr_hash, cipher) = {
        match (it.next(), it.next(), it.next(), it.next(), it.next()) {
            (Some(key), Some(ns), Some(secr), Some(cipher), None) => {
                (key, ns, secr, base64::decode(cipher)?)
            }
            _ => bail!("invalid key format"),
        }
    };

    let plain = nacl::crypto_box_edwards_seal_open(
        &cipher, &key_bytes[32..], &key_bytes[..32])?;
    let mut pair = plain.splitn(2, |&x| x == b':');
    let namespace = pair.next().unwrap();
    let secret = pair.next().ok_or(format_err!("decrypted data is invalid"))?;

    if b2_short_hash(&key_bytes[32..]) != key_hash {
        bail!("invalid key hash");
    }
    if b2_short_hash(&namespace) != ns_hash {
        bail!("invalid namespace hash");
    }
    if b2_short_hash(&secret) != secr_hash {
        bail!("invalid secret hash");
    }

    let mut err = stderr();
    err.write_all(&namespace)?;
    err.write_all(b":")?;
    err.flush()?;
    let mut out = stdout();
    out.write_all(&secret)?;
    out.flush()?;
    err.write_all(b"\n")?; // nicer in print
    Ok(())
}

fn main() {
    use Options::*;
    let opt = Options::from_args();
    let res = match opt {
        Encrypt(e) => encrypt(e),
        Decrypt(d) => decrypt(d),
        CheckKey(c) => check_key(c),
    };
    match res {
        Ok(()) => {
            exit(0);
        }
        Err(e) => {
            eprintln!("{}", e);
            exit(1);
        }
    }
}
<commit_msg>Fix `lithos_crypt check-key` command<commit_after>extern crate base64;
extern crate blake2;
extern crate rand;
extern crate regex;
extern crate lithos;
extern crate ssh_keys;
extern crate sha2;
extern crate crypto;
#[macro_use] extern crate failure;
#[macro_use] extern crate structopt;

use std::fs::File;
use std::io::{Read, BufReader, BufRead, Write, stdout, stderr};
use std::path::Path;
use std::process::exit;

use blake2::{Blake2b, digest::VariableOutput, digest::Input};
use failure::{Error, ResultExt};
use regex::Regex;
use ssh_keys::{PublicKey, PrivateKey, openssh};
use structopt::StructOpt;

use lithos::nacl;

#[derive(Debug, StructOpt)]
#[structopt(name = "lithos_crypt",
            about = "An utility to encrypt secrets for lithos. \
                     It also allows to decrypt secrets for introspection if \
                     you have access for private key (only for debugging)")]
enum Options {
    #[structopt(name="encrypt")]
    Encrypt(EncryptOpt),
    #[structopt(name="decrypt")]
    Decrypt(DecryptOpt),
    #[structopt(name="check-key")]
    CheckKey(CheckKeyOpt),
}

#[derive(Debug, StructOpt)]
#[structopt(about = "Encrypt secret value to put in config")]
pub struct EncryptOpt {
    #[structopt(long="key-file", short="k", help="
        A openssh-formatted ed25519 public key to use for encryption
    ", parse(try_from_str="parse_public_key"))]
    key: PublicKey,
    #[structopt(long="data", short="d", help="data to encrypt")]
    data: String,
    #[structopt(long="namespace", short="n", help="
        secrets namespace. Only processes \"authorized\" to read this namespace
        will be able do decrypt the data.
    ", default_value="", parse(try_from_str="validate_namespace"))]
    namespace: String,
}

#[derive(Debug, StructOpt)]
#[structopt(about = "Check that the secret value is encrypted \
                     with specified public key")]
pub struct CheckKeyOpt {
    #[structopt(long="key-file", short="k", help="
        A openssh-formatted ed25519 public key to use for encryption
    ", parse(try_from_str="parse_public_key"))]
    key: PublicKey,
    #[structopt(long="data", short="d", help="data to encrypt")]
    data: String,
}

#[derive(Debug, StructOpt)]
#[structopt(about = "Decrypt secret value from config")]
pub struct DecryptOpt {
    #[structopt(long="key-file", short="i", help="
        A openssh-formatted ed25519 private key to use for decryption
    ", parse(try_from_str="parse_private_key"))]
    key: PrivateKey,
    #[structopt(long="data", short="d", help="base64-encoded data to decrypt")]
    data: String,
}

fn validate_namespace(namespace: &str) -> Result<String, Error> {
    if !Regex::new("^[a-zA-Z0-9_.-]*$").expect("valid re").is_match(namespace) {
        bail!("invalid namespace, \
            valid on should match regex `^[a-zA-Z0-9_.-]*$`");
    }
    Ok(namespace.to_string())
}

fn parse_public_key(filename: &str) -> Result<PublicKey, Error> {
    let mut buf = String::with_capacity(1024);
    File::open(filename)
        .and_then(|f| BufReader::new(f).read_line(&mut buf))
        .context(Path::new(filename).display().to_string())?;
    let key = openssh::parse_public_key(&buf)?;
    Ok(key)
}

fn parse_private_key(filename: &str) -> Result<PrivateKey, Error> {
    let mut buf = String::with_capacity(1024);
    File::open(filename)
        .and_then(|mut f| f.read_to_string(&mut buf))
        .context(Path::new(filename).display().to_string())?;
    let mut key = openssh::parse_private_key(&buf)?;
    Ok(key.pop().expect("at least one key parsed"))
}

fn b2_short_hash(data: &[u8]) -> String {
    let mut buf = [0u8; 6];
    let mut hash: Blake2b = VariableOutput::new(buf.len()).expect("blake2b");
    hash.process(data);
    hash.variable_result(&mut buf[..]).expect("blake2b");
    return base64::encode(&buf[..])
}

fn encrypt(e: EncryptOpt) -> Result<(), Error> {
    let key_bytes = match e.key {
        PublicKey::Ed25519(key) => key,
        _ => bail!("Only ed25519 keys are supported"),
    };
    let plaintext = format!("{}:{}", e.namespace, e.data);
    let cypher = nacl::crypto_box_edwards_seal(
        plaintext.as_bytes(), &key_bytes[..]);
    let mut buf = Vec::with_capacity(cypher.len() + 24);
    buf.write(&cypher).unwrap();
    let data = base64::encode(&buf);
    println!("v2:{}:{}:{}:{}",
        b2_short_hash(&key_bytes[..]),
        b2_short_hash(e.namespace.as_bytes()),
        b2_short_hash(e.data.as_bytes()),
        data);
    Ok(())
}

fn check_key(o: CheckKeyOpt) -> Result<(), Error> {
    let key_bytes = match o.key {
        PublicKey::Ed25519(key) => key,
        _ => bail!("Only ed25519 keys are supported"),
    };
    if !o.data.starts_with("v2:") {
        bail!("Only v1 secrets are supported");
    }
    let mut it = o.data.splitn(3, ":");
    it.next(); // skip version
    let key_hash = it.next().ok_or(format_err!("bad format of data"))?;
    if b2_short_hash(&key_bytes) != key_hash {
        bail!("key doesn't match");
    }
    Ok(())
}

fn decrypt(e: DecryptOpt) -> Result<(), Error> {
    let key_bytes = match e.key {
        PrivateKey::Ed25519(key) => key,
        _ => bail!("Only ed25519 keys are supported"),
    };
    if !e.data.starts_with("v2:") {
        bail!("Only v2 secrets are supported");
    }
    let mut it = e.data.split(":");
    it.next(); // skip version
    let (key_hash, ns_hash, secr_hash, cipher) = {
        match (it.next(), it.next(), it.next(), it.next(), it.next()) {
            (Some(key), Some(ns), Some(secr), Some(cipher), None) => {
                (key, ns, secr, base64::decode(cipher)?)
            }
            _ => bail!("invalid key format"),
        }
    };

    let plain = nacl::crypto_box_edwards_seal_open(
        &cipher, &key_bytes[32..], &key_bytes[..32])?;
    let mut pair = plain.splitn(2, |&x| x == b':');
    let namespace = pair.next().unwrap();
    let secret = pair.next().ok_or(format_err!("decrypted data is invalid"))?;

    if b2_short_hash(&key_bytes[32..]) != key_hash {
        bail!("invalid key hash");
    }
    if b2_short_hash(&namespace) != ns_hash {
        bail!("invalid namespace hash");
    }
    if b2_short_hash(&secret) != secr_hash {
        bail!("invalid secret hash");
    }

    let mut err = stderr();
    err.write_all(&namespace)?;
    err.write_all(b":")?;
    err.flush()?;
    let mut out = stdout();
    out.write_all(&secret)?;
    out.flush()?;
    err.write_all(b"\n")?; // nicer in print
    Ok(())
}

fn main() {
    use Options::*;
    let opt = Options::from_args();
    let res = match opt {
        Encrypt(e) => encrypt(e),
        Decrypt(d) => decrypt(d),
        CheckKey(c) => check_key(c),
    };
    match res {
        Ok(()) => {
            exit(0);
        }
        Err(e) => {
            eprintln!("{}", e);
            exit(1);
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern crate gcc;
extern crate build_helper;

use std::env;
use std::fs;
use std::path::PathBuf;
use std::process::Command;

use build_helper::run;

fn main() {
    println!("cargo:rustc-cfg=cargobuild");

    let target = env::var("TARGET").unwrap();
    let host = env::var("HOST").unwrap();
    if !target.contains("apple") && !target.contains("msvc") {
        build_libbacktrace(&host, &target);
    }

    if target.contains("unknown-linux") {
        if target.contains("musl") {
            println!("cargo:rustc-link-lib=static=unwind");
        } else {
            println!("cargo:rustc-link-lib=dl");
            println!("cargo:rustc-link-lib=rt");
            println!("cargo:rustc-link-lib=pthread");
            println!("cargo:rustc-link-lib=gcc_s");
        }
    } else if target.contains("android") {
        println!("cargo:rustc-link-lib=dl");
        println!("cargo:rustc-link-lib=log");
        println!("cargo:rustc-link-lib=gcc");
    } else if target.contains("freebsd") {
        println!("cargo:rustc-link-lib=execinfo");
        println!("cargo:rustc-link-lib=pthread");
        println!("cargo:rustc-link-lib=gcc_s");
    } else if target.contains("dragonfly") || target.contains("bitrig") ||
              target.contains("netbsd") || target.contains("openbsd") {
        println!("cargo:rustc-link-lib=pthread");

        if target.contains("rumprun") {
            println!("cargo:rustc-link-lib=unwind");
        } else if target.contains("netbsd") || target.contains("openbsd") {
            println!("cargo:rustc-link-lib=gcc");
        } else if target.contains("bitrig") {
            println!("cargo:rustc-link-lib=c++abi");
        } else if target.contains("dragonfly") {
            println!("cargo:rustc-link-lib=gcc_pic");
        }
    } else if target.contains("apple-darwin") {
        println!("cargo:rustc-link-lib=System");
    } else if target.contains("apple-ios") {
        println!("cargo:rustc-link-lib=System");
        println!("cargo:rustc-link-lib=objc");
        println!("cargo:rustc-link-lib=framework=Security");
        println!("cargo:rustc-link-lib=framework=Foundation");
    } else if target.contains("windows") {
        if target.contains("windows-gnu") {
            println!("cargo:rustc-link-lib=gcc_eh");
        }
        println!("cargo:rustc-link-lib=advapi32");
        println!("cargo:rustc-link-lib=ws2_32");
        println!("cargo:rustc-link-lib=userenv");
        println!("cargo:rustc-link-lib=shell32");
    }
}

fn build_libbacktrace(host: &str, target: &str) {
    let src_dir = env::current_dir().unwrap().join("../libbacktrace");
    let build_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());

    println!("cargo:rustc-link-lib=static=backtrace");
    println!("cargo:rustc-link-search=native={}/.libs", build_dir.display());

    if fs::metadata(&build_dir.join(".libs/libbacktrace.a")).is_ok() {
        return
    }

    let compiler = gcc::Config::new().get_compiler();
    let ar = build_helper::cc2ar(compiler.path(), target);
    let cflags = compiler.args().iter().map(|s| s.to_str().unwrap())
                         .collect::<Vec<_>>().join(" ");
    run(Command::new("sh")
                .current_dir(&build_dir)
                .arg(src_dir.join("configure").to_str().unwrap()
                            .replace("C:\\", "/c/")
                            .replace("\\", "/"))
                .arg("--with-pic")
                .arg("--disable-multilib")
                .arg("--disable-shared")
                .arg("--disable-host-shared")
                .arg(format!("--host={}", build_helper::gnu_target(target)))
                .arg(format!("--build={}", build_helper::gnu_target(host)))
                .env("CC", compiler.path())
                .env("AR", &ar)
                .env("RANLIB", format!("{} s", ar.display()))
                .env("CFLAGS", cflags));
    run(Command::new("make")
                .current_dir(&build_dir)
                .arg(format!("INCDIR={}", src_dir.display()))
                .arg("-j").arg(env::var("NUM_JOBS").unwrap()));
}
<commit_msg>Fix compiling libstd with emscripten target. Was getting error: ``` running: "sh" "/home/flubba86/rust/src/libstd/../libbacktrace/configure" "--with-pic" "--disable-multilib" "--disable-shared" "--disable-host-shared" "--host=asmjs-unknown-emscripten" "--build=x86_64-unknown-linux-gnu" ... Invalid configuration `asmjs-unknown-emscripten': system `emscripten' not recognized ```<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern crate gcc;
extern crate build_helper;

use std::env;
use std::fs;
use std::path::PathBuf;
use std::process::Command;

use build_helper::run;

fn main() {
    println!("cargo:rustc-cfg=cargobuild");

    let target = env::var("TARGET").unwrap();
    let host = env::var("HOST").unwrap();
    if !target.contains("apple") && !target.contains("msvc") && !target.contains("emscripten"){
        build_libbacktrace(&host, &target);
    }

    if target.contains("unknown-linux") {
        if target.contains("musl") {
            println!("cargo:rustc-link-lib=static=unwind");
        } else {
            println!("cargo:rustc-link-lib=dl");
            println!("cargo:rustc-link-lib=rt");
            println!("cargo:rustc-link-lib=pthread");
            println!("cargo:rustc-link-lib=gcc_s");
        }
    } else if target.contains("android") {
        println!("cargo:rustc-link-lib=dl");
        println!("cargo:rustc-link-lib=log");
        println!("cargo:rustc-link-lib=gcc");
    } else if target.contains("freebsd") {
        println!("cargo:rustc-link-lib=execinfo");
        println!("cargo:rustc-link-lib=pthread");
        println!("cargo:rustc-link-lib=gcc_s");
    } else if target.contains("dragonfly") || target.contains("bitrig") ||
              target.contains("netbsd") || target.contains("openbsd") {
        println!("cargo:rustc-link-lib=pthread");

        if target.contains("rumprun") {
            println!("cargo:rustc-link-lib=unwind");
        } else if target.contains("netbsd") || target.contains("openbsd") {
            println!("cargo:rustc-link-lib=gcc");
        } else if target.contains("bitrig") {
            println!("cargo:rustc-link-lib=c++abi");
        } else if target.contains("dragonfly") {
            println!("cargo:rustc-link-lib=gcc_pic");
        }
    } else if target.contains("apple-darwin") {
        println!("cargo:rustc-link-lib=System");
    } else if target.contains("apple-ios") {
        println!("cargo:rustc-link-lib=System");
        println!("cargo:rustc-link-lib=objc");
        println!("cargo:rustc-link-lib=framework=Security");
        println!("cargo:rustc-link-lib=framework=Foundation");
    } else if target.contains("windows") {
        if target.contains("windows-gnu") {
            println!("cargo:rustc-link-lib=gcc_eh");
        }
        println!("cargo:rustc-link-lib=advapi32");
        println!("cargo:rustc-link-lib=ws2_32");
        println!("cargo:rustc-link-lib=userenv");
        println!("cargo:rustc-link-lib=shell32");
    }
}

fn build_libbacktrace(host: &str, target: &str) {
    let src_dir = env::current_dir().unwrap().join("../libbacktrace");
    let build_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());

    println!("cargo:rustc-link-lib=static=backtrace");
    println!("cargo:rustc-link-search=native={}/.libs", build_dir.display());

    if fs::metadata(&build_dir.join(".libs/libbacktrace.a")).is_ok() {
        return
    }

    let compiler = gcc::Config::new().get_compiler();
    let ar = build_helper::cc2ar(compiler.path(), target);
    let cflags = compiler.args().iter().map(|s| s.to_str().unwrap())
                         .collect::<Vec<_>>().join(" ");
    run(Command::new("sh")
                .current_dir(&build_dir)
                .arg(src_dir.join("configure").to_str().unwrap()
                            .replace("C:\\", "/c/")
                            .replace("\\", "/"))
                .arg("--with-pic")
                .arg("--disable-multilib")
                .arg("--disable-shared")
                .arg("--disable-host-shared")
                .arg(format!("--host={}", build_helper::gnu_target(target)))
                .arg(format!("--build={}", build_helper::gnu_target(host)))
                .env("CC", compiler.path())
                .env("AR", &ar)
                .env("RANLIB", format!("{} s", ar.display()))
                .env("CFLAGS", cflags));
    run(Command::new("make")
                .current_dir(&build_dir)
                .arg(format!("INCDIR={}", src_dir.display()))
                .arg("-j").arg(env::var("NUM_JOBS").unwrap()));
}
<|endoftext|>


<commit_before>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the terms of the
// Mozilla Public License, v. 2.0. If a copy of the MPL was not
// distributed with this file, You can obtain one at
// http://mozilla.org/MPL/2.0/.

use std::{u16, fmt, mem};
use std::default::Default;

use super::{Frame, FrameBuilder};

bitflags! {
    flags OpCode: u8 {
        const CONTINUATION  = 0b0000_0000,
        const TEXT          = 0b0000_0001,
        const BINARY        = 0b0000_0010,
        const CLOSE         = 0b0000_1000,
        const PING          = 0b0000_1001,
        const PONG          = 0b0000_1010
    }
}

#[derive(Clone, PartialEq, Eq)]
pub enum FrameType {
    Control,
    Data
}

#[derive(Clone, PartialEq, Eq)]
pub enum OpType {
    Continuation,
    Text,
    Binary,
    Close,
    Ping,
    Pong
}

#[derive(Clone)]
struct Header {
    op_code: OpCode,
    mask: bool,
    payload_len: u64,
    masking_key: [u8; 4]
}

#[derive(Clone)]
struct Payload {
    data: Vec<u8>
}

#[derive(Clone)]
pub struct WebSocketFrame {
    frame_type: FrameType,
    header: Header,
    payload: Payload
}

#[derive(Clone)]
pub struct WebSocketFrameBuilder;
impl FrameBuilder for WebSocketFrameBuilder {
    fn from_bytes(buf: &mut Vec<u8>) -> Option<Box<Frame>> {
        if buf.len() < 5 {
            trace!("Buffer length is less than 5, not worth trying...");
            return None;
        }

        let mut frame: WebSocketFrame = Default::default();

        // OpCode and FrameType
        const FIN_CLEAR_MASK: u8 = 0b0000_1111;
        let op_byte = buf[0] & FIN_CLEAR_MASK;
        match OpCode::from_bits(op_byte) {
            Some(op_code) => {
                if op_code == CONTINUATION {
                    frame.frame_type = FrameType::Data;
                    frame.header.op_code = CONTINUATION;
                } else if op_code == TEXT {
                    frame.frame_type = FrameType::Data;
                    frame.header.op_code = TEXT;
                } else if op_code == BINARY {
                    frame.frame_type = FrameType::Data;
                    frame.header.op_code = BINARY;
                } else if op_code == CLOSE {
                    frame.frame_type = FrameType::Control;
                    frame.header.op_code = CLOSE;
                } else if op_code == PING {
                    frame.frame_type = FrameType::Control;
                    frame.header.op_code = PING;
                } else if op_code == PONG {
                    frame.frame_type = FrameType::Control;
                    frame.header.op_code = PONG;
                } else {
                    unreachable!();
                }
            }
            None => {
                error!("Invalid OpCode bits: {:#b}", buf[0]);
                return None;
            }
        }

        trace!("Frame info:   Type: {} | OpType: {}", frame.frame_type, frame.op_type());

        // Payload masked (If from client, must always be true)
        let mask_bit = 0b1000_0000 & buf[1];
        frame.header.mask = mask_bit > 0;

        trace!("Frame masked: {}", frame.header.mask);

        // Payload data length
        let payload_len = 0b0111_1111 & buf[1];
        let mut next_offset: usize = 2;
        if payload_len <= 125 {
            frame.header.payload_len = payload_len as u64;
        } else if payload_len == 126 {
            let mut len = (buf[2] as u16) << 8;
            len |= buf[3] as u16;
            frame.header.payload_len = len as u64;
            next_offset = 4;
        } else {
            // We don't want to cause a panic
            if buf.len() < 10 {
                trace!("Not enough payload to continue reading payload length");
                return None;
            }

            let mut len = (buf[2] as u64) << 56;
            len |= (buf[3] as u64) << 48;
            len |= (buf[4] as u64) << 40;
            len |= (buf[5] as u64) << 32;
            len |= (buf[6] as u64) << 24;
            len |= (buf[7] as u64) << 16;
            len |= (buf[8] as u64) << 8;
            len |= buf[9] as u64;
            frame.header.payload_len = len;
            next_offset = 10;
        }

        trace!("Payload length: {}", frame.header.payload_len);

        // Optional masking key
        if frame.header.mask {
            if buf.len() <= next_offset + 4 {
                trace!("Payload masked, not enough in buffer to read masking key");
                return None;
            }
            frame.header.masking_key[0] = buf[next_offset];
            frame.header.masking_key[1] = buf[next_offset + 1];
            frame.header.masking_key[2] = buf[next_offset + 2];
            frame.header.masking_key[3] = buf[next_offset + 3];
            next_offset += 4;
        }

        if buf.len() < next_offset + frame.header.payload_len as usize {
            trace!("Not enough in buffer to read payload");
            return None;
        }

        // Payload data
        let len = frame.header.payload_len as usize;
        frame.payload.data.extend_from_slice(&buf[next_offset..(len + next_offset)]);

        // Remove from buffer
        let mut remainder = Vec::<u8>::with_capacity(buf.len() - frame.len_as_vec());
        remainder.extend_from_slice(&buf[frame.len_as_vec()..buf.len()]);
        mem::swap(buf, &mut remainder);

        return Some(Box::new(frame));
    }
}

impl WebSocketFrame {
    pub fn new(buf: &[u8], frame_type: FrameType, op_type: OpType) -> WebSocketFrame {
        WebSocketFrame {
            frame_type: frame_type,
            header: Header {
                op_code: match op_type {
                    OpType::Continuation => CONTINUATION,
                    OpType::Text => TEXT,
                    OpType::Binary => BINARY,
                    OpType::Close => CLOSE,
                    OpType::Ping => PING,
                    OpType::Pong => PONG,
                },
                mask: false,
                payload_len: buf.len() as u64,
                masking_key: [0u8; 4]
            },
            payload: Payload {
                data: buf.to_vec()
            }
        }
    }

    pub fn op_type(&self) -> OpType {
        match self.header.op_code {
            CONTINUATION => OpType::Continuation,
            TEXT => OpType::Text,
            BINARY => OpType::Binary,
            CLOSE => OpType::Close,
            PING => OpType::Ping,
            PONG => OpType::Pong,
            _ => unreachable!()
        }
    }

    pub fn frame_type(&self) -> FrameType {
        self.frame_type.clone()
    }

    pub fn is_masked(&self) -> bool {
        self.header.mask
    }

    pub fn payload_unmasked(&self) -> Vec<u8> {
        let len = self.payload.data.len();
        let mut buf = Vec::<u8>::with_capacity(len);
        for x in 0..len {
            buf.push(self.payload.data[x] ^ self.header.masking_key[x % 4]);
        }

        buf
    }
}

impl Frame for WebSocketFrame {
    fn payload(&self) -> Vec<u8> {
        if self.header.mask {
            self.payload_unmasked()
        } else {
            self.payload.data.clone()
        }
    }

    fn to_bytes(&self) -> Vec<u8> {
        let mut buf = Vec::<u8>::with_capacity(self.len_as_vec());

        // OpCode
        buf.push(self.header.op_code.bits());

        // Mask and Payload len
        let mask_bit: u8 = if self.header.mask {
            0b1000_000
        } else {
            0b0000_000
        };
        let next_7_bits: u8 = if self.header.payload_len <= 125 {
            self.header.payload_len as u8
        } else if self.header.payload_len <= u16::MAX as u64 {
            126u8
        } else {
            127u8
        };
        let next_byte: u8 = mask_bit & next_7_bits;
        buf.push(next_byte);

        // Optional payload len
        if next_byte == 126 {
            buf.push(((self.header.payload_len as u16) >> 8) as u8);
            buf.push(self.header.payload_len as u8);
        } else if next_byte == 127 {
            buf.push((self.header.payload_len >> 56) as u8);
            buf.push((self.header.payload_len >> 48) as u8);
            buf.push((self.header.payload_len >> 40) as u8);
            buf.push((self.header.payload_len >> 32) as u8);
            buf.push((self.header.payload_len >> 24) as u8);
            buf.push((self.header.payload_len >> 16) as u8);
            buf.push((self.header.payload_len >> 8) as u8);
            buf.push(self.header.payload_len as u8);
        }

        // Optional masking key
        if self.header.mask {
            buf.push(self.header.masking_key[0]);
            buf.push(self.header.masking_key[1]);
            buf.push(self.header.masking_key[2]);
            buf.push(self.header.masking_key[3]);
        }

        // Payload data
        buf.extend_from_slice(&self.payload.data[..]);

        buf
    }

    fn len_as_vec(&self) -> usize {
        let mut len = 0usize;

        // OpCode
        len += 1;

        // Mask and paylaod length
        len += 1;

        // Extended Payload length
        if self.header.payload_len > 125 && self.header.payload_len < u16::MAX as u64 {
            len += 2;
        } else if self.header.payload_len > u16::MAX as u64 {
            len += 8;
        }

        // Optional masking key
        if self.header.mask {
            len += 4;
        }

        // Payload data
        len += self.header.payload_len as usize;

        len
    }

    fn as_mut_raw_erased(&self) -> *mut () {
        let dup = Box::new(self.clone());
        return Box::into_raw(dup) as *mut _ as *mut ();
    }
}

impl Default for WebSocketFrame {
    fn default() -> WebSocketFrame {
        WebSocketFrame {
            frame_type: FrameType::Control,
            header: Header {
                op_code: CONTINUATION,
                mask: false,
                payload_len: 0u64,
                masking_key: [0u8; 4]
            },
            payload: Payload {
                data: Vec::<u8>::new()
            }
        }
    }
}

impl fmt::Debug for FrameType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            FrameType::Control => write!(f, "FrameType::Control"),
            FrameType::Data => write!(f, "FrameType::Data")
        }
    }
}

impl fmt::Display for FrameType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            FrameType::Control => write!(f, "FrameType::Control"),
            FrameType::Data => write!(f, "FrameType::Data")
        }
    }
}

impl fmt::Debug for OpType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            OpType::Continuation => write!(f, "OpType::Continuation"),
            OpType::Text => write!(f, "OpType::Text"),
            OpType::Binary => write!(f, "OpType::Binary"),
            OpType::Close => write!(f, "OpType::Close"),
            OpType::Ping => write!(f, "OpType::Ping"),
            OpType::Pong => write!(f, "OpType::Pong"),
        }
    }
}

impl fmt::Display for OpType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            OpType::Continuation => write!(f, "OpType::Continuation"),
            OpType::Text => write!(f, "OpType::Text"),
            OpType::Binary => write!(f, "OpType::Binary"),
            OpType::Close => write!(f, "OpType::Close"),
            OpType::Ping => write!(f, "OpType::Ping"),
            OpType::Pong => write!(f, "OpType::Pong"),
        }
    }
}
<commit_msg>Cleaning up ws tx framing.<commit_after>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the terms of the
// Mozilla Public License, v. 2.0. If a copy of the MPL was not
// distributed with this file, You can obtain one at
// http://mozilla.org/MPL/2.0/.

use std::{u16, fmt, mem};
use std::default::Default;

use super::{Frame, FrameBuilder};

bitflags! {
    flags OpCode: u8 {
        const CONTINUATION  = 0b0000_0000,
        const TEXT          = 0b0000_0001,
        const BINARY        = 0b0000_0010,
        const CLOSE         = 0b0000_1000,
        const PING          = 0b0000_1001,
        const PONG          = 0b0000_1010
    }
}

#[derive(Clone, PartialEq, Eq)]
pub enum FrameType {
    Control,
    Data
}

#[derive(Clone, PartialEq, Eq)]
pub enum OpType {
    Continuation,
    Text,
    Binary,
    Close,
    Ping,
    Pong
}

#[derive(Clone)]
struct Header {
    op_code: OpCode,
    mask: bool,
    payload_len: u64,
    masking_key: [u8; 4]
}

#[derive(Clone)]
struct Payload {
    data: Vec<u8>
}

#[derive(Clone)]
pub struct WebSocketFrame {
    frame_type: FrameType,
    header: Header,
    payload: Payload
}

#[derive(Clone)]
pub struct WebSocketFrameBuilder;
impl FrameBuilder for WebSocketFrameBuilder {
    fn from_bytes(buf: &mut Vec<u8>) -> Option<Box<Frame>> {
        if buf.len() < 5 {
            trace!("Buffer length is less than 5, not worth trying...");
            return None;
        }

        let mut frame: WebSocketFrame = Default::default();

        // OpCode and FrameType
        const FIN_CLEAR_MASK: u8 = 0b0000_1111;
        let op_byte = buf[0] & FIN_CLEAR_MASK;
        match OpCode::from_bits(op_byte) {
            Some(op_code) => {
                if op_code == CONTINUATION {
                    frame.frame_type = FrameType::Data;
                    frame.header.op_code = CONTINUATION;
                } else if op_code == TEXT {
                    frame.frame_type = FrameType::Data;
                    frame.header.op_code = TEXT;
                } else if op_code == BINARY {
                    frame.frame_type = FrameType::Data;
                    frame.header.op_code = BINARY;
                } else if op_code == CLOSE {
                    frame.frame_type = FrameType::Control;
                    frame.header.op_code = CLOSE;
                } else if op_code == PING {
                    frame.frame_type = FrameType::Control;
                    frame.header.op_code = PING;
                } else if op_code == PONG {
                    frame.frame_type = FrameType::Control;
                    frame.header.op_code = PONG;
                } else {
                    unreachable!();
                }
            }
            None => {
                error!("Invalid OpCode bits: {:#b}", buf[0]);
                return None;
            }
        }

        // Payload masked (If from client, must always be true)
        let mask_bit = 0b1000_0000 & buf[1];
        frame.header.mask = mask_bit > 0;

        // Payload data length
        let payload_len = 0b0111_1111 & buf[1];
        let mut next_offset: usize = 2;
        if payload_len <= 125 {
            frame.header.payload_len = payload_len as u64;
        } else if payload_len == 126 {
            let mut len = (buf[2] as u16) << 8;
            len |= buf[3] as u16;
            frame.header.payload_len = len as u64;
            next_offset = 4;
        } else {
            // We don't want to cause a panic
            if buf.len() < 10 {
                trace!("Not enough payload to continue reading payload length");
                return None;
            }

            let mut len = (buf[2] as u64) << 56;
            len |= (buf[3] as u64) << 48;
            len |= (buf[4] as u64) << 40;
            len |= (buf[5] as u64) << 32;
            len |= (buf[6] as u64) << 24;
            len |= (buf[7] as u64) << 16;
            len |= (buf[8] as u64) << 8;
            len |= buf[9] as u64;
            frame.header.payload_len = len;
            next_offset = 10;
        }

        // Optional masking key
        if frame.header.mask {
            if buf.len() <= next_offset + 4 {
                trace!("Payload masked, not enough in buffer to read masking key");
                return None;
            }
            frame.header.masking_key[0] = buf[next_offset];
            frame.header.masking_key[1] = buf[next_offset + 1];
            frame.header.masking_key[2] = buf[next_offset + 2];
            frame.header.masking_key[3] = buf[next_offset + 3];
            next_offset += 4;
        }

        if buf.len() < next_offset + frame.header.payload_len as usize {
            trace!("Not enough in buffer to read payload");
            return None;
        }

        // Payload data
        let len = frame.header.payload_len as usize;
        frame.payload.data.extend_from_slice(&buf[next_offset..(len + next_offset)]);

        // Remove from buffer
        let mut remainder = Vec::<u8>::with_capacity(buf.len() - frame.len_as_vec());
        remainder.extend_from_slice(&buf[frame.len_as_vec()..buf.len()]);
        mem::swap(buf, &mut remainder);

        return Some(Box::new(frame));
    }
}

impl WebSocketFrame {
    pub fn new(buf: &[u8], frame_type: FrameType, op_type: OpType) -> WebSocketFrame {
        WebSocketFrame {
            frame_type: frame_type,
            header: Header {
                op_code: match op_type {
                    OpType::Continuation => CONTINUATION,
                    OpType::Text => TEXT,
                    OpType::Binary => BINARY,
                    OpType::Close => CLOSE,
                    OpType::Ping => PING,
                    OpType::Pong => PONG,
                },
                mask: false,
                payload_len: buf.len() as u64,
                masking_key: [0u8; 4]
            },
            payload: Payload {
                data: buf.to_vec()
            }
        }
    }

    pub fn op_type(&self) -> OpType {
        match self.header.op_code {
            CONTINUATION => OpType::Continuation,
            TEXT => OpType::Text,
            BINARY => OpType::Binary,
            CLOSE => OpType::Close,
            PING => OpType::Ping,
            PONG => OpType::Pong,
            _ => unreachable!()
        }
    }

    pub fn frame_type(&self) -> FrameType {
        self.frame_type.clone()
    }

    pub fn is_masked(&self) -> bool {
        self.header.mask
    }

    pub fn payload_unmasked(&self) -> Vec<u8> {
        let len = self.payload.data.len();
        let mut buf = Vec::<u8>::with_capacity(len);
        for x in 0..len {
            buf.push(self.payload.data[x] ^ self.header.masking_key[x % 4]);
        }

        buf
    }
}

impl Frame for WebSocketFrame {
    fn payload(&self) -> Vec<u8> {
        if self.header.mask {
            self.payload_unmasked()
        } else {
            self.payload.data.clone()
        }
    }

    fn to_bytes(&self) -> Vec<u8> {
        let mut buf = Vec::<u8>::with_capacity(self.len_as_vec());

        // OpCode
        const FIN: u8 = 0b1000_0000;
        let op_code_with_fin = FIN | self.header.op_code.bits();
        buf.push(op_code_with_fin);

        // Mask and Payload len
        let mask_bit: u8 = if self.header.mask {
            0b1000_0000
        } else {
            0b0000_0000
        };
        let next_7_bits: u8 = if self.header.payload_len <= 125 {
            self.header.payload_len as u8
        } else if self.header.payload_len <= u16::MAX as u64 {
            126u8
        } else {
            127u8
        };
        let next_byte: u8 = mask_bit | next_7_bits;
        buf.push(next_byte);

        // Optional payload len
        if next_byte == 126 {
            buf.push(((self.header.payload_len as u16) >> 8) as u8);
            buf.push(self.header.payload_len as u8);
        } else if next_byte == 127 {
            buf.push((self.header.payload_len >> 56) as u8);
            buf.push((self.header.payload_len >> 48) as u8);
            buf.push((self.header.payload_len >> 40) as u8);
            buf.push((self.header.payload_len >> 32) as u8);
            buf.push((self.header.payload_len >> 24) as u8);
            buf.push((self.header.payload_len >> 16) as u8);
            buf.push((self.header.payload_len >> 8) as u8);
            buf.push(self.header.payload_len as u8);
        }

        // Optional masking key
        if self.header.mask {
            buf.push(self.header.masking_key[0]);
            buf.push(self.header.masking_key[1]);
            buf.push(self.header.masking_key[2]);
            buf.push(self.header.masking_key[3]);
        }

        // Payload data
        buf.extend_from_slice(&self.payload.data[..]);

        buf
    }

    fn len_as_vec(&self) -> usize {
        let mut len = 0usize;

        // OpCode
        len += 1;

        // Mask and paylaod length
        len += 1;

        // Extended Payload length
        if self.header.payload_len > 125 && self.header.payload_len < u16::MAX as u64 {
            len += 2;
        } else if self.header.payload_len > u16::MAX as u64 {
            len += 8;
        }

        // Optional masking key
        if self.header.mask {
            len += 4;
        }

        // Payload data
        len += self.header.payload_len as usize;

        len
    }

    fn as_mut_raw_erased(&self) -> *mut () {
        let dup = Box::new(self.clone());
        return Box::into_raw(dup) as *mut _ as *mut ();
    }
}

impl Default for WebSocketFrame {
    fn default() -> WebSocketFrame {
        WebSocketFrame {
            frame_type: FrameType::Control,
            header: Header {
                op_code: CONTINUATION,
                mask: false,
                payload_len: 0u64,
                masking_key: [0u8; 4]
            },
            payload: Payload {
                data: Vec::<u8>::new()
            }
        }
    }
}

impl fmt::Debug for FrameType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            FrameType::Control => write!(f, "FrameType::Control"),
            FrameType::Data => write!(f, "FrameType::Data")
        }
    }
}

impl fmt::Display for FrameType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            FrameType::Control => write!(f, "FrameType::Control"),
            FrameType::Data => write!(f, "FrameType::Data")
        }
    }
}

impl fmt::Debug for OpType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            OpType::Continuation => write!(f, "OpType::Continuation"),
            OpType::Text => write!(f, "OpType::Text"),
            OpType::Binary => write!(f, "OpType::Binary"),
            OpType::Close => write!(f, "OpType::Close"),
            OpType::Ping => write!(f, "OpType::Ping"),
            OpType::Pong => write!(f, "OpType::Pong"),
        }
    }
}

impl fmt::Display for OpType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            OpType::Continuation => write!(f, "OpType::Continuation"),
            OpType::Text => write!(f, "OpType::Text"),
            OpType::Binary => write!(f, "OpType::Binary"),
            OpType::Close => write!(f, "OpType::Close"),
            OpType::Ping => write!(f, "OpType::Ping"),
            OpType::Pong => write!(f, "OpType::Pong"),
        }
    }
}
<|endoftext|>


<commit_before>extern crate libc;
extern crate std;
extern crate sync;

use super::liblua;
use { Lua, Pushable, CopyReadable };

extern fn wrapper1(lua: *mut liblua::lua_State) -> libc::c_int {
    // TODO: in the future the value to load will not be the upvalue itself, but the value pointed by the upvalue
    let wrapper2raw = unsafe { liblua::lua_touserdata(lua, liblua::lua_upvalueindex(2)) };
    let wrapper2: fn(*mut liblua::lua_State)->libc::c_int = unsafe { std::mem::transmute(wrapper2raw) };
    wrapper2(lua)
}

fn wrapper2<T: AnyCallable>(lua: *mut liblua::lua_State) -> libc::c_int {
    let dataRaw = unsafe { liblua::lua_touserdata(lua, liblua::lua_upvalueindex(1)) };
    let data: &T = unsafe { std::mem::transmute(&dataRaw) };

    data.load_args_and_call(lua)
}

trait AnyCallable {
    fn load_args_and_call(&self, lua: *mut liblua::lua_State)
        -> libc::c_int;
}

trait Callable<Args: CopyReadable, Ret: Pushable> {
    fn do_call(&self, args: Args) -> Ret;
}

impl<Args: CopyReadable, Ret: Pushable, T: Callable<Args, Ret>> AnyCallable for T {
    fn load_args_and_call(&self, lua: *mut liblua::lua_State)
        -> libc::c_int
    {
        let mut tmpLua = Lua{lua:lua};      // this is actually pretty dangerous (even if we forget it at the end) because in case of unwinding lua_close will be called

        let argumentsCount = unsafe { liblua::lua_gettop(lua) } as int;

        let args = match CopyReadable::read_from_lua(&mut tmpLua, -argumentsCount as libc::c_int) {      // TODO: what if the user has the wrong params?
            None => {
                let errMsg = format!("wrong parameter types for callback function");
                errMsg.push_to_lua(&mut tmpLua);
                unsafe { liblua::lua_error(lua); }
                unreachable!()
            },
            Some(a) => a
        };

        let retValue = self.do_call(args);
        let nb = retValue.push_to_lua(&mut tmpLua);

        unsafe { std::mem::forget(tmpLua) };   // do not call lua_close on this temporary context

        nb as libc::c_int
    }
}

macro_rules! pushable_function(
    ($b:block | $($ty:ident),*) => (
        impl<Ret: Pushable $(, $ty : CopyReadable+Clone)*> Pushable for fn($($ty),*)->Ret {
            fn push_to_lua(&self, lua: &mut Lua) -> uint {
                // pushing the function pointer as a lightuserdata
                unsafe { liblua::lua_pushlightuserdata(lua.lua, std::mem::transmute(*self)) };

                // pushing wrapper2 as a lightuserdata
                let wrapper2 = wrapper2::<fn($($ty),*)->Ret>;
                unsafe { liblua::lua_pushlightuserdata(lua.lua, std::mem::transmute(wrapper2)) };

                // pushing wrapper1 as a closure
                unsafe { liblua::lua_pushcclosure(lua.lua, std::mem::transmute(wrapper1), 2) };

                1
            }
        }

        #[allow(unused_variable)]
        impl<Ret: Pushable $(, $ty : CopyReadable+Clone)*> Callable<($($ty),*),Ret> for fn($($ty),*)->Ret {
            fn do_call(&self, args: ($($ty),*))
                -> Ret
            {
                $b
            }
        }
    );
)

pushable_function!({ (*self)() } | )
pushable_function!({ (*self)(args) } | Arg1 )
pushable_function!({ (*self)(args.ref0().clone(), args.ref1().clone()) } | Arg1, Arg2 )
pushable_function!({ (*self)(args.ref0().clone(), args.ref1().clone(), args.ref2().clone()) } | Arg1, Arg2, Arg3 )
pushable_function!({ (*self)(args.ref0().clone(), args.ref1().clone(), args.ref2().clone(), args.ref3().clone()) } | Arg1, Arg2, Arg3, Arg4 )
pushable_function!({ (*self)(args.ref0().clone(), args.ref1().clone(), args.ref2().clone(), args.ref3().clone(), args.ref4().clone()) } | Arg1, Arg2, Arg3, Arg4, Arg5 )
// TODO: finish

#[cfg(test)]
mod tests {
    #[test]
    fn simple_function() {
        let mut lua = super::super::Lua::new();

        fn ret5() -> int { 5 };
        lua.set("ret5", ret5);

        let val: int = lua.execute("return ret5()").unwrap();
        assert_eq!(val, 5);
    }

    #[test]
    fn one_argument() {
        let mut lua = super::super::Lua::new();

        fn plus_one(val: int) -> int { val + 1 };
        lua.set("plus_one", plus_one);

        let val: int = lua.execute("return plus_one(3)").unwrap();
        assert_eq!(val, 4);
    }

    #[test]
    fn two_arguments() {
        let mut lua = super::super::Lua::new();

        fn add(val1: int, val2: int) -> int { val1 + val2 };
        lua.set("add", add);

        let val: int = lua.execute("return add(3, 7)").unwrap();
        assert_eq!(val, 10);
    }

    #[test]
    fn wrong_arguments_types() {
        let mut lua = super::super::Lua::new();

        fn add(val1: int, val2: int) -> int { val1 + val2 };
        lua.set("add", add);

        match lua.execute("return add(3, \"hello\")") {
            Ok(x) => { let _: int = x; fail!() },
            Err(_) => ()        // TODO: check for execerror
        }
    }
}
<commit_msg>Add comment to functions_write<commit_after>extern crate libc;
extern crate std;
extern crate sync;

use super::liblua;
use { Lua, Pushable, CopyReadable };

// this function is the main entry point when Lua wants to call one of our functions
extern fn wrapper1(lua: *mut liblua::lua_State) -> libc::c_int {
    // we load the pointer to the wrapper2 function from an upvalue (an upvalue is a value that was pushed alongside our function)
    let wrapper2raw = unsafe { liblua::lua_touserdata(lua, liblua::lua_upvalueindex(2)) };
    let wrapper2: fn(*mut liblua::lua_State)->libc::c_int = unsafe { std::mem::transmute(wrapper2raw) };

    wrapper2(lua)
}

// this function is called when Lua wants to call one of our functions
fn wrapper2<T: AnyCallable>(lua: *mut liblua::lua_State) -> libc::c_int {
    // loading the object that we want to call from the Lua context
    // TODO: in the future the value to load will not be the upvalue itself, but the value pointed by the upvalue
    let dataRaw = unsafe { liblua::lua_touserdata(lua, liblua::lua_upvalueindex(1)) };
    let data: &T = unsafe { std::mem::transmute(&dataRaw) };

    data.load_args_and_call(lua)
}

// this trait should be implemented on objects that are pushed to be callbacks
trait AnyCallable {
    fn load_args_and_call(&self, lua: *mut liblua::lua_State) -> libc::c_int;
}

// should be implemented by objects that can be called
// this will be removed in favor of std::ops::Fn when it is widely supported
// "Args" should be a tuple containing the parameters
trait Callable<Args: CopyReadable, Ret: Pushable> {
    fn do_call(&self, args: Args) -> Ret;
}

impl<Args: CopyReadable, Ret: Pushable, T: Callable<Args, Ret>> AnyCallable for T {
    fn load_args_and_call(&self, lua: *mut liblua::lua_State)
        -> libc::c_int
    {
        // creating a temporary Lua context in order to pass it to push & read functions
        // this is actually pretty dangerous (even if we forget it at the end) because in case of unwinding lua_close will be called
        let mut tmpLua = Lua{lua:lua};

        // trying to read the arguments
        let argumentsCount = unsafe { liblua::lua_gettop(lua) } as int;
        let args = match CopyReadable::read_from_lua(&mut tmpLua, -argumentsCount as libc::c_int) {      // TODO: what if the user has the wrong params?
            None => {
                let errMsg = format!("wrong parameter types for callback function");
                errMsg.push_to_lua(&mut tmpLua);
                unsafe { liblua::lua_error(lua); }
                unreachable!()
            },
            Some(a) => a
        };

        let retValue = self.do_call(args);

        // pushing back the result of the function on the stack
        let nb = retValue.push_to_lua(&mut tmpLua);

        // do not call lua_close on this temporary context
        unsafe { std::mem::forget(tmpLua) };

        nb as libc::c_int
    }
}

// this macro will allow us to handle multiple parameters count
macro_rules! pushable_function(
    ($b:block | $($ty:ident),*) => (
        impl<Ret: Pushable $(, $ty : CopyReadable+Clone)*> Pushable for fn($($ty),*)->Ret {
            fn push_to_lua(&self, lua: &mut Lua) -> uint {
                // pushing the function pointer as a lightuserdata
                // TODO: should be pushed as a real user data instead, for compatibility with non-functions
                unsafe { liblua::lua_pushlightuserdata(lua.lua, std::mem::transmute(*self)) };

                // pushing wrapper2 as a lightuserdata
                let wrapper2: fn(*mut liblua::lua_State)->libc::c_int = wrapper2::<fn($($ty),*)->Ret>;
                unsafe { liblua::lua_pushlightuserdata(lua.lua, std::mem::transmute(wrapper2)) };

                // pushing wrapper1 as a closure
                unsafe { liblua::lua_pushcclosure(lua.lua, std::mem::transmute(wrapper1), 2) };

                1
            }
        }

        #[allow(unused_variable)]
        impl<Ret: Pushable $(, $ty : CopyReadable+Clone)*> Callable<($($ty),*),Ret> for fn($($ty),*)->Ret {
            fn do_call(&self, args: ($($ty),*)) -> Ret {
                $b
            }
        }
    );
)

pushable_function!({ (*self)() } | )
pushable_function!({ (*self)(args) } | Arg1 )
pushable_function!({ (*self)(args.ref0().clone(), args.ref1().clone()) } | Arg1, Arg2 )
pushable_function!({ (*self)(args.ref0().clone(), args.ref1().clone(), args.ref2().clone()) } | Arg1, Arg2, Arg3 )
pushable_function!({ (*self)(args.ref0().clone(), args.ref1().clone(), args.ref2().clone(), args.ref3().clone()) } | Arg1, Arg2, Arg3, Arg4 )
pushable_function!({ (*self)(args.ref0().clone(), args.ref1().clone(), args.ref2().clone(), args.ref3().clone(), args.ref4().clone()) } | Arg1, Arg2, Arg3, Arg4, Arg5 )
// TODO: finish

#[cfg(test)]
mod tests {
    #[test]
    fn simple_function() {
        let mut lua = super::super::Lua::new();

        fn ret5() -> int { 5 };
        lua.set("ret5", ret5);

        let val: int = lua.execute("return ret5()").unwrap();
        assert_eq!(val, 5);
    }

    #[test]
    fn one_argument() {
        let mut lua = super::super::Lua::new();

        fn plus_one(val: int) -> int { val + 1 };
        lua.set("plus_one", plus_one);

        let val: int = lua.execute("return plus_one(3)").unwrap();
        assert_eq!(val, 4);
    }

    #[test]
    fn two_arguments() {
        let mut lua = super::super::Lua::new();

        fn add(val1: int, val2: int) -> int { val1 + val2 };
        lua.set("add", add);

        let val: int = lua.execute("return add(3, 7)").unwrap();
        assert_eq!(val, 10);
    }

    #[test]
    fn wrong_arguments_types() {
        let mut lua = super::super::Lua::new();

        fn add(val1: int, val2: int) -> int { val1 + val2 };
        lua.set("add", add);

        match lua.execute("return add(3, \"hello\")") {
            Ok(x) => { let _: int = x; fail!() },
            Err(_) => ()        // TODO: check for execerror
        }
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
use raft::raftpb::{Entry, Snapshot};
use std::collections::VecDeque;

// unstable.entris[i] has raft log position i+unstable.offset.
// Note that unstable.offset may be less than the highest log
// position in storage; this means that the next write to storage
// might need to truncate the log before persisting unstable.entries.
pub struct Unstable {
    // the incoming unstable snapshot, if any.
    snapshot: Option<Box<Snapshot>>,
    // all entries that have not yet been written to storage.
    entries: VecDeque<Entry>,
    offset: u64,
}

impl Unstable {
    // maybe_first_index returns the last index if it has at least one
    // unstable entry or snapshot.
    fn maybe_first_index(&self) -> Option<u64> {
        self.snapshot
            .as_ref()
            .map_or(None, |snap| Some(snap.get_metadata().get_index() + 1))
    }

    // maybe_last_index returns the last index if it has at least one
    // unstable entry or snapshot.
    fn maybe_last_index(&self) -> Option<u64> {
        match self.entries.len() {
            0 => {
                self.snapshot
                    .as_ref()
                    .map_or(None, |snap| Some(snap.get_metadata().get_index()))
            }
            len => Some(self.offset + len as u64 - 1),
        }
    }

    // maybe_term returns the term of the entry at index idx, if there
    // is any.
    fn maybe_term(&self, idx: u64) -> Option<u64> {
        if idx < self.offset {
            if self.snapshot.is_none() {
                return None;
            }

            let meta = self.snapshot.as_ref().unwrap().get_metadata().clone();
            if idx == meta.get_index() {
                return Some(meta.get_term());
            }
            return None;
        }
        match self.maybe_last_index() {
            None => None,
            Some(last) => {
                if idx > last {
                    return None;
                }
                Some(self.entries[(idx - self.offset) as usize].get_Term())
            }
        }
    }

    fn stable_to(&mut self, idx: u64, term: u64) {
        let t = self.maybe_term(idx);
        if t.is_none() {
            return;
        }

        if t.unwrap() == term && idx >= self.offset {
            let start = idx + 1 - self.offset;
            for _ in 0..start {
                self.entries.pop_front();
            }
            self.offset = idx + 1;
        }
    }

    fn stable_snap_to(&mut self, idx: u64) {
        if self.snapshot.is_none() {
            return;
        }
        if idx == self.snapshot.as_ref().unwrap().get_metadata().get_index() {
            self.snapshot = None;
        }
    }

    fn restore(&mut self, snap: Snapshot) {
        self.offset = snap.get_metadata().get_index() + 1;
        self.entries.clear();
        self.snapshot = Some(Box::new(snap));
    }

    fn truncate_and_append(&mut self, ents: &[Entry]) {
        let after = ents[0].get_Index() - 1;
        if after == self.offset + self.entries.len() as u64 - 1 {
            for e in ents {
                self.entries.push_back(e.clone());
            }
        } else if after < self.offset {
            // The log is being truncated to before our current offset
            // portion, so set the offset and replace the entries
            self.offset = after + 1;
            self.entries.clear();

            for e in ents {
                self.entries.push_back(e.clone());
            }
        } else {
            // truncate to after and copy to self.entries
            // then append
            let off = self.offset.clone();
            let cut_ents = self.cut_slice(off, after + 1);
            self.entries.clear();
            for e in cut_ents {
                self.entries.push_back(e);
            }

            for e in ents {
                self.entries.push_back(e.clone());
            }
        }
    }

    fn cut_slice(&mut self, lo: u64, hi: u64) -> Vec<Entry> {
        self.must_check_outofbounds(lo, hi);
        let l = lo as usize;
        let h = lo as usize;
        let off = self.offset as usize;
        return self.entries.drain(l - off..h - off).map(|e| e).collect();
    }

    fn must_check_outofbounds(&self, lo: u64, hi: u64) {
        if lo > hi {
            panic!("invalid unstable.slice {} > {}", lo, hi)
        }
        let upper = self.offset + self.entries.len() as u64;
        if lo < self.offset || hi > upper {
            panic!("unstable.slice[{}, {}] out of bound[{}, {}]",
                   lo,
                   hi,
                   self.offset,
                   upper)
        }
    }
}

mod test {
    use raft::raftpb::{Entry, Snapshot};
    use raft::log_unstable::Unstable;
    pub struct Obj {
        entry: Entry,
        offset: u64,
        snap: Option<Snapshot>,

        wok: bool,
        windex: u64,
    }

    fn new_entry(index: u64, term: u64) -> Entry {
        let mut e = Entry::new();
        e.set_Term(term);
        e.set_Index(index);
        e
    }

    fn new_obj(entry: Entry, offset: u64, snap: Option<Snapshot>, wok: bool, windex: u64) -> Obj {
        Obj {
            entry: entry,
            offset: offset,
            snap: snap,
            wok: wok,
            windex: windex,
        }
    }

    fn new_snapshot(index: u64, term: u64) -> Snapshot {
        use raft::raftpb::{SnapshotMetadata, Snapshot};
        let mut snap = Snapshot::new();
        let mut meta = SnapshotMetadata::new();
        meta.set_index(index);
        meta.set_term(term);
        snap.set_metadata(meta);
        snap
    }

    #[test]
    #[cfg(test)]
    fn test_maybe_first_index() {
        let tests: Vec<Obj> = vec![
            // no snapshot
            new_obj(new_entry(5,1), 5, None, false, 0),
            new_obj( Entry::new(), 0, None, false, 0,),
            // has snapshot
            new_obj( new_entry(5, 1), 5, Some(new_snapshot(4,1)), true, 5,),
            new_obj( Entry::new(), 5, Some(new_snapshot(4,1)), true, 5,),
        ];

        for tt in tests {
            let u = Unstable {
                entries: vec![tt.entry].into_iter().collect(),
                offset: tt.offset,
                snapshot: tt.snap.map_or(None, |snap| Some(Box::new(snap))),
            };
            let index = u.maybe_first_index();
            match index {
                None => assert!(!tt.wok),
                Some(index) => assert_eq!(index, tt.windex),
            }
        }
    }
}
<commit_msg>Address comments<commit_after>#![allow(dead_code)]
use raft::raftpb::{Entry, Snapshot};
use std::collections::VecDeque;

// unstable.entris[i] has raft log position i+unstable.offset.
// Note that unstable.offset may be less than the highest log
// position in storage; this means that the next write to storage
// might need to truncate the log before persisting unstable.entries.
pub struct Unstable {
    // the incoming unstable snapshot, if any.
    snapshot: Option<Box<Snapshot>>,
    // all entries that have not yet been written to storage.
    entries: VecDeque<Entry>,
    offset: u64,
}

impl Unstable {
    // maybe_first_index returns the last index if it has at least one
    // unstable entry or snapshot.
    fn maybe_first_index(&self) -> Option<u64> {
        self.snapshot
            .as_ref()
            .map_or(None, |snap| Some(snap.get_metadata().get_index() + 1))
    }

    // maybe_last_index returns the last index if it has at least one
    // unstable entry or snapshot.
    fn maybe_last_index(&self) -> Option<u64> {
        match self.entries.len() {
            0 => {
                self.snapshot
                    .as_ref()
                    .map_or(None, |snap| Some(snap.get_metadata().get_index()))
            }
            len => Some(self.offset + len as u64 - 1),
        }
    }

    // maybe_term returns the term of the entry at index idx, if there
    // is any.
    fn maybe_term(&self, idx: u64) -> Option<u64> {
        if idx < self.offset {
            if self.snapshot.is_none() {
                return None;
            }

            let meta = self.snapshot.as_ref().unwrap().get_metadata().clone();
            if idx == meta.get_index() {
                return Some(meta.get_term());
            }
            return None;
        }
        match self.maybe_last_index() {
            None => None,
            Some(last) => {
                if idx > last {
                    return None;
                }
                Some(self.entries[(idx - self.offset) as usize].get_Term())
            }
        }
    }

    fn stable_to(&mut self, idx: u64, term: u64) {
        let t = self.maybe_term(idx);
        if t.is_none() {
            return;
        }

        if t.unwrap() == term && idx >= self.offset {
            let start = idx + 1 - self.offset;
            for _ in 0..start {
                self.entries.pop_front();
            }
            self.offset = idx + 1;
        }
    }

    fn stable_snap_to(&mut self, idx: u64) {
        if self.snapshot.is_none() {
            return;
        }
        if idx == self.snapshot.as_ref().unwrap().get_metadata().get_index() {
            self.snapshot = None;
        }
    }

    fn restore(&mut self, snap: Snapshot) {
        self.offset = snap.get_metadata().get_index() + 1;
        self.entries.clear();
        self.snapshot = Some(Box::new(snap));
    }

    fn truncate_and_append(&mut self, ents: &[Entry]) {
        let after = ents[0].get_Index() - 1;
        if after == self.offset + self.entries.len() as u64 - 1 {
            for e in ents {
                self.entries.push_back(e.clone());
            }
        } else if after < self.offset {
            // The log is being truncated to before our current offset
            // portion, so set the offset and replace the entries
            self.offset = after + 1;
            self.entries.clear();

            for e in ents {
                self.entries.push_back(e.clone());
            }
        } else {
            // truncate to after and copy to self.entries
            // then append
            let off = self.offset.clone();
            let cut_ents = self.cut_slice(off, after + 1);
            self.entries.clear();
            for e in cut_ents {
                self.entries.push_back(e);
            }

            for e in ents {
                self.entries.push_back(e.clone());
            }
        }
    }

    fn cut_slice(&mut self, lo: u64, hi: u64) -> Vec<Entry> {
        self.must_check_outofbounds(lo, hi);
        let l = lo as usize;
        let h = lo as usize;
        let off = self.offset as usize;
        return self.entries.drain(l - off..h - off).map(|e| e).collect();
    }

    fn must_check_outofbounds(&self, lo: u64, hi: u64) {
        if lo > hi {
            panic!("invalid unstable.slice {} > {}", lo, hi)
        }
        let upper = self.offset + self.entries.len() as u64;
        if lo < self.offset || hi > upper {
            panic!("unstable.slice[{}, {}] out of bound[{}, {}]",
                   lo,
                   hi,
                   self.offset,
                   upper)
        }
    }
}

#[cfg(test)]
mod test {
    use raft::raftpb::{Entry, Snapshot};
    use raft::log_unstable::Unstable;
    pub struct Obj {
        entry: Entry,
        offset: u64,
        snap: Option<Snapshot>,

        wok: bool,
        windex: u64,
    }

    fn new_entry(index: u64, term: u64) -> Entry {
        let mut e = Entry::new();
        e.set_Term(term);
        e.set_Index(index);
        e
    }

    fn new_obj(entry: Entry, offset: u64, snap: Option<Snapshot>, wok: bool, windex: u64) -> Obj {
        Obj {
            entry: entry,
            offset: offset,
            snap: snap,
            wok: wok,
            windex: windex,
        }
    }

    fn new_snapshot(index: u64, term: u64) -> Snapshot {
        use raft::raftpb::{SnapshotMetadata, Snapshot};
        let mut snap = Snapshot::new();
        let mut meta = SnapshotMetadata::new();
        meta.set_index(index);
        meta.set_term(term);
        snap.set_metadata(meta);
        snap
    }

    #[test]
    fn test_maybe_first_index() {
        let tests: Vec<Obj> = vec![
            // no snapshot
            new_obj(new_entry(5,1), 5, None, false, 0),
            new_obj(Entry::new(), 0, None, false, 0,),
            // has snapshot
            new_obj(new_entry(5, 1), 5, Some(new_snapshot(4,1)), true, 5,),
            new_obj(Entry::new(), 5, Some(new_snapshot(4,1)), true, 5,),
        ];

        for tt in tests {
            let u = Unstable {
                entries: vec![tt.entry].into_iter().collect(),
                offset: tt.offset,
                snapshot: tt.snap.map_or(None, |snap| Some(Box::new(snap))),
            };
            let index = u.maybe_first_index();
            match index {
                None => assert!(!tt.wok),
                Some(index) => assert_eq!(index, tt.windex),
            }
        }
    }
}
<|endoftext|>