<commit_before>use std::mem;
use std::fmt;
use std::fs::File;
use std::io::{self, Seek, Read};
use std::io::SeekFrom::Start;

// Constants for the flags field of the mach_header
pub const MH_NOUNDEFS: u32 = 0x1; // the object file has no undefined references
pub const MH_INCRLINK: u32 = 0x2; // the object file is the output of an incremental link against a base file and can't be link edited again
pub const MH_DYLDLINK: u32 = 0x4; // the object file is input for the dynamic linker and can't be staticly link edited again
pub const MH_BINDATLOAD: u32 = 0x8; // the object file's undefined references are bound by the dynamic linker when loaded.
pub const MH_PREBOUND: u32 = 0x10; // the file has its dynamic undefined references prebound.
pub const MH_SPLIT_SEGS: u32 = 0x20; // the file has its read-only and read-write segments split
pub const MH_LAZY_INIT: u32 = 0x40; // the shared library init routine is to be run lazily via catching memory faults to its writeable segments (obsolete)
pub const MH_TWOLEVEL: u32 = 0x80; // the image is using two-level name space bindings
pub const MH_FORCE_FLAT: u32 = 0x100; // the executable is forcing all images to use flat name space bindings
pub const MH_NOMULTIDEFS: u32 = 0x200; // this umbrella guarantees no multiple defintions of symbols in its sub-images so the two-level namespace hints can always be used.
pub const MH_NOFIXPREBINDING: u32 = 0x400; // do not have dyld notify the prebinding agent about this executable
pub const MH_PREBINDABLE: u32 = 0x800; // the binary is not prebound but can have its prebinding redone. only used when MH_PREBOUND is not set.
pub const MH_ALLMODSBOUND: u32 = 0x1000; // indicates that this binary binds to all two-level namespace modules of its dependent libraries. only used when MH_PREBINDABLE and MH_TWOLEVEL are both set.
pub const MH_SUBSECTIONS_VIA_SYMBOLS: u32 = 0x2000; // safe to divide up the sections into sub-sections via symbols for dead code stripping
pub const MH_CANONICAL: u32 = 0x4000; // the binary has been canonicalized via the unprebind operation
pub const MH_WEAK_DEFINES: u32 = 0x8000; // the final linked image contains external weak symbols
pub const MH_BINDS_TO_WEAK: u32 = 0x10000; // the final linked image uses weak symbols

pub const MH_ALLOW_STACK_EXECUTION: u32 = 0x20000; // When this bit is set, all stacks in the task will be given stack execution privilege.  Only used in MH_EXECUTE filetypes.
pub const MH_ROOT_SAFE: u32 = 0x40000; // When this bit is set, the binary declares it is safe for use in processes with uid zero

pub const MH_SETUID_SAFE: u32 = 0x80000; // When this bit is set, the binary declares it is safe for use in processes when issetugid() is true

pub const MH_NO_REEXPORTED_DYLIBS: u32 = 0x100000; // When this bit is set on a dylib,  the static linker does not need to examine dependent dylibs to see if any are re-exported
pub const MH_PIE: u32 = 0x200000; // When this bit is set, the OS will load the main executable at a random address.  Only used in MH_EXECUTE filetypes.
pub const MH_DEAD_STRIPPABLE_DYLIB: u32 = 0x400000; // Only for use on dylibs.  When linking against a dylib that has this bit set, the static linker will automatically not create a LC_LOAD_DYLIB load command to the dylib if no symbols are being referenced from the dylib.
pub const MH_HAS_TLV_DESCRIPTORS: u32 = 0x800000; // Contains a section of type S_THREAD_LOCAL_VARIABLES

pub const MH_NO_HEAP_EXECUTION: u32 = 0x1000000; // When this bit is set, the OS will run the main executable with a non-executable heap even on platforms (e.g. i386) that don't require it. Only used in MH_EXECUTE filetypes.

// TODO: verify this number is correct, it was previously 0x02000000 which could indicate a typo/data entry error
pub const MH_APP_EXTENSION_SAFE: u32 = 0x2000000; // The code was linked for use in an application extension.

#[inline(always)]
pub fn flag_to_str(flag: u32) -> &'static str {
    match flag {
        MH_NOUNDEFS => "MH_NOUNDEFS",
        MH_INCRLINK => "MH_INCRLINK",
        MH_DYLDLINK => "MH_DYLDLINK",
        MH_BINDATLOAD => "MH_BINDATLOAD",
        MH_PREBOUND => "MH_PREBOUND",
        MH_SPLIT_SEGS => "MH_SPLIT_SEGS",
        MH_LAZY_INIT => "MH_LAZY_INIT",
        MH_TWOLEVEL => "MH_TWOLEVEL",
        MH_FORCE_FLAT => "MH_FORCE_FLAT",
        MH_NOMULTIDEFS => "MH_NOMULTIDEFS",
        MH_NOFIXPREBINDING => "MH_NOFIXPREBINDING",
        MH_PREBINDABLE => "MH_PREBINDABLE ",
        MH_ALLMODSBOUND => "MH_ALLMODSBOUND",
        MH_SUBSECTIONS_VIA_SYMBOLS => "MH_SUBSECTIONS_VIA_SYMBOLS",
        MH_CANONICAL => "MH_CANONICAL",
        MH_WEAK_DEFINES => "MH_WEAK_DEFINES",
        MH_BINDS_TO_WEAK => "MH_BINDS_TO_WEAK",
        MH_ALLOW_STACK_EXECUTION => "MH_ALLOW_STACK_EXECUTION",
        MH_ROOT_SAFE => "MH_ROOT_SAFE",
        MH_SETUID_SAFE => "MH_SETUID_SAFE",
        MH_NO_REEXPORTED_DYLIBS => "MH_NO_REEXPORTED_DYLIBS",
        MH_PIE => "MH_PIE",
        MH_DEAD_STRIPPABLE_DYLIB => "MH_DEAD_STRIPPABLE_DYLIB",
        MH_HAS_TLV_DESCRIPTORS => "MH_HAS_TLV_DESCRIPTORS",
        MH_NO_HEAP_EXECUTION => "MH_NO_HEAP_EXECUTION",
        MH_APP_EXTENSION_SAFE => "MH_APP_EXTENSION_SAFE",
        _ => "UNKNOWN FLAG",
    }
}

// magic constants
pub const MH_MAGIC: u32 = 0xfeedface;
pub const MH_CIGAM: u32 = 0xcefaedfe;
pub const MH_MAGIC_64: u32 = 0xfeedfacf;
pub const MH_CIGAM_64: u32 = 0xcffaedfe;

// Constants for the filetype field of the mach_header
pub const MH_OBJECT: u32 = 0x1; // relocatable object file
pub const MH_EXECUTE: u32 = 0x2; // demand paged executable file
pub const MH_FVMLIB: u32 = 0x3; // fixed VM shared library file
pub const MH_CORE: u32 = 0x4; // core file
pub const MH_PRELOAD: u32 = 0x5; // preloaded executable file
pub const MH_DYLIB: u32 = 0x6; // dynamically bound shared library
pub const MH_DYLINKER: u32 = 0x7; // dynamic link editor
pub const MH_BUNDLE: u32 = 0x8; // dynamically bound bundle file
pub const MH_DYLIB_STUB: u32 = 0x9; // shared library stub for static linking only, no section contents
pub const MH_DSYM: u32 = 0xa; // companion file with only debug sections
pub const MH_KEXT_BUNDLE: u32 = 0xb; // x86_64 kexts

pub fn filetype_to_str(filetype: u32) -> &'static str {
    match filetype {
        MH_OBJECT => "OBJECT",
        MH_EXECUTE => "EXECUTE",
        MH_FVMLIB => "FVMLIB",
        MH_CORE => "CORE",
        MH_PRELOAD => "PRELOAD",
        MH_DYLIB => "DYLIB",
        MH_DYLINKER => "DYLINKER",
        MH_BUNDLE => "BUNDLE",
        MH_DYLIB_STUB => "DYLIB_STUB",
        MH_DSYM => "DSYM",
        MH_KEXT_BUNDLE => "KEXT_BUNDLE",
        _ => "UNKNOWN FILETYPE",
    }
}

#[repr(C)]
#[derive(Clone, Copy, Default)]
pub struct Header {
    pub magic: u32,
    pub cputype: u32,
    pub cpusubtype: u8,
    pub padding1: u8,
    pub padding2: u8,
    pub caps: u8,
    pub filetype: u32,
    pub ncmds: u32,
    pub sizeofcmds: u32,
    pub flags: u32,
    pub reserved: u32,
}

pub const SIZEOF_MACH_HEADER: usize = 32;

impl fmt::Debug for Header {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "0x{:x} {} {} 0x{:x} {} {} {} 0x{:x} 0x{:x}",
               self.magic,
               self.cputype,
               self.cpusubtype,
               self.caps,
               filetype_to_str(self.filetype),
               self.ncmds,
               self.sizeofcmds,
               self.flags,
               self.reserved)
    }
}

impl Header {
    /// Returns the corresponding Mach-o header from the given byte array
    pub fn from_bytes(bytes: &[u8; SIZEOF_MACH_HEADER]) -> &Header {
        let header: &Header = unsafe { mem::transmute(bytes) };
        header
    }

    // #[cfg(feature = "no_endian_fd")]
    pub fn from_fd(fd: &mut File, offset: u64) -> io::Result<Header> {
        let mut header = [0; SIZEOF_MACH_HEADER];
        try!(fd.seek(Start(offset)));
        try!(fd.read(&mut header));
        Ok(*Header::from_bytes(&header))
    }
}
<commit_msg>mach: add some doc comments to mach constants<commit_after>use std::mem;
use std::fmt;
use std::fs::File;
use std::io::{self, Seek, Read};
use std::io::SeekFrom::Start;

// Constants for the flags field of the mach_header
/// the object file has no undefined references
pub const MH_NOUNDEFS: u32 = 0x1;
/// the object file is the output of an incremental link against a base file and can't be
/// link edited again
pub const MH_INCRLINK: u32 = 0x2;
/// the object file is input for the dynamic linker and can't be staticly link edited again
pub const MH_DYLDLINK: u32 = 0x4;
/// the object file's undefined references are bound by the dynamic linker when loaded.
pub const MH_BINDATLOAD: u32 = 0x8;
/// the file has its dynamic undefined references prebound.
pub const MH_PREBOUND: u32 = 0x10;
/// the file has its read-only and read-write segments split
pub const MH_SPLIT_SEGS: u32 = 0x20;
/// the shared library init routine is to be run lazily via catching memory faults to its writeable
/// segments (obsolete)
pub const MH_LAZY_INIT: u32 = 0x40;
/// the image is using two-level name space bindings
pub const MH_TWOLEVEL: u32 = 0x80;
/// the executable is forcing all images to use flat name space bindings
pub const MH_FORCE_FLAT: u32 = 0x100;
/// this umbrella guarantees no multiple defintions of symbols in its sub-images so the
/// two-level namespace hints can always be used.
pub const MH_NOMULTIDEFS: u32 = 0x200;
/// do not have dyld notify the prebinding agent about this executable
pub const MH_NOFIXPREBINDING: u32 = 0x400;
/// the binary is not prebound but can have its prebinding redone. only used when MH_PREBOUND is not set.
pub const MH_PREBINDABLE: u32 = 0x800;
/// indicates that this binary binds to all two-level namespace modules of its dependent libraries.
/// Only used when MH_PREBINDABLE and MH_TWOLEVEL are both set.
pub const MH_ALLMODSBOUND: u32 = 0x1000;
/// safe to divide up the sections into sub-sections via symbols for dead code stripping
pub const MH_SUBSECTIONS_VIA_SYMBOLS: u32 = 0x2000;
/// the binary has been canonicalized via the unprebind operation
pub const MH_CANONICAL: u32 = 0x4000;
/// the final linked image contains external weak symbols
pub const MH_WEAK_DEFINES: u32 = 0x8000;
/// the final linked image uses weak symbols
pub const MH_BINDS_TO_WEAK: u32 = 0x10000;
/// When this bit is set, all stacks in the task will be given stack execution privilege.
/// Only used in MH_EXECUTE filetypes.
pub const MH_ALLOW_STACK_EXECUTION: u32 = 0x20000;
/// When this bit is set, the binary declares it is safe for use in processes with uid zero
pub const MH_ROOT_SAFE: u32 = 0x40000;
/// When this bit is set, the binary declares it is safe for use in processes when issetugid() is true
pub const MH_SETUID_SAFE: u32 = 0x80000;
/// When this bit is set on a dylib,  the static linker does not need to examine dependent dylibs to
/// see if any are re-exported
pub const MH_NO_REEXPORTED_DYLIBS: u32 = 0x100000;
/// When this bit is set, the OS will load the main executable at a random address.
/// Only used in MH_EXECUTE filetypes.
pub const MH_PIE: u32 = 0x200000;
/// Only for use on dylibs.  When linking against a dylib that has this bit set, the static linker
/// will automatically not create a LC_LOAD_DYLIB load command to the dylib if no symbols are being
/// referenced from the dylib.
pub const MH_DEAD_STRIPPABLE_DYLIB: u32 = 0x400000;
/// Contains a section of type S_THREAD_LOCAL_VARIABLES
pub const MH_HAS_TLV_DESCRIPTORS: u32 = 0x800000;
/// When this bit is set, the OS will run the main executable with a non-executable heap even on
/// platforms (e.g. i386) that don't require it. Only used in MH_EXECUTE filetypes.
pub const MH_NO_HEAP_EXECUTION: u32 = 0x1000000;

// TODO: verify this number is correct, it was previously 0x02000000 which could indicate a typo/data entry error
pub const MH_APP_EXTENSION_SAFE: u32 = 0x2000000; // The code was linked for use in an application extension.

#[inline(always)]
pub fn flag_to_str(flag: u32) -> &'static str {
    match flag {
        MH_NOUNDEFS => "MH_NOUNDEFS",
        MH_INCRLINK => "MH_INCRLINK",
        MH_DYLDLINK => "MH_DYLDLINK",
        MH_BINDATLOAD => "MH_BINDATLOAD",
        MH_PREBOUND => "MH_PREBOUND",
        MH_SPLIT_SEGS => "MH_SPLIT_SEGS",
        MH_LAZY_INIT => "MH_LAZY_INIT",
        MH_TWOLEVEL => "MH_TWOLEVEL",
        MH_FORCE_FLAT => "MH_FORCE_FLAT",
        MH_NOMULTIDEFS => "MH_NOMULTIDEFS",
        MH_NOFIXPREBINDING => "MH_NOFIXPREBINDING",
        MH_PREBINDABLE => "MH_PREBINDABLE ",
        MH_ALLMODSBOUND => "MH_ALLMODSBOUND",
        MH_SUBSECTIONS_VIA_SYMBOLS => "MH_SUBSECTIONS_VIA_SYMBOLS",
        MH_CANONICAL => "MH_CANONICAL",
        MH_WEAK_DEFINES => "MH_WEAK_DEFINES",
        MH_BINDS_TO_WEAK => "MH_BINDS_TO_WEAK",
        MH_ALLOW_STACK_EXECUTION => "MH_ALLOW_STACK_EXECUTION",
        MH_ROOT_SAFE => "MH_ROOT_SAFE",
        MH_SETUID_SAFE => "MH_SETUID_SAFE",
        MH_NO_REEXPORTED_DYLIBS => "MH_NO_REEXPORTED_DYLIBS",
        MH_PIE => "MH_PIE",
        MH_DEAD_STRIPPABLE_DYLIB => "MH_DEAD_STRIPPABLE_DYLIB",
        MH_HAS_TLV_DESCRIPTORS => "MH_HAS_TLV_DESCRIPTORS",
        MH_NO_HEAP_EXECUTION => "MH_NO_HEAP_EXECUTION",
        MH_APP_EXTENSION_SAFE => "MH_APP_EXTENSION_SAFE",
        _ => "UNKNOWN FLAG",
    }
}

/// Mach Header magic constant
pub const MH_MAGIC: u32 = 0xfeedface;
pub const MH_CIGAM: u32 = 0xcefaedfe;
/// Mach Header magic constant for 64-bit
pub const MH_MAGIC_64: u32 = 0xfeedfacf;
pub const MH_CIGAM_64: u32 = 0xcffaedfe;

// Constants for the filetype field of the mach_header
/// relocatable object file
pub const MH_OBJECT: u32 = 0x1;
/// demand paged executable file
pub const MH_EXECUTE: u32 = 0x2;
/// fixed VM shared library file
pub const MH_FVMLIB: u32 = 0x3;
/// core file
pub const MH_CORE: u32 = 0x4;
/// preloaded executable file
pub const MH_PRELOAD: u32 = 0x5;
/// dynamically bound shared library
pub const MH_DYLIB: u32 = 0x6;
/// dynamic link editor
pub const MH_DYLINKER: u32 = 0x7;
/// dynamically bound bundle file
pub const MH_BUNDLE: u32 = 0x8;
/// shared library stub for static linking only, no section contents
pub const MH_DYLIB_STUB: u32 = 0x9;
/// companion file with only debug sections
pub const MH_DSYM: u32 = 0xa;
/// x86_64 kexts
pub const MH_KEXT_BUNDLE: u32 = 0xb;

pub fn filetype_to_str(filetype: u32) -> &'static str {
    match filetype {
        MH_OBJECT => "OBJECT",
        MH_EXECUTE => "EXECUTE",
        MH_FVMLIB => "FVMLIB",
        MH_CORE => "CORE",
        MH_PRELOAD => "PRELOAD",
        MH_DYLIB => "DYLIB",
        MH_DYLINKER => "DYLINKER",
        MH_BUNDLE => "BUNDLE",
        MH_DYLIB_STUB => "DYLIB_STUB",
        MH_DSYM => "DSYM",
        MH_KEXT_BUNDLE => "KEXT_BUNDLE",
        _ => "UNKNOWN FILETYPE",
    }
}

#[repr(C)]
#[derive(Clone, Copy, Default)]
pub struct Header {
    pub magic: u32,
    pub cputype: u32,
    pub cpusubtype: u8,
    pub padding1: u8,
    pub padding2: u8,
    pub caps: u8,
    pub filetype: u32,
    pub ncmds: u32,
    pub sizeofcmds: u32,
    pub flags: u32,
    pub reserved: u32,
}

pub const SIZEOF_MACH_HEADER: usize = 32;

impl fmt::Debug for Header {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "0x{:x} {} {} 0x{:x} {} {} {} 0x{:x} 0x{:x}",
               self.magic,
               self.cputype,
               self.cpusubtype,
               self.caps,
               filetype_to_str(self.filetype),
               self.ncmds,
               self.sizeofcmds,
               self.flags,
               self.reserved)
    }
}

impl Header {
    /// Returns the corresponding Mach-o header from the given byte array
    pub fn from_bytes(bytes: &[u8; SIZEOF_MACH_HEADER]) -> &Header {
        let header: &Header = unsafe { mem::transmute(bytes) };
        header
    }

    // #[cfg(feature = "no_endian_fd")]
    pub fn from_fd(fd: &mut File, offset: u64) -> io::Result<Header> {
        let mut header = [0; SIZEOF_MACH_HEADER];
        try!(fd.seek(Start(offset)));
        try!(fd.read(&mut header));
        Ok(*Header::from_bytes(&header))
    }
}
<|endoftext|>


<commit_before>//! Network ID (NID), Network Access Code (NAC), and Data Unit utilities.

use bits::Dibit;
use buffer;
use coding::bch;
use error::{Result, P25Error};

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum NetworkAccessCode {
    Default,
    ReceiveAny,
    RepeatAny,
    Other(u16),
}

impl NetworkAccessCode {
    pub fn from_bits(bits: u16) -> NetworkAccessCode {
        use self::NetworkAccessCode::*;

        assert!(bits >> 12 == 0);

        match bits {
            0x293 => Default,
            0xF7E => ReceiveAny,
            0xF7F => RepeatAny,
            _ => Other(bits),
        }
    }

    pub fn to_bits(&self) -> u16 {
        use self::NetworkAccessCode::*;

        match *self {
            Default => 0x293,
            ReceiveAny => 0xF7E,
            RepeatAny => 0xF7F,
            Other(bits) => bits,
        }
    }
}

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum DataUnit {
    VoiceHeader,
    VoiceSimpleTerminator,
    VoiceLCTerminator,
    VoiceLCFrameGroup,
    VoiceCCFrameGroup,
    DataPacket,
    TrunkingSignaling,
}

impl DataUnit {
    pub fn from_bits(bits: u8) -> Option<DataUnit> {
        use self::DataUnit::*;

        assert!(bits >> 4 == 0);

        match bits {
            0b0000 => Some(VoiceHeader),
            0b0011 => Some(VoiceSimpleTerminator),
            0b1111 => Some(VoiceLCTerminator),
            0b0101 => Some(VoiceLCFrameGroup),
            0b1010 => Some(VoiceCCFrameGroup),
            0b1100 => Some(DataPacket),
            0b0111 => Some(TrunkingSignaling),
            _ => None,
        }
    }

    pub fn to_bits(&self) -> u8 {
        use self::DataUnit::*;

        match *self {
            VoiceHeader => 0b0000,
            VoiceSimpleTerminator => 0b0011,
            VoiceLCTerminator => 0b1111,
            VoiceLCFrameGroup => 0b0101,
            VoiceCCFrameGroup => 0b1010,
            DataPacket => 0b1100,
            TrunkingSignaling => 0b0111,
        }
    }
}

#[derive(Copy, Clone, Debug)]
pub struct NetworkID {
    pub access_code: NetworkAccessCode,
    pub data_unit: DataUnit,
}

impl NetworkID {
    pub fn new(access_code: NetworkAccessCode, data_unit: DataUnit) -> NetworkID {
        NetworkID {
            access_code: access_code,
            data_unit: data_unit,
        }
    }

    pub fn from_bits(bits: u16) -> Option<NetworkID> {
        match DataUnit::from_bits(bits as u8 & 0b1111) {
            Some(du) => Some(NetworkID::new(NetworkAccessCode::from_bits(bits >> 4), du)),
            None => None,
        }
    }

    pub fn to_bits(&self) -> u16 {
        (self.access_code.to_bits() as u16) << 4 | self.data_unit.to_bits() as u16
    }

    pub fn encode(&self) -> [u8; 8] {
        let bits = self.to_bits();
        let e = bch::encode(bits);

        [
            (e >> 56) as u8,
            (e >> 48) as u8,
            (e >> 40) as u8,
            (e >> 32) as u8,
            (e >> 24) as u8,
            (e >> 16) as u8,
            (e >> 8) as u8,
            e as u8,
        ]
    }
}

pub struct NIDReceiver {
    dibits: buffer::Buffer<buffer::NIDStorage>,
}

impl NIDReceiver {
    pub fn new() -> NIDReceiver {
        NIDReceiver {
            dibits: buffer::Buffer::new(buffer::NIDStorage::new()),
        }
    }

    pub fn feed(&mut self, dibit: Dibit) -> Option<Result<NetworkID>> {
        let buf = match self.dibits.feed(dibit) {
            Some(buf) => *buf,
            None => return None,
        };

        let data = match bch::decode(buf) {
            Some((data, err)) => data,
            None => return Some(Err(P25Error::BCHUnrecoverable)),
        };

        match NetworkID::from_bits(data) {
            Some(nid) => Some(Ok(nid)),
            None => Some(Err(P25Error::UnknownNID)),
        }
    }
}
<commit_msg>Add more docs to nid module<commit_after>//! Network ID (NID), Network Access Code (NAC), and Data Unit utilities.

use bits::Dibit;
use buffer;
use coding::bch;
use error::{Result, P25Error};

/// "Digital squelch" NAC field of the NID.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum NetworkAccessCode {
    /// Default P25 NAC.
    Default,
    /// Allows receiver to unsquelch on any NAC (shouldn't be transmitted.)
    ReceiveAny,
    /// Allows repeater to unsquelch/retransmit any NAC (shouldn't be transmitted.)
    RepeatAny,
    /// Custom NAC.
    Other(u16),
}

impl NetworkAccessCode {
    /// Parse 12 bits into a NAC.
    pub fn from_bits(bits: u16) -> NetworkAccessCode {
        use self::NetworkAccessCode::*;

        assert!(bits >> 12 == 0);

        match bits {
            0x293 => Default,
            0xF7E => ReceiveAny,
            0xF7F => RepeatAny,
            _ => Other(bits),
        }
    }

    /// Convert NAC to a 12-bit word.
    pub fn to_bits(&self) -> u16 {
        use self::NetworkAccessCode::*;

        match *self {
            Default => 0x293,
            ReceiveAny => 0xF7E,
            RepeatAny => 0xF7F,
            Other(bits) => bits,
        }
    }
}

/// Data unit of associated packet.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum DataUnit {
    /// Voice header packet.
    VoiceHeader,
    /// Simple terminator packet.
    VoiceSimpleTerminator,
    /// Terminator packet with link control word.
    VoiceLCTerminator,
    /// Link control voice frame group.
    VoiceLCFrameGroup,
    /// Crypto control voice frame group.
    VoiceCCFrameGroup,
    /// Confirmed/Unconfirmed data packet
    DataPacket,
    /// Trunking signalling packet.
    TrunkingSignaling,
}

impl DataUnit {
    /// Parse 4 bits into a data unit type.
    pub fn from_bits(bits: u8) -> Option<DataUnit> {
        use self::DataUnit::*;

        assert!(bits >> 4 == 0);

        match bits {
            0b0000 => Some(VoiceHeader),
            0b0011 => Some(VoiceSimpleTerminator),
            0b1111 => Some(VoiceLCTerminator),
            0b0101 => Some(VoiceLCFrameGroup),
            0b1010 => Some(VoiceCCFrameGroup),
            0b1100 => Some(DataPacket),
            0b0111 => Some(TrunkingSignaling),
            _ => None,
        }
    }

    /// Convert data unit to 4-bit word.
    pub fn to_bits(&self) -> u8 {
        use self::DataUnit::*;

        match *self {
            VoiceHeader => 0b0000,
            VoiceSimpleTerminator => 0b0011,
            VoiceLCTerminator => 0b1111,
            VoiceLCFrameGroup => 0b0101,
            VoiceCCFrameGroup => 0b1010,
            DataPacket => 0b1100,
            TrunkingSignaling => 0b0111,
        }
    }
}

/// NID word associated with each P25 packet.
#[derive(Copy, Clone, Debug)]
pub struct NetworkID {
    pub access_code: NetworkAccessCode,
    pub data_unit: DataUnit,
}

impl NetworkID {
    /// Create an NID word from the given NAC and data unit.
    pub fn new(access_code: NetworkAccessCode, data_unit: DataUnit) -> NetworkID {
        NetworkID {
            access_code: access_code,
            data_unit: data_unit,
        }
    }

    /// Parse NID from the given 16-bit word.
    pub fn from_bits(bits: u16) -> Option<NetworkID> {
        match DataUnit::from_bits(bits as u8 & 0b1111) {
            Some(du) => Some(NetworkID::new(NetworkAccessCode::from_bits(bits >> 4), du)),
            None => None,
        }
    }

    /// Convert NID to 16-bit representation.
    pub fn to_bits(&self) -> u16 {
        (self.access_code.to_bits() as u16) << 4 | self.data_unit.to_bits() as u16
    }

    /// Encode NID into a byte sequence.
    pub fn encode(&self) -> [u8; 8] {
        let bits = self.to_bits();
        let e = bch::encode(bits);

        [
            (e >> 56) as u8,
            (e >> 48) as u8,
            (e >> 40) as u8,
            (e >> 32) as u8,
            (e >> 24) as u8,
            (e >> 16) as u8,
            (e >> 8) as u8,
            e as u8,
        ]
    }
}

/// State machine that attempts to parse a stream of dibits into an NID word.
pub struct NIDReceiver {
    /// Buffered dibits.
    dibits: buffer::Buffer<buffer::NIDStorage>,
}

impl NIDReceiver {
    /// Create a new `NIDReceiver` with an empty buffer.
    pub fn new() -> NIDReceiver {
        NIDReceiver {
            dibits: buffer::Buffer::new(buffer::NIDStorage::new()),
        }
    }

    /// Feed in a data symbol, possibly producing a decoded NID. Return `Some(Ok(nid))` if
    /// an NID was successfully parsed, `Some(Err(err))` if an unrecoverable error
    /// occurred, and `None` for no event.
    pub fn feed(&mut self, dibit: Dibit) -> Option<Result<NetworkID>> {
        let buf = match self.dibits.feed(dibit) {
            Some(buf) => *buf,
            None => return None,
        };

        let data = match bch::decode(buf) {
            Some((data, err)) => data,
            None => return Some(Err(P25Error::BCHUnrecoverable)),
        };

        match NetworkID::from_bits(data) {
            Some(nid) => Some(Ok(nid)),
            None => Some(Err(P25Error::UnknownNID)),
        }
    }
}
<|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.

#![allow(non_snake_case)]

register_long_diagnostics! {
E0454: r##"
A link name was given with an empty name. Erroneous code example:

```compile_fail,E0454
#[link(name = "")] extern {} // error: #[link(name = "")] given with empty name
```

The rust compiler cannot link to an external library if you don't give it its
name. Example:

```
#[link(name = "some_lib")] extern {} // ok!
```
"##,

E0455: r##"
Linking with `kind=framework` is only supported when targeting OS X,
as frameworks are specific to that operating system.

Erroneous code example:

```compile_fail,E0455
#[link(name = "FooCoreServices",  kind = "framework")] extern {}
// OS used to compile is Linux for example
```

To solve this error you can use conditional compilation:

```
#[cfg_attr(target="macos", link(name = "FooCoreServices", kind = "framework"))]
extern {}
```

See more: https://doc.rust-lang.org/book/conditional-compilation.html
"##,

E0458: r##"
An unknown "kind" was specified for a link attribute. Erroneous code example:

```compile_fail,E0458
#[link(kind = "wonderful_unicorn")] extern {}
// error: unknown kind: `wonderful_unicorn`
```

Please specify a valid "kind" value, from one of the following:
 * static
 * dylib
 * framework
"##,

E0459: r##"
A link was used without a name parameter. Erroneous code example:

```compile_fail,E0459
#[link(kind = "dylib")] extern {}
// error: #[link(...)] specified without `name = "foo"`
```

Please add the name parameter to allow the rust compiler to find the library
you want. Example:

```
#[link(kind = "dylib", name = "some_lib")] extern {} // ok!
```
"##,

E0463: r##"
A plugin/crate was declared but cannot be found. Erroneous code example:

```compile_fail,E0463
#![feature(plugin)]
#![plugin(cookie_monster)] // error: can't find crate for `cookie_monster`
extern crate cake_is_a_lie; // error: can't find crate for `cake_is_a_lie`
```

You need to link your code to the relevant crate in order to be able to use it
(through Cargo or the `-L` option of rustc example). Plugins are crates as
well, and you link to them the same way.
"##,

E0466: r##"
Macro import declarations were malformed.

Erroneous code examples:

```compile_fail,E0466
#[macro_use(a_macro(another_macro))] // error: invalid import declaration
extern crate some_crate;

#[macro_use(i_want = "some_macros")] // error: invalid import declaration
extern crate another_crate;
```

This is a syntax error at the level of attribute declarations. The proper
syntax for macro imports is the following:

```ignore
// In some_crate:
#[macro_export]
macro_rules! get_tacos {
    ...
}

#[macro_export]
macro_rules! get_pimientos {
    ...
}

// In your crate:
#[macro_use(get_tacos, get_pimientos)] // It imports `get_tacos` and
extern crate some_crate;               // `get_pimientos` macros from some_crate.
```

If you would like to import all exported macros, write `macro_use` with no
arguments.
"##,

}

register_diagnostics! {
    E0456, // plugin `..` is not available for triple `..`
    E0457, // plugin `..` only found in rlib format, but must be available...
    E0514, // metadata version mismatch
    E0460, // found possibly newer version of crate `..`
    E0461, // couldn't find crate `..` with expected target triple ..
    E0462, // found staticlib `..` instead of rlib or dylib
    E0464, // multiple matching crates for `..`
    E0465, // multiple .. candidates for `..` found
    E0467, // bad macro reexport
    E0468, // an `extern crate` loading macros must be at the crate root
    E0469, // imported macro not found
    E0470, // reexported macro not found
    E0519, // local crate and dependency have same (crate-name, disambiguator)
    E0523, // two dependencies have same (crate-name, disambiguator) but different SVH
}
<commit_msg>Add E0467 error explanation<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.

#![allow(non_snake_case)]

register_long_diagnostics! {
E0454: r##"
A link name was given with an empty name. Erroneous code example:

```compile_fail,E0454
#[link(name = "")] extern {} // error: #[link(name = "")] given with empty name
```

The rust compiler cannot link to an external library if you don't give it its
name. Example:

```
#[link(name = "some_lib")] extern {} // ok!
```
"##,

E0455: r##"
Linking with `kind=framework` is only supported when targeting OS X,
as frameworks are specific to that operating system.

Erroneous code example:

```compile_fail,E0455
#[link(name = "FooCoreServices",  kind = "framework")] extern {}
// OS used to compile is Linux for example
```

To solve this error you can use conditional compilation:

```
#[cfg_attr(target="macos", link(name = "FooCoreServices", kind = "framework"))]
extern {}
```

See more: https://doc.rust-lang.org/book/conditional-compilation.html
"##,

E0458: r##"
An unknown "kind" was specified for a link attribute. Erroneous code example:

```compile_fail,E0458
#[link(kind = "wonderful_unicorn")] extern {}
// error: unknown kind: `wonderful_unicorn`
```

Please specify a valid "kind" value, from one of the following:
 * static
 * dylib
 * framework
"##,

E0459: r##"
A link was used without a name parameter. Erroneous code example:

```compile_fail,E0459
#[link(kind = "dylib")] extern {}
// error: #[link(...)] specified without `name = "foo"`
```

Please add the name parameter to allow the rust compiler to find the library
you want. Example:

```
#[link(kind = "dylib", name = "some_lib")] extern {} // ok!
```
"##,

E0463: r##"
A plugin/crate was declared but cannot be found. Erroneous code example:

```compile_fail,E0463
#![feature(plugin)]
#![plugin(cookie_monster)] // error: can't find crate for `cookie_monster`
extern crate cake_is_a_lie; // error: can't find crate for `cake_is_a_lie`
```

You need to link your code to the relevant crate in order to be able to use it
(through Cargo or the `-L` option of rustc example). Plugins are crates as
well, and you link to them the same way.
"##,

E0466: r##"
Macro import declarations were malformed.

Erroneous code examples:

```compile_fail,E0466
#[macro_use(a_macro(another_macro))] // error: invalid import declaration
extern crate some_crate;

#[macro_use(i_want = "some_macros")] // error: invalid import declaration
extern crate another_crate;
```

This is a syntax error at the level of attribute declarations. The proper
syntax for macro imports is the following:

```ignore
// In some_crate:
#[macro_export]
macro_rules! get_tacos {
    ...
}

#[macro_export]
macro_rules! get_pimientos {
    ...
}

// In your crate:
#[macro_use(get_tacos, get_pimientos)] // It imports `get_tacos` and
extern crate some_crate;               // `get_pimientos` macros from some_crate.
```

If you would like to import all exported macros, write `macro_use` with no
arguments.
"##,

E0467: r##"
Macro reexport declarations were empty or malformed.

Erroneous code examples:

```compile_fail,E0467
#[macro_reexport]                    // error: no macros listed for export
extern crate macros_for_good;

#[macro_reexport(fun_macro = "foo")] // error: not a macro identifier
extern crate other_macros_for_good;
```

This is a syntax error at the level of attribute declarations.

Currently, `macro_reexport` requires at least one macro name to be listed.
Unlike `macro_use`, listing no names does not reexport all macros from the
given crate.

Decide which macros you would like to export and list them properly.

These are proper reexport declarations:

```ignore
#[macro_reexport(some_macro, another_macro)]
extern crate macros_for_good;
```
"##,

}

register_diagnostics! {
    E0456, // plugin `..` is not available for triple `..`
    E0457, // plugin `..` only found in rlib format, but must be available...
    E0514, // metadata version mismatch
    E0460, // found possibly newer version of crate `..`
    E0461, // couldn't find crate `..` with expected target triple ..
    E0462, // found staticlib `..` instead of rlib or dylib
    E0464, // multiple matching crates for `..`
    E0465, // multiple .. candidates for `..` found
    E0468, // an `extern crate` loading macros must be at the crate root
    E0469, // imported macro not found
    E0470, // reexported macro not found
    E0519, // local crate and dependency have same (crate-name, disambiguator)
    E0523, // two dependencies have same (crate-name, disambiguator) but different SVH
}
<|endoftext|>


<commit_before>// https://leetcode.com/problems/minimum-hours-of-training-to-win-a-competition/
pub fn min_number_of_hours(
    initial_energy: i32,
    initial_experience: i32,
    energy: Vec<i32>,
    experience: Vec<i32>,
) -> i32 {
    todo!()
}

fn main() {
    println!(
        "{}",
        min_number_of_hours(5, 3, vec![1, 4, 3, 2], vec![2, 6, 3, 1])
    ); // 8
    println!("{}", min_number_of_hours(2, 4, vec![1], vec![3])); // 0
}
<commit_msg>Update problem 2383<commit_after>// https://leetcode.com/problems/minimum-hours-of-training-to-win-a-competition/
pub fn min_number_of_hours(
    initial_energy: i32,
    initial_experience: i32,
    energy: Vec<i32>,
    experience: Vec<i32>,
) -> i32 {
    let total_energy: i32 = energy.into_iter().sum();
    let energy_required = total_energy - initial_energy + 1;
    let mut experience_required = 0;
    let mut total_experience = initial_experience;
    for exp in experience.into_iter() {
        if exp >= total_experience {
            let training = exp - total_experience + 1;
            experience_required += training;
            total_experience += training;
        } else {
            total_experience += exp;
        }
    }
    energy_required + experience_required
}

fn main() {
    // println!(
    //     "{}",
    //     min_number_of_hours(5, 3, vec![1, 4, 3, 2], vec![2, 6, 3, 1])
    // ); // 8
    // println!("{}", min_number_of_hours(2, 4, vec![1], vec![3])); // 0
    // println!(
    //     "{}",
    //     min_number_of_hours(1, 1, vec![1, 1, 1, 1], vec![1, 1, 1, 50])
    // ); // 51
    println!("{}", min_number_of_hours(1, 1, vec![1, 1], vec![1, 50])); // 51
                                                                        // println!("{}", min_number_of_hours(5, 3, vec![1, 4], vec![2, 5])); // 2
}
<|endoftext|>


<commit_before>// https://leetcode.com/problems/number-of-common-factors/
pub fn common_factors(a: i32, b: i32) -> i32 {
    todo!()
}

fn main() {
    println!("{}", common_factors(12, 6)); // 4
    println!("{}", common_factors(25, 30)); // 2
    println!("{}", common_factors(8, 12)); // 3
    println!("{}", common_factors(50, 48)); // 2
    println!("{}", common_factors(50, 45)); // 2
    println!("{}", common_factors(12, 24)); // 6
}
<commit_msg>Solve problem 2427<commit_after>// https://leetcode.com/problems/number-of-common-factors/
pub fn common_factors(a: i32, b: i32) -> i32 {
    let mut answer = 0;
    for i in 1..=a.min(b) {
        answer += if a % i == 0 && b % i == 0 { 1 } else { 0 };
    }
    answer
}

fn main() {
    println!("{}", common_factors(12, 6)); // 4
    println!("{}", common_factors(25, 30)); // 2
    println!("{}", common_factors(8, 12)); // 3
    println!("{}", common_factors(50, 48)); // 2
    println!("{}", common_factors(50, 45)); // 2
    println!("{}", common_factors(12, 24)); // 6
}
<|endoftext|>


<commit_before>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::Error;
use enum_dispatch::enum_dispatch;
use serde::{de::DeserializeOwned, Deserialize, Serialize};

/// A secure key/value storage engine. Create takes a policy that is enforced internally by the
/// actual backend. The policy contains public identities that the backend can translate into a
/// unique and private token for another service. Hence get and set internally will pass the
/// current service private token to the backend to gain its permissions.
#[enum_dispatch]
pub trait KVStorage {
    /// Returns an error if the backend service is not online and available.
    fn available(&self) -> Result<(), Error>;

    /// Retrieves a value from storage and fails if the backend is unavailable or the process has
    /// invalid permissions.
    fn get<T: DeserializeOwned>(&self, key: &str) -> Result<GetResponse<T>, Error>;

    /// Sets a value in storage and fails if the backend is unavailable or the process has
    /// invalid permissions.
    fn set<T: Serialize>(&mut self, key: &str, value: T) -> Result<(), Error>;

    /// Resets and clears all data held in the storage engine.
    /// Note: this should only be exposed and used for testing. Resetting the storage engine is not
    /// something that should be supported in production.
    #[cfg(any(test, feature = "testing"))]
    fn reset_and_clear(&mut self) -> Result<(), Error>;
}

/// A container for a get response that contains relevant metadata and the value stored at the
/// given key.
#[derive(Debug, Deserialize, PartialEq, Serialize)]
#[serde(tag = "data")]
pub struct GetResponse<T> {
    /// Time since Unix Epoch in seconds.
    pub last_update: u64,
    /// Value stored at the provided key
    pub value: T,
}

impl<T> GetResponse<T> {
    /// Creates a GetResponse
    pub fn new(value: T, last_update: u64) -> Self {
        Self { last_update, value }
    }
}
<commit_msg>secure-storage: implement KVStorage for &mut S where S: KVStorage<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::Error;
use enum_dispatch::enum_dispatch;
use serde::{de::DeserializeOwned, Deserialize, Serialize};

/// A secure key/value storage engine. Create takes a policy that is enforced internally by the
/// actual backend. The policy contains public identities that the backend can translate into a
/// unique and private token for another service. Hence get and set internally will pass the
/// current service private token to the backend to gain its permissions.
#[enum_dispatch]
pub trait KVStorage {
    /// Returns an error if the backend service is not online and available.
    fn available(&self) -> Result<(), Error>;

    /// Retrieves a value from storage and fails if the backend is unavailable or the process has
    /// invalid permissions.
    fn get<T: DeserializeOwned>(&self, key: &str) -> Result<GetResponse<T>, Error>;

    /// Sets a value in storage and fails if the backend is unavailable or the process has
    /// invalid permissions.
    fn set<T: Serialize>(&mut self, key: &str, value: T) -> Result<(), Error>;

    /// Resets and clears all data held in the storage engine.
    /// Note: this should only be exposed and used for testing. Resetting the storage engine is not
    /// something that should be supported in production.
    #[cfg(any(test, feature = "testing"))]
    fn reset_and_clear(&mut self) -> Result<(), Error>;
}

impl<'a, S> KVStorage for &'a mut S
where
    S: KVStorage,
{
    fn available(&self) -> Result<(), Error> {
        S::available(self)
    }

    fn get<T: DeserializeOwned>(&self, key: &str) -> Result<GetResponse<T>, Error> {
        S::get(self, key)
    }

    fn set<T: Serialize>(&mut self, key: &str, value: T) -> Result<(), Error> {
        S::set(self, key, value)
    }

    #[cfg(any(test, feature = "testing"))]
    fn reset_and_clear(&mut self) -> Result<(), Error> {
        S::reset_and_clear(self)
    }
}

/// A container for a get response that contains relevant metadata and the value stored at the
/// given key.
#[derive(Debug, Deserialize, PartialEq, Serialize)]
#[serde(tag = "data")]
pub struct GetResponse<T> {
    /// Time since Unix Epoch in seconds.
    pub last_update: u64,
    /// Value stored at the provided key
    pub value: T,
}

impl<T> GetResponse<T> {
    /// Creates a GetResponse
    pub fn new(value: T, last_update: u64) -> Self {
        Self { last_update, value }
    }
}
<|endoftext|>


<commit_before>use specs::{Entities, LazyUpdate, Read, ReadExpect, ReadStorage, System, WriteStorage};

use crate::animation::SpriteData;
use crate::combat::components::{Action, Draw, Position, State, UnitType, Velocity, Weapon};

pub struct StateUpdater;

impl<'a> System<'a> for StateUpdater {
    type SystemData = (
        WriteStorage<'a, State>,
        ReadStorage<'a, Position>,
        Entities<'a>,
        Read<'a, LazyUpdate>,
        ReadExpect<'a, SpriteData>,
    );

    fn run(&mut self, (mut state, position, entities, updater, sprite_data): Self::SystemData) {
        use specs::Join;
        let sprites = &sprite_data.sprites;

        for (state, entity) in (&mut state, &*entities).join() {
            // Handle dagger throwing.
            if state.action.is_throw_dagger() && state.ticks == 4 {
                let position: Option<&Position> = position.get(entity);
                if let Some(position) = position {
                    let dagger = entities.create();
                    updater.insert(
                        dagger,
                        Position {
                            x: position.x + 5 * state.direction as i32,
                            y: position.y,
                        },
                    );
                    updater.insert(
                        dagger,
                        Velocity {
                            x: 10 * state.direction as i32, //TODO: check velocity.
                            y: 0,
                        },
                    );
                    let frame = sprites
                        .get("dagger")
                        .and_then(|s| s.animations.get("fly"))
                        .and_then(|a| a.frames.get(0))
                        .expect("dagger entity yaml not loaded");
                    updater.insert(
                        dagger,
                        UnitType {
                            name: "dagger".to_string(),
                        },
                    );
                    updater.insert(
                        dagger,
                        Draw {
                            frame: frame.clone(),
                            animation: "fly".to_string(),
                            resource_name: "dagger".to_string(),
                            direction: state.direction,
                        },
                    );
                    updater.insert(
                        dagger,
                        Weapon {
                            ..Default::default()
                        },
                    )
                }
            }

            match state.action {
                Action::Attack(..) | Action::Hit(..) | Action::AttackRecovery => {
                    state.ticks += 1;
                    if state.ticks == state.length && state.length != 0 {
                        // assuming: that all states that match this arm have a
                        // length > 1 means we don't need to update state.length
                        // in the ResolveCollisions with the animation length
                        // whenever that system changes state of an entity.
                        if state.ticks > 1 {
                            state.action = Action::Idle;
                        }
                    }
                }
                Action::Defend(..) => {
                    // defend actions are 1 frame long, so we switch to idle
                    // immediately
                    state.action = Action::Idle;
                }
                Action::Death => {
                    state.ticks += 1;
                    if state.ticks == state.length && state.length != 0 {
                        if state.ticks > 1 {
                            state.action = Action::Dead;
                        }
                    }
                }
                _ => (),
            }
        }
    }
}
<commit_msg>correct dagger velocity.<commit_after>use specs::{Entities, LazyUpdate, Read, ReadExpect, ReadStorage, System, WriteStorage};

use crate::animation::SpriteData;
use crate::combat::components::{Action, Draw, Position, State, UnitType, Velocity, Weapon};

pub struct StateUpdater;

impl<'a> System<'a> for StateUpdater {
    type SystemData = (
        WriteStorage<'a, State>,
        ReadStorage<'a, Position>,
        Entities<'a>,
        Read<'a, LazyUpdate>,
        ReadExpect<'a, SpriteData>,
    );

    fn run(&mut self, (mut state, position, entities, updater, sprite_data): Self::SystemData) {
        use specs::Join;
        let sprites = &sprite_data.sprites;

        for (state, entity) in (&mut state, &*entities).join() {
            // Handle dagger throwing.
            if state.action.is_throw_dagger() && state.ticks == 4 {
                let position: Option<&Position> = position.get(entity);
                if let Some(position) = position {
                    let dagger = entities.create();
                    updater.insert(
                        dagger,
                        Position {
                            x: position.x + 5 * state.direction as i32,
                            y: position.y,
                        },
                    );
                    updater.insert(
                        dagger,
                        Velocity {
                            x: 20 * state.direction as i32, //TODO: change hardcoded dagger vel.
                            y: 0,
                        },
                    );
                    let frame = sprites
                        .get("dagger")
                        .and_then(|s| s.animations.get("fly"))
                        .and_then(|a| a.frames.get(0))
                        .expect("dagger entity yaml not loaded");
                    updater.insert(
                        dagger,
                        UnitType {
                            name: "dagger".to_string(),
                        },
                    );
                    updater.insert(
                        dagger,
                        Draw {
                            frame: frame.clone(),
                            animation: "fly".to_string(),
                            resource_name: "dagger".to_string(),
                            direction: state.direction,
                        },
                    );
                    updater.insert(
                        dagger,
                        Weapon {
                            ..Default::default()
                        },
                    )
                }
            }

            match state.action {
                Action::Attack(..) | Action::Hit(..) | Action::AttackRecovery => {
                    state.ticks += 1;
                    if state.ticks == state.length && state.length != 0 {
                        // assuming: that all states that match this arm have a
                        // length > 1 means we don't need to update state.length
                        // in the ResolveCollisions with the animation length
                        // whenever that system changes state of an entity.
                        if state.ticks > 1 {
                            state.action = Action::Idle;
                        }
                    }
                }
                Action::Defend(..) => {
                    // defend actions are 1 frame long, so we switch to idle
                    // immediately
                    state.action = Action::Idle;
                }
                Action::Death => {
                    state.ticks += 1;
                    if state.ticks == state.length && state.length != 0 {
                        if state.ticks > 1 {
                            state.action = Action::Dead;
                        }
                    }
                }
                _ => (),
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::env;
use git2;
use errors::*;

pub trait Config {
  fn get(&self, name: &str) -> Result<String>;
  fn get_all(&self, glob: &str) -> Result<HashMap<String, String>>;
  fn set(&mut self, name: &str, value: &str) -> Result<()>;
}

pub struct GitConfig {
  repo: git2::Repository,
  config: git2::Config,
}

impl GitConfig {
  pub fn new() -> Result<GitConfig> {
    let path =
      env::current_dir().chain_err(|| "error getting current directory")?;
    let repo = git2::Repository::discover(path)
      .chain_err(|| "error discovering git repo")?;
    let config = repo.config().chain_err(|| "error getting git config")?;

    Ok(GitConfig {
      repo: repo,
      config: config,
    })
  }

  pub fn auto_include(&mut self, filename: &str) {
    let include_path = format!("../{}", filename);
    let file_exists = self.repo.workdir().map(|path| {
      let mut path_buf = path.to_path_buf();
      path_buf.push(&filename);
      path_buf.exists()
    });

    // Make sure .git-together exists
    if !file_exists.unwrap_or(false) {
      return;
    }

    if self.already_included(&include_path).unwrap_or(true) {
      return;
    }

    let _ = self.config.set_multivar("include.path", "^$", &include_path);
  }

  fn already_included(&self, include_path: &str) -> Result<bool> {
    let local_config = self.config
      .open_level(git2::ConfigLevel::Local)
      .chain_err(|| "error opening local git config")?;
    let entries = local_config.entries(None)
      .chain_err(|| "error getting git config entries")?;
    Ok(entries.into_iter().any(|entry| {
      entry.map(|entry| entry.value() == Some(include_path)).unwrap_or(true)
    }))
  }
}

impl Config for GitConfig {
  fn get(&self, name: &str) -> Result<String> {
    self.config
      .get_string(name)
      .chain_err(|| format!("error getting git config for '{}'", name))
  }

  fn get_all(&self, glob: &str) -> Result<HashMap<String, String>> {
    let mut result = HashMap::new();
    let entries = self.config
      .entries(Some(glob))
      .chain_err(|| "error getting git config entries")?;
    for entry in &entries {
      let entry = entry.chain_err(|| "error getting git config entry")?;
      if let (Some(name), Some(value)) = (entry.name(), entry.value()) {
        result.insert(name.into(), value.into());
      }
    }
    Ok(result)
  }

  fn set(&mut self, name: &str, value: &str) -> Result<()> {
    self.config
      .set_str(name, value)
      .chain_err(|| format!("error setting git config '{}': '{}'", name, value))
  }
}
<commit_msg>NamespacedConfig<commit_after>use std::collections::HashMap;
use std::env;
use git2;
use errors::*;

pub trait Config {
  fn get(&self, name: &str) -> Result<String>;
  fn get_all(&self, glob: &str) -> Result<HashMap<String, String>>;
  fn set(&mut self, name: &str, value: &str) -> Result<()>;
}

pub struct NamespacedConfig<C> {
  namespace: String,
  config: C,
}

impl<C> NamespacedConfig<C> {
  fn namespaced(&self, name: &str) -> String {
    format!("{}.{}", self.namespace, name)
  }
}

impl<C: Config> Config for NamespacedConfig<C> {
  fn get(&self, name: &str) -> Result<String> {
    self.config.get(&self.namespaced(name))
  }

  fn get_all(&self, glob: &str) -> Result<HashMap<String, String>> {
    self.config.get_all(&self.namespaced(glob))
  }

  fn set(&mut self, name: &str, value: &str) -> Result<()> {
    let name = self.namespaced(name);
    self.config.set(&name, value)
  }
}

pub struct GitConfig {
  repo: git2::Repository,
  config: git2::Config,
}

impl GitConfig {
  pub fn new() -> Result<GitConfig> {
    let path =
      env::current_dir().chain_err(|| "error getting current directory")?;
    let repo = git2::Repository::discover(path)
      .chain_err(|| "error discovering git repo")?;
    let config = repo.config().chain_err(|| "error getting git config")?;

    Ok(GitConfig {
      repo: repo,
      config: config,
    })
  }

  pub fn auto_include(&mut self, filename: &str) {
    let include_path = format!("../{}", filename);
    let file_exists = self.repo.workdir().map(|path| {
      let mut path_buf = path.to_path_buf();
      path_buf.push(&filename);
      path_buf.exists()
    });

    // Make sure .git-together exists
    if !file_exists.unwrap_or(false) {
      return;
    }

    if self.already_included(&include_path).unwrap_or(true) {
      return;
    }

    let _ = self.config.set_multivar("include.path", "^$", &include_path);
  }

  fn already_included(&self, include_path: &str) -> Result<bool> {
    let local_config = self.config
      .open_level(git2::ConfigLevel::Local)
      .chain_err(|| "error opening local git config")?;
    let entries = local_config.entries(None)
      .chain_err(|| "error getting git config entries")?;
    Ok(entries.into_iter().any(|entry| {
      entry.map(|entry| entry.value() == Some(include_path)).unwrap_or(true)
    }))
  }
}

impl Config for GitConfig {
  fn get(&self, name: &str) -> Result<String> {
    self.config
      .get_string(name)
      .chain_err(|| format!("error getting git config for '{}'", name))
  }

  fn get_all(&self, glob: &str) -> Result<HashMap<String, String>> {
    let mut result = HashMap::new();
    let entries = self.config
      .entries(Some(glob))
      .chain_err(|| "error getting git config entries")?;
    for entry in &entries {
      let entry = entry.chain_err(|| "error getting git config entry")?;
      if let (Some(name), Some(value)) = (entry.name(), entry.value()) {
        result.insert(name.into(), value.into());
      }
    }
    Ok(result)
  }

  fn set(&mut self, name: &str, value: &str) -> Result<()> {
    self.config
      .set_str(name, value)
      .chain_err(|| format!("error setting git config '{}': '{}'", name, value))
  }
}
<|endoftext|>


<commit_before>// Copyright 2015-2016 Intecture Developers. See the COPYRIGHT file at the
// top-level directory of this distribution and at
// https://intecture.io/COPYRIGHT.
//
// Licensed under the Mozilla Public License 2.0 <LICENSE or
// https://www.tldrlegal.com/l/mpl-2.0>. This file may not be copied,
// modified, or distributed except according to those terms.

//! Payloads are self-contained projects that encapsulate a specific
//! feature or system function. Think of them as reusable chunks of
//! code that can be run across multiple hosts. Any time you have a
//! task that you want to repeat, it should probably go into a
//! payload.
//!
//! For example, a payload could handle installing a specific
//! package, such as Nginx. Or, you could create a payload that
//! configures iptables.
//!
//! # Examples
//!
//! ```no_run
//! # use inapi::{Host, Payload};
#![cfg_attr(feature = "local-run", doc = "# let mut host = Host::local(Some(\"nodes/mynode.json\")).unwrap();")]
#![cfg_attr(feature = "remote-run", doc = "# let mut host = Host::connect(\"nodes/mynode.json\").unwrap();")]
//! let payload = Payload::new("nginx::install").unwrap(); // format is "payload::executable"
//! payload.run(&mut host, None).unwrap();
//! ```

pub mod config;
pub mod ffi;

use czmq::{ZMsg, ZPoller, ZSock, ZSockType, ZSys};
use error::{Error, Result};
use host::{Host,HostSendRecv};
use project::Language;
use self::config::Config;
use serde_json;
use std::env::{current_dir, set_current_dir};
use std::process::Command;
use std::path::PathBuf;
use std::thread;
use zdaemon::ConfigFile;

/// Container for running a Payload.
pub struct Payload {
    /// Path to the payload directory.
    path: PathBuf,
    /// Name of the executable/source file to run.
    artifact: Option<String>,
    /// Language the payload is written in.
    language: Language,
}

impl Payload {
    /// Create a new Payload using the payload::artifact notation.
    /// This notation is simply "payload" + separator ("::") +
    /// "executable/source file". For example: "nginx::install".
    ///
    /// By default, payloads live in
    /// <project root>/payloads/<payload_name>. Thus the payload name
    /// "nginx" will resolve to <project root>/payloads/nginx/. You
    /// can also specify an absolute path to your payload, which will
    /// override the resolved path.
    ///
    /// ```no_run
    /// # use inapi::Payload;
    /// // Using standard payload/artifact notation...
    /// let payload = Payload::new("iptables::update").unwrap();
    ///
    /// // Using an absolute path...
    /// let payload = Payload::new("/mnt/intecture/payloads/iptables::update").unwrap();
    /// ```
    pub fn new(payload_artifact: &str) -> Result<Payload> {
        let mut parts: Vec<&str> = payload_artifact.split("::").collect();
        let payload = if parts.len() > 0 {
            parts.remove(0)
        } else {
            return Err(Error::Generic("Invalid payload string".into()));
        };

        let mut buf = PathBuf::from("payloads");
        buf.push(payload);

        buf.push("payload.json");
        let config = try!(Config::load(&buf));
        buf.pop();

        // Check dependencies
        if let Some(deps) = config.dependencies {
            try!(Self::check_deps(&deps));
        }

        Ok(Payload {
            path: buf,
            artifact: if parts.len() > 1 {
                Some(parts.remove(1).into())
            } else {
                None
            },
            language: config.language,
        })
    }

    /// Compile a payload's source code. This function is also called
    /// by Payload::run(), but is useful for precompiling payloads
    /// ahead of time to catch build errors early.
    ///
    /// Note that this is only useful for compiled languages. If this
    /// function is run on a payload that uses an interpreted
    /// language, it will safely be ignored.
    pub fn build(&self) -> Result<()> {
        let mut make_path = self.path.clone();
        make_path.push("Makefile");

        match self.language {
            Language::C | Language::Rust if make_path.exists() && make_path.is_file() => {
                let current_dir = try!(current_dir());
                try!(set_current_dir(&self.path));

                let output = try!(Command::new("make").output());

                try!(set_current_dir(&current_dir));

                if !output.status.success() {
                    return Err(Error::BuildFailed(try!(String::from_utf8(output.stderr))).into());
                }
            },
            Language::Rust => {
                let manifest_path = format!("{}/Cargo.toml", self.path.to_str().unwrap());
                let output = try!(Command::new("cargo").args(&["build", "--release", "--manifest-path", &manifest_path]).output());
                if !output.status.success() {
                    return Err(Error::BuildFailed(try!(String::from_utf8(output.stderr))).into());
                }
            },
            _ => ()
        }

        Ok(())
    }

    /// Execute the payload's artifact.
    ///
    /// For compiled languages, the artifact will be executed
    /// directly. For interpreted languages, the artifact will be
    /// passed as an argument to the interpreter.
    ///
    /// ```no_run
    /// # use inapi::{Host, Payload};
    #[cfg_attr(feature = "local-run", doc = "# let mut host = Host::local(Some(\"nodes/mynode.json\")).unwrap();")]
    #[cfg_attr(feature = "remote-run", doc = "# let mut host = Host::connect(\"nodes/mynode.json\").unwrap();")]
    /// let payload = Payload::new("iptables::configure").unwrap();
    /// payload.run(&mut host, Some(vec![
    ///     "add_rule",
    ///     "..."
    /// ])).unwrap();
    /// ```
    pub fn run(&self, host: &mut Host, user_args: Option<Vec<&str>>) -> Result<()> {
        // XXX This ugly cloning is a wasteful solution. New ZMQ
        // socket types (SERVER & CLIENT) are threadsafe, which will
        // allow us to thread the ZMQ poller and avoid having to
        // clone half the world. When these are implemented, this
        // code should be changed.

        // Build payload to make sure it's up to date
        try!(self.build());

        let artifact_default = self.artifact.as_ref().map(|a| &**a).unwrap_or("main");
        let api_endpoint = format!("ipc://{}/{}_api.ipc", self.path.to_str().unwrap(), artifact_default);
        let mut api_pipe = ZSock::new(ZSockType::DEALER);
        try!(api_pipe.bind(&api_endpoint));

        let file_endpoint = format!("ipc://{}/{}_file.ipc", self.path.to_str().unwrap(), artifact_default);
        let mut file_pipe = ZSock::new(ZSockType::DEALER);
        try!(file_pipe.bind(&file_endpoint));

        let (mut parent, child) = try!(ZSys::create_pipe());
        let language = self.language.clone();
        let mut payload_path = self.path.clone();
        let artifact = self.artifact.clone();
        let user_args_c: Option<Vec<String>> = match user_args {
            Some(a) => Some(a.into_iter().map(|arg| String::from(arg)).collect()),
            None => None,
        };

        let handle = thread::spawn(move || {
            match language {
                Language::C => {
                    payload_path.push(artifact.as_ref().map(|a| &**a).unwrap_or("main"));

                    let mut args = vec![api_endpoint, file_endpoint];
                    if let Some(mut a) = user_args_c {
                        args.append(&mut a);
                    }

                    let output = try!(Command::new(payload_path.to_str().unwrap()).args(&args).output());

                    if !output.status.success() {
                        try!(child.signal(0));
                        return Err(Error::RunFailed(try!(String::from_utf8(output.stderr))).into());
                    }
                },
                Language::Php => {
                    payload_path.push("src");
                    payload_path.push(artifact.as_ref().map(|a| &**a).unwrap_or("main"));
                    if payload_path.extension().is_none() {
                        payload_path.set_extension("php");
                    }

                    let mut args = vec![payload_path.to_str().unwrap().into(), api_endpoint, file_endpoint];
                    if let Some(mut a) = user_args_c {
                        args.append(&mut a);
                    }

                    let output = try!(Command::new("php").args(&args).output());

                    if !output.status.success() {
                        try!(child.signal(0));
                        return Err(Error::RunFailed(try!(String::from_utf8(output.stderr))).into());
                    }
                },
                Language::Rust => {
                    payload_path.push("Cargo.toml");

                    let mut args = vec![
                        "run".into(),
                        "--release".into(),
                        "--manifest-path".into(),
                        payload_path.to_str().unwrap().into()
                    ];

                    if let Some(a) = artifact {
                        args.push("--bin".into());
                        args.push(a);
                    }

                    args.push("--".into());
                    args.push(api_endpoint);
                    args.push(file_endpoint);

                    if let Some(mut a) = user_args_c {
                        args.append(&mut a);
                    }

                    let output = try!(Command::new("cargo").args(&args).output());

                    if !output.status.success() {
                        try!(child.signal(0));
                        return Err(Error::RunFailed(try!(String::from_utf8(output.stderr))).into());
                    }
                }
            }

            try!(child.signal(0));
            Ok(())
        });

        // Send data to payload
        let json = try!(serde_json::to_string(host.data()));
        try!(api_pipe.send_str(&json));

        let mut poller = try!(ZPoller::new());
        try!(poller.add(&mut parent));
        try!(poller.add(&mut api_pipe));
        try!(poller.add(&mut file_pipe));

        loop {
            let sock: Option<ZSock> = poller.wait(None);
            if let Some(mut s) = sock {
                if s == api_pipe || s == file_pipe {
                    let msg = try!(ZMsg::recv(&mut s));
                    try!(host.send(msg));
                }
                else if s == parent {
                    break;
                } else {
                    unreachable!();
                }
            }

            if poller.terminated() {
                break;
            }
        }

        let cmd_result: Result<()> = try!(handle.join());
        try!(cmd_result);

        Ok(())
    }

    fn check_deps(payloads: &[String]) -> Result<()> {
        for payload in payloads {
            try!(Payload::new(payload));
        }

        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use czmq::{ZSock, ZSockType};
    use host::Host;
    use project::Language;
    use std::fs;
    use std::io::Write;
    use std::path::PathBuf;
    use std::process::Command;
    use std::thread;
    use super::*;
    use super::config::Config;
    use tempdir::TempDir;
    use zdaemon::ConfigFile;

    #[test]
    fn test_new_nodeps() {
        let _ = ::_MOCK_ENV.init();

        let tempdir = TempDir::new("test_payload_new_nodeps").unwrap();
        let mut buf = tempdir.path().to_owned();

        create_cargo_proj(&mut buf);

        let conf = Config {
            author: "Dr. Hibbert".into(),
            repository: "https://github.com/dhibbz/hehehe.git".into(),
            language: Language::Rust,
            dependencies: Some(vec!["missing_payload".into()]),
        };

        buf.push("payload.json");
        conf.save(&buf).unwrap();
        buf.pop();

        assert!(Payload::new(buf.to_str().unwrap()).is_err());
    }

    #[test]
    fn test_build_rust() {
        let _ = ::_MOCK_ENV.init();

        let tempdir = TempDir::new("test_payload_build_rust").unwrap();
        let mut buf = tempdir.path().to_owned();

        create_cargo_proj(&mut buf);

        let conf = Config {
            author: "Dr. Hibbert".into(),
            repository: "https://github.com/dhibbz/hehehe.git".into(),
            language: Language::Rust,
            dependencies: None,
        };

        buf.push("payload.json");
        conf.save(&buf).unwrap();
        buf.pop();

        let payload = Payload::new(buf.to_str().unwrap()).unwrap();
        payload.build().unwrap();
    }

    #[test]
    fn test_build_c() {
        let _ = ::_MOCK_ENV.init();

        let tempdir = TempDir::new("test_payload_build_c").unwrap();
        let mut buf = tempdir.path().to_owned();

        buf.push("Makefile");
        let mut fh = fs::File::create(&buf).unwrap();
        fh.write_all(b"all:
\ttouch test").unwrap();
        buf.pop();

        let conf = Config {
            author: "Dr. Hibbert".into(),
            repository: "https://github.com/dhibbz/hehehe.git".into(),
            language: Language::C,
            dependencies: None,
        };

        buf.push("payload.json");
        conf.save(&buf).unwrap();
        buf.pop();

        let payload = Payload::new(buf.to_str().unwrap()).unwrap();
        payload.build().unwrap();

        buf.push("test");
        assert!(buf.exists());
    }

    #[test]
    fn test_run() {
        let _ = ::_MOCK_ENV.init();

        let tempdir = TempDir::new("test_payload_run").unwrap();
        let mut buf = tempdir.path().to_owned();

        create_cargo_proj(&mut buf);

        let conf = Config {
            author: "Dr. Hibbert".into(),
            repository: "https://github.com/dhibbz/hehehe.git".into(),
            language: Language::Rust,
            dependencies: None,
        };

        buf.push("payload.json");
        conf.save(&buf).unwrap();
        buf.pop();

        let payload_name = buf.into_os_string().into_string().unwrap();
        let payload_name_clone = payload_name.clone();

        let handle = thread::spawn(move || {
            let s = ZSock::new(ZSockType::DEALER);
            s.connect(&format!("ipc://{}/main_api.ipc", payload_name_clone)).unwrap();
            s.recv_str().unwrap().unwrap();
        });

        let mut host = Host::test_new(None, None, None, None);
        let payload = Payload::new(&payload_name).unwrap();
        payload.run(&mut host, Some(vec!["abc"])).unwrap();

        handle.join().unwrap();
    }

    fn create_cargo_proj(buf: &mut PathBuf) {
        let status = Command::new("cargo")
                             .args(&["init", buf.to_str().unwrap(), "--bin", "--name", "payload"])
                             .status()
                             .expect("Failed to execute process");

        assert!(status.success());
    }
}
<commit_msg>Command stdout for Payload::build and Payload::run inherited from parent<commit_after>// Copyright 2015-2016 Intecture Developers. See the COPYRIGHT file at the
// top-level directory of this distribution and at
// https://intecture.io/COPYRIGHT.
//
// Licensed under the Mozilla Public License 2.0 <LICENSE or
// https://www.tldrlegal.com/l/mpl-2.0>. This file may not be copied,
// modified, or distributed except according to those terms.

//! Payloads are self-contained projects that encapsulate a specific
//! feature or system function. Think of them as reusable chunks of
//! code that can be run across multiple hosts. Any time you have a
//! task that you want to repeat, it should probably go into a
//! payload.
//!
//! For example, a payload could handle installing a specific
//! package, such as Nginx. Or, you could create a payload that
//! configures iptables.
//!
//! # Examples
//!
//! ```no_run
//! # use inapi::{Host, Payload};
#![cfg_attr(feature = "local-run", doc = "# let mut host = Host::local(Some(\"nodes/mynode.json\")).unwrap();")]
#![cfg_attr(feature = "remote-run", doc = "# let mut host = Host::connect(\"nodes/mynode.json\").unwrap();")]
//! let payload = Payload::new("nginx::install").unwrap(); // format is "payload::executable"
//! payload.run(&mut host, None).unwrap();
//! ```

pub mod config;
pub mod ffi;

use czmq::{ZMsg, ZPoller, ZSock, ZSockType, ZSys};
use error::{Error, Result};
use host::{Host,HostSendRecv};
use project::Language;
use self::config::Config;
use serde_json;
use std::env::{current_dir, set_current_dir};
use std::process;
use std::path::PathBuf;
use std::thread;
use zdaemon::ConfigFile;

/// Container for running a Payload.
pub struct Payload {
    /// Path to the payload directory.
    path: PathBuf,
    /// Name of the executable/source file to run.
    artifact: Option<String>,
    /// Language the payload is written in.
    language: Language,
}

impl Payload {
    /// Create a new Payload using the payload::artifact notation.
    /// This notation is simply "payload" + separator ("::") +
    /// "executable/source file". For example: "nginx::install".
    ///
    /// By default, payloads live in
    /// <project root>/payloads/<payload_name>. Thus the payload name
    /// "nginx" will resolve to <project root>/payloads/nginx/. You
    /// can also specify an absolute path to your payload, which will
    /// override the resolved path.
    ///
    /// ```no_run
    /// # use inapi::Payload;
    /// // Using standard payload/artifact notation...
    /// let payload = Payload::new("iptables::update").unwrap();
    ///
    /// // Using an absolute path...
    /// let payload = Payload::new("/mnt/intecture/payloads/iptables::update").unwrap();
    /// ```
    pub fn new(payload_artifact: &str) -> Result<Payload> {
        let mut parts: Vec<&str> = payload_artifact.split("::").collect();
        let payload = if parts.len() > 0 {
            parts.remove(0)
        } else {
            return Err(Error::Generic("Invalid payload string".into()));
        };

        let mut buf = PathBuf::from("payloads");
        buf.push(payload);

        buf.push("payload.json");
        let config = try!(Config::load(&buf));
        buf.pop();

        // Check dependencies
        if let Some(deps) = config.dependencies {
            try!(Self::check_deps(&deps));
        }

        Ok(Payload {
            path: buf,
            artifact: if parts.len() > 1 {
                Some(parts.remove(1).into())
            } else {
                None
            },
            language: config.language,
        })
    }

    /// Compile a payload's source code. This function is also called
    /// by Payload::run(), but is useful for precompiling payloads
    /// ahead of time to catch build errors early.
    ///
    /// Note that this is only useful for compiled languages. If this
    /// function is run on a payload that uses an interpreted
    /// language, it will safely be ignored.
    pub fn build(&self) -> Result<()> {
        let mut make_path = self.path.clone();
        make_path.push("Makefile");

        match self.language {
            Language::C | Language::Rust if make_path.exists() && make_path.is_file() => {
                let current_dir = try!(current_dir());
                try!(set_current_dir(&self.path));

                let output = try!(process::Command::new("make")
                                                   .stdout(process::Stdio::inherit())
                                                   .output());

                try!(set_current_dir(&current_dir));

                if !output.status.success() {
                    return Err(Error::BuildFailed(try!(String::from_utf8(output.stderr))).into());
                }
            },
            Language::Rust => {
                let manifest_path = format!("{}/Cargo.toml", self.path.to_str().unwrap());
                let output = try!(process::Command::new("cargo")
                                                   .args(&["build", "--release", "--manifest-path", &manifest_path])
                                                   .stdout(process::Stdio::inherit())
                                                   .output());
                if !output.status.success() {
                    return Err(Error::BuildFailed(try!(String::from_utf8(output.stderr))).into());
                }
            },
            _ => ()
        }

        Ok(())
    }

    /// Execute the payload's artifact.
    ///
    /// For compiled languages, the artifact will be executed
    /// directly. For interpreted languages, the artifact will be
    /// passed as an argument to the interpreter.
    ///
    /// ```no_run
    /// # use inapi::{Host, Payload};
    #[cfg_attr(feature = "local-run", doc = "# let mut host = Host::local(Some(\"nodes/mynode.json\")).unwrap();")]
    #[cfg_attr(feature = "remote-run", doc = "# let mut host = Host::connect(\"nodes/mynode.json\").unwrap();")]
    /// let payload = Payload::new("iptables::configure").unwrap();
    /// payload.run(&mut host, Some(vec![
    ///     "add_rule",
    ///     "..."
    /// ])).unwrap();
    /// ```
    pub fn run(&self, host: &mut Host, user_args: Option<Vec<&str>>) -> Result<()> {
        // XXX This ugly cloning is a wasteful solution. New ZMQ
        // socket types (SERVER & CLIENT) are threadsafe, which will
        // allow us to thread the ZMQ poller and avoid having to
        // clone half the world. When these are implemented, this
        // code should be changed.

        // Build payload to make sure it's up to date
        try!(self.build());

        let artifact_default = self.artifact.as_ref().map(|a| &**a).unwrap_or("main");
        let api_endpoint = format!("ipc://{}/{}_api.ipc", self.path.to_str().unwrap(), artifact_default);
        let mut api_pipe = ZSock::new(ZSockType::DEALER);
        try!(api_pipe.bind(&api_endpoint));

        let file_endpoint = format!("ipc://{}/{}_file.ipc", self.path.to_str().unwrap(), artifact_default);
        let mut file_pipe = ZSock::new(ZSockType::DEALER);
        try!(file_pipe.bind(&file_endpoint));

        let (mut parent, child) = try!(ZSys::create_pipe());
        let language = self.language.clone();
        let mut payload_path = self.path.clone();
        let artifact = self.artifact.clone();
        let user_args_c: Option<Vec<String>> = match user_args {
            Some(a) => Some(a.into_iter().map(|arg| String::from(arg)).collect()),
            None => None,
        };

        let handle = thread::spawn(move || {
            match language {
                Language::C => {
                    payload_path.push(artifact.as_ref().map(|a| &**a).unwrap_or("main"));

                    let mut args = vec![api_endpoint, file_endpoint];
                    if let Some(mut a) = user_args_c {
                        args.append(&mut a);
                    }

                    let output = try!(process::Command::new(payload_path.to_str().unwrap())
                                                       .args(&args)
                                                       .stdout(process::Stdio::inherit())
                                                       .output());

                    if !output.status.success() {
                        try!(child.signal(0));
                        return Err(Error::RunFailed(try!(String::from_utf8(output.stderr))).into());
                    }
                },
                Language::Php => {
                    payload_path.push("src");
                    payload_path.push(artifact.as_ref().map(|a| &**a).unwrap_or("main"));
                    if payload_path.extension().is_none() {
                        payload_path.set_extension("php");
                    }

                    let mut args = vec![payload_path.to_str().unwrap().into(), api_endpoint, file_endpoint];
                    if let Some(mut a) = user_args_c {
                        args.append(&mut a);
                    }

                    let output = try!(process::Command::new("php")
                                                       .args(&args)
                                                       .stdout(process::Stdio::inherit())
                                                       .output());

                    if !output.status.success() {
                        try!(child.signal(0));
                        return Err(Error::RunFailed(try!(String::from_utf8(output.stderr))).into());
                    }
                },
                Language::Rust => {
                    payload_path.push("Cargo.toml");

                    let mut args = vec![
                        "run".into(),
                        "--release".into(),
                        "--manifest-path".into(),
                        payload_path.to_str().unwrap().into()
                    ];

                    if let Some(a) = artifact {
                        args.push("--bin".into());
                        args.push(a);
                    }

                    args.push("--".into());
                    args.push(api_endpoint);
                    args.push(file_endpoint);

                    if let Some(mut a) = user_args_c {
                        args.append(&mut a);
                    }

                    let output = try!(process::Command::new("cargo")
                                                       .args(&args)
                                                       .stdout(process::Stdio::inherit())
                                                       .output());

                    if !output.status.success() {
                        try!(child.signal(0));
                        return Err(Error::RunFailed(try!(String::from_utf8(output.stderr))).into());
                    }
                }
            }

            try!(child.signal(0));
            Ok(())
        });

        // Send data to payload
        let json = try!(serde_json::to_string(host.data()));
        try!(api_pipe.send_str(&json));

        let mut poller = try!(ZPoller::new());
        try!(poller.add(&mut parent));
        try!(poller.add(&mut api_pipe));
        try!(poller.add(&mut file_pipe));

        loop {
            let sock: Option<ZSock> = poller.wait(None);
            if let Some(mut s) = sock {
                if s == api_pipe || s == file_pipe {
                    let msg = try!(ZMsg::recv(&mut s));
                    try!(host.send(msg));
                }
                else if s == parent {
                    break;
                } else {
                    unreachable!();
                }
            }

            if poller.terminated() {
                break;
            }
        }

        let cmd_result: Result<()> = try!(handle.join());
        try!(cmd_result);

        Ok(())
    }

    fn check_deps(payloads: &[String]) -> Result<()> {
        for payload in payloads {
            try!(Payload::new(payload));
        }

        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use czmq::{ZSock, ZSockType};
    use host::Host;
    use project::Language;
    use std::fs;
    use std::io::Write;
    use std::path::PathBuf;
    use std::process::Command;
    use std::thread;
    use super::*;
    use super::config::Config;
    use tempdir::TempDir;
    use zdaemon::ConfigFile;

    #[test]
    fn test_new_nodeps() {
        let _ = ::_MOCK_ENV.init();

        let tempdir = TempDir::new("test_payload_new_nodeps").unwrap();
        let mut buf = tempdir.path().to_owned();

        create_cargo_proj(&mut buf);

        let conf = Config {
            author: "Dr. Hibbert".into(),
            repository: "https://github.com/dhibbz/hehehe.git".into(),
            language: Language::Rust,
            dependencies: Some(vec!["missing_payload".into()]),
        };

        buf.push("payload.json");
        conf.save(&buf).unwrap();
        buf.pop();

        assert!(Payload::new(buf.to_str().unwrap()).is_err());
    }

    #[test]
    fn test_build_rust() {
        let _ = ::_MOCK_ENV.init();

        let tempdir = TempDir::new("test_payload_build_rust").unwrap();
        let mut buf = tempdir.path().to_owned();

        create_cargo_proj(&mut buf);

        let conf = Config {
            author: "Dr. Hibbert".into(),
            repository: "https://github.com/dhibbz/hehehe.git".into(),
            language: Language::Rust,
            dependencies: None,
        };

        buf.push("payload.json");
        conf.save(&buf).unwrap();
        buf.pop();

        let payload = Payload::new(buf.to_str().unwrap()).unwrap();
        payload.build().unwrap();
    }

    #[test]
    fn test_build_c() {
        let _ = ::_MOCK_ENV.init();

        let tempdir = TempDir::new("test_payload_build_c").unwrap();
        let mut buf = tempdir.path().to_owned();

        buf.push("Makefile");
        let mut fh = fs::File::create(&buf).unwrap();
        fh.write_all(b"all:
\ttouch test").unwrap();
        buf.pop();

        let conf = Config {
            author: "Dr. Hibbert".into(),
            repository: "https://github.com/dhibbz/hehehe.git".into(),
            language: Language::C,
            dependencies: None,
        };

        buf.push("payload.json");
        conf.save(&buf).unwrap();
        buf.pop();

        let payload = Payload::new(buf.to_str().unwrap()).unwrap();
        payload.build().unwrap();

        buf.push("test");
        assert!(buf.exists());
    }

    #[test]
    fn test_run() {
        let _ = ::_MOCK_ENV.init();

        let tempdir = TempDir::new("test_payload_run").unwrap();
        let mut buf = tempdir.path().to_owned();

        create_cargo_proj(&mut buf);

        let conf = Config {
            author: "Dr. Hibbert".into(),
            repository: "https://github.com/dhibbz/hehehe.git".into(),
            language: Language::Rust,
            dependencies: None,
        };

        buf.push("payload.json");
        conf.save(&buf).unwrap();
        buf.pop();

        let payload_name = buf.into_os_string().into_string().unwrap();
        let payload_name_clone = payload_name.clone();

        let handle = thread::spawn(move || {
            let s = ZSock::new(ZSockType::DEALER);
            s.connect(&format!("ipc://{}/main_api.ipc", payload_name_clone)).unwrap();
            s.recv_str().unwrap().unwrap();
        });

        let mut host = Host::test_new(None, None, None, None);
        let payload = Payload::new(&payload_name).unwrap();
        payload.run(&mut host, Some(vec!["abc"])).unwrap();

        handle.join().unwrap();
    }

    fn create_cargo_proj(buf: &mut PathBuf) {
        let status = Command::new("cargo")
                             .args(&["init", buf.to_str().unwrap(), "--bin", "--name", "payload"])
                             .status()
                             .expect("Failed to execute process");

        assert!(status.success());
    }
}
<|endoftext|>


<commit_before>extern crate collections;

use std::str;
use collections::HashMap;
use std::io::File;
use std::io::BufferedReader;
use std::cmp;

fn sort_string(string: &str) -> ~str {
	let mut chars: ~[char] = string.chars().collect();
	chars.sort();
	str::from_chars(chars)
}

fn main () {
	let path = Path::new("unixdict.txt");
	let mut file = BufferedReader::new(File::open(&path));

	let mut map: HashMap<~str, ~[~str]> = HashMap::new();

	for line in file.lines() {
		let s = line.unwrap().trim().to_owned();
		map.insert_or_update_with(sort_string(s.clone()), ~[s.clone()],
				   |_k, v| v.push(s.clone())
				);
	}

	let max_length = map.iter().fold(0, |s, (_k, v)| cmp::max(s, v.len()));

	for (_k, v) in map.iter() {
		if v.len() == max_length {
			for s in v.iter() {
				print!("{} ", *s)
			}
			println!("")
		}
	}
}
<commit_msg>Fixed anagrams.rs<commit_after>extern crate collections;

use std::str;
use collections::HashMap;
use std::io::File;
use std::io::BufferedReader;
use std::cmp;

fn sort_string(string: &str) -> ~str {
	let mut chars: ~[char] = string.chars().collect();
	chars.sort();
	str::from_chars(chars)
}

fn main () {
	let path = Path::new("unixdict.txt");
	let mut file = BufferedReader::new(File::open(&path));

	let mut map: HashMap<~str, Vec<~str>> = HashMap::new();

	for line in file.lines() {
		let s = line.unwrap().trim().to_owned();
		map.insert_or_update_with(sort_string(s.clone()), vec!(s.clone()),
				   |_k, v| v.push(s.clone())
				);
	}

	let max_length = map.iter().fold(0, |s, (_k, v)| cmp::max(s, v.len()));

	for (_k, v) in map.iter() {
		if v.len() == max_length {
			for s in v.iter() {
				print!("{} ", *s)
			}
			println!("")
		}
	}
}
<|endoftext|>