<commit_before>extern crate libc;

use libc::{c_void, c_int, c_char, pid_t, ssize_t};

#[allow(non_camel_case_types)]
type cap_t = *mut c_void;

#[allow(non_camel_case_types)]
type cap_value_t = isize;

#[allow(non_camel_case_types)]
#[repr(C)]
enum cap_flag_t {
    CAP_EFFECTIVE=0,
    CAP_PERMITTED=1,
    CAP_INHERITABLE=2
}

#[allow(non_camel_case_types)]
#[repr(C)]
enum cap_flag_value_t {
    CAP_CLEAR=0,
    CAP_SET=1
}

#[link(name="cap")]
extern "C" {

    /* libcap/cap_alloc.c */
    fn cap_init() -> cap_t;
	fn cap_free(ptr: *mut c_void) -> c_int;
	fn cap_dup(cap: cap_t) -> cap_t;

    /* libcap/cap_flag.c */
    fn cap_get_flag(c: cap_t, vt: cap_value_t,
                    ft: cap_flag_t,
                    val: *mut cap_flag_value_t) -> c_int;

    fn cap_set_flag(c: cap_t, f: cap_flag_t,
                    ncap: c_int,
                    caps: *const cap_value_t,
                    val: cap_flag_value_t) -> c_int;

    fn cap_clear(c: cap_t) -> c_int;
    fn cap_clear_flag(c: cap_t, flag: cap_flag_t) -> c_int;

    /* libcap/cap_file.c */
    fn cap_get_fd(fd: c_int) -> cap_t;
    fn cap_get_file(filename: *const c_char) -> cap_t;
    fn cap_set_fd(fd: c_int, cap: cap_t) -> c_int;
    fn cap_set_file(filename: *const c_char, cap: cap_t) -> c_int;

    /* libcap/cap_proc.c */
    fn cap_get_proc() -> cap_t;
    fn cap_get_pid(pid: pid_t) -> cap_t;
    fn cap_set_proc(cap: cap_t) -> c_int;
    fn cap_get_bound(vt: cap_value_t) -> c_int;
    fn cap_drop_bound(vt: cap_value_t) -> c_int;

    /* libcap/cap_extint.c */
    fn cap_size(cap: cap_t) -> ssize_t;
    fn cap_copy_ext(ptr: *mut c_void, cap: cap_t, size: ssize_t) -> ssize_t;
    fn cap_copy_int(ptr: *const c_void) -> cap_t;
    fn cap_compare(a: cap_t, b: cap_t) -> c_int;

}

// Capability descriptions taken from:
//  https://github.com/torvalds/linux/blob/master/include/uapi/linux/capability.h

/// In a system with the [_POSIX_CHOWN_RESTRICTED] option defined, this
/// overrides the restriction of changing file ownership and group
/// ownership.
pub const CAP_CHOWN: isize = 0;

/// Override all DAC access, including ACL execute access if
/// [_POSIX_ACL] is defined. Excluding DAC access covered by
/// CAP_LINUX_IMMUTABLE.
pub const CAP_DAC_OVERRIDE: isize = 1;

/// Overrides all DAC restrictions regarding read and search on files
/// and directories, including ACL restrictions if [_POSIX_ACL] is
/// defined. Excluding DAC access covered by CAP_LINUX_IMMUTABLE.
pub const CAP_DAC_READ_SEARCH: isize = 2;

/// Overrides all restrictions about allowed operations on files, where
/// file owner ID must be equal to the user ID, except where CAP_FSETID
/// is applicable. It doesn't override MAC and DAC restrictions.
pub const CAP_FOWNER: isize = 3;

/// Overrides the following restrictions that the effective user ID
/// shall match the file owner ID when setting the S_ISUID and S_ISGID
/// bits on that file; that the effective group ID (or one of the
/// supplementary group IDs) shall match the file owner ID when setting
/// the S_ISGID bit on that file; that the S_ISUID and S_ISGID bits are
/// cleared on successful return from chown(2) (not implemented).
pub const CAP_FSETID: isize = 4;

/// Overrides the restriction that the real or effective user ID of a
/// process sending a signal must match the real or effective user ID
/// of the process receiving the signal.
pub const CAP_KILL: isize = 5;

/// - Allows setgid(2) manipulation
/// - Allows setgroups(2) manipulation
/// - Allows forged gids on socket credentials passing.
pub const CAP_SETGID: isize = 6;

/// - Allows set*uid(2) manipulation (including fsuid).
/// - Allows forged pids on socket credentials passing.
pub const CAP_SETUID: isize = 7;

/// - Without VFS support for capabilities:
///   * Transfer any capability in your permitted set to any pid,
///     remove any capability in your permitted set from any pid.
/// - With VFS support for capabilities (neither of above, but)
///   * Add any capability from current's capability bounding set
///     to the current process' inheritable set.
///   * Allow taking bits out of capability bounding set
///   * Allow modification of the securebits for a process
pub const CAP_SETPCAP: isize = 8;

/// Allow modification of S_IMMUTABLE and S_APPEND file attributes
pub const CAP_LINUX_IMMUTABLE: isize = 9;

/// - Allows binding to TCP/UDP sockets below 1024,
/// - Allows binding to ATM VCIs below 32
pub const CAP_NET_BIND_SERVICE: isize = 10;

/// Allows broadcasting, listen to multicast
pub const CAP_NET_BROADCAST: isize = 11;

/// - Allow interface configuration
/// - Allow administration of IP firewall, masquerading and accounting
/// - Allow setting debug option on sockets
/// - Allow modification of routing tables
/// - Allow setting arbitrary process / process group ownership on sockets
/// - Allow binding to any address for transparent proxying (also via NET_RAW)
/// - Allow setting TOS (type of service)
/// - Allow setting promiscuous mode
/// - Allow clearing driver statistics
/// - Allow multicasting
/// - Allow read/write of device-specific registers
/// - Allow activation of ATM control sockets
pub const CAP_NET_ADMIN: isize = 12;

/// - Allow use of RAW sockets
/// - Allow use of PACKET sockets
/// - Allow binding to any address for transparent proxying (also via NET_ADMIN)
pub const CAP_NET_RAW: isize = 13;

/// - Allow locking of shared memory segments
/// - Allow mlock and mlockall (which doesn't really have anything to do with IPC)
pub const CAP_IPC_LOCK: isize = 14;

/// Override IPC ownership checks
pub const CAP_IPC_OWNER: isize = 15;

/// Insert and remove kernel modules - modify kernel without limit
pub const CAP_SYS_MODULE: isize = 16;

/// - Allow ioperm/iopl access
/// - Allow sending USB messages to any device via /proc/bus/usb
pub const CAP_SYS_RAWIO: isize = 17;

/// Allow the use of chroot
pub const CAP_SYS_CHROOT: isize = 18;

/// Allow ptrace() of any process
pub const CAP_SYS_PTRACE: isize = 19;

/// Allow configuration of process accounting
pub const CAP_SYS_PACCT: isize = 20;

/// - Allow configuration of the secure attention key
/// - Allow administration of the random device
/// - Allow examination and configuration of disk quotas
/// - Allow setting the domainname
/// - Allow setting the hostname
/// - Allow calling bdflush()
/// - Allow mount() and umount(), setting up new smb connection
/// - Allow some autofs root ioctls
/// - Allow nfsservctl
/// - Allow VM86_REQUEST_IRQ
/// - Allow to read/write pci config on alpha
/// - Allow irix_prctl on mips (setstacksize)
/// - Allow flushing all cache on m68k (sys_cacheflush)
/// - Allow removing semaphores
/// - Used instead of CAP_CHOWN to "chown" IPC message queues, semaphores
///   and shared memory
/// - Allow locking/unlocking of shared memory segment
/// - Allow turning swap on/off
/// - Allow forged pids on socket credentials passing
/// - Allow setting readahead and flushing buffers on block devices
/// - Allow setting geometry in floppy driver
/// - Allow turning DMA on/off in xd driver
/// - Allow administration of md devices (mostly the above, but some
///   extra ioctls)
/// - Allow tuning the ide driver
/// - Allow access to the nvram device
/// - Allow administration of apm_bios, serial and bttv (TV) device
/// - Allow manufacturer commands in isdn CAPI support driver
/// - Allow reading non-standardized portions of pci configuration space
/// - Allow DDI debug ioctl on sbpcd driver
/// - Allow setting up serial ports
/// - Allow sending raw qic-117 commands
/// - Allow enabling/disabling tagged queuing on SCSI controllers and sending
///   arbitrary SCSI commands
/// - Allow setting encryption key on loopback filesystem
/// - Allow setting zone reclaim policy
pub const CAP_SYS_ADMIN: isize = 21;

/// Allow use of reboot()
pub const CAP_SYS_BOOT: isize = 22;

/// - Allow raising priority and setting priority on other (different
///   UID) processes
/// - Allow use of FIFO and round-robin (realtime) scheduling on own
///   processes and setting the scheduling algorithm used by another
///   process.
/// - Allow setting cpu affinity on other processes
pub const CAP_SYS_NICE: isize = 23;

/// - Override resource limits. Set resource limits.
/// - Override quota limits.
/// - Override reserved space on ext2 filesystem
/// - Modify data journaling mode on ext3 filesystem (uses journaling
///   resources)
/// - **NOTE**: *ext2 honors fsuid when checking for resource overrides, so
///   you can override using fsuid too.*
/// - Override size restrictions on IPC message queues
/// - Allow more than 64hz interrupts from the real-time clock
/// - Override max number of consoles on console allocation
/// - Override max number of keymaps
pub const CAP_SYS_RESOURCE: isize = 24;

/// - Allow manipulation of system clock
/// - Allow irix_stime on mips
/// - Allow setting the real-time clock
pub const CAP_SYS_TIME: isize = 25;

/// - Allow configuration of tty devices
/// - Allow vhangup() of tty
pub const CAP_SYS_TTY_CONFIG: isize = 26;

/// Allow the privileged aspects of mknod()
pub const CAP_MKNOD: isize = 27;

/// Allow taking of leases on files
pub const CAP_LEASE: isize = 28;

/// Allow writing the audit log via unicast netlink socket
pub const CAP_AUDIT_WRITE: isize = 29;

/// Allow configurationof audit via unicast netlink socket
pub const CAP_AUDIT_CONTROL: isize = 30;

/// Set file capabilities
pub const CAP_SETFCAP: isize = 31;

/// Override MAC access.
/// The base kernel enforces no MAC policy.
/// An LSM may enforce a MAC policy, and if it does and it chooses
/// to implement capability based overrides of that policy, this is
/// the capability it should use to do so.
pub const CAP_MAC_OVERRIDE: isize = 32;

/// Allow MAC configuration or state changes.
/// The base kernel requires no MAC configuration.
/// An LSM may enforce a MAC policy, and if it does and it chooses
/// to implement capability based checks on modifications to that
/// policy or the data required to maintain it, this is the
/// capability it should use to do so.
pub const CAP_MAC_ADMIN: isize = 33;

/// Allow configuring the kernel's syslog (printk behaviour)
pub const CAP_SYSLOG: isize = 34;

/// Allow triggering something that will wake the system
pub const CAP_WAKE_ALARM: isize = 35;

/// Allow preventing system suspends
pub const CAP_BLOCK_SUSPEND: isize = 36;

/// Allow reading the audit log via multicast netlink socket
pub const CAP_AUDIT_READ: isize = 37;

const CAP_LAST_CAP: isize = CAP_AUDIT_READ;
pub fn cap_valid(x: isize) -> bool { x >= 0 && x <= CAP_LAST_CAP }

<commit_msg>Add to/from text c api<commit_after>extern crate libc;

use libc::{c_void, c_int, c_char, pid_t, ssize_t};

#[allow(non_camel_case_types)]
type cap_t = *mut c_void;

#[allow(non_camel_case_types)]
type cap_value_t = isize;

#[allow(non_camel_case_types)]
#[repr(C)]
enum cap_flag_t {
    CAP_EFFECTIVE=0,
    CAP_PERMITTED=1,
    CAP_INHERITABLE=2
}

#[allow(non_camel_case_types)]
#[repr(C)]
enum cap_flag_value_t {
    CAP_CLEAR=0,
    CAP_SET=1
}

#[link(name="cap")]
extern "C" {

    /* libcap/cap_alloc.c */
    fn cap_init() -> cap_t;
	fn cap_free(ptr: *mut c_void) -> c_int;
	fn cap_dup(cap: cap_t) -> cap_t;

    /* libcap/cap_flag.c */
    fn cap_get_flag(c: cap_t, vt: cap_value_t,
                    ft: cap_flag_t,
                    val: *mut cap_flag_value_t) -> c_int;

    fn cap_set_flag(c: cap_t, f: cap_flag_t,
                    ncap: c_int,
                    caps: *const cap_value_t,
                    val: cap_flag_value_t) -> c_int;

    fn cap_clear(c: cap_t) -> c_int;
    fn cap_clear_flag(c: cap_t, flag: cap_flag_t) -> c_int;

    /* libcap/cap_file.c */
    fn cap_get_fd(fd: c_int) -> cap_t;
    fn cap_get_file(filename: *const c_char) -> cap_t;
    fn cap_set_fd(fd: c_int, cap: cap_t) -> c_int;
    fn cap_set_file(filename: *const c_char, cap: cap_t) -> c_int;

    /* libcap/cap_proc.c */
    fn cap_get_proc() -> cap_t;
    fn cap_get_pid(pid: pid_t) -> cap_t;
    fn cap_set_proc(cap: cap_t) -> c_int;
    fn cap_get_bound(vt: cap_value_t) -> c_int;
    fn cap_drop_bound(vt: cap_value_t) -> c_int;

    /* libcap/cap_extint.c */
    fn cap_size(cap: cap_t) -> ssize_t;
    fn cap_copy_ext(ptr: *mut c_void, cap: cap_t, size: ssize_t) -> ssize_t;
    fn cap_copy_int(ptr: *const c_void) -> cap_t;
    fn cap_compare(a: cap_t, b: cap_t) -> c_int;

    /* libcap/cap_text.c */
    fn cap_from_text(txt: *const c_char) -> cap_t;
    fn cap_to_text(cap: cap_t, size: *mut ssize_t) -> *mut c_char;
    fn cap_from_name(name: *const c_char, val: *mut cap_value_t) -> c_int;
    fn cap_to_name(val: cap_value_t) -> *mut c_char;

}

// Capability descriptions taken from:
//  https://github.com/torvalds/linux/blob/master/include/uapi/linux/capability.h

/// In a system with the [_POSIX_CHOWN_RESTRICTED] option defined, this
/// overrides the restriction of changing file ownership and group
/// ownership.
pub const CAP_CHOWN: isize = 0;

/// Override all DAC access, including ACL execute access if
/// [_POSIX_ACL] is defined. Excluding DAC access covered by
/// CAP_LINUX_IMMUTABLE.
pub const CAP_DAC_OVERRIDE: isize = 1;

/// Overrides all DAC restrictions regarding read and search on files
/// and directories, including ACL restrictions if [_POSIX_ACL] is
/// defined. Excluding DAC access covered by CAP_LINUX_IMMUTABLE.
pub const CAP_DAC_READ_SEARCH: isize = 2;

/// Overrides all restrictions about allowed operations on files, where
/// file owner ID must be equal to the user ID, except where CAP_FSETID
/// is applicable. It doesn't override MAC and DAC restrictions.
pub const CAP_FOWNER: isize = 3;

/// Overrides the following restrictions that the effective user ID
/// shall match the file owner ID when setting the S_ISUID and S_ISGID
/// bits on that file; that the effective group ID (or one of the
/// supplementary group IDs) shall match the file owner ID when setting
/// the S_ISGID bit on that file; that the S_ISUID and S_ISGID bits are
/// cleared on successful return from chown(2) (not implemented).
pub const CAP_FSETID: isize = 4;

/// Overrides the restriction that the real or effective user ID of a
/// process sending a signal must match the real or effective user ID
/// of the process receiving the signal.
pub const CAP_KILL: isize = 5;

/// - Allows setgid(2) manipulation
/// - Allows setgroups(2) manipulation
/// - Allows forged gids on socket credentials passing.
pub const CAP_SETGID: isize = 6;

/// - Allows set*uid(2) manipulation (including fsuid).
/// - Allows forged pids on socket credentials passing.
pub const CAP_SETUID: isize = 7;

/// - Without VFS support for capabilities:
///   * Transfer any capability in your permitted set to any pid,
///     remove any capability in your permitted set from any pid.
/// - With VFS support for capabilities (neither of above, but)
///   * Add any capability from current's capability bounding set
///     to the current process' inheritable set.
///   * Allow taking bits out of capability bounding set
///   * Allow modification of the securebits for a process
pub const CAP_SETPCAP: isize = 8;

/// Allow modification of S_IMMUTABLE and S_APPEND file attributes
pub const CAP_LINUX_IMMUTABLE: isize = 9;

/// - Allows binding to TCP/UDP sockets below 1024,
/// - Allows binding to ATM VCIs below 32
pub const CAP_NET_BIND_SERVICE: isize = 10;

/// Allows broadcasting, listen to multicast
pub const CAP_NET_BROADCAST: isize = 11;

/// - Allow interface configuration
/// - Allow administration of IP firewall, masquerading and accounting
/// - Allow setting debug option on sockets
/// - Allow modification of routing tables
/// - Allow setting arbitrary process / process group ownership on sockets
/// - Allow binding to any address for transparent proxying (also via NET_RAW)
/// - Allow setting TOS (type of service)
/// - Allow setting promiscuous mode
/// - Allow clearing driver statistics
/// - Allow multicasting
/// - Allow read/write of device-specific registers
/// - Allow activation of ATM control sockets
pub const CAP_NET_ADMIN: isize = 12;

/// - Allow use of RAW sockets
/// - Allow use of PACKET sockets
/// - Allow binding to any address for transparent proxying (also via NET_ADMIN)
pub const CAP_NET_RAW: isize = 13;

/// - Allow locking of shared memory segments
/// - Allow mlock and mlockall (which doesn't really have anything to do with IPC)
pub const CAP_IPC_LOCK: isize = 14;

/// Override IPC ownership checks
pub const CAP_IPC_OWNER: isize = 15;

/// Insert and remove kernel modules - modify kernel without limit
pub const CAP_SYS_MODULE: isize = 16;

/// - Allow ioperm/iopl access
/// - Allow sending USB messages to any device via /proc/bus/usb
pub const CAP_SYS_RAWIO: isize = 17;

/// Allow the use of chroot
pub const CAP_SYS_CHROOT: isize = 18;

/// Allow ptrace() of any process
pub const CAP_SYS_PTRACE: isize = 19;

/// Allow configuration of process accounting
pub const CAP_SYS_PACCT: isize = 20;

/// - Allow configuration of the secure attention key
/// - Allow administration of the random device
/// - Allow examination and configuration of disk quotas
/// - Allow setting the domainname
/// - Allow setting the hostname
/// - Allow calling bdflush()
/// - Allow mount() and umount(), setting up new smb connection
/// - Allow some autofs root ioctls
/// - Allow nfsservctl
/// - Allow VM86_REQUEST_IRQ
/// - Allow to read/write pci config on alpha
/// - Allow irix_prctl on mips (setstacksize)
/// - Allow flushing all cache on m68k (sys_cacheflush)
/// - Allow removing semaphores
/// - Used instead of CAP_CHOWN to "chown" IPC message queues, semaphores
///   and shared memory
/// - Allow locking/unlocking of shared memory segment
/// - Allow turning swap on/off
/// - Allow forged pids on socket credentials passing
/// - Allow setting readahead and flushing buffers on block devices
/// - Allow setting geometry in floppy driver
/// - Allow turning DMA on/off in xd driver
/// - Allow administration of md devices (mostly the above, but some
///   extra ioctls)
/// - Allow tuning the ide driver
/// - Allow access to the nvram device
/// - Allow administration of apm_bios, serial and bttv (TV) device
/// - Allow manufacturer commands in isdn CAPI support driver
/// - Allow reading non-standardized portions of pci configuration space
/// - Allow DDI debug ioctl on sbpcd driver
/// - Allow setting up serial ports
/// - Allow sending raw qic-117 commands
/// - Allow enabling/disabling tagged queuing on SCSI controllers and sending
///   arbitrary SCSI commands
/// - Allow setting encryption key on loopback filesystem
/// - Allow setting zone reclaim policy
pub const CAP_SYS_ADMIN: isize = 21;

/// Allow use of reboot()
pub const CAP_SYS_BOOT: isize = 22;

/// - Allow raising priority and setting priority on other (different
///   UID) processes
/// - Allow use of FIFO and round-robin (realtime) scheduling on own
///   processes and setting the scheduling algorithm used by another
///   process.
/// - Allow setting cpu affinity on other processes
pub const CAP_SYS_NICE: isize = 23;

/// - Override resource limits. Set resource limits.
/// - Override quota limits.
/// - Override reserved space on ext2 filesystem
/// - Modify data journaling mode on ext3 filesystem (uses journaling
///   resources)
/// - **NOTE**: *ext2 honors fsuid when checking for resource overrides, so
///   you can override using fsuid too.*
/// - Override size restrictions on IPC message queues
/// - Allow more than 64hz interrupts from the real-time clock
/// - Override max number of consoles on console allocation
/// - Override max number of keymaps
pub const CAP_SYS_RESOURCE: isize = 24;

/// - Allow manipulation of system clock
/// - Allow irix_stime on mips
/// - Allow setting the real-time clock
pub const CAP_SYS_TIME: isize = 25;

/// - Allow configuration of tty devices
/// - Allow vhangup() of tty
pub const CAP_SYS_TTY_CONFIG: isize = 26;

/// Allow the privileged aspects of mknod()
pub const CAP_MKNOD: isize = 27;

/// Allow taking of leases on files
pub const CAP_LEASE: isize = 28;

/// Allow writing the audit log via unicast netlink socket
pub const CAP_AUDIT_WRITE: isize = 29;

/// Allow configurationof audit via unicast netlink socket
pub const CAP_AUDIT_CONTROL: isize = 30;

/// Set file capabilities
pub const CAP_SETFCAP: isize = 31;

/// Override MAC access.
/// The base kernel enforces no MAC policy.
/// An LSM may enforce a MAC policy, and if it does and it chooses
/// to implement capability based overrides of that policy, this is
/// the capability it should use to do so.
pub const CAP_MAC_OVERRIDE: isize = 32;

/// Allow MAC configuration or state changes.
/// The base kernel requires no MAC configuration.
/// An LSM may enforce a MAC policy, and if it does and it chooses
/// to implement capability based checks on modifications to that
/// policy or the data required to maintain it, this is the
/// capability it should use to do so.
pub const CAP_MAC_ADMIN: isize = 33;

/// Allow configuring the kernel's syslog (printk behaviour)
pub const CAP_SYSLOG: isize = 34;

/// Allow triggering something that will wake the system
pub const CAP_WAKE_ALARM: isize = 35;

/// Allow preventing system suspends
pub const CAP_BLOCK_SUSPEND: isize = 36;

/// Allow reading the audit log via multicast netlink socket
pub const CAP_AUDIT_READ: isize = 37;

const CAP_LAST_CAP: isize = CAP_AUDIT_READ;
pub fn cap_valid(x: isize) -> bool { x >= 0 && x <= CAP_LAST_CAP }

<|endoftext|>


<commit_before>extern crate serial;
#[macro_use] extern crate serde_derive;
extern crate serde;

use serde::ser::{Serializer, Serialize};
use serde::de::{self, Deserializer, Deserialize};

pub use serial::Error;

mod enttec;

pub use enttec::{available_enttec_ports, EnttecDmxPort, ENTTEC_NAMESPACE};

/// Trait for the general notion of a DMX port.
/// This enables creation of an "offline" port to slot into place if an API requires an output.
pub trait DmxPort {
    /// Write a DMX frame out to the port.  If the frame is smaller than the minimum universe size,
    /// it will be padded with zeros.  If the frame is larger than the maximum universe size, the
    /// values beyond the max size will be ignored.
    fn write(&mut self, frame: &[u8]) -> Result<(), Error>;

    /// Return the name of this port.  Should only be used for display purposes.
    fn port_name(&self) -> &str;

    /// Return a tuple of (namespace, port_identifier) to be used to try to reopen a port
    /// after deserialization of a saved show or after application restart.
    fn serializable(&self) -> SerializablePort;
}

pub struct OfflineDmxPort {}

const OFFLINE_NAMESPACE: &'static str = "offline";
const OFFLINE_ID: &'static str = "offline";

impl DmxPort for OfflineDmxPort {
    fn write(&mut self, _: &[u8]) -> Result<(), Error> {
        Ok(())
    }
    fn port_name(&self) -> &str {
        OFFLINE_ID
    }
    fn serializable(&self) -> SerializablePort {
        SerializablePort::new(OFFLINE_NAMESPACE, OFFLINE_ID)
    }
}

#[derive(Serialize, Deserialize)]
/// A serializable data structure for persisting a record of a port to disk, also providing
/// for attempted reopening of a port.
pub struct SerializablePort {
    namespace: String,
    id: String,
}

impl SerializablePort {
    fn new<N: Into<String>, I: Into<String>>(namespace: N, id: I) -> Self {
        SerializablePort { namespace: namespace.into(), id: id.into() }
    }
    /// Based on the namespace and id, try to reopen this DMX port.
    /// If we don't know the namespace or the port isn't available, return an offline port.
    fn reopen(self) -> Box<DmxPort> {
        fn offline() -> Box<DmxPort> {
            Box::new(OfflineDmxPort{})
        }
        match self.namespace.as_ref() {
            OFFLINE_NAMESPACE => offline(),
            ENTTEC_NAMESPACE =>
                match EnttecDmxPort::new(self.id) {
                    Ok(port) => Box::new(port),
                    Err(_) => offline()
                },
            _ => offline()
        }
    }
}

// Helper functions to use when serializing and deserializing DmxPort trait objects contained in
// other structs, using Serde attributes.
fn serialize<S>(port: &DmxPort, serializer: S) -> Result<S::Ok, S::Error>
    where S: Serializer
{
    port.serializable().serialize(serializer)
}

fn deserialize<'de, D>(deserializer: D) -> Result<Box<DmxPort>, D::Error>
    where D: Deserializer<'de>
{
    SerializablePort::deserialize(deserializer).map(SerializablePort::reopen)
}<commit_msg>ENH: add port serialization support through the trait object<commit_after>extern crate serial;
#[macro_use] extern crate serde_derive;
extern crate serde;

use serde::ser::{Serializer, Serialize};
use serde::de::{self, Deserializer, Deserialize};

pub use serial::Error;

mod enttec;

pub use enttec::{available_enttec_ports, EnttecDmxPort, ENTTEC_NAMESPACE};

/// Trait for the general notion of a DMX port.
/// This enables creation of an "offline" port to slot into place if an API requires an output.
pub trait DmxPort {
    /// Write a DMX frame out to the port.  If the frame is smaller than the minimum universe size,
    /// it will be padded with zeros.  If the frame is larger than the maximum universe size, the
    /// values beyond the max size will be ignored.
    fn write(&mut self, frame: &[u8]) -> Result<(), Error>;

    /// Return the name of this port.  Should only be used for display purposes.
    fn port_name(&self) -> &str;

    /// Return a tuple of (namespace, port_identifier) to be used to try to reopen a port
    /// after deserialization of a saved show or after application restart.
    fn serializable(&self) -> SerializablePort;
}

pub struct OfflineDmxPort {}

const OFFLINE_NAMESPACE: &'static str = "offline";
const OFFLINE_ID: &'static str = "offline";

impl DmxPort for OfflineDmxPort {
    fn write(&mut self, _: &[u8]) -> Result<(), Error> {
        Ok(())
    }
    fn port_name(&self) -> &str {
        OFFLINE_ID
    }
    fn serializable(&self) -> SerializablePort {
        SerializablePort::new(OFFLINE_NAMESPACE, OFFLINE_ID)
    }
}

#[derive(Serialize, Deserialize)]
/// A serializable data structure for persisting a record of a port to disk, also providing
/// for attempted reopening of a port.
pub struct SerializablePort {
    namespace: String,
    id: String,
}

impl SerializablePort {
    fn new<N: Into<String>, I: Into<String>>(namespace: N, id: I) -> Self {
        SerializablePort { namespace: namespace.into(), id: id.into() }
    }
    /// Based on the namespace and id, try to reopen this DMX port.
    /// If we don't know the namespace or the port isn't available, return an offline port.
    fn reopen(self) -> Box<DmxPort> {
        fn offline() -> Box<DmxPort> {
            Box::new(OfflineDmxPort{})
        }
        match self.namespace.as_ref() {
            OFFLINE_NAMESPACE => offline(),
            ENTTEC_NAMESPACE =>
                match EnttecDmxPort::new(self.id) {
                    Ok(port) => Box::new(port),
                    Err(_) => offline()
                },
            _ => offline()
        }
    }
}

// Helper functions to use when serializing and deserializing DmxPort trait objects contained in
// other structs.  This can be done using the serde with attribute.
pub fn serialize<S>(port: &DmxPort, serializer: S) -> Result<S::Ok, S::Error>
    where S: Serializer
{
    port.serializable().serialize(serializer)
}

pub fn deserialize<'de, D>(deserializer: D) -> Result<Box<DmxPort>, D::Error>
    where D: Deserializer<'de>
{
    SerializablePort::deserialize(deserializer).map(SerializablePort::reopen)
}<|endoftext|>


<commit_before>/// Checks whether its argument is a valid UUID, per
/// https://webbluetoothcg.github.io/web-bluetooth/#dfn-valid-uuid
pub fn valid_uuid(uuid: &str) -> bool {
    if uuid.len() != 36 {
        return false;
    }
    for (index, char) in uuid.chars().enumerate() {
        match index {
            8 | 13 | 18 | 23 => {
                if char != '-' {
                    return false;
                }
            }
            _ => {
                match char {
                    '0' ... '9' | 'a' ... 'f' => (),
                    _ => return false,
                }
            }
        }
    }
    return true;
}

/// Checks whether its argument is a blacklist file that's usable in the algorithm at
/// https://webbluetoothcg.github.io/web-bluetooth/#dfn-parsing-the-blacklist
pub fn validate_blacklist(blacklist: &str) -> Option<String> {
    for (index, line) in blacklist.lines().enumerate() {
        let line_num = index + 1;
        if line.is_empty() || line.starts_with("#") {
            // Comment or blank line.
            continue;
        }
        let tokens: Vec<&str> = line.split(' ').collect();
        match tokens.len() {
            0 => unreachable!("split(' ') never returns an empty array"),
            1 | 2 => {
                let uuid = tokens[0];
                if !valid_uuid(uuid) {
                    return Some(format!("line {}: '{}' is not a valid UUID", line_num, uuid));
                }
                if tokens.len() == 2 {
                    let exclusion = tokens[1];
                    match exclusion {
                        "exclude-reads" | "exclude-writes" => (),
                        _ => return Some(format!(
			    "line {}: '{}' should be 'exclude-reads', or 'exclude-writes'",
			    line_num, exclusion)),
                    }
                }
            },
            _ => return Some(format!("line {}: Too many tokens", line_num)),
        }
    }
    return None;
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::fs::File;
    use std::io::prelude::*;

    #[test]
    fn test_valid_uuid() {
	assert!( valid_uuid("00000000-0000-0000-0000-000000000000"));
	assert!( valid_uuid("01234567-89ab-cdef-0123-456789abcdef"));
	assert!(!valid_uuid("01234567-89AB-CDEF-0123-456789ABCDEF"));
	assert!(!valid_uuid("g1234567-89ab-cdef-0123-456789abcdef"));
	assert!(!valid_uuid("01234567-89ab-cdef-0123-456789abcdef0"));
	assert!(!valid_uuid("0123456789abcdef0123456789abcdef"));
	assert!(!valid_uuid("01234567089ab0cdef001230456789abcdef"));
    }

    #[test]
    fn test_validate_blacklist() {
        assert_eq!(None, validate_blacklist(""));
        // Lines are terminated by \n, not \r\n.
        assert_eq!(Some("line 1: '\r' is not a valid UUID".to_string()),
                   validate_blacklist("\r\n"));
        assert_eq!(None, validate_blacklist("# comment"));
        assert_eq!(None, validate_blacklist("# comment
00001812-0000-1000-8000-00805f9b34fb"));
        // No extraneous spaces.
        assert_eq!(Some("line 1: Too many tokens".to_string()),
		   validate_blacklist("  # comment
  00001812-0000-1000-8000-00805f9b34fb"));
        assert_eq!(
	    Some("line 1: Too many tokens".to_string()),
	    validate_blacklist("00001812-0000-1000-8000-00805f9b34fb # not a comment"));
        assert_eq!(
            Some("line 1: 'X0001812-0000-1000-8000-00805f9b34fb' is not a valid UUID".to_string()),
            validate_blacklist("X0001812-0000-1000-8000-00805f9b34fb"));
        assert_eq!(None,
                   validate_blacklist("00001812-0000-1000-8000-00805f9b34fb exclude-reads"));
        assert_eq!(None,
                   validate_blacklist("00001812-0000-1000-8000-00805f9b34fb exclude-writes"));
        assert_eq!(
            Some("line 1: '00001812-0000-1000-8000-00805f9b34fb\u{A0}exclude-reads' is not a valid UUID".to_string()),
            validate_blacklist("00001812-0000-1000-8000-00805f9b34fb\u{A0}exclude-reads"));
        assert_eq!(
            Some("line 1: 'X0001812-0000-1000-8000-00805f9b34fb' is not a valid UUID".to_string()),
            validate_blacklist("X0001812-0000-1000-8000-00805f9b34fb exclude-reads"));
        assert_eq!(
            Some("line 1: 'exclude' should be 'exclude-reads', or 'exclude-writes'".to_string()),
            validate_blacklist("00001812-0000-1000-8000-00805f9b34fb exclude"));
        assert_eq!(Some("line 1: Too many tokens".to_string()),
                   validate_blacklist("00001812-0000-1000-8000-00805f9b34fb token token"));
    }

    #[test]
    fn validate_gatt_blacklist() {
	let filename = "gatt_blacklist.txt";
        let content = File::open(filename).and_then(|mut file| {
            let mut result = String::new();
            try!(file.read_to_string(&mut result));
            Ok(result)
        }).unwrap_or_else(|e| { panic!("Error reading {}: {}", filename, e) });

        if let Some(error) = validate_blacklist(&content) {
	    panic!("{} is invalid: {}", filename, error);
	}
    }
}
<commit_msg>Enforce that UUIDs aren't repeated.<commit_after>use std::collections::HashMap;

/// Checks whether its argument is a valid UUID, per
/// https://webbluetoothcg.github.io/web-bluetooth/#dfn-valid-uuid
pub fn valid_uuid(uuid: &str) -> bool {
    if uuid.len() != 36 {
        return false;
    }
    for (index, char) in uuid.chars().enumerate() {
        match index {
            8 | 13 | 18 | 23 => {
                if char != '-' {
                    return false;
                }
            }
            _ => {
                match char {
                    '0' ... '9' | 'a' ... 'f' => (),
                    _ => return false,
                }
            }
        }
    }
    return true;
}

/// Checks whether its argument is a blacklist file that's usable in the algorithm at
/// https://webbluetoothcg.github.io/web-bluetooth/#dfn-parsing-the-blacklist
pub fn validate_blacklist(blacklist: &str) -> Option<String> {
    let mut result = HashMap::<&str, &str>::new();
    for (index, line) in blacklist.lines().enumerate() {
        let line_num = index + 1;
        if line.is_empty() || line.starts_with("#") {
            // Comment or blank line.
            continue;
        }
        let tokens: Vec<&str> = line.split(' ').collect();
        match tokens.len() {
            0 => unreachable!("split(' ') never returns an empty array"),
            1 | 2 => {
                let uuid = tokens[0];
                if !valid_uuid(uuid) {
                    return Some(format!("line {}: '{}' is not a valid UUID", line_num, uuid));
                }
                let mut exclusion = "exclude";
                if tokens.len() == 2 {
                    exclusion = tokens[1];
                    match exclusion {
                        "exclude-reads" | "exclude-writes" => (),
                        _ => return Some(format!(
			    "line {}: '{}' should be 'exclude-reads', or 'exclude-writes'",
			    line_num, exclusion)),
                    }
                }
                if let Some(_) = result.insert(uuid, exclusion) {
                    return Some(format!(
                        "line {}: '{}' appears multiple times",
                        line_num, uuid));
                }
            },
            _ => return Some(format!("line {}: Too many tokens", line_num)),
        }
    }
    return None;
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::fs::File;
    use std::io::prelude::*;

    #[test]
    fn test_valid_uuid() {
	assert!( valid_uuid("00000000-0000-0000-0000-000000000000"));
	assert!( valid_uuid("01234567-89ab-cdef-0123-456789abcdef"));
	assert!(!valid_uuid("01234567-89AB-CDEF-0123-456789ABCDEF"));
	assert!(!valid_uuid("g1234567-89ab-cdef-0123-456789abcdef"));
	assert!(!valid_uuid("01234567-89ab-cdef-0123-456789abcdef0"));
	assert!(!valid_uuid("0123456789abcdef0123456789abcdef"));
	assert!(!valid_uuid("01234567089ab0cdef001230456789abcdef"));
    }

    #[test]
    fn test_validate_blacklist() {
        assert_eq!(None, validate_blacklist(""));
        // Lines are terminated by \n, not \r\n.
        assert_eq!(Some("line 1: '\r' is not a valid UUID".to_string()),
                   validate_blacklist("\r\n"));
        assert_eq!(None, validate_blacklist("# comment"));
        assert_eq!(None, validate_blacklist("# comment
00001812-0000-1000-8000-00805f9b34fb"));
        // No extraneous spaces.
        assert_eq!(Some("line 1: Too many tokens".to_string()),
		   validate_blacklist("  # comment
  00001812-0000-1000-8000-00805f9b34fb"));
        assert_eq!(
	    Some("line 1: Too many tokens".to_string()),
	    validate_blacklist("00001812-0000-1000-8000-00805f9b34fb # not a comment"));
        assert_eq!(
            Some("line 1: 'X0001812-0000-1000-8000-00805f9b34fb' is not a valid UUID".to_string()),
            validate_blacklist("X0001812-0000-1000-8000-00805f9b34fb"));
        assert_eq!(None,
                   validate_blacklist("00001812-0000-1000-8000-00805f9b34fb exclude-reads"));
        assert_eq!(None,
                   validate_blacklist("00001812-0000-1000-8000-00805f9b34fb exclude-writes"));
        assert_eq!(
            Some("line 1: '00001812-0000-1000-8000-00805f9b34fb\u{A0}exclude-reads' is not a valid UUID".to_string()),
            validate_blacklist("00001812-0000-1000-8000-00805f9b34fb\u{A0}exclude-reads"));
        assert_eq!(
            Some("line 1: 'X0001812-0000-1000-8000-00805f9b34fb' is not a valid UUID".to_string()),
            validate_blacklist("X0001812-0000-1000-8000-00805f9b34fb exclude-reads"));
        assert_eq!(
            Some("line 1: 'exclude' should be 'exclude-reads', or 'exclude-writes'".to_string()),
            validate_blacklist("00001812-0000-1000-8000-00805f9b34fb exclude"));
        assert_eq!(Some("line 1: Too many tokens".to_string()),
                   validate_blacklist("00001812-0000-1000-8000-00805f9b34fb token token"));

        // Check all variants of repeated UUIDs.
        assert_eq!(
            Some("line 3: '00001812-0000-1000-8000-00805f9b34fb' appears multiple times".to_string()),
            validate_blacklist("00001812-0000-1000-8000-00805f9b34fb\n\
                                00001810-0000-1000-8000-00805f9b34fb\n\
                                00001812-0000-1000-8000-00805f9b34fb\n"));
        assert_eq!(
            Some("line 3: '00001812-0000-1000-8000-00805f9b34fb' appears multiple times".to_string()),
            validate_blacklist("00001812-0000-1000-8000-00805f9b34fb\n\
                                00001810-0000-1000-8000-00805f9b34fb\n\
                                00001812-0000-1000-8000-00805f9b34fb exclude-reads\n"));
        assert_eq!(
            Some("line 3: '00001812-0000-1000-8000-00805f9b34fb' appears multiple times".to_string()),
            validate_blacklist("00001812-0000-1000-8000-00805f9b34fb exclude-reads\n\
                                00001810-0000-1000-8000-00805f9b34fb\n\
                                00001812-0000-1000-8000-00805f9b34fb\n"));
        assert_eq!(
            Some("line 3: '00001812-0000-1000-8000-00805f9b34fb' appears multiple times".to_string()),
            validate_blacklist("00001812-0000-1000-8000-00805f9b34fb exclude-reads\n\
                                00001810-0000-1000-8000-00805f9b34fb\n\
                                00001812-0000-1000-8000-00805f9b34fb exclude-reads\n"));
    }

    #[test]
    fn validate_gatt_blacklist() {
	let filename = "gatt_blacklist.txt";
        let content = File::open(filename).and_then(|mut file| {
            let mut result = String::new();
            try!(file.read_to_string(&mut result));
            Ok(result)
        }).unwrap_or_else(|e| { panic!("Error reading {}: {}", filename, e) });

        if let Some(error) = validate_blacklist(&content) {
	    panic!("{} is invalid: {}", filename, error);
	}
    }
}
<|endoftext|>


<commit_before>extern crate libc;
extern crate time;

mod error;
pub mod cpu;
pub mod disk_stats;
pub mod disk_usage;
pub mod load;
pub mod memory;
pub mod network;
pub mod process_memory;

use std::fs;
use std::io;
use std::io::Read;
use std::path::Path;
use std::result;

pub use error::ProbeError;

pub type Result<T> = result::Result<T, error::ProbeError>;

#[inline]
fn file_to_string(path: &Path) -> io::Result<String> {
    let mut file = try!(fs::File::open(path));
    let mut read = String::new();
    try!(file.read_to_string(&mut read));
    Ok(read)
}

#[inline]
fn file_to_buf_reader(path: &Path) -> io::Result<io::BufReader<fs::File>> {
    fs::File::open(path).and_then(|f| Ok(io::BufReader::new(f)))
}

#[inline]
fn calculate_time_difference(first_time: u64, second_time: u64) -> Result<u64> {
    if first_time > second_time {
        Err(ProbeError::InvalidInput("first time was after second time".to_string()))
    } else {
        Ok(second_time - first_time)
    }
}

#[inline]
fn time_adjusted(first_value: u64, second_value: u64, time_difference_ns: u64) -> Result<u64> {
    if first_value < second_value {
        Err(ProbeError::UnexpectedContent("Value in first value was lower than in second value".to_string()))
    } else {
        Ok((first_value - second_value) * time_difference_ns / 60_000_000)
    }
}

#[inline]
fn parse_u64(segment: &str) -> Result<u64> {
    segment.parse().map_err(|_| {
        ProbeError::UnexpectedContent(format!("Could not parse '{}' as u64", segment).to_owned())
    })
}

#[cfg(test)]
mod tests {
    use error::ProbeError;

    #[test]
    fn test_calculate_time_difference() {
        assert_eq!(100, super::calculate_time_difference(100, 200).unwrap());
        assert!(super::calculate_time_difference(200, 100).is_err());
    }

    #[test]
    fn test_time_adjusted() {
        assert_eq!(1200, super::time_adjusted(2400, 1200, 60_000_000).unwrap());
        assert_eq!(600, super::time_adjusted(2400, 1200, 30_000_000).unwrap());
        assert_eq!(300, super::time_adjusted(2400, 1200, 15_000_000).unwrap());
    }

    #[test]
    fn test_time_adjusted_first_higher_than_lower() {
        match super::time_adjusted(1200, 2400, 60_000_000) {
            Err(ProbeError::UnexpectedContent(_)) => (),
            r => panic!("Unexpected result: {:?}", r)
        }
    }

    #[test]
    fn test_parse_u64() {
        assert_eq!(100, super::parse_u64("100").unwrap());
        assert!(super::parse_u64("something").is_err());
    }
}
<commit_msg>Fix weird grammar in error message<commit_after>extern crate libc;
extern crate time;

mod error;
pub mod cpu;
pub mod disk_stats;
pub mod disk_usage;
pub mod load;
pub mod memory;
pub mod network;
pub mod process_memory;

use std::fs;
use std::io;
use std::io::Read;
use std::path::Path;
use std::result;

pub use error::ProbeError;

pub type Result<T> = result::Result<T, error::ProbeError>;

#[inline]
fn file_to_string(path: &Path) -> io::Result<String> {
    let mut file = try!(fs::File::open(path));
    let mut read = String::new();
    try!(file.read_to_string(&mut read));
    Ok(read)
}

#[inline]
fn file_to_buf_reader(path: &Path) -> io::Result<io::BufReader<fs::File>> {
    fs::File::open(path).and_then(|f| Ok(io::BufReader::new(f)))
}

#[inline]
fn calculate_time_difference(first_time: u64, second_time: u64) -> Result<u64> {
    if first_time > second_time {
        Err(ProbeError::InvalidInput("first time was after second time".to_string()))
    } else {
        Ok(second_time - first_time)
    }
}

#[inline]
fn time_adjusted(first_value: u64, second_value: u64, time_difference_ns: u64) -> Result<u64> {
    if first_value < second_value {
        Err(ProbeError::UnexpectedContent("First value was lower than second value".to_string()))
    } else {
        Ok((first_value - second_value) * time_difference_ns / 60_000_000)
    }
}

#[inline]
fn parse_u64(segment: &str) -> Result<u64> {
    segment.parse().map_err(|_| {
        ProbeError::UnexpectedContent(format!("Could not parse '{}' as u64", segment).to_owned())
    })
}

#[cfg(test)]
mod tests {
    use error::ProbeError;

    #[test]
    fn test_calculate_time_difference() {
        assert_eq!(100, super::calculate_time_difference(100, 200).unwrap());
        assert!(super::calculate_time_difference(200, 100).is_err());
    }

    #[test]
    fn test_time_adjusted() {
        assert_eq!(1200, super::time_adjusted(2400, 1200, 60_000_000).unwrap());
        assert_eq!(600, super::time_adjusted(2400, 1200, 30_000_000).unwrap());
        assert_eq!(300, super::time_adjusted(2400, 1200, 15_000_000).unwrap());
    }

    #[test]
    fn test_time_adjusted_first_higher_than_lower() {
        match super::time_adjusted(1200, 2400, 60_000_000) {
            Err(ProbeError::UnexpectedContent(_)) => (),
            r => panic!("Unexpected result: {:?}", r)
        }
    }

    #[test]
    fn test_parse_u64() {
        assert_eq!(100, super::parse_u64("100").unwrap());
        assert!(super::parse_u64("something").is_err());
    }
}
<|endoftext|>


<commit_before>#![feature(associated_consts)]
#![feature(drain)]

extern crate uuid;

mod js_types;
mod alloc;

use std::cell::RefCell;
use std::collections::hash_set::HashSet;
use std::rc::Rc;

use uuid::Uuid;

use alloc::AllocBox;
use alloc::scope::Scope;
use js_types::js_type::{JsPtrEnum, JsVar};

pub struct ScopeManager {
    curr_scope: Rc<Scope>,
    alloc_box: Rc<RefCell<AllocBox>>
}

impl ScopeManager {
    pub fn new<F>(alloc_box: Rc<RefCell<AllocBox>>, callback: F) -> ScopeManager
        where F: Fn() -> HashSet<Uuid> + 'static {
        ScopeManager {
            curr_scope: Rc::new(Scope::new(&alloc_box, callback)),
            alloc_box: alloc_box,
        }
    }

    pub fn push_scope<F>(&mut self, callback: F) where F: Fn() -> HashSet<Uuid> + 'static {
        self.curr_scope = Rc::new(Scope::as_child(&self.curr_scope, &self.alloc_box, callback));
    }

    pub fn pop_scope(&mut self) {
        if let Some(parent) = self.curr_scope.parent.clone() {
            self.curr_scope = parent;
        } else {
            panic!("Tried to pop to parent scope, but parent did not exist!");
        }
    }

    pub fn alloc(&mut self, var: JsVar, ptr: Option<JsPtrEnum>) -> Uuid {
        Rc::get_mut(&mut self.curr_scope).unwrap().push(var, ptr)
    }

    pub fn load(&self, uuid: &Uuid) -> Result<(JsVar, Option<JsPtrEnum>), String> {
        if let (Some(v), ptr) = self.curr_scope.get_var_copy(uuid) {
            Ok((v, ptr))
        } else { Err(format!("Lookup of uuid {} failed!", uuid)) }
    }

    pub fn store(&mut self, var: JsVar, ptr: Option<JsPtrEnum>) -> bool {
        Rc::get_mut(&mut self.curr_scope).unwrap().update_var(var, ptr)
    }
}

pub fn init_gc<F>(callback: F) -> ScopeManager
    where F: Fn() -> HashSet<Uuid> + 'static {
    let alloc_box = Rc::new(RefCell::new(AllocBox::new()));
    ScopeManager::new(alloc_box, callback)
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::collections::hash_set::HashSet;
    use std::ptr::null_mut;
    use std::rc::Rc;
    use uuid::Uuid;

    fn dummy_callback() -> HashSet<Uuid> {
        HashSet::new()
    }
    // TODO
}
<commit_msg>Fix lib test imports<commit_after>#![feature(associated_consts)]
#![feature(drain)]

extern crate uuid;

mod js_types;
mod alloc;

use std::cell::RefCell;
use std::collections::hash_set::HashSet;
use std::rc::Rc;

use uuid::Uuid;

use alloc::AllocBox;
use alloc::scope::Scope;
use js_types::js_type::{JsPtrEnum, JsVar};

pub struct ScopeManager {
    curr_scope: Rc<Scope>,
    alloc_box: Rc<RefCell<AllocBox>>
}

impl ScopeManager {
    pub fn new<F>(alloc_box: Rc<RefCell<AllocBox>>, callback: F) -> ScopeManager
        where F: Fn() -> HashSet<Uuid> + 'static {
        ScopeManager {
            curr_scope: Rc::new(Scope::new(&alloc_box, callback)),
            alloc_box: alloc_box,
        }
    }

    pub fn push_scope<F>(&mut self, callback: F) where F: Fn() -> HashSet<Uuid> + 'static {
        self.curr_scope = Rc::new(Scope::as_child(&self.curr_scope, &self.alloc_box, callback));
    }

    pub fn pop_scope(&mut self) {
        if let Some(parent) = self.curr_scope.parent.clone() {
            self.curr_scope = parent;
        } else {
            panic!("Tried to pop to parent scope, but parent did not exist!");
        }
    }

    pub fn alloc(&mut self, var: JsVar, ptr: Option<JsPtrEnum>) -> Uuid {
        Rc::get_mut(&mut self.curr_scope).unwrap().push(var, ptr)
    }

    pub fn load(&self, uuid: &Uuid) -> Result<(JsVar, Option<JsPtrEnum>), String> {
        if let (Some(v), ptr) = self.curr_scope.get_var_copy(uuid) {
            Ok((v, ptr))
        } else { Err(format!("Lookup of uuid {} failed!", uuid)) }
    }

    pub fn store(&mut self, var: JsVar, ptr: Option<JsPtrEnum>) -> bool {
        Rc::get_mut(&mut self.curr_scope).unwrap().update_var(var, ptr)
    }
}

pub fn init_gc<F>(callback: F) -> ScopeManager
    where F: Fn() -> HashSet<Uuid> + 'static {
    let alloc_box = Rc::new(RefCell::new(AllocBox::new()));
    ScopeManager::new(alloc_box, callback)
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::collections::hash_set::HashSet;
    use uuid::Uuid;

    fn dummy_callback() -> HashSet<Uuid> {
        HashSet::new()
    }
    // TODO
}
<|endoftext|>


<commit_before>//!
//! ```
//! use document::Package;
//! let package = Package::new();
//! let doc = package.as_document();
//!
//! let hello = doc.create_element("hello");
//! hello.set_attribute_value("planet", "Earth");
//! let comment = doc.create_comment("What about other planets?");
//! let text = doc.create_text("Greetings, Earthlings!");
//!
//! hello.append_child(comment);
//! hello.append_child(text);
//! doc.root().append_child(hello);
//! ```
//!
//! ### Design decisions
//!
//! Try to leverage the type system as much as possible.

#![crate_name = "document"]

#![feature(collections)]
#![feature(core)]
#![feature(io)]
#![feature(rustc_private)]
#![feature(std_misc)]
#![feature(test)]

extern crate arena;
extern crate test;
extern crate xxhash;

#[macro_use]
extern crate peresil;

use std::fmt;

mod string_pool;
mod raw;

pub mod str;
pub mod thindom4;
pub mod dom4;
pub mod parser;
pub mod writer;

#[derive(Debug,PartialEq,Eq,PartialOrd)]
pub struct QName<'s> {
    namespace_uri: Option<&'s str>,
    local_part: &'s str,
}

impl<'s> QName<'s> {
    pub fn new(local_part: &'s str) -> QName<'s> {
        QName::with_namespace_uri(None, local_part)
    }

    pub fn with_namespace_uri(namespace_uri: Option<&'s str>, local_part: &'s str) -> QName<'s> {
        QName {
            namespace_uri: namespace_uri,
            local_part: local_part,
        }
    }

    pub fn namespace_uri(&self) -> Option<&'s str> { self.namespace_uri }
    pub fn local_part(&self) -> &'s str { self.local_part }
}

impl<'s> Ord for QName<'s> {
    fn cmp(&self, other: &QName<'s>) -> std::cmp::Ordering {
        self.partial_cmp(other).unwrap()
    }
}

pub trait ToQName<'s> {
    fn to_qname(self) -> QName<'s>;
}

impl<'s> ToQName<'s> for QName<'s> {
    fn to_qname(self) -> QName<'s> { self }
}

impl<'s> ToQName<'s> for (&'s str, &'s str) {
    fn to_qname(self) -> QName<'s> { QName { namespace_uri: Some(self.0), local_part: self.1 } }
}

impl<'s> ToQName<'s> for &'s str {
    fn to_qname(self) -> QName<'s> { QName { namespace_uri: None, local_part: self } }
}

pub struct Package {
    storage: raw::Storage,
    connections: raw::Connections,
}

impl Package {
    pub fn new() -> Package {
        let s = raw::Storage::new();
        let root = s.create_root();
        Package {
            storage: s,
            connections: raw::Connections::new(root),
        }
    }

    pub fn as_document(&self) -> dom4::Document {
        dom4::Document::new(&self.storage, &self.connections)
    }

    pub fn as_thin_document(&self) -> (thindom4::Storage, thindom4::Connections) {
        let s = thindom4::Storage::new(&self.storage);
        let c = thindom4::Connections::new(&self.connections);
        (s, c)
    }
}

impl PartialEq for Package {
    fn eq(&self, other: &Package) -> bool {
        self as *const Package == other as *const Package
    }
}

impl fmt::Debug for Package {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Package")
    }
}
<commit_msg>Document items in top-level module<commit_after>//!
//! ```
//! use document::Package;
//! let package = Package::new();
//! let doc = package.as_document();
//!
//! let hello = doc.create_element("hello");
//! hello.set_attribute_value("planet", "Earth");
//! let comment = doc.create_comment("What about other planets?");
//! let text = doc.create_text("Greetings, Earthlings!");
//!
//! hello.append_child(comment);
//! hello.append_child(text);
//! doc.root().append_child(hello);
//! ```
//!
//! ### Design decisions
//!
//! Try to leverage the type system as much as possible.

#![crate_name = "document"]

#![feature(collections)]
#![feature(core)]
#![feature(io)]
#![feature(rustc_private)]
#![feature(std_misc)]
#![feature(test)]

extern crate arena;
extern crate test;
extern crate xxhash;

#[macro_use]
extern crate peresil;

use std::fmt;

mod string_pool;
mod raw;

pub mod str;
#[doc(hidden)]
pub mod thindom4;
pub mod dom4;
pub mod parser;
pub mod writer;

/// A namespace-qualified name
#[derive(Debug,PartialEq,Eq,PartialOrd)]
pub struct QName<'s> {
    namespace_uri: Option<&'s str>,
    local_part: &'s str,
}

impl<'s> QName<'s> {
    /// Create a `QName` without a namespace
    pub fn new(local_part: &'s str) -> QName<'s> {
        QName::with_namespace_uri(None, local_part)
    }

    /// Create a `QName` with an optional namespace
    pub fn with_namespace_uri(namespace_uri: Option<&'s str>, local_part: &'s str) -> QName<'s> {
        QName {
            namespace_uri: namespace_uri,
            local_part: local_part,
        }
    }

    pub fn namespace_uri(&self) -> Option<&'s str> { self.namespace_uri }
    pub fn local_part(&self) -> &'s str { self.local_part }
}

impl<'s> Ord for QName<'s> {
    fn cmp(&self, other: &QName<'s>) -> std::cmp::Ordering {
        self.partial_cmp(other).unwrap()
    }
}

/// Convert item into a `QName`
pub trait ToQName<'s> {
    fn to_qname(self) -> QName<'s>;
}

impl<'s> ToQName<'s> for QName<'s> {
    fn to_qname(self) -> QName<'s> { self }
}

impl<'s> ToQName<'s> for (&'s str, &'s str) {
    fn to_qname(self) -> QName<'s> { QName { namespace_uri: Some(self.0), local_part: self.1 } }
}

impl<'s> ToQName<'s> for &'s str {
    fn to_qname(self) -> QName<'s> { QName { namespace_uri: None, local_part: self } }
}

/// The main entrypoint to an XML document
///
/// This is an opaque structure that stores the internal details of
/// the XML document. Modify the document via `as_document`.
pub struct Package {
    storage: raw::Storage,
    connections: raw::Connections,
}

impl Package {
    pub fn new() -> Package {
        let s = raw::Storage::new();
        let root = s.create_root();
        Package {
            storage: s,
            connections: raw::Connections::new(root),
        }
    }

    pub fn as_document(&self) -> dom4::Document {
        dom4::Document::new(&self.storage, &self.connections)
    }

    #[doc(hidden)]
    pub fn as_thin_document(&self) -> (thindom4::Storage, thindom4::Connections) {
        let s = thindom4::Storage::new(&self.storage);
        let c = thindom4::Connections::new(&self.connections);
        (s, c)
    }
}

impl PartialEq for Package {
    fn eq(&self, other: &Package) -> bool {
        self as *const Package == other as *const Package
    }
}

impl fmt::Debug for Package {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Package")
    }
}
<|endoftext|>


<commit_before>extern crate graphics;
extern crate input;

use graphics::{ Context, Graphics };
use input::{ GenericEvent };

mod drawutils;

pub struct Timeline {
    pub frames: u32,
    pub current_frame: u32,
    pub hover_frame: Option<u32>,
    pub start_frame: u32,
    pub bounds: [u32; 4],
    pub settings: TimelineSettings,
}

pub struct TimelineSettings {
    pub left_to_frame: f64,
    pub right_to_frame: f64,
    pub top_to_frame: f64,
    pub frame_width: f64,
    pub frame_height: f64,
    pub frame_offset_x: f64,
    pub left_to_goto_beginning: f64,
    pub right_to_goto_end: f64,
}

impl TimelineSettings {
    pub fn new() -> TimelineSettings {
        TimelineSettings {
            left_to_frame: 20.0,
            right_to_frame: 20.0,
            top_to_frame: 15.0,
            frame_width: 10.0,
            frame_height: 10.0,
            frame_offset_x: 5.0,
            left_to_goto_beginning: 15.0,
            right_to_goto_end: 15.0,
        }
    }
}

pub struct ComputedTimelineSettings {
    pub width_for_frames: f64,
    pub max_visible_frames: u32,
    pub end_frame: u32,
}

impl ComputedTimelineSettings {
    pub fn new(timeline: &Timeline, settings: &TimelineSettings)
        -> ComputedTimelineSettings
    {
        use std::cmp::min;

        let width_for_frames = timeline.bounds[2] as f64
            - settings.left_to_frame - settings.right_to_frame;
        let max_visible_frames: u32 =
            if width_for_frames < settings.frame_width {
                0
            } else {
                1
                + (
                    (width_for_frames - settings.frame_width)
                    / (settings.frame_width + settings.frame_offset_x)
                ) as u32
            };
        let end_frame = min(
            timeline.frames,
            timeline.start_frame + max_visible_frames
        );

        ComputedTimelineSettings {
            width_for_frames: width_for_frames,
            max_visible_frames: max_visible_frames,
            end_frame: end_frame
        }
    }
}

impl Timeline {
    pub fn new_frames_bounds(frames: u32, bounds: [u32; 4]) -> Timeline {
        Timeline {
            frames: frames,
            current_frame: 0,
            hover_frame: None,
            start_frame: 0,
            bounds: bounds,
            settings: TimelineSettings::new(),
        }
    }

    pub fn event<E: GenericEvent>(&mut self, e: &E) {
        use input::MouseCursorEvent;

        if let Some(pos) = e.mouse_cursor_args() {
            let computed_settings = ComputedTimelineSettings::new(self,
                &self.settings);

            let left_to_frame: f64 = self.settings.left_to_frame;
            let frame_width: f64 = self.settings.frame_width;
            let frame_offset_x: f64 = self.settings.frame_offset_x;

            let end_frame: u32 = computed_settings.end_frame;

            let x = pos[0];
            let left = self.bounds[0] as f64 + left_to_frame;
            let right = left + end_frame as f64 * (frame_width + frame_offset_x);

            if x < left || x > right {
                self.hover_frame = None;
            } else {
                let i: u32 = ((x - left) / (frame_width + frame_offset_x)) as u32;
                self.hover_frame = Some(i);
            }
        }
    }

    pub fn draw_timeline<G: Graphics>(&self, c: &Context, g: &mut G) {
        use std::cmp::min;

        let left_to_frame: f64 = self.settings.left_to_frame;
        let right_to_frame: f64 = self.settings.right_to_frame;
        let top_to_frame: f64 = self.settings.top_to_frame;
        let frame_width: f64 = self.settings.frame_width;
        let frame_height: f64 = self.settings.frame_height;
        let frame_offset_x: f64 = self.settings.frame_offset_x;
        let left_to_goto_beginning: f64 = self.settings.left_to_goto_beginning;
        let right_to_goto_end: f64 = self.settings.right_to_goto_end;

        let computed_settings = ComputedTimelineSettings::new(self, &self.settings);

        let slide_offset: f64 = 0.0;

        let width_for_frames = computed_settings.width_for_frames;
        let max_visible_frames: u32 = computed_settings.max_visible_frames;
        let end_frame = computed_settings.end_frame;

        // Draw bounds to see where the control is.
        {
            use graphics::Rectangle;

            let bounds = [
                    self.bounds[0] as f64,
                    self.bounds[1] as f64,
                    self.bounds[2] as f64,
                    self.bounds[3] as f64
                ];
            Rectangle::new_border([0.0, 0.0, 1.0, 1.0], 0.5)
                .draw(bounds, &c.draw_state, c.transform, g);
        }

        // Draw a sequence of squares for each frame.
        {
            use graphics::Rectangle;

            let rect = Rectangle::new_border([0.0, 0.0, 1.0, 1.0], 0.5);
            for i in 0..end_frame - self.start_frame {
                // Don't draw the hover frame.
                if Some(i) == self.hover_frame { continue; }

                let bounds = [
                    self.bounds[0] as f64 + left_to_frame
                        + i as f64 * (frame_width + frame_offset_x)
                        - slide_offset,
                    self.bounds[1] as f64 + top_to_frame,
                    frame_width,
                    frame_height
                ];
                rect.draw(bounds, &c.draw_state, c.transform, g);
            }
        }

        // Draw navigate to beginning button.
        {
            use graphics::Line;
            use graphics::math::*;

            let line = Line::new([0.0, 0.0, 1.0, 1.0], 0.5);

            let at_beginning: bool = false;
            drawutils::draw_goto_end(
                at_beginning,
                [
                    self.bounds[0] as f64 + left_to_goto_beginning,
                    self.bounds[1] as f64 + top_to_frame
                ],
                [
                    -frame_width * 0.5,
                    frame_height
                ],
                &line,
                c, g
            );

            let at_end: bool = true;
            drawutils::draw_goto_end(
                at_end,
                [
                    self.bounds[0] as f64 + self.bounds[2] as f64
                        - right_to_goto_end,
                    self.bounds[1] as f64 + top_to_frame
                ],
                [
                    frame_width * 0.5,
                    frame_height
                ],
                &line,
                c, g
            );
        }
    }

    pub fn draw_drag<G: Graphics>(&self, c: &Context, g: &mut G) {

    }
}
<commit_msg>Don't hover outside<commit_after>extern crate graphics;
extern crate input;

use graphics::{ Context, Graphics };
use input::{ GenericEvent };

mod drawutils;

pub struct Timeline {
    pub frames: u32,
    pub current_frame: u32,
    pub hover_frame: Option<u32>,
    pub start_frame: u32,
    pub bounds: [u32; 4],
    pub settings: TimelineSettings,
}

pub struct TimelineSettings {
    pub left_to_frame: f64,
    pub right_to_frame: f64,
    pub top_to_frame: f64,
    pub frame_width: f64,
    pub frame_height: f64,
    pub frame_offset_x: f64,
    pub left_to_goto_beginning: f64,
    pub right_to_goto_end: f64,
}

impl TimelineSettings {
    pub fn new() -> TimelineSettings {
        TimelineSettings {
            left_to_frame: 20.0,
            right_to_frame: 20.0,
            top_to_frame: 15.0,
            frame_width: 10.0,
            frame_height: 10.0,
            frame_offset_x: 5.0,
            left_to_goto_beginning: 15.0,
            right_to_goto_end: 15.0,
        }
    }
}

pub struct ComputedTimelineSettings {
    pub width_for_frames: f64,
    pub max_visible_frames: u32,
    pub end_frame: u32,
}

impl ComputedTimelineSettings {
    pub fn new(timeline: &Timeline, settings: &TimelineSettings)
        -> ComputedTimelineSettings
    {
        use std::cmp::min;

        let width_for_frames = timeline.bounds[2] as f64
            - settings.left_to_frame - settings.right_to_frame;
        let max_visible_frames: u32 =
            if width_for_frames < settings.frame_width {
                0
            } else {
                1
                + (
                    (width_for_frames - settings.frame_width)
                    / (settings.frame_width + settings.frame_offset_x)
                ) as u32
            };
        let end_frame = min(
            timeline.frames,
            timeline.start_frame + max_visible_frames
        );

        ComputedTimelineSettings {
            width_for_frames: width_for_frames,
            max_visible_frames: max_visible_frames,
            end_frame: end_frame
        }
    }
}

impl Timeline {
    pub fn new_frames_bounds(frames: u32, bounds: [u32; 4]) -> Timeline {
        Timeline {
            frames: frames,
            current_frame: 0,
            hover_frame: None,
            start_frame: 0,
            bounds: bounds,
            settings: TimelineSettings::new(),
        }
    }

    pub fn event<E: GenericEvent>(&mut self, e: &E) {
        use input::MouseCursorEvent;

        if let Some(pos) = e.mouse_cursor_args() {
            let computed_settings = ComputedTimelineSettings::new(self,
                &self.settings);

            let left_to_frame: f64 = self.settings.left_to_frame;
            let frame_width: f64 = self.settings.frame_width;
            let frame_offset_x: f64 = self.settings.frame_offset_x;

            let end_frame: u32 = computed_settings.end_frame;

            let (x, y) = (pos[0], pos[1]);

            let left = self.bounds[0] as f64 + left_to_frame;
            let right = left + end_frame as f64 * (frame_width + frame_offset_x);
            let top = self.bounds[1] as f64;
            let bottom = top + self.bounds[3] as f64;

            if x < left || x > right
            || y < top || y > bottom {
                self.hover_frame = None;
            } else {
                let i: u32 = ((x - left) / (frame_width + frame_offset_x)) as u32;
                self.hover_frame = Some(i);
            }
        }
    }

    pub fn draw_timeline<G: Graphics>(&self, c: &Context, g: &mut G) {
        use std::cmp::min;

        let left_to_frame: f64 = self.settings.left_to_frame;
        let right_to_frame: f64 = self.settings.right_to_frame;
        let top_to_frame: f64 = self.settings.top_to_frame;
        let frame_width: f64 = self.settings.frame_width;
        let frame_height: f64 = self.settings.frame_height;
        let frame_offset_x: f64 = self.settings.frame_offset_x;
        let left_to_goto_beginning: f64 = self.settings.left_to_goto_beginning;
        let right_to_goto_end: f64 = self.settings.right_to_goto_end;

        let computed_settings = ComputedTimelineSettings::new(self, &self.settings);

        let slide_offset: f64 = 0.0;

        let width_for_frames = computed_settings.width_for_frames;
        let max_visible_frames: u32 = computed_settings.max_visible_frames;
        let end_frame = computed_settings.end_frame;

        // Draw bounds to see where the control is.
        {
            use graphics::Rectangle;

            let bounds = [
                    self.bounds[0] as f64,
                    self.bounds[1] as f64,
                    self.bounds[2] as f64,
                    self.bounds[3] as f64
                ];
            Rectangle::new_border([0.0, 0.0, 1.0, 1.0], 0.5)
                .draw(bounds, &c.draw_state, c.transform, g);
        }

        // Draw a sequence of squares for each frame.
        {
            use graphics::Rectangle;

            let rect = Rectangle::new_border([0.0, 0.0, 1.0, 1.0], 0.5);
            for i in 0..end_frame - self.start_frame {
                // Don't draw the hover frame.
                if Some(i) == self.hover_frame { continue; }

                let bounds = [
                    self.bounds[0] as f64 + left_to_frame
                        + i as f64 * (frame_width + frame_offset_x)
                        - slide_offset,
                    self.bounds[1] as f64 + top_to_frame,
                    frame_width,
                    frame_height
                ];
                rect.draw(bounds, &c.draw_state, c.transform, g);
            }
        }

        // Draw navigate to beginning button.
        {
            use graphics::Line;
            use graphics::math::*;

            let line = Line::new([0.0, 0.0, 1.0, 1.0], 0.5);

            let at_beginning: bool = false;
            drawutils::draw_goto_end(
                at_beginning,
                [
                    self.bounds[0] as f64 + left_to_goto_beginning,
                    self.bounds[1] as f64 + top_to_frame
                ],
                [
                    -frame_width * 0.5,
                    frame_height
                ],
                &line,
                c, g
            );

            let at_end: bool = true;
            drawutils::draw_goto_end(
                at_end,
                [
                    self.bounds[0] as f64 + self.bounds[2] as f64
                        - right_to_goto_end,
                    self.bounds[1] as f64 + top_to_frame
                ],
                [
                    frame_width * 0.5,
                    frame_height
                ],
                &line,
                c, g
            );
        }
    }

    pub fn draw_drag<G: Graphics>(&self, c: &Context, g: &mut G) {

    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate serde_derive;

extern crate serde;
extern crate serde_json;
extern crate toml;

#[cfg(test)]
extern crate tempdir;

use std::path;
use std::error;
use std::fs;

pub mod dict;

pub struct Cascade {
    pub dicts: Vec<dict::Dictionary>,
}

impl Cascade {
    pub fn with_filepath_strs(files: &Vec<&str>, delimiter: &str) -> Result<Cascade, Box<error::Error>> {
        let mut ds: Vec<dict::Dictionary> = Vec::new();
        for f in files {
            if let Some(ext) = path::Path::new(f).extension() {
                if ext == "json" {
                    ds.push(try!(dict::Dictionary::with_json_filepath(f, delimiter)));
                    continue;
                }else if ext == "toml" {
                    ds.push(try!(dict::Dictionary::with_toml_filepath(f, delimiter)));
                    continue;
                }
            }

            // Try to read it as json if the file type couldn't be guessed from its extension.
            ds.push(try!(dict::Dictionary::with_json_filepath(f, delimiter)));
        }
        Ok(Self{dicts: ds})
    }

    pub fn with_dirpath<P: AsRef<path::Path>>(dir: P, delimiter: &str) -> Result<Cascade, Box<error::Error>> {
        let rd = try!(fs::read_dir(dir));
        let mut v:Vec<Box<String>> = Vec::new();
        for f in rd {
            if let Some(pathstr) = try!(f).path().to_str() {
                v.push(Box::new(pathstr.to_string()));
            }
        }
        return Self::with_filepath_strs((&v.iter().map(|s| &*s as &str).collect::<Vec<&str>>()), delimiter);
    }

    pub fn translate<'a, 'b>(&'a self, key: &'b str) -> Option<&'a str> {
        for dict in &self.dicts {
            if let Some(x) = dict.translate(key) {
                return Some(&x);
            }
        }
        return None;
    }
}

#[cfg(test)]
mod tests {
    use ::*;
    use ::dict::*;
    use std::fs::File;
    use std::io::Write;

    #[test]
    fn test_cascade() {
        let d1 = Dictionary::with_json_str("{\"name\":\"ja\", \"map\":{\"a\":\"b\"}}", ".").unwrap();
        let d2 = Dictionary::with_json_str("{\"name\":\"en\", \"map\":{\"a\":\"c\", \"x\":\"y\"}}", ".").unwrap();
        let ds = vec![d1, d2];
        let c = Cascade{dicts: ds};
        let t = |key| c.translate(key).unwrap();
        assert_eq!(c.translate("a").unwrap(), "b");
        assert_eq!(c.translate("x").unwrap(), "y");
        assert_eq!(t("a"), "b");
        assert_eq!(t("x"), "y");
    }

    #[test]
    fn test_cascade_from_dir() {
        let tmpdir = tempdir::TempDir::new("test").unwrap();
        let s1 = "{\"name\":\"ja\", \"map\":{\"a\":\"b\"}}";
        let s2 = "{\"name\":\"en\", \"map\":{\"a\":\"c\", \"x\":\"y\"}}";
        let s3 = r#"
            name = "t"

            [map]
            a = "d"
            z = "Z"
        "#;

        let mut f1 = File::create(tmpdir.path().join("1.json")).unwrap();
        let mut f2 = File::create(tmpdir.path().join("2.json")).unwrap();
        let mut f3 = File::create(tmpdir.path().join("3.toml")).unwrap();
        let _ = f1.write_all(s1.as_bytes());
        let _ = f2.write_all(s2.as_bytes());
        let _ = f3.write_all(s3.as_bytes());

        let c = Cascade::with_dirpath(&tmpdir.path().to_str().unwrap(), ".").unwrap();
        let t = |key| c.translate(key).unwrap();
        assert_eq!(c.translate("a").unwrap(), "b");
        assert_eq!(c.translate("x").unwrap(), "y");
        assert_eq!(c.translate("z").unwrap(), "Z");
        assert_eq!(t("a"), "b");
        assert_eq!(t("x"), "y");
        assert_eq!(t("z"), "Z");

        tmpdir.close().unwrap();
    }
}
<commit_msg>Added pub use dict in lib.rs<commit_after>#[macro_use]
extern crate serde_derive;

extern crate serde;
extern crate serde_json;
extern crate toml;

#[cfg(test)]
extern crate tempdir;

use std::path;
use std::error;
use std::fs;

pub mod dict;
pub use dict::Dictionary;

pub struct Cascade {
    pub dicts: Vec<Dictionary>,
}

impl Cascade {
    pub fn with_filepath_strs(files: &Vec<&str>, delimiter: &str) -> Result<Cascade, Box<error::Error>> {
        let mut ds: Vec<Dictionary> = Vec::new();
        for f in files {
            if let Some(ext) = path::Path::new(f).extension() {
                if ext == "json" {
                    ds.push(try!(Dictionary::with_json_filepath(f, delimiter)));
                    continue;
                }else if ext == "toml" {
                    ds.push(try!(Dictionary::with_toml_filepath(f, delimiter)));
                    continue;
                }
            }

            // Try to read it as json if the file type couldn't be guessed from its extension.
            ds.push(try!(Dictionary::with_json_filepath(f, delimiter)));
        }
        Ok(Self{dicts: ds})
    }

    pub fn with_dirpath<P: AsRef<path::Path>>(dir: P, delimiter: &str) -> Result<Cascade, Box<error::Error>> {
        let rd = try!(fs::read_dir(dir));
        let mut v:Vec<Box<String>> = Vec::new();
        for f in rd {
            if let Some(pathstr) = try!(f).path().to_str() {
                v.push(Box::new(pathstr.to_string()));
            }
        }
        return Self::with_filepath_strs((&v.iter().map(|s| &*s as &str).collect::<Vec<&str>>()), delimiter);
    }

    pub fn translate<'a, 'b>(&'a self, key: &'b str) -> Option<&'a str> {
        for dict in &self.dicts {
            if let Some(x) = dict.translate(key) {
                return Some(&x);
            }
        }
        return None;
    }
}

#[cfg(test)]
mod tests {
    use ::*;
    use std::fs::File;
    use std::io::Write;

    #[test]
    fn test_cascade() {
        let d1 = Dictionary::with_json_str("{\"name\":\"ja\", \"map\":{\"a\":\"b\"}}", ".").unwrap();
        let d2 = Dictionary::with_json_str("{\"name\":\"en\", \"map\":{\"a\":\"c\", \"x\":\"y\"}}", ".").unwrap();
        let ds = vec![d1, d2];
        let c = Cascade{dicts: ds};
        let t = |key| c.translate(key).unwrap();
        assert_eq!(c.translate("a").unwrap(), "b");
        assert_eq!(c.translate("x").unwrap(), "y");
        assert_eq!(t("a"), "b");
        assert_eq!(t("x"), "y");
    }

    #[test]
    fn test_cascade_from_dir() {
        let tmpdir = tempdir::TempDir::new("test").unwrap();
        let s1 = "{\"name\":\"ja\", \"map\":{\"a\":\"b\"}}";
        let s2 = "{\"name\":\"en\", \"map\":{\"a\":\"c\", \"x\":\"y\"}}";
        let s3 = r#"
            name = "t"

            [map]
            a = "d"
            z = "Z"
        "#;

        let mut f1 = File::create(tmpdir.path().join("1.json")).unwrap();
        let mut f2 = File::create(tmpdir.path().join("2.json")).unwrap();
        let mut f3 = File::create(tmpdir.path().join("3.toml")).unwrap();
        let _ = f1.write_all(s1.as_bytes());
        let _ = f2.write_all(s2.as_bytes());
        let _ = f3.write_all(s3.as_bytes());

        let c = Cascade::with_dirpath(&tmpdir.path().to_str().unwrap(), ".").unwrap();
        let t = |key| c.translate(key).unwrap();
        assert_eq!(c.translate("a").unwrap(), "b");
        assert_eq!(c.translate("x").unwrap(), "y");
        assert_eq!(c.translate("z").unwrap(), "Z");
        assert_eq!(t("a"), "b");
        assert_eq!(t("x"), "y");
        assert_eq!(t("z"), "Z");

        tmpdir.close().unwrap();
    }
}
<|endoftext|>


<commit_before>//! This crate provides native rust implementations of
//! Image encoders and decoders and basic image manipulation
//! functions.

#![crate_name = "image"]
#![crate_type = "rlib"]

#![warn(missing_docs)]
#![warn(unused_qualifications)]
#![warn(unused_typecasts)]
#![deny(missing_copy_implementations)]
// necessary for Primitive trait
#![feature(old_orphan_check, old_impl_check)]

extern crate flate;
extern crate num;

pub use color::ColorType as ColorType;
pub use traits::Primitive;

pub use color::ColorType:: {
    Grey,
    RGB,
    Palette,
    GreyA,
    RGBA,
};
pub use color:: {
    Luma,
    LumaA,
    Rgb,
    Rgba,
};

pub use buffer::Pixel;

pub use image::ImageDecoder as ImageDecoder;
pub use image::ImageError as ImageError;
pub use image::ImageResult as ImageResult;
pub use image::ImageFormat as ImageFormat;
pub use imageops::FilterType as FilterType;

pub use imageops:: {
    Triangle,
    Nearest,
    CatmullRom,
    Gaussian,
    Lanczos3
};

pub use image::ImageFormat:: {
    PNG,
    JPEG,
    GIF,
    WEBP,
    PPM
};

// Image Types
pub use image::SubImage as SubImage;
pub use dynimage::DynamicImage as DynamicImage;
pub use buffer::{
    ImageBuffer,
    RgbImage,
    RgbaImage,
    GreyImage,
    GreyAlphaImage
};

// Traits
pub use image::GenericImage as GenericImage;

// Iterators
pub use image::Pixels as Pixels;
pub use image::MutPixels as MutPixels;

/// Opening and loading images
pub use dynimage:: {
    open,
    load,
    load_from_memory,
    load_from_memory_with_format,
    save_buffer,
};
pub use dynimage::DynamicImage:: {
    ImageRgb8,
    ImageRgba8,
    ImageLuma8,
    ImageLumaA8,
};

pub use animation:: {
    Frame, Frames
};

// Math utils
pub mod math;

// Image Processing Functions
pub mod imageops;

// Image Codecs
pub mod webp;
pub mod ppm;
pub mod png;
pub mod jpeg;
pub mod gif;
pub mod tiff;
pub mod tga;

mod image;
mod dynimage;
mod color;
mod buffer;
mod traits;
mod animation;
<commit_msg>Allow unstable code<commit_after>//! This crate provides native rust implementations of
//! Image encoders and decoders and basic image manipulation
//! functions.

#![crate_name = "image"]
#![crate_type = "rlib"]

#![warn(missing_docs)]
#![warn(unused_qualifications)]
#![warn(unused_typecasts)]
#![deny(missing_copy_implementations)]
#![allow(unstable)]
// necessary for Primitive trait
#![feature(old_orphan_check, old_impl_check)]

extern crate flate;
extern crate num;

pub use color::ColorType as ColorType;
pub use traits::Primitive;

pub use color::ColorType:: {
    Grey,
    RGB,
    Palette,
    GreyA,
    RGBA,
};
pub use color:: {
    Luma,
    LumaA,
    Rgb,
    Rgba,
};

pub use buffer::Pixel;

pub use image::ImageDecoder as ImageDecoder;
pub use image::ImageError as ImageError;
pub use image::ImageResult as ImageResult;
pub use image::ImageFormat as ImageFormat;
pub use imageops::FilterType as FilterType;

pub use imageops:: {
    Triangle,
    Nearest,
    CatmullRom,
    Gaussian,
    Lanczos3
};

pub use image::ImageFormat:: {
    PNG,
    JPEG,
    GIF,
    WEBP,
    PPM
};

// Image Types
pub use image::SubImage as SubImage;
pub use dynimage::DynamicImage as DynamicImage;
pub use buffer::{
    ImageBuffer,
    RgbImage,
    RgbaImage,
    GreyImage,
    GreyAlphaImage
};

// Traits
pub use image::GenericImage as GenericImage;

// Iterators
pub use image::Pixels as Pixels;
pub use image::MutPixels as MutPixels;

/// Opening and loading images
pub use dynimage:: {
    open,
    load,
    load_from_memory,
    load_from_memory_with_format,
    save_buffer,
};
pub use dynimage::DynamicImage:: {
    ImageRgb8,
    ImageRgba8,
    ImageLuma8,
    ImageLumaA8,
};

pub use animation:: {
    Frame, Frames
};

// Math utils
pub mod math;

// Image Processing Functions
pub mod imageops;

// Image Codecs
pub mod webp;
pub mod ppm;
pub mod png;
pub mod jpeg;
pub mod gif;
pub mod tiff;
pub mod tga;

mod image;
mod dynimage;
mod color;
mod buffer;
mod traits;
mod animation;
<|endoftext|>


<commit_before>extern crate handlebars;
extern crate tempdir;

pub mod errors;
pub use errors::Error;

use handlebars::{Context, Handlebars, Helper, RenderContext, RenderError};
use std::collections::BTreeMap;
use std::env;
use std::fs::{self, File, create_dir_all};
use std::path::{Path, PathBuf, MAIN_SEPARATOR};
use std::process::{self, Stdio, Command};
use std::io::{self, Read, Write};

const TMP_PREFIX: &'static str = "porteurbars";

pub type Result<T> = std::result::Result<T, Error>;

pub struct Template<'a> {
    /// target output dir
    pub target: &'a Path,
    /// defaults env faile
    pub defaults: &'a str,
    /// relative path to project template src
    pub project: &'a Path,
    /// remote git repo
    pub repo: &'a str,
}

impl<'a> Template<'a> {
    /// Apply project template
    pub fn apply(&self) -> Result<&'a Path> {
        // resolve template
        let scratch = try!(tempdir::TempDir::new(TMP_PREFIX));
        try!(clone(self.repo, scratch.path().to_str().unwrap(), None));

        match find(scratch.path(), self.defaults) {
            Ok(Some(defaults)) => {

                // resolve context
                let map = try!(parse_defaults(defaults.as_path()));
                let resolved = try!(interact(&map));
                let data = Context::wraps(&resolved);

                let mut template_dir = scratch.path().to_path_buf();
                template_dir.push("template");

                // apply handlebars processing
                let apply = |path: &Path, hbs: &mut Handlebars| -> Result<()> {
                    // /tmp/download_dir/
                    let scratchpath =
                        &format!("{}{}", template_dir.to_str().unwrap(), MAIN_SEPARATOR)[..];

                    // path relatived based on scratch dir
                    let localpath = path.to_str()
                        .unwrap()
                        .trim_left_matches(scratchpath);

                    // eval path as template
                    let evalpath = try!(hbs.template_render(&localpath, &resolved));

                    // rewritten path, based on target dir and eval path
                    let targetpath = self.target.join(evalpath);

                    if path.is_file() {
                        let mut file = try!(File::open(path));
                        let mut s = String::new();
                        try!(file.read_to_string(&mut s));
                        let mut file = try!(File::create(targetpath));
                        try!(hbs.template_renderw(&s, &data, &mut file));
                    } else {
                        try!(fs::create_dir_all(targetpath))
                    }
                    Ok(())
                };

                try!(create_dir_all(self.target));
                let mut hbs = bars();

                try!(walk(&mut hbs, &template_dir.as_path(), &apply, false));

                Ok(self.target)
            }
            _ => Err(Error::DefaultsNotFound),
        }
    }
}

pub fn bars() -> Handlebars {
    let mut hbs = Handlebars::new();
    fn transform<F>(bars: &mut Handlebars, name: &str, f: F)
        where F: 'static + Fn(&str) -> String + Sync + Send
    {
        bars.register_helper(name,
                             Box::new(move |c: &Context,
                                            h: &Helper,
                                            _: &Handlebars,
                                            rc: &mut RenderContext|
                                            -> std::result::Result<(), RenderError> {
                                 let param = h.params().get(0).unwrap();
                                 let value = c.navigate(rc.get_path(), param);
                                 try!(rc.writer.write(f(value.as_string().unwrap()).as_bytes()));
                                 Ok(())
                             }));
    }

    transform(&mut hbs, "upper", str::to_uppercase);
    transform(&mut hbs, "lower", str::to_lowercase);

    hbs
}

/// prompt for a value defaulting to a given string when an answer is not available
fn prompt(name: &str, default: &str) -> io::Result<String> {
    let mut answer = String::new();
    print!("{} [{}]: ", name, default);
    try!(io::stdout().flush());
    try!(io::stdin().read_line(&mut answer));
    let trimmed = answer.trim();
    if trimmed.trim().is_empty() {
        Ok(default.to_owned())
    } else {
        Ok(trimmed.to_owned())
    }
}

/// clone a repository to a given location
fn clone(repo: &str, to: &str, branch: Option<&str>) -> io::Result<process::Output> {
    let mut git = Command::new("git");
    git.arg("clone");

    if let Some(b) = branch {
        git.arg(format!("-b {}", b));
        git.arg("--single-branch");
    };

    git.arg(repo)
        .arg(to)
        .stdout(Stdio::inherit())
        .stderr(Stdio::inherit())
        .output()
}

fn parse_defaults(p: &Path) -> io::Result<BTreeMap<String, String>> {
    let mut map = BTreeMap::new();
    let mut f = try!(File::open(p));
    let mut s = String::new();
    try!(f.read_to_string(&mut s));

    let values = s.lines()
        .map(|l| l.split("=").take(2).collect::<Vec<&str>>())
        .collect::<Vec<Vec<&str>>>();
    for pair in values.iter() {
        if pair.len() == 2 {
            map.insert(pair[0].trim().to_owned(), pair[1].trim().to_owned());
        }
    }

    Ok(map)
}

/// given a set of defaults, attempt to interact with a user
/// to resolve the parameters that can not be inferred
fn interact(defaults: &BTreeMap<String, String>) -> io::Result<BTreeMap<String, String>> {
    let mut resolved = BTreeMap::new();
    for (k, v) in defaults {
        let answer = match env::var(k) {
            Ok(v) => v,
            _ => try!(prompt(k, v)),
        };
        resolved.insert(k.clone(), answer);
    }
    Ok(resolved)
}

fn walk<F>(hbs: &mut Handlebars, dir: &Path, f: &F, include_dir: bool) -> Result<()>
    where F: Fn(&Path, &mut Handlebars) -> Result<()>
{
    if try!(fs::metadata(dir)).is_dir() {
        if include_dir {
            try!(f(&dir, hbs));
        }
        for entry in try!(fs::read_dir(dir)) {
            let entry = try!(entry);
            if try!(fs::metadata(entry.path())).is_dir() {
                try!(walk(hbs, &entry.path(), f, true));
            } else {
                try!(f(&entry.path().as_path(), hbs));
            }
        }
    }
    Ok(())
}

fn find(target_dir: &Path, target_name: &str) -> io::Result<Option<PathBuf>> {
    for entry in try!(fs::read_dir(target_dir)) {
        let e = try!(entry);
        if let Some(name) = e.file_name().to_str() {
            if name == target_name {
                return Ok(Some(e.path()));
            }
        }
    }
    Ok(None)
}

#[cfg(test)]
mod tests {
    use std::collections::BTreeMap;
    use super::*;
    #[test]
    fn test_bars() {
        let mut map = BTreeMap::new();
        map.insert("name".to_owned(), "porteurbars".to_owned());
        assert_eq!("Hello, PORTEURBARS",
                   bars().template_render("Hello, {{upper name}}", &map).unwrap());
    }
}
<commit_msg>const<commit_after>extern crate handlebars;
extern crate tempdir;

pub mod errors;
pub use errors::Error;

use handlebars::{Context, Handlebars, Helper, RenderContext, RenderError};
use std::collections::BTreeMap;
use std::env;
use std::fs::{self, File, create_dir_all};
use std::path::{Path, PathBuf, MAIN_SEPARATOR};
use std::process::{self, Stdio, Command};
use std::io::{self, Read, Write};

const TMP_PREFIX: &'static str = "porteurbars";
const TEMPLATE_DIR: &'static str = "template";

pub type Result<T> = std::result::Result<T, Error>;

pub struct Template<'a> {
    /// target output dir
    pub target: &'a Path,
    /// defaults env faile
    pub defaults: &'a str,
    /// relative path to project template src
    pub project: &'a Path,
    /// remote git repo
    pub repo: &'a str,
}

impl<'a> Template<'a> {
    /// Apply project template
    pub fn apply(&self) -> Result<&'a Path> {
        // resolve template
        let scratch = try!(tempdir::TempDir::new(TMP_PREFIX));
        try!(clone(self.repo, scratch.path().to_str().unwrap(), None));

        match find(scratch.path(), self.defaults) {
            Ok(Some(defaults)) => {

                // resolve context
                let map = try!(parse_defaults(defaults.as_path()));
                let resolved = try!(interact(&map));
                let data = Context::wraps(&resolved);

                let mut template_dir = scratch.path().to_path_buf();
                template_dir.push(TEMPLATE_DIR);

                // apply handlebars processing
                let apply = |path: &Path, hbs: &mut Handlebars| -> Result<()> {
                    // /tmp/download_dir/templates
                    let scratchpath =
                        &format!("{}{}", template_dir.to_str().unwrap(), MAIN_SEPARATOR)[..];

                    // path relatived based on scratch dir
                    let localpath = path.to_str()
                        .unwrap()
                        .trim_left_matches(scratchpath);

                    // eval path as template
                    let evalpath = try!(hbs.template_render(&localpath, &resolved));

                    // rewritten path, based on target dir and eval path
                    let targetpath = self.target.join(evalpath);

                    if path.is_file() {
                        let mut file = try!(File::open(path));
                        let mut s = String::new();
                        try!(file.read_to_string(&mut s));
                        let mut file = try!(File::create(targetpath));
                        try!(hbs.template_renderw(&s, &data, &mut file));
                    } else {
                        try!(fs::create_dir_all(targetpath))
                    }
                    Ok(())
                };

                try!(create_dir_all(self.target));
                let mut hbs = bars();

                try!(walk(&mut hbs, &template_dir.as_path(), &apply, false));

                Ok(self.target)
            }
            _ => Err(Error::DefaultsNotFound),
        }
    }
}

pub fn bars() -> Handlebars {
    let mut hbs = Handlebars::new();
    fn transform<F>(bars: &mut Handlebars, name: &str, f: F)
        where F: 'static + Fn(&str) -> String + Sync + Send
    {
        bars.register_helper(name,
                             Box::new(move |c: &Context,
                                            h: &Helper,
                                            _: &Handlebars,
                                            rc: &mut RenderContext|
                                            -> std::result::Result<(), RenderError> {
                                 let param = h.params().get(0).unwrap();
                                 let value = c.navigate(rc.get_path(), param);
                                 try!(rc.writer.write(f(value.as_string().unwrap()).as_bytes()));
                                 Ok(())
                             }));
    }

    transform(&mut hbs, "upper", str::to_uppercase);
    transform(&mut hbs, "lower", str::to_lowercase);

    hbs
}

/// prompt for a value defaulting to a given string when an answer is not available
fn prompt(name: &str, default: &str) -> io::Result<String> {
    let mut answer = String::new();
    print!("{} [{}]: ", name, default);
    try!(io::stdout().flush());
    try!(io::stdin().read_line(&mut answer));
    let trimmed = answer.trim();
    if trimmed.trim().is_empty() {
        Ok(default.to_owned())
    } else {
        Ok(trimmed.to_owned())
    }
}

/// clone a repository to a given location
fn clone(repo: &str, to: &str, branch: Option<&str>) -> io::Result<process::Output> {
    let mut git = Command::new("git");
    git.arg("clone");

    if let Some(b) = branch {
        git.arg(format!("-b {}", b));
        git.arg("--single-branch");
    };

    git.arg(repo)
        .arg(to)
        .stdout(Stdio::inherit())
        .stderr(Stdio::inherit())
        .output()
}

fn parse_defaults(p: &Path) -> io::Result<BTreeMap<String, String>> {
    let mut map = BTreeMap::new();
    let mut f = try!(File::open(p));
    let mut s = String::new();
    try!(f.read_to_string(&mut s));

    let values = s.lines()
        .map(|l| l.split("=").take(2).collect::<Vec<&str>>())
        .collect::<Vec<Vec<&str>>>();
    for pair in values.iter() {
        if pair.len() == 2 {
            map.insert(pair[0].trim().to_owned(), pair[1].trim().to_owned());
        }
    }

    Ok(map)
}

/// given a set of defaults, attempt to interact with a user
/// to resolve the parameters that can not be inferred
fn interact(defaults: &BTreeMap<String, String>) -> io::Result<BTreeMap<String, String>> {
    let mut resolved = BTreeMap::new();
    for (k, v) in defaults {
        let answer = match env::var(k) {
            Ok(v) => v,
            _ => try!(prompt(k, v)),
        };
        resolved.insert(k.clone(), answer);
    }
    Ok(resolved)
}

fn walk<F>(hbs: &mut Handlebars, dir: &Path, f: &F, include_dir: bool) -> Result<()>
    where F: Fn(&Path, &mut Handlebars) -> Result<()>
{
    if try!(fs::metadata(dir)).is_dir() {
        if include_dir {
            try!(f(&dir, hbs));
        }
        for entry in try!(fs::read_dir(dir)) {
            let entry = try!(entry);
            if try!(fs::metadata(entry.path())).is_dir() {
                try!(walk(hbs, &entry.path(), f, true));
            } else {
                try!(f(&entry.path().as_path(), hbs));
            }
        }
    }
    Ok(())
}

fn find(target_dir: &Path, target_name: &str) -> io::Result<Option<PathBuf>> {
    for entry in try!(fs::read_dir(target_dir)) {
        let e = try!(entry);
        if let Some(name) = e.file_name().to_str() {
            if name == target_name {
                return Ok(Some(e.path()));
            }
        }
    }
    Ok(None)
}

#[cfg(test)]
mod tests {
    use std::collections::BTreeMap;
    use super::*;
    #[test]
    fn test_bars() {
        let mut map = BTreeMap::new();
        map.insert("name".to_owned(), "porteurbars".to_owned());
        assert_eq!("Hello, PORTEURBARS",
                   bars().template_render("Hello, {{upper name}}", &map).unwrap());
    }
}
<|endoftext|>


<commit_before>// Copyright 2015, Paul Osborne <osbpau@gmail.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/license/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.

//! Generic Interface for GPIOs Across Many Systems
//!
//! This crate provides a set of core traits and related types
//! for accessing GPIOs across a variety of systems.  The goal
//! is that devices may be written depending on these traits
//! and consequently be portable to various systems.

#![crate_type = "lib"]
#![crate_name = "gpio"]

#![feature(no_std)]
#![no_std]

#[cfg(test)]
#[macro_use] extern crate std;

#[derive(Copy, Clone)]
pub enum Error {
    /// The GPIO was configured as an input but an output action was attempted
    IllegalOperationOnInput,
    /// The GPIO was configured as an output but an input action was attempted
    IllegalOperationOnOutput,
    /// Some other error occurred
    Other(&'static str),
}

pub type Result<T> = core::result::Result<T, Error>;

/// The direction of a GPIO Pin
#[derive(Copy, Clone)]
pub enum Direction {
    /// The pin is an input
    In,
    /// The pin is an output
    Out,
}

/// The logic level of a GPIO Pin
#[derive(Copy, Clone, PartialEq)]
pub enum Level {
    /// Logic low
    Low,
    /// Logic high
    High,
}

/// Generic trait providing access to a single GPIO
pub trait Gpio {
    /// Get the currently configured direciton of this GPIO
    fn get_direction(&self) -> Result<Direction>;
    /// Set the pin to be an input
    fn set_input(&mut self) -> Result<()>;
    /// Set the pin to be an output with the provided level
    fn set_output(&mut self, value: Level) -> Result<()>;
    /// Get the current level of this GPIO (input only)
    fn get_level(&self) -> Result<Level>;
    /// Set the current level of this GPIO (output only)
    fn set_level(&mut self, value: Level) -> Result<()>;
}
<commit_msg>api: add support for stable and nightly<commit_after>// Copyright 2015, Paul Osborne <osbpau@gmail.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/license/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.

//! Generic Interface for GPIOs Across Many Systems
//!
//! This crate provides a set of core traits and related types
//! for accessing GPIOs across a variety of systems.  The goal
//! is that devices may be written depending on these traits
//! and consequently be portable to various systems.

#![crate_type = "lib"]
#![crate_name = "gpio"]

// until core is stabilized, we need some hacks to support
// both nightly and stable
#![cfg_attr(nightly, feature(no_std))]
#![cfg_attr(nightly, no_std)]

#[cfg(any(not(nightly), test))]
#[macro_use] extern crate std as core;

/// Indication that an error occurred with a GPIO operation
#[derive(Copy, Clone)]
pub enum Error {
    /// The GPIO was configured as an input but an output action was attempted
    IllegalOperationOnInput,
    /// The GPIO was configured as an output but an input action was attempted
    IllegalOperationOnOutput,
    /// Some other error occurred
    Other(&'static str),
}

/// GPIO Result
pub type Result<T> = core::result::Result<T, Error>;

/// The direction of a GPIO Pin
#[derive(Copy, Clone)]
pub enum Direction {
    /// The pin is an input
    In,
    /// The pin is an output
    Out,
}

/// The logic level of a GPIO Pin
#[derive(Copy, Clone, PartialEq)]
pub enum Level {
    /// Logic low
    Low,
    /// Logic high
    High,
}

/// Generic trait providing access to a single GPIO
pub trait Gpio {
    /// Get the currently configured direciton of this GPIO
    fn get_direction(&self) -> Result<Direction>;
    /// Set the pin to be an input
    fn set_input(&mut self) -> Result<()>;
    /// Set the pin to be an output with the provided level
    fn set_output(&mut self, value: Level) -> Result<()>;
    /// Get the current level of this GPIO (input only)
    fn get_level(&self) -> Result<Level>;
    /// Set the current level of this GPIO (output only)
    fn set_level(&mut self, value: Level) -> Result<()>;
}
<|endoftext|>


<commit_before>#![deny(clippy::undocumented_unsafe_blocks)]
// workarounds
#![allow(unused_doc_comments)]

// crates

// local crates
extern crate av_bitstream;
extern crate av_data;
extern crate av_format;

pub mod data {
    pub use av_data::*;
}

pub mod format {
    pub use av_format::*;
}

pub mod bitstream {
    pub use av_bitstream::*;
}

pub use av_data::rational;

// core functionalities
mod entropy;
mod io;

// raw multimedia data manipulation
mod filter;
mod resample;
mod scale;
<commit_msg>lib: Simplify importing crates<commit_after>#![deny(clippy::undocumented_unsafe_blocks)]
// workarounds
#![allow(unused_doc_comments)]

pub mod data {
    pub use av_data::*;
}

pub mod format {
    pub use av_format::*;
}

pub mod bitstream {
    pub use av_bitstream::*;
}

pub use av_data::rational;

// core functionalities
mod entropy;
mod io;

// raw multimedia data manipulation
mod filter;
mod resample;
mod scale;
<|endoftext|>