<commit_before>use ffi;
use std::str::from_utf8;
use std::slice::from_raw_parts;
use std::mem::size_of;
use std::ffi::CString;

pub unsafe trait OdbcType<'a>: Sized {
    fn sql_data_type() -> ffi::SqlDataType;
    fn c_data_type() -> ffi::SqlCDataType;
    fn convert(_: &'a [u8]) -> Self;
    fn column_size(&self) -> ffi::SQLULEN;
    fn value_ptr(&self) -> ffi::SQLPOINTER;
    fn decimal_digits(&self) -> ffi::SQLSMALLINT {
        0
    }
}

unsafe impl<'a> OdbcType<'a> for &'a[u8] {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_EXT_VARBINARY
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_BINARY
    }

    fn convert(buffer: &'a [u8]) -> Self {
        buffer
    }

    fn column_size(&self) -> ffi::SQLULEN {
        self.len() as ffi::SQLULEN
    }

    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self.as_ptr() as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for Vec<u8> {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_EXT_VARBINARY
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_BINARY
    }

    fn convert(buffer: &'a [u8]) -> Self {
        buffer.to_vec()
    }

    fn column_size(&self) -> ffi::SQLULEN {
        self.len() as ffi::SQLULEN
    }

    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self.as_ptr() as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for CString {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_VARCHAR
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_CHAR
    }

    fn convert(buffer: &'a [u8]) -> Self {
        CString::new(buffer).unwrap()
    }

    fn column_size(&self) -> ffi::SQLULEN {
        self.as_bytes().len() as ffi::SQLULEN
    }

    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self.as_bytes().as_ptr() as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for String {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_VARCHAR
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_CHAR
    }

    fn convert(buffer: &'a [u8]) -> Self {
        from_utf8(buffer).unwrap().to_owned()
    }

    fn column_size(&self) -> ffi::SQLULEN {
        self.as_bytes().len() as ffi::SQLULEN
    }

    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self.as_bytes().as_ptr() as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for &'a str {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_VARCHAR
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_CHAR
    }

    fn convert(buffer: &'a [u8]) -> Self {
        from_utf8(buffer).unwrap()
    }

    fn column_size(&self) -> ffi::SQLULEN {
        self.as_bytes().len() as ffi::SQLULEN
    }

    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self.as_bytes().as_ptr() as *const Self as ffi::SQLPOINTER
    }
}

fn convert_primitive<T>(buf: &[u8]) -> T
where
    T: Copy,
{
    unsafe { from_raw_parts(buf.as_ptr() as *const T, 1)[0] }
}

unsafe impl<'a> OdbcType<'a> for u8 {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_SMALLINT
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_UTINYINT
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }

    fn column_size(&self) -> ffi::SQLULEN {
        size_of::<Self>() as ffi::SQLULEN
    }
    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for i8 {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_SMALLINT
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_STINYINT
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }

    fn column_size(&self) -> ffi::SQLULEN {
        size_of::<Self>() as ffi::SQLULEN
    }
    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for i16 {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_SMALLINT
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_SSHORT
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }

    fn column_size(&self) -> ffi::SQLULEN {
        size_of::<Self>() as ffi::SQLULEN
    }
    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for u16 {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_SMALLINT
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_USHORT
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }

    fn column_size(&self) -> ffi::SQLULEN {
        size_of::<Self>() as ffi::SQLULEN
    }
    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for i32 {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_INTEGER
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_SLONG
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }

    fn column_size(&self) -> ffi::SQLULEN {
        size_of::<Self>() as ffi::SQLULEN
    }
    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for u32 {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_INTEGER
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_ULONG
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }

    fn column_size(&self) -> ffi::SQLULEN {
        size_of::<Self>() as ffi::SQLULEN
    }
    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for i64 {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_INTEGER
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_SBIGINT
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }

    fn column_size(&self) -> ffi::SQLULEN {
        size_of::<Self>() as ffi::SQLULEN
    }
    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for u64 {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_INTEGER
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_UBIGINT
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }

    fn column_size(&self) -> ffi::SQLULEN {
        size_of::<Self>() as ffi::SQLULEN
    }
    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for f32 {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_FLOAT
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_FLOAT
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }

    fn column_size(&self) -> ffi::SQLULEN {
        size_of::<Self>() as ffi::SQLULEN
    }
    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for f64 {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_DOUBLE
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_DOUBLE
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }

    fn column_size(&self) -> ffi::SQLULEN {
        size_of::<Self>() as ffi::SQLULEN
    }
    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self as *const Self as ffi::SQLPOINTER
    }
}
<commit_msg>Add support for retrieving wide strings as UTF-16<commit_after>use ffi;
use std::str::from_utf8;
use std::slice::from_raw_parts;
use std::mem::size_of;
use std::ffi::CString;

pub unsafe trait OdbcType<'a>: Sized {
    fn sql_data_type() -> ffi::SqlDataType;
    fn c_data_type() -> ffi::SqlCDataType;
    fn convert(_: &'a [u8]) -> Self;
    fn column_size(&self) -> ffi::SQLULEN;
    fn value_ptr(&self) -> ffi::SQLPOINTER;
    fn decimal_digits(&self) -> ffi::SQLSMALLINT {
        0
    }
}

unsafe impl<'a> OdbcType<'a> for &'a[u8] {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_EXT_VARBINARY
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_BINARY
    }

    fn convert(buffer: &'a [u8]) -> Self {
        buffer
    }

    fn column_size(&self) -> ffi::SQLULEN {
        self.len() as ffi::SQLULEN
    }

    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self.as_ptr() as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for Vec<u8> {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_EXT_VARBINARY
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_BINARY
    }

    fn convert(buffer: &'a [u8]) -> Self {
        buffer.to_vec()
    }

    fn column_size(&self) -> ffi::SQLULEN {
        self.len() as ffi::SQLULEN
    }

    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self.as_ptr() as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for &'a[u16] {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_EXT_WVARCHAR
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_WCHAR
    }

    fn convert(buffer: &'a [u8]) -> Self {
        unsafe { from_raw_parts(buffer.as_ptr() as *const u16, buffer.len() / 2) }
    }

    fn column_size(&self) -> ffi::SQLULEN {
        self.len() as ffi::SQLULEN
    }

    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self.as_ptr() as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for Vec<u16> {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_EXT_WVARCHAR
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_WCHAR
    }

    fn convert(buffer: &'a [u8]) -> Self {
        let buffer = unsafe { from_raw_parts(buffer.as_ptr() as *const u16, buffer.len() / 2) };
        buffer.to_vec()
    }

    fn column_size(&self) -> ffi::SQLULEN {
        self.len() as ffi::SQLULEN
    }

    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self.as_ptr() as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for CString {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_VARCHAR
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_CHAR
    }

    fn convert(buffer: &'a [u8]) -> Self {
        CString::new(buffer).unwrap()
    }

    fn column_size(&self) -> ffi::SQLULEN {
        self.as_bytes().len() as ffi::SQLULEN
    }

    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self.as_bytes().as_ptr() as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for String {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_VARCHAR
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_CHAR
    }

    fn convert(buffer: &'a [u8]) -> Self {
        from_utf8(buffer).unwrap().to_owned()
    }

    fn column_size(&self) -> ffi::SQLULEN {
        self.as_bytes().len() as ffi::SQLULEN
    }

    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self.as_bytes().as_ptr() as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for &'a str {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_VARCHAR
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_CHAR
    }

    fn convert(buffer: &'a [u8]) -> Self {
        from_utf8(buffer).unwrap()
    }

    fn column_size(&self) -> ffi::SQLULEN {
        self.as_bytes().len() as ffi::SQLULEN
    }

    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self.as_bytes().as_ptr() as *const Self as ffi::SQLPOINTER
    }
}

fn convert_primitive<T>(buf: &[u8]) -> T
where
    T: Copy,
{
    unsafe { from_raw_parts(buf.as_ptr() as *const T, 1)[0] }
}

unsafe impl<'a> OdbcType<'a> for u8 {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_SMALLINT
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_UTINYINT
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }

    fn column_size(&self) -> ffi::SQLULEN {
        size_of::<Self>() as ffi::SQLULEN
    }
    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for i8 {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_SMALLINT
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_STINYINT
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }

    fn column_size(&self) -> ffi::SQLULEN {
        size_of::<Self>() as ffi::SQLULEN
    }
    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for i16 {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_SMALLINT
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_SSHORT
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }

    fn column_size(&self) -> ffi::SQLULEN {
        size_of::<Self>() as ffi::SQLULEN
    }
    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for u16 {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_SMALLINT
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_USHORT
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }

    fn column_size(&self) -> ffi::SQLULEN {
        size_of::<Self>() as ffi::SQLULEN
    }
    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for i32 {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_INTEGER
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_SLONG
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }

    fn column_size(&self) -> ffi::SQLULEN {
        size_of::<Self>() as ffi::SQLULEN
    }
    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for u32 {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_INTEGER
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_ULONG
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }

    fn column_size(&self) -> ffi::SQLULEN {
        size_of::<Self>() as ffi::SQLULEN
    }
    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for i64 {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_INTEGER
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_SBIGINT
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }

    fn column_size(&self) -> ffi::SQLULEN {
        size_of::<Self>() as ffi::SQLULEN
    }
    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for u64 {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_INTEGER
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_UBIGINT
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }

    fn column_size(&self) -> ffi::SQLULEN {
        size_of::<Self>() as ffi::SQLULEN
    }
    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for f32 {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_FLOAT
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_FLOAT
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }

    fn column_size(&self) -> ffi::SQLULEN {
        size_of::<Self>() as ffi::SQLULEN
    }
    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for f64 {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_DOUBLE
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_DOUBLE
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }

    fn column_size(&self) -> ffi::SQLULEN {
        size_of::<Self>() as ffi::SQLULEN
    }
    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self as *const Self as ffi::SQLPOINTER
    }
}
<|endoftext|>


<commit_before>//! Decode various trunking-related packet fields.

use util::{slice_u16, slice_u32};

pub struct ServiceOptions(u8);

impl ServiceOptions {
    pub fn new(opts: u8) -> ServiceOptions { ServiceOptions(opts) }

    pub fn emergency(&self) -> bool { self.0 >> 7 == 1 }
    pub fn protected(&self) -> bool { self.0 >> 6 & 1 == 1 }
    pub fn duplex(&self) -> bool { self.0 >> 5 & 1 == 1 }
    pub fn packet_switched(&self) -> bool { self.0 >> 4 & 1 == 1 }
    pub fn prio(&self) -> u8 { self.0 & 0x7 }
}

/// Uniquely identifies a channel within a site.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct Channel(u16);

impl Channel {
    /// Create a new `Channel` from the given 16 bits.
    pub fn new(bytes: &[u8]) -> Channel { Channel(slice_u16(bytes)) }

    /// Channel ID whose parameters to use.
    pub fn id(&self) -> u8 { (self.0 >> 12) as u8 }
    /// Individual channel number within the channel.
    pub fn number(&self) -> u16 { self.0 & 0xFFF }
}

/// Identifies which group a message belongs to.
///
/// In a production P25 system, users can set their radios to receive one or more
/// talkgroups, and the radio will only unsquelch if one of those talkgroups is seen.
/// Additionally, the user directs each transmission to a talkgroup selected on the
/// radio.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum TalkGroup {
    /// Includes nobody.
    Nobody,
    /// Default talkgroup when no other is selected.
    Default,
    /// Includes everybody.
    Everbody,
    /// Specific group of users.
    Other(u16),
}

impl TalkGroup {
    /// Parse a talkgroup from the given 16 bit slice.
    pub fn new(bytes: &[u8]) -> TalkGroup {
        Self::from_bits(slice_u16(bytes))
    }

    /// Parse a talkgroup from the given 16 bits.
    pub fn from_bits(bits: u16) -> TalkGroup {
        use self::TalkGroup::*;

        match bits {
            0x0000 => Nobody,
            0x0001 => Default,
            0xFFFF => Everbody,
            _ => Other(bits),
        }
    }
}

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct SystemServices(u8);

impl SystemServices {
    pub fn new(ssc: u8) -> Self { SystemServices(ssc) }

    pub fn is_composite(&self) -> bool { self.0 & 0x01 != 0 }
    pub fn has_updates(&self) -> bool { self.0 & 0x02 != 0 }
    pub fn is_backup(&self) -> bool { self.0 & 0x04 != 0 }
    pub fn has_data(&self) -> bool { self.0 & 0x10 != 0 }
    pub fn has_voice(&self) -> bool { self.0 & 0x20 != 0 }
    pub fn has_registration(&self) -> bool { self.0 & 0x40 != 0 }
    pub fn has_auth(&self) -> bool { self.0 & 0x80 != 0 }
}

/// Map channel identifier (maximum 16 per control channel) to its parameters.
pub type ChannelParamsMap = [Option<ChannelParams>; 16];

/// Computes TX/RX frequencies and bandwidth for channel numbers within a site.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct ChannelParams {
    /// Base frequency in Hz.
    base: u32,
    /// Channel spacing in Hz.
    spacing: u32,
    /// Transmit frequency offset in Hz.
    offset: i32,
    /// Channel bandwidth in Hz.
    pub bandwidth: u32,
}

impl ChannelParams {
    /// Create a new `ChannelParams` from the given base frequency (5Hz steps), bandwidth
    /// (125Hz steps), TX offset (250kHz steps), and inter-channel spacing (125Hz steps.)
    pub fn new(base: u32, bandwidth: u16, offset: u16, spacing: u16) -> ChannelParams {
        // The MSB denotes the sign and the lower byte is the actual offset.
        let off = (offset as i32 & 0xFF) * 250_000;

        ChannelParams {
            base: base * 5,
            spacing: spacing as u32 * 125,
            offset: if offset >> 8 == 0 { -off } else { off },
            bandwidth: bandwidth as u32 * 125,
        }
    }

    /// Receive frequency for the given channel number in Hz.
    pub fn rx_freq(&self, ch: u16) -> u32 {
        self.base + self.spacing * ch as u32
    }

    /// Transmit frequency for the given channel number in Hz.
    pub fn tx_freq(&self, ch: u16) -> u32 {
        self.rx_freq(ch) + self.offset as u32
    }
}

/// Options for a P25 site.
pub struct SiteOptions(u8);

impl SiteOptions {
    /// Create a new `SiteOptions` from the given 4-bit word.
    pub fn new(opts: u8) -> SiteOptions {
        assert!(opts >> 4 == 0);
        SiteOptions(opts)
    }

    /// Whether site is "conventional", with no trunking.
    pub fn conventional(&self) -> bool { self.0 & 0b1000 != 0 }
    /// Whether site is in a failure state.
    pub fn failing(&self) -> bool { self.0 & 0b100 != 0 }
    /// Whether this information is up-to-date (whether broadcasting site is in
    /// communication with adjacent site.)
    pub fn current(&self) -> bool { self.0 & 0b10 != 0 }
    /// Whether site has active network connection with RFSS controller and can
    /// communicate with other sites.
    pub fn networked(&self) -> bool { self.0 & 1 != 0 }
}

/// Represents the channel updates seen in a Group Voice Update.
pub type ChannelUpdates = [(Channel, TalkGroup); 2];

/// Updates subscribers about new or ongoing talkgroup conversations.
pub struct GroupVoiceUpdate<'a>(&'a [u8]);

impl<'a> GroupVoiceUpdate<'a> {
    /// Create a new `GroupVoiceUpdate` decoder from the given payload bytes.
    pub fn new(payload: &'a [u8]) -> Self { GroupVoiceUpdate(payload) }

    /// Retrieve the set of active talkgroups included in the update along with the
    /// parameters for tuning to the traffic channel of each.
    pub fn updates(&self) -> ChannelUpdates {
        [
            (Channel::new(&self.0[0...1]), TalkGroup::new(&self.0[2...3])),
            (Channel::new(&self.0[4...5]), TalkGroup::new(&self.0[6...7])),
        ]
    }
}

/// Advertisement of an adjacent/nearby site within the same WACN (Wide Area Communication
/// Network.)
pub struct AdjacentSite<'a>(&'a [u8]);

impl<'a> AdjacentSite<'a> {
    /// Create a new `AdjacentSite` decoder from the given payload bytes.
    pub fn new(payload: &'a [u8]) -> Self { AdjacentSite(payload) }

    /// Location registration area of adjacent site, which determines whether a subscriber
    /// must update the network before roaming to the site.
    pub fn area(&self) -> u8 { self.0[0] }
    /// Description of adjacent site.
    pub fn opts(&self) -> SiteOptions { SiteOptions::new(self.0[1] >> 4) }
    /// System ID of adjacent site within WACN.
    pub fn system(&self) -> u16 { slice_u16(&self.0[1...2]) & 0xFFF }
    /// RF Subsystem ID of adjacent site within the System.
    pub fn rfss(&self) -> u8 { self.0[3] }
    /// Site ID of adjacent site within the RFSS.
    pub fn site(&self) -> u8 { self.0[4] }
    /// Channel information for computing TX/RX frequencies.
    pub fn channel(&self) -> Channel { Channel::new(&self.0[5...6]) }
    /// Services supported by the adjacent site.
    pub fn services(&self) -> SystemServices { SystemServices::new(self.0[7]) }
}

/// Advertisement of parameters used to calculate TX/RX frequencies within the given
/// associated channel.
pub struct ChannelParamsUpdate<'a>(&'a [u8]);

impl<'a> ChannelParamsUpdate<'a> {
    /// Create a new `ChannelParamsUpdate` decoder from the given payload bytes.
    pub fn new(payload: &'a [u8]) -> Self { ChannelParamsUpdate(payload) }

    /// Channel ID associated with the enclosed parameters (can be up to 16 per control
    /// channel.)
    pub fn id(&self) -> u8 { self.0[0] >> 4 }

    /// Parameters for the associated channel.
    pub fn params(&self) -> ChannelParams {
        ChannelParams::new(self.base(), self.bandwidth(), self.offset(), self.spacing())
    }

    /// Bandwidth in steps of 125Hz.
    fn bandwidth(&self) -> u16 {
        (self.0[0] as u16 & 0xF) << 5 | (self.0[1] >> 3) as u16
    }

    /// Offset of TX frequency from base RX frequency in steps of 250kHz.
    fn offset(&self) -> u16 {
        (self.0[1] as u16 & 0x7) << 6 | (self.0[2] >> 2) as u16
    }

    /// Spacing between individual channel numbers in steps of 125Hz.
    fn spacing(&self) -> u16 {
        (self.0[2] as u16 & 0x3) << 8 | self.0[3] as u16
    }

    /// Base RX frequency in steps of 5Hz.
    fn base(&self) -> u32 { slice_u32(&self.0[4...7]) }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_channel_params() {
        // Example from the standard.
        let p = ChannelParams::new(170201250, 0x64, 0b010110100, 0x32);
        assert_eq!(p.base, 851_006_250);
        assert_eq!(p.spacing, 6_250);
        assert_eq!(p.offset, -45_000_000);
        assert_eq!(p.bandwidth, 12_500);
        assert_eq!(p.rx_freq(0b1001), 851_062_500);
    }

    #[test]
    fn test_parse_updates() {
        let buf = [
            0b10001000,
            0b01110111,
            0b11111111,
            0b11111111,
            0b10010001,
            0b00000001,
            0b10101010,
            0b10101010,
        ];

        let u = GroupVoiceUpdate(&buf[..]).updates();

        assert_eq!(u[0].0.id(), 0b1000);
        assert_eq!(u[0].0.number(), 0b100001110111);
        assert_eq!(u[0].1, TalkGroup::Everbody);
        assert_eq!(u[1].0.id(), 0b1001);
        assert_eq!(u[1].0.number(), 0b000100000001);
        assert_eq!(u[1].1, TalkGroup::Other(0b1010101010101010));
    }
}
<commit_msg>Remove ChannelUpdates type<commit_after>//! Decode various trunking-related packet fields.

use util::{slice_u16, slice_u32};

pub struct ServiceOptions(u8);

impl ServiceOptions {
    pub fn new(opts: u8) -> ServiceOptions { ServiceOptions(opts) }

    pub fn emergency(&self) -> bool { self.0 >> 7 == 1 }
    pub fn protected(&self) -> bool { self.0 >> 6 & 1 == 1 }
    pub fn duplex(&self) -> bool { self.0 >> 5 & 1 == 1 }
    pub fn packet_switched(&self) -> bool { self.0 >> 4 & 1 == 1 }
    pub fn prio(&self) -> u8 { self.0 & 0x7 }
}

/// Uniquely identifies a channel within a site.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct Channel(u16);

impl Channel {
    /// Create a new `Channel` from the given 16 bits.
    pub fn new(bytes: &[u8]) -> Channel { Channel(slice_u16(bytes)) }

    /// Channel ID whose parameters to use.
    pub fn id(&self) -> u8 { (self.0 >> 12) as u8 }
    /// Individual channel number within the channel.
    pub fn number(&self) -> u16 { self.0 & 0xFFF }
}

/// Identifies which group a message belongs to.
///
/// In a production P25 system, users can set their radios to receive one or more
/// talkgroups, and the radio will only unsquelch if one of those talkgroups is seen.
/// Additionally, the user directs each transmission to a talkgroup selected on the
/// radio.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum TalkGroup {
    /// Includes nobody.
    Nobody,
    /// Default talkgroup when no other is selected.
    Default,
    /// Includes everybody.
    Everbody,
    /// Specific group of users.
    Other(u16),
}

impl TalkGroup {
    /// Parse a talkgroup from the given 16 bit slice.
    pub fn new(bytes: &[u8]) -> TalkGroup {
        Self::from_bits(slice_u16(bytes))
    }

    /// Parse a talkgroup from the given 16 bits.
    pub fn from_bits(bits: u16) -> TalkGroup {
        use self::TalkGroup::*;

        match bits {
            0x0000 => Nobody,
            0x0001 => Default,
            0xFFFF => Everbody,
            _ => Other(bits),
        }
    }
}

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct SystemServices(u8);

impl SystemServices {
    pub fn new(ssc: u8) -> Self { SystemServices(ssc) }

    pub fn is_composite(&self) -> bool { self.0 & 0x01 != 0 }
    pub fn has_updates(&self) -> bool { self.0 & 0x02 != 0 }
    pub fn is_backup(&self) -> bool { self.0 & 0x04 != 0 }
    pub fn has_data(&self) -> bool { self.0 & 0x10 != 0 }
    pub fn has_voice(&self) -> bool { self.0 & 0x20 != 0 }
    pub fn has_registration(&self) -> bool { self.0 & 0x40 != 0 }
    pub fn has_auth(&self) -> bool { self.0 & 0x80 != 0 }
}

/// Map channel identifier (maximum 16 per control channel) to its parameters.
pub type ChannelParamsMap = [Option<ChannelParams>; 16];

/// Computes TX/RX frequencies and bandwidth for channel numbers within a site.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct ChannelParams {
    /// Base frequency in Hz.
    base: u32,
    /// Channel spacing in Hz.
    spacing: u32,
    /// Transmit frequency offset in Hz.
    offset: i32,
    /// Channel bandwidth in Hz.
    pub bandwidth: u32,
}

impl ChannelParams {
    /// Create a new `ChannelParams` from the given base frequency (5Hz steps), bandwidth
    /// (125Hz steps), TX offset (250kHz steps), and inter-channel spacing (125Hz steps.)
    pub fn new(base: u32, bandwidth: u16, offset: u16, spacing: u16) -> ChannelParams {
        // The MSB denotes the sign and the lower byte is the actual offset.
        let off = (offset as i32 & 0xFF) * 250_000;

        ChannelParams {
            base: base * 5,
            spacing: spacing as u32 * 125,
            offset: if offset >> 8 == 0 { -off } else { off },
            bandwidth: bandwidth as u32 * 125,
        }
    }

    /// Receive frequency for the given channel number in Hz.
    pub fn rx_freq(&self, ch: u16) -> u32 {
        self.base + self.spacing * ch as u32
    }

    /// Transmit frequency for the given channel number in Hz.
    pub fn tx_freq(&self, ch: u16) -> u32 {
        self.rx_freq(ch) + self.offset as u32
    }
}

/// Options for a P25 site.
pub struct SiteOptions(u8);

impl SiteOptions {
    /// Create a new `SiteOptions` from the given 4-bit word.
    pub fn new(opts: u8) -> SiteOptions {
        assert!(opts >> 4 == 0);
        SiteOptions(opts)
    }

    /// Whether site is "conventional", with no trunking.
    pub fn conventional(&self) -> bool { self.0 & 0b1000 != 0 }
    /// Whether site is in a failure state.
    pub fn failing(&self) -> bool { self.0 & 0b100 != 0 }
    /// Whether this information is up-to-date (whether broadcasting site is in
    /// communication with adjacent site.)
    pub fn current(&self) -> bool { self.0 & 0b10 != 0 }
    /// Whether site has active network connection with RFSS controller and can
    /// communicate with other sites.
    pub fn networked(&self) -> bool { self.0 & 1 != 0 }
}

/// Updates subscribers about new or ongoing talkgroup conversations.
pub struct GroupVoiceUpdate<'a>(&'a [u8]);

impl<'a> GroupVoiceUpdate<'a> {
    /// Create a new `GroupVoiceUpdate` decoder from the given payload bytes.
    pub fn new(payload: &'a [u8]) -> Self { GroupVoiceUpdate(payload) }

    /// Retrieve the set of active talkgroups included in the update along with the
    /// parameters for tuning to the traffic channel of each.
    pub fn updates(&self) -> [(Channel, TalkGroup); 2] {
        [
            (Channel::new(&self.0[0...1]), TalkGroup::new(&self.0[2...3])),
            (Channel::new(&self.0[4...5]), TalkGroup::new(&self.0[6...7])),
        ]
    }
}

/// Advertisement of an adjacent/nearby site within the same WACN (Wide Area Communication
/// Network.)
pub struct AdjacentSite<'a>(&'a [u8]);

impl<'a> AdjacentSite<'a> {
    /// Create a new `AdjacentSite` decoder from the given payload bytes.
    pub fn new(payload: &'a [u8]) -> Self { AdjacentSite(payload) }

    /// Location registration area of adjacent site, which determines whether a subscriber
    /// must update the network before roaming to the site.
    pub fn area(&self) -> u8 { self.0[0] }
    /// Description of adjacent site.
    pub fn opts(&self) -> SiteOptions { SiteOptions::new(self.0[1] >> 4) }
    /// System ID of adjacent site within WACN.
    pub fn system(&self) -> u16 { slice_u16(&self.0[1...2]) & 0xFFF }
    /// RF Subsystem ID of adjacent site within the System.
    pub fn rfss(&self) -> u8 { self.0[3] }
    /// Site ID of adjacent site within the RFSS.
    pub fn site(&self) -> u8 { self.0[4] }
    /// Channel information for computing TX/RX frequencies.
    pub fn channel(&self) -> Channel { Channel::new(&self.0[5...6]) }
    /// Services supported by the adjacent site.
    pub fn services(&self) -> SystemServices { SystemServices::new(self.0[7]) }
}

/// Advertisement of parameters used to calculate TX/RX frequencies within the given
/// associated channel.
pub struct ChannelParamsUpdate<'a>(&'a [u8]);

impl<'a> ChannelParamsUpdate<'a> {
    /// Create a new `ChannelParamsUpdate` decoder from the given payload bytes.
    pub fn new(payload: &'a [u8]) -> Self { ChannelParamsUpdate(payload) }

    /// Channel ID associated with the enclosed parameters (can be up to 16 per control
    /// channel.)
    pub fn id(&self) -> u8 { self.0[0] >> 4 }

    /// Parameters for the associated channel.
    pub fn params(&self) -> ChannelParams {
        ChannelParams::new(self.base(), self.bandwidth(), self.offset(), self.spacing())
    }

    /// Bandwidth in steps of 125Hz.
    fn bandwidth(&self) -> u16 {
        (self.0[0] as u16 & 0xF) << 5 | (self.0[1] >> 3) as u16
    }

    /// Offset of TX frequency from base RX frequency in steps of 250kHz.
    fn offset(&self) -> u16 {
        (self.0[1] as u16 & 0x7) << 6 | (self.0[2] >> 2) as u16
    }

    /// Spacing between individual channel numbers in steps of 125Hz.
    fn spacing(&self) -> u16 {
        (self.0[2] as u16 & 0x3) << 8 | self.0[3] as u16
    }

    /// Base RX frequency in steps of 5Hz.
    fn base(&self) -> u32 { slice_u32(&self.0[4...7]) }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_channel_params() {
        // Example from the standard.
        let p = ChannelParams::new(170201250, 0x64, 0b010110100, 0x32);
        assert_eq!(p.base, 851_006_250);
        assert_eq!(p.spacing, 6_250);
        assert_eq!(p.offset, -45_000_000);
        assert_eq!(p.bandwidth, 12_500);
        assert_eq!(p.rx_freq(0b1001), 851_062_500);
    }

    #[test]
    fn test_parse_updates() {
        let buf = [
            0b10001000,
            0b01110111,
            0b11111111,
            0b11111111,
            0b10010001,
            0b00000001,
            0b10101010,
            0b10101010,
        ];

        let u = GroupVoiceUpdate(&buf[..]).updates();

        assert_eq!(u[0].0.id(), 0b1000);
        assert_eq!(u[0].0.number(), 0b100001110111);
        assert_eq!(u[0].1, TalkGroup::Everbody);
        assert_eq!(u[1].0.id(), 0b1001);
        assert_eq!(u[1].0.number(), 0b000100000001);
        assert_eq!(u[1].1, TalkGroup::Other(0b1010101010101010));
    }
}
<|endoftext|>


<commit_before>// This file is part of Grust, GObject introspection bindings for Rust
//
// Copyright (C) 2013, 2014  Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

//! This crate provides definitions for types that are intrinsic in
//! GObject introspection, unlike all other types that have a definition in
//! a GIR file. All crates generated from GObject introspection data should
//! use these shared definitions, usable in FFI declarations as well as
//! in idiomatic Rust bindings.
//!
//! Some types are omitted because a suitable equivalent is readily available
//! in Rust:
//!
//! 1. Fixed-size integer types. These have straightforward built-in
//!    counterparts in Rust.
//! 2. Strings can have GI types `utf8` or `filename`. In the FFI all string
//!    values are represented as raw pointers to `gchar`. A safe
//!    representation of C strings in idiomatic Rust bindings
//!    needs some wrapper types which are not defined here.

#![allow(non_camel_case_types)]

extern crate libc;

// The fundamental types are defined in Python module giscanner.ast

pub type gboolean       = libc::c_int;
pub type gchar          = libc::c_char;
pub type guchar         = libc::c_uchar;
pub type gshort         = libc::c_short;
pub type gushort        = libc::c_ushort;
pub type gint           = libc::c_int;
pub type guint          = libc::c_uint;
pub type glong          = libc::c_long;
pub type gulong         = libc::c_ulong;
pub type gsize          = libc::size_t;
pub type gssize         = libc::ssize_t;
pub type gintptr        = libc::intptr_t;
pub type guintptr       = libc::uintptr_t;
pub type gfloat         = libc::c_float;
pub type gdouble        = libc::c_double;
pub type gunichar       = u32;
pub type gpointer       = *mut   libc::c_void;
pub type gconstpointer  = *const libc::c_void;

pub const FALSE: gboolean = 0;
pub const TRUE : gboolean = 1;
<commit_msg>Added GType<commit_after>// This file is part of Grust, GObject introspection bindings for Rust
//
// Copyright (C) 2013, 2014  Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

//! This crate provides definitions for types that are intrinsic in
//! GObject introspection, unlike all other types that have a definition in
//! a GIR file. All crates generated from GObject introspection data should
//! use these shared definitions, usable in FFI declarations as well as
//! in idiomatic Rust bindings.
//!
//! Some types are omitted because a suitable equivalent is readily available
//! in Rust:
//!
//! 1. Fixed-size integer types. These have straightforward built-in
//!    counterparts in Rust.
//! 2. Strings can have GI types `utf8` or `filename`. In the FFI all string
//!    values are represented as raw pointers to `gchar`. A safe
//!    representation of C strings in idiomatic Rust bindings
//!    needs some wrapper types which are not defined here.

#![allow(non_camel_case_types)]

extern crate libc;

// The fundamental types are defined in Python module giscanner.ast

pub type gboolean       = libc::c_int;
pub type gchar          = libc::c_char;
pub type guchar         = libc::c_uchar;
pub type gshort         = libc::c_short;
pub type gushort        = libc::c_ushort;
pub type gint           = libc::c_int;
pub type guint          = libc::c_uint;
pub type glong          = libc::c_long;
pub type gulong         = libc::c_ulong;
pub type gsize          = libc::size_t;
pub type gssize         = libc::ssize_t;
pub type gintptr        = libc::intptr_t;
pub type guintptr       = libc::uintptr_t;
pub type gfloat         = libc::c_float;
pub type gdouble        = libc::c_double;
pub type gunichar       = u32;
pub type gpointer       = *mut   libc::c_void;
pub type gconstpointer  = *const libc::c_void;

// GType is considered a fundamental type and used by the unqualified name
// in GIR files, despite being also defined in both GLib and GObject.
pub type GType = gsize;

pub const FALSE: gboolean = 0;
pub const TRUE : gboolean = 1;
<|endoftext|>


<commit_before>use criterion::BenchmarkId;
use criterion::Criterion;
use criterion::{criterion_group, criterion_main};

// The benchmarks here verify that the complexity grows as O(*n*)
// where *n* is the number of characters in the text to be wrapped.

use lipsum::lipsum_words_from_seed;

const LINE_LENGTH: usize = 60;

/// Generate a lorem ipsum text with the given number of characters.
fn lorem_ipsum(length: usize) -> String {
    // The average word length in the lorem ipsum text is somewhere
    // between 6 and 7. So we conservatively divide by 5 to have a
    // long enough text that we can truncate below.
    let mut text = lipsum_words_from_seed(length / 5, 42);
    text.truncate(length);
    text
}

pub fn benchmark(c: &mut Criterion) {
    let mut group = c.benchmark_group("String lengths");
    for length in [100, 200, 400, 800, 1600, 3200, 6400].iter() {
        let text = lorem_ipsum(*length);
        let options = textwrap::Options::new(LINE_LENGTH)
            .wrap_algorithm(textwrap::core::WrapAlgorithm::OptimalFit);
        group.bench_with_input(
            BenchmarkId::new("fill_optimal_fit", length),
            &text,
            |b, text| {
                b.iter(|| textwrap::fill(text, &options));
            },
        );

        let options = textwrap::Options::new(LINE_LENGTH)
            .wrap_algorithm(textwrap::core::WrapAlgorithm::FirstFit);
        group.bench_with_input(
            BenchmarkId::new("fill_first_fit", length),
            &text,
            |b, text| {
                b.iter(|| textwrap::fill(text, &options));
            },
        );

        let options: textwrap::Options =
            textwrap::Options::new(LINE_LENGTH).splitter(Box::new(textwrap::HyphenSplitter));
        group.bench_with_input(BenchmarkId::new("fill_boxed", length), &text, |b, text| {
            b.iter(|| textwrap::fill(text, &options));
        });

        group.bench_with_input(BenchmarkId::new("fill_usize", length), &text, |b, text| {
            b.iter(|| textwrap::fill(text, LINE_LENGTH));
        });

        group.bench_function(BenchmarkId::new("fill_inplace", length), |b| {
            b.iter_batched(
                || text.clone(),
                |mut text| textwrap::fill_inplace(&mut text, LINE_LENGTH),
                criterion::BatchSize::SmallInput,
            );
        });

        #[cfg(feature = "hyphenation")]
        {
            use hyphenation::{Language, Load, Standard};
            let path = std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
                .join("benches")
                .join("la.standard.bincode");
            let dictionary = Standard::from_path(Language::Latin, &path).unwrap();
            let options = options.splitter(dictionary);
            group.bench_with_input(BenchmarkId::new("hyphenation", length), &text, |b, text| {
                b.iter(|| textwrap::fill(text, &options));
            });
        };
    }
    group.finish();
}

criterion_group!(benches, benchmark);
criterion_main!(benches);
<commit_msg>Add more intermediate steps to linear benchmark<commit_after>use criterion::BenchmarkId;
use criterion::Criterion;
use criterion::{criterion_group, criterion_main};

// The benchmarks here verify that the complexity grows as O(*n*)
// where *n* is the number of characters in the text to be wrapped.

use lipsum::lipsum_words_from_seed;

const LINE_LENGTH: usize = 60;

/// Generate a lorem ipsum text with the given number of characters.
fn lorem_ipsum(length: usize) -> String {
    // The average word length in the lorem ipsum text is somewhere
    // between 6 and 7. So we conservatively divide by 5 to have a
    // long enough text that we can truncate below.
    let mut text = lipsum_words_from_seed(length / 5, 42);
    text.truncate(length);
    text
}

pub fn benchmark(c: &mut Criterion) {
    let mut group = c.benchmark_group("String lengths");
    for length in [200, 300, 400, 600, 800, 1200, 1600, 2400, 3200, 4800, 6400].iter() {
        let text = lorem_ipsum(*length);
        let options = textwrap::Options::new(LINE_LENGTH)
            .wrap_algorithm(textwrap::core::WrapAlgorithm::OptimalFit);
        group.bench_with_input(
            BenchmarkId::new("fill_optimal_fit", length),
            &text,
            |b, text| {
                b.iter(|| textwrap::fill(text, &options));
            },
        );

        let options = textwrap::Options::new(LINE_LENGTH)
            .wrap_algorithm(textwrap::core::WrapAlgorithm::FirstFit);
        group.bench_with_input(
            BenchmarkId::new("fill_first_fit", length),
            &text,
            |b, text| {
                b.iter(|| textwrap::fill(text, &options));
            },
        );

        let options: textwrap::Options =
            textwrap::Options::new(LINE_LENGTH).splitter(Box::new(textwrap::HyphenSplitter));
        group.bench_with_input(BenchmarkId::new("fill_boxed", length), &text, |b, text| {
            b.iter(|| textwrap::fill(text, &options));
        });

        group.bench_with_input(BenchmarkId::new("fill_usize", length), &text, |b, text| {
            b.iter(|| textwrap::fill(text, LINE_LENGTH));
        });

        group.bench_function(BenchmarkId::new("fill_inplace", length), |b| {
            b.iter_batched(
                || text.clone(),
                |mut text| textwrap::fill_inplace(&mut text, LINE_LENGTH),
                criterion::BatchSize::SmallInput,
            );
        });

        #[cfg(feature = "hyphenation")]
        {
            use hyphenation::{Language, Load, Standard};
            let path = std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
                .join("benches")
                .join("la.standard.bincode");
            let dictionary = Standard::from_path(Language::Latin, &path).unwrap();
            let options = options.splitter(dictionary);
            group.bench_with_input(BenchmarkId::new("hyphenation", length), &text, |b, text| {
                b.iter(|| textwrap::fill(text, &options));
            });
        };
    }
    group.finish();
}

criterion_group!(benches, benchmark);
criterion_main!(benches);
<|endoftext|>


<commit_before>// Copyright 2016 Pierre Talbot (IRCAM)

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// This example example of PCP use.
//
// to run all example : cargo run.
// to test : cargo test -- --nocapture
// to bench: cargo bench

#![feature(test, box_syntax)]
extern crate pcp;
extern crate interval;
extern crate gcollections;
extern crate test;

mod nqueens;
mod robot;
mod robot2;
// mod robot3;

use nqueens::nqueens;

fn main() {
//  nqueens(100);
//  let robot = robot::RobotScheduling::new(3, 500).solve();
//  println!("{}", robot);

// !!! le solveur plante avec une erreur 'index out of bounds sur un vecteur
   println!("Solve robot2 domaine 400");
   let test1 = robot2::RobotScheduling::new_test1(2, 400, 10, 25, 240, 25).solve();
   println!("{}", test1);

//   //ok bonne réponses. Le wait est bien intercallé
   println!("Solve robot2 domaine 400");
   let test2 = robot2::RobotScheduling::new_test2(2, 400, 10, 25, 240, 25, 5).solve();
   println!("{}", test2);

// // !!! Non satisfaisable alors que robot 2 l'est avec les même données.
   println!("Solve robot1 domaine 34");
   let test1 = robot2::RobotScheduling::new_test1(2, 34, 1, 3, 24, 3).solve(); // dure et ne rend pas le mains
   println!("{}", test1);

//   // !!! dure et ne rend pas le mains pourtant le problème est plus simple qu'avec le robot2 après
   println!("Solve robot1 domaine 38");
   let test1 = robot2::RobotScheduling::new_test1(2, 38, 1, 3, 24, 3).solve();
   println!("{}", test1);

//   //Ok bonne solution
   println!("Solve robot2 domaine 38");
   let test2 = robot2::RobotScheduling::new_test2(2, 38, 1, 3, 24, 3, 1).solve();
   println!("{}", test2);

  //erreur durant la résolution.
//  let robot3 = robot3::RobotScheduling::new(2, 40, 1, 3, 24, 3).solve();
//  println!("{}", robot3);

}
<commit_msg>update robot2 exemple<commit_after>// Copyright 2016 Pierre Talbot (IRCAM)

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// This example example of PCP use.
//
// to run all example : cargo run.
// to test : cargo test -- --nocapture
// to bench: cargo bench

#![feature(test, box_syntax)]
extern crate pcp;
extern crate interval;
extern crate gcollections;
extern crate test;

mod nqueens;
mod robot;
mod robot2;
// mod robot3;

use nqueens::nqueens;

fn main() {
//  nqueens(100);
//  let robot = robot::RobotScheduling::new(3, 500).solve();
//  println!("{}", robot);

// !!! Ok with 2 robot. doesn't stop with 3 robot.
   println!("Solve robot2 domaine 400");
   let test1 = robot2::RobotScheduling::new_test1(2, 400, 10, 25, 240, 25).solve();
   println!("{}", test1);

//   //ok bonne réponses. Le wait est bien intercallé
   println!("Solve robot2 domaine 400");
   let test2 = robot2::RobotScheduling::new_test2(2, 400, 10, 25, 240, 25, 5).solve();
   println!("{}", test2);

// Non satisfi
   println!("Solve robot1 domaine 36");
   let test1 = robot2::RobotScheduling::new_test1(2, 37, 1, 3, 24, 3).solve();  //non satisfauisable
   println!("{}", test1);

//   //Ok bonne solution
   println!("Solve robot2 domaine 38");
   let test2 = robot2::RobotScheduling::new_test2(2, 38, 1, 3, 24, 3, 1).solve(); //durée des varibales est une variables.
   println!("{}", test2);

   println!("Solve robot1 domaine 38");
   let test1 = robot2::RobotScheduling::new_test1(2, 38, 1, 3, 24, 3).solve(); //ne rend pas la main trop long alors que le problème
   //est plus simple que test précédent. Dans cette version la durée des taches est fixée
   println!("{}", test1);

  //erreur durant la résolution.
//  let robot3 = robot3::RobotScheduling::new(2, 40, 1, 3, 24, 3).solve();
//  println!("{}", robot3);

}
<|endoftext|>


<commit_before>use std::convert;
use std::ops::{Add, Sub};
use std::default::Default;
use internals::{Node, BranchNode};

/// The class of monoids
///
/// The class of monoids (types with an accumulative binary operation that has
/// an identity).
///
/// Technically, `Add<Self, Output=Self>` is standing in for "semigroup" here,
/// while `Default` is standing in for "identity".
///
/// An instance _M_ should satisfy the following laws:
///
///  + _x_`.add(`_M_`::default())` = _x_
///  + _M_`::default().add(`_x_`)` = _x_
///  + _x_`.add(`_y_`.add(`_z_`))` = _z_`.add(`_x_`.add(`_y_`))`
///  + _M_`::accumulate(`_a_`)` = _a_`.fold(`_M_`::default,`_M_`::sum)`
///
pub trait Monoid: Add<Self, Output=Self> + Default + Sized {
    #[inline]
    fn accumulate<F>(xs: F) -> Self
    where F: Iterator<Item=Self>
        , Self: Sized {
        xs.fold(Self::default(), Self::add)
    }
}

pub trait Measured<M: Metric> {
    /// Apply `Metric` to `Self`
    ///
    /// Although we aren't currently enforcing this, `measure`ing a `Node` with
    /// two children should produce the same result as `measure`ing both
    /// children and `Monoid::sum`ming the result. That is to say, `measure`
    /// should be a [_monoid homomorphism_]
    /// (https://en.wikipedia.org/wiki/Monoid#Monoid_homomorphisms).
    fn measure(&self) -> M;

    /// Measure the `weight` of `Node` by this `metric`.
    fn measure_weight(&self) -> M;
}

/// A monoid that can be applied to a `Node` as a measurement
pub trait Metric: Monoid + Eq + Add<usize, Output=Self>
                         + Sub<usize, Output=Self>
                         + Sized {

    fn is_splittable() -> bool;

    /// Convert the `Metric` into a byte index into the given `Node`
    ///
    /// # Returns
    /// - `Some` with the byte index of the beginning of the `n`th  element
    ///    in `node` measured by this `Metric`, if there is an `n`th element
    /// - `None` if there is no `n`th element in `node`
    fn to_byte_index<M: Measured<Self>>(&self, node: &M) -> Option<usize>;

    /// Returns the byte index of the next element of this metric in `Node`
    #[inline]
    fn next<M: Measured<Self> >(self, node: &M) -> Option<usize> {
        (self + 1).to_byte_index(node)
    }

    /// Returns the byte index of the previous element of this metric in `Node`
    #[inline]
    fn back<M: Measured<Self>>(self, node: &M) -> Option<usize> {
        (self - 1).to_byte_index(node)
    }

    /// Returns true if index `i` in `node` is a boundary along this `Metric`
    fn is_boundary<M: Measured<Self>>(node: &M, i: usize) -> bool;
}

#[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub struct Grapheme(usize);
impl Default for Grapheme {
    #[inline] fn default() -> Self { Grapheme(0) }
}
impl convert::From<usize> for Grapheme {
    #[inline] fn from(u: usize) -> Self { Grapheme(u) }
}
impl Add<usize> for Grapheme {
    type Output = Self;
    #[inline] fn add(self, rhs: usize) -> Self { Grapheme(self.0 + rhs) }
}
impl Add<Grapheme> for Grapheme {
    type Output = Self;
    #[inline] fn add(self, rhs: Self) -> Self { Grapheme(self.0 + rhs.0) }
}
impl Monoid for Grapheme { }
impl Sub<usize> for Grapheme {
    type Output = Self;
    #[inline] fn sub(self, rhs: usize) -> Self { Grapheme(self.0 - rhs) }
}

#[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub struct Line(usize);
impl Default for Line {
    #[inline] fn default() -> Self { Line(0) }
}
impl Add<Line> for Line {
    type Output = Self;
    #[inline] fn add(self, rhs: Self) -> Self { Line(self.0 + rhs.0) }
}
impl convert::From<usize> for Line {
    #[inline] fn from(u: usize) -> Self { Line(u) }
}
impl Add<usize> for Line {
    type Output = Self;
    #[inline] fn add(self, rhs: usize) -> Self { Line(self.0 + rhs) }
}
impl Sub<usize> for Line {
    type Output = Self;
    #[inline] fn sub(self, rhs: usize) -> Self { Line(self.0 - rhs) }
}
<commit_msg>feat(rope): add Ordering to Metric<commit_after>use std::convert;
use std::ops::{Add, Sub};
use std::default::Default;
use internals::{Node, BranchNode};

/// The class of monoids
///
/// The class of monoids (types with an accumulative binary operation that has
/// an identity).
///
/// Technically, `Add<Self, Output=Self>` is standing in for "semigroup" here,
/// while `Default` is standing in for "identity".
///
/// An instance _M_ should satisfy the following laws:
///
///  + _x_`.add(`_M_`::default())` = _x_
///  + _M_`::default().add(`_x_`)` = _x_
///  + _x_`.add(`_y_`.add(`_z_`))` = _z_`.add(`_x_`.add(`_y_`))`
///  + _M_`::accumulate(`_a_`)` = _a_`.fold(`_M_`::default,`_M_`::sum)`
///
pub trait Monoid: Add<Self, Output=Self> + Default + Sized {
    #[inline]
    fn accumulate<F>(xs: F) -> Self
    where F: Iterator<Item=Self>
        , Self: Sized {
        xs.fold(Self::default(), Self::add)
    }
}

pub trait Measured<M: Metric> {
    /// Apply `Metric` to `Self`
    ///
    /// Although we aren't currently enforcing this, `measure`ing a `Node` with
    /// two children should produce the same result as `measure`ing both
    /// children and `Monoid::sum`ming the result. That is to say, `measure`
    /// should be a [_monoid homomorphism_]
    /// (https://en.wikipedia.org/wiki/Monoid#Monoid_homomorphisms).
    fn measure(&self) -> M;

    /// Measure the `weight` of `Node` by this `metric`.
    fn measure_weight(&self) -> M;
}

/// A monoid that can be applied to a `Node` as a measurement
pub trait Metric: Monoid + Eq + Add<usize, Output=Self>
                         + Sub<usize, Output=Self>
                         + Eq + Ord
                         + Sized {

    fn is_splittable() -> bool;

    /// Convert the `Metric` into a byte index into the given `Node`
    ///
    /// # Returns
    /// - `Some` with the byte index of the beginning of the `n`th  element
    ///    in `node` measured by this `Metric`, if there is an `n`th element
    /// - `None` if there is no `n`th element in `node`
    fn to_byte_index<M: Measured<Self>>(&self, node: &M) -> Option<usize>;

    /// Returns the byte index of the next element of this metric in `Node`
    #[inline]
    fn next<M: Measured<Self> >(self, node: &M) -> Option<usize> {
        (self + 1).to_byte_index(node)
    }

    /// Returns the byte index of the previous element of this metric in `Node`
    #[inline]
    fn back<M: Measured<Self>>(self, node: &M) -> Option<usize> {
        (self - 1).to_byte_index(node)
    }

    /// Returns true if index `i` in `node` is a boundary along this `Metric`
    fn is_boundary<M: Measured<Self>>(node: &M, i: usize) -> bool;
}

#[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub struct Grapheme(usize);
impl Default for Grapheme {
    #[inline] fn default() -> Self { Grapheme(0) }
}
impl convert::From<usize> for Grapheme {
    #[inline] fn from(u: usize) -> Self { Grapheme(u) }
}
impl Add<usize> for Grapheme {
    type Output = Self;
    #[inline] fn add(self, rhs: usize) -> Self { Grapheme(self.0 + rhs) }
}
impl Add<Grapheme> for Grapheme {
    type Output = Self;
    #[inline] fn add(self, rhs: Self) -> Self { Grapheme(self.0 + rhs.0) }
}
impl Monoid for Grapheme { }
impl Sub<usize> for Grapheme {
    type Output = Self;
    #[inline] fn sub(self, rhs: usize) -> Self { Grapheme(self.0 - rhs) }
}

#[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub struct Line(usize);
impl Default for Line {
    #[inline] fn default() -> Self { Line(0) }
}
impl Add<Line> for Line {
    type Output = Self;
    #[inline] fn add(self, rhs: Self) -> Self { Line(self.0 + rhs.0) }
}
impl convert::From<usize> for Line {
    #[inline] fn from(u: usize) -> Self { Line(u) }
}
impl Add<usize> for Line {
    type Output = Self;
    #[inline] fn add(self, rhs: usize) -> Self { Line(self.0 + rhs) }
}
impl Sub<usize> for Line {
    type Output = Self;
    #[inline] fn sub(self, rhs: usize) -> Self { Line(self.0 - rhs) }
}
<|endoftext|>


<commit_before>//! A hangman game to guess the hidden word.
// To run this example, use the command: cargo run --features unstable --example flower
#[cfg(all(not(feature = "unstable")))]
compile_error!("This example relies on unstable features. Run with `--features unstable`");

use std::io::{Error, Write};

use graphic::HangmanDesign;
use turtle::{rand::RandomSlice, Drawing, Point, Speed, Turtle};

// A small word list to choose from
const WORDS: &[&str; 28] = &[
    "poetry",
    "formal",
    "type",
    "expresses",
    "personal",
    "emotions",
    "feelings",
    "typically",
    "spoken",
    "equivalent",
    "lyrics",
    "term",
    "derives",
    "literature",
    "defined",
    "musical",
    "accompaniment",
    "usually",
    "stringed",
    "instrument",
    "term",
    "importance",
    "literary",
    "theory",
    "division",
    "developed",
    "between",
    "categories",
];

fn main() {
    let mut drawing = Drawing::new();

    // the turtle that is responsible for drawing the hangman design
    let mut hangman = drawing.add_turtle();

    // the turtle that is responsible for drawing the lines on which the letters appear.
    let mut lines = drawing.add_turtle();

    // the turtle that is responsible for drawing the Won or lost smiley.
    let mut wl = drawing.add_turtle();
    wl.hide();

    // the secret word that is to be guessed
    let secret = *WORDS.choose().unwrap();

    // this list stores all the steps of the hangman so that they can be drawn from a for loop or an index.
    let hangman_design = HangmanDesign::default();
    graphic::setup(&mut hangman);

    let mut all_guesses = String::new();

    // Loop over each step basically there are two ways to do this either one loops over the steps or one loops over guesses. Both need two nested loops.
    // HangmanDesign has the [`Iterator`] trait implemented which is why we can loop it directly.
    // The `'won:` syntax is to be able to conviniently `break` from both nested loops.
    'won: for step in hangman_design {
        // for each step we only draw it after a wron guess. So the following loops guesses and only `break`s to the for loop on a wrong guess. If all characters have been guessed correctly then it `break`s both loops and continues with a won or lost smiley.
        loop {
            draw_lines(&mut lines, secret, &all_guesses);
            let mut new_guess = String::new();
            ask_for_letter(&mut new_guess).expect("Failed to read letter");
            if secret.contains(&new_guess) {
                println!("This was correct!");
                all_guesses += &new_guess;
                if secret.chars().all(|c| all_guesses.contains(c)) {
                    break 'won;
                }
            } else {
                println!("No that letter is not in the word");
                break;
            }
        }
        step(&mut hangman);
    }
    // Redraw the lines else they could be outdated.
    draw_lines(&mut lines, secret, &all_guesses);
    wl.set_speed(Speed::instant());
    // Draw a circle
    wl.arc_right(100.0, 360.0);
    // Draw the left eye
    teleport_relative(&mut wl, Point { x: 55.0, y: 40.0 });
    wl.arc_right(5.0, 360.0);
    // Draw the right eye
    teleport_relative(&mut wl, Point { x: 85.0, y: 0.0 });
    wl.arc_right(5.0, 360.0);
    // Go to the start of the mouth
    teleport_relative(&mut wl, Point { x: -85.0, y: -80.0 });
    wl.right(90.0);
    // Either draw it smiling or sad
    if secret.chars().all(|c| all_guesses.contains(c)) {
        println!("You Won!");
        wl.right(45.0);
        wl.arc_left(65.0, 90.0);
    } else {
        println!("You Lost!");
        wl.left(45.0);
        wl.arc_right(65.0, 90.0);
    }
}

/// A function to ask the user for a letter
fn ask_for_letter(guess: &mut String) -> Result<(), Error> {
    print!("Please guess a letter: ");
    std::io::stdout().flush()?;
    std::io::stdin().read_line(guess)?;

    // remove trailing newline characters
    let to_trim = guess.trim_end_matches(&['\r', '\n'][..]).len();
    guess.truncate(to_trim);

    println!("You guessed: {}", &guess);
    Ok(())
}

/// A function to conveniently teleport the turtle relative to its current position.
fn teleport_relative(turtle: &mut Turtle, direction: Point) {
    let cur = turtle.position();
    let new: Point = cur + direction;
    turtle.pen_up();
    turtle.go_to(new);
    turtle.pen_down();
}

/// Draw the lines one for each character. If the character has been guessed already correctly draw a green circle above the line.
fn draw_lines(lines: &mut Turtle, secret: &str, all_guesses: &str) {
    // hide the lines-turtle and go th the startigpoint of the lines.
    lines.reset();
    lines.hide();
    lines.set_speed(Speed::instant());
    lines.right(90.0);
    teleport_relative(lines, Point { x: -300.0, y: 200.0 });

    // draw a line for every character in the secret.
    for letter in secret.chars() {
        if all_guesses.contains(letter) {
            teleport_relative(lines, Point { x: 2.5, y: 10.0 });

            // as turtle is not yet able to draw text draw a green replacement circle.
            lines.left(90.0);
            lines.set_fill_color("green");
            lines.set_pen_color("green");
            lines.begin_fill();
            lines.arc_right(7.5, 360.0);
            lines.end_fill();
            lines.set_pen_color("black");
            lines.right(90.0);

            teleport_relative(lines, Point { x: -2.5, y: -10.0 });

            // print to the terminal
            print!(" {} ", letter);
        } else {
            print!(" _ ");
        }
        lines.forward(20.0);
        teleport_relative(lines, Point { x: 20.0, y: 0.0 });
    }
    println!(); // to switch to the next line and flush the output.
}

mod graphic {
    //! This module contains the drawing logic for the hangman graphic
    //!
    //! It is used by creating an instance of a [`HangmanDesign`] struct using [`HangmanDesign::default()`].
    //! Therein is contained a list of all the steps neccessary to draw the hangman in chronologic order.

    use turtle::{Point, Speed, Turtle};

    use crate::teleport_relative;

    pub struct HangmanDesign {
        state: usize,
        steps: &'static [fn(&mut turtle::Turtle); 9],
    }

    impl Default for HangmanDesign {
        fn default() -> Self {
            Self {
                state: 0,
                steps: &[hill, mast, bar, support, rope, head, arms, body, legs],
            }
        }
    }

    impl Iterator for HangmanDesign {
        type Item = &'static fn(&mut turtle::Turtle);

        fn next(&mut self) -> Option<Self::Item> {
            self.state += 1;
            self.steps.get(self.state - 1)
        }
    }

    pub fn setup(hangman: &mut Turtle) {
        // hide the hangman-turtle and go th the startigpoint of the graphic.
        hangman.hide();
        hangman.set_speed(Speed::instant());
        hangman.set_pen_size(10.0);
        teleport_relative(hangman, Point { x: -300.0, y: -300.0 });
    }

    fn hill(hangman: &mut Turtle) {
        // start drawing
        hangman.arc_right(100.0, 180.0);
        hangman.left(180.0);
        hangman.arc_left(100.0, 90.0);
        hangman.right(90.0);
    }

    fn mast(hangman: &mut Turtle) {
        hangman.forward(300.0);
    }

    fn bar(hangman: &mut Turtle) {
        hangman.right(90.0);
        hangman.forward(150.0);
    }

    fn support(hangman: &mut Turtle) {
        hangman.backward(100.0);
        hangman.right(135.0);
        hangman.forward(70.710678119);
        hangman.backward(70.710678119);
        hangman.left(135.0);
        hangman.forward(100.0);
    }

    fn rope(hangman: &mut Turtle) {
        hangman.set_pen_size(3.0);
        hangman.right(90.0);
        hangman.forward(70.0);
    }

    fn head(hangman: &mut Turtle) {
        hangman.left(90.0);
        hangman.arc_right(30.0, 540.0);
    }

    fn arms(hangman: &mut Turtle) {
        hangman.left(60.0);
        hangman.forward(100.0);
        hangman.backward(100.0);
        hangman.left(60.0);
        hangman.forward(100.0);
        hangman.backward(100.0);
        hangman.right(30.0);
    }

    fn body(hangman: &mut Turtle) {
        hangman.forward(100.0);
    }

    fn legs(hangman: &mut Turtle) {
        hangman.right(20.0);
        hangman.forward(120.0);
        hangman.backward(120.0);
        hangman.left(40.0);
        hangman.forward(120.0);
        hangman.backward(120.0);
        hangman.right(20.0);
    }
}
<commit_msg>fix a copy paste error<commit_after>//! A hangman game to guess the hidden word.
// To run this example, use the command: cargo run --features unstable --example hangman
#[cfg(all(not(feature = "unstable")))]
compile_error!("This example relies on unstable features. Run with `--features unstable`");

use std::io::{Error, Write};

use graphic::HangmanDesign;
use turtle::{rand::RandomSlice, Drawing, Point, Speed, Turtle};

// A small word list to choose from
const WORDS: &[&str; 28] = &[
    "poetry",
    "formal",
    "type",
    "expresses",
    "personal",
    "emotions",
    "feelings",
    "typically",
    "spoken",
    "equivalent",
    "lyrics",
    "term",
    "derives",
    "literature",
    "defined",
    "musical",
    "accompaniment",
    "usually",
    "stringed",
    "instrument",
    "term",
    "importance",
    "literary",
    "theory",
    "division",
    "developed",
    "between",
    "categories",
];

fn main() {
    let mut drawing = Drawing::new();

    // the turtle that is responsible for drawing the hangman design
    let mut hangman = drawing.add_turtle();

    // the turtle that is responsible for drawing the lines on which the letters appear.
    let mut lines = drawing.add_turtle();

    // the turtle that is responsible for drawing the Won or lost smiley.
    let mut wl = drawing.add_turtle();
    wl.hide();

    // the secret word that is to be guessed
    let secret = *WORDS.choose().unwrap();

    // this list stores all the steps of the hangman so that they can be drawn from a for loop or an index.
    let hangman_design = HangmanDesign::default();
    graphic::setup(&mut hangman);

    let mut all_guesses = String::new();

    // Loop over each step basically there are two ways to do this either one loops over the steps or one loops over guesses. Both need two nested loops.
    // HangmanDesign has the [`Iterator`] trait implemented which is why we can loop it directly.
    // The `'won:` syntax is to be able to conviniently `break` from both nested loops.
    'won: for step in hangman_design {
        // for each step we only draw it after a wron guess. So the following loops guesses and only `break`s to the for loop on a wrong guess. If all characters have been guessed correctly then it `break`s both loops and continues with a won or lost smiley.
        loop {
            draw_lines(&mut lines, secret, &all_guesses);
            let mut new_guess = String::new();
            ask_for_letter(&mut new_guess).expect("Failed to read letter");
            if secret.contains(&new_guess) {
                println!("This was correct!");
                all_guesses += &new_guess;
                if secret.chars().all(|c| all_guesses.contains(c)) {
                    break 'won;
                }
            } else {
                println!("No that letter is not in the word");
                break;
            }
        }
        step(&mut hangman);
    }
    // Redraw the lines else they could be outdated.
    draw_lines(&mut lines, secret, &all_guesses);
    wl.set_speed(Speed::instant());
    // Draw a circle
    wl.arc_right(100.0, 360.0);
    // Draw the left eye
    teleport_relative(&mut wl, Point { x: 55.0, y: 40.0 });
    wl.arc_right(5.0, 360.0);
    // Draw the right eye
    teleport_relative(&mut wl, Point { x: 85.0, y: 0.0 });
    wl.arc_right(5.0, 360.0);
    // Go to the start of the mouth
    teleport_relative(&mut wl, Point { x: -85.0, y: -80.0 });
    wl.right(90.0);
    // Either draw it smiling or sad
    if secret.chars().all(|c| all_guesses.contains(c)) {
        println!("You Won!");
        wl.right(45.0);
        wl.arc_left(65.0, 90.0);
    } else {
        println!("You Lost!");
        wl.left(45.0);
        wl.arc_right(65.0, 90.0);
    }
}

/// A function to ask the user for a letter
fn ask_for_letter(guess: &mut String) -> Result<(), Error> {
    print!("Please guess a letter: ");
    std::io::stdout().flush()?;
    std::io::stdin().read_line(guess)?;

    // remove trailing newline characters
    let to_trim = guess.trim_end_matches(&['\r', '\n'][..]).len();
    guess.truncate(to_trim);

    println!("You guessed: {}", &guess);
    Ok(())
}

/// A function to conveniently teleport the turtle relative to its current position.
fn teleport_relative(turtle: &mut Turtle, direction: Point) {
    let cur = turtle.position();
    let new: Point = cur + direction;
    turtle.pen_up();
    turtle.go_to(new);
    turtle.pen_down();
}

/// Draw the lines one for each character. If the character has been guessed already correctly draw a green circle above the line.
fn draw_lines(lines: &mut Turtle, secret: &str, all_guesses: &str) {
    // hide the lines-turtle and go th the startigpoint of the lines.
    lines.reset();
    lines.hide();
    lines.set_speed(Speed::instant());
    lines.right(90.0);
    teleport_relative(lines, Point { x: -300.0, y: 200.0 });

    // draw a line for every character in the secret.
    for letter in secret.chars() {
        if all_guesses.contains(letter) {
            teleport_relative(lines, Point { x: 2.5, y: 10.0 });

            // as turtle is not yet able to draw text draw a green replacement circle.
            lines.left(90.0);
            lines.set_fill_color("green");
            lines.set_pen_color("green");
            lines.begin_fill();
            lines.arc_right(7.5, 360.0);
            lines.end_fill();
            lines.set_pen_color("black");
            lines.right(90.0);

            teleport_relative(lines, Point { x: -2.5, y: -10.0 });

            // print to the terminal
            print!(" {} ", letter);
        } else {
            print!(" _ ");
        }
        lines.forward(20.0);
        teleport_relative(lines, Point { x: 20.0, y: 0.0 });
    }
    println!(); // to switch to the next line and flush the output.
}

mod graphic {
    //! This module contains the drawing logic for the hangman graphic
    //!
    //! It is used by creating an instance of a [`HangmanDesign`] struct using [`HangmanDesign::default()`].
    //! Therein is contained a list of all the steps neccessary to draw the hangman in chronologic order.

    use turtle::{Point, Speed, Turtle};

    use crate::teleport_relative;

    pub struct HangmanDesign {
        state: usize,
        steps: &'static [fn(&mut turtle::Turtle); 9],
    }

    impl Default for HangmanDesign {
        fn default() -> Self {
            Self {
                state: 0,
                steps: &[hill, mast, bar, support, rope, head, arms, body, legs],
            }
        }
    }

    impl Iterator for HangmanDesign {
        type Item = &'static fn(&mut turtle::Turtle);

        fn next(&mut self) -> Option<Self::Item> {
            self.state += 1;
            self.steps.get(self.state - 1)
        }
    }

    pub fn setup(hangman: &mut Turtle) {
        // hide the hangman-turtle and go th the startigpoint of the graphic.
        hangman.hide();
        hangman.set_speed(Speed::instant());
        hangman.set_pen_size(10.0);
        teleport_relative(hangman, Point { x: -300.0, y: -300.0 });
    }

    fn hill(hangman: &mut Turtle) {
        // start drawing
        hangman.arc_right(100.0, 180.0);
        hangman.left(180.0);
        hangman.arc_left(100.0, 90.0);
        hangman.right(90.0);
    }

    fn mast(hangman: &mut Turtle) {
        hangman.forward(300.0);
    }

    fn bar(hangman: &mut Turtle) {
        hangman.right(90.0);
        hangman.forward(150.0);
    }

    fn support(hangman: &mut Turtle) {
        hangman.backward(100.0);
        hangman.right(135.0);
        hangman.forward(70.710678119);
        hangman.backward(70.710678119);
        hangman.left(135.0);
        hangman.forward(100.0);
    }

    fn rope(hangman: &mut Turtle) {
        hangman.set_pen_size(3.0);
        hangman.right(90.0);
        hangman.forward(70.0);
    }

    fn head(hangman: &mut Turtle) {
        hangman.left(90.0);
        hangman.arc_right(30.0, 540.0);
    }

    fn arms(hangman: &mut Turtle) {
        hangman.left(60.0);
        hangman.forward(100.0);
        hangman.backward(100.0);
        hangman.left(60.0);
        hangman.forward(100.0);
        hangman.backward(100.0);
        hangman.right(30.0);
    }

    fn body(hangman: &mut Turtle) {
        hangman.forward(100.0);
    }

    fn legs(hangman: &mut Turtle) {
        hangman.right(20.0);
        hangman.forward(120.0);
        hangman.backward(120.0);
        hangman.left(40.0);
        hangman.forward(120.0);
        hangman.backward(120.0);
        hangman.right(20.0);
    }
}
<|endoftext|>


<commit_before>extern crate isosurface;
extern crate gnuplot;
extern crate ndarray;

use ndarray::Array;
use isosurface::marching_triangles;
use gnuplot::{Figure, AxesCommon};

fn main() {
    let n = 5;
    let xs = Array::linspace(-0.5f64, 0.5, n);
    let ys = Array::linspace(-0.5, 0.5, n);

    let dim = (xs.len(), ys.len());

    let u = {
        let mut u = Array::from_elem(dim, 0.);

        for ((i, j), u) in u.indexed_iter_mut() {
            let (x, y) = (xs[i], ys[j]);
            *u = (x * x + y * y).sqrt() - 0.3;
        }
        u
    };

    let mut fg = Figure::new();

    {
        let mut axes = fg.axes2d();
        axes.set_aspect_ratio(gnuplot::AutoOption::Fix(1.));

        for &level in &[-0.1, 0., 0.1] {
            let verts = marching_triangles(u.as_slice().unwrap(), dim, level);

            for line in verts.chunks(2) {
                axes.lines(line.iter().map(|p| p[0]), line.iter().map(|p| p[1]), &[]);
            }
        }
    }
    fg.show();
}
<commit_msg>Add grid to example<commit_after>extern crate isosurface;
extern crate gnuplot;
extern crate ndarray;

use ndarray::Array;
use isosurface::marching_triangles;
use gnuplot::{Figure, AxesCommon};

fn main() {
    let n = 6;
    let xs = Array::linspace(-0.5f64, 0.5, n);
    let ys = Array::linspace(-0.5, 0.5, n);

    let dim = (xs.len(), ys.len());

    let u = {
        let mut u = Array::from_elem(dim, 0.);

        for ((i, j), u) in u.indexed_iter_mut() {
            let (x, y) = (xs[i], ys[j]);
            *u = (x * x + y * y).sqrt() - 0.3;
        }
        u
    };

    let mut fg = Figure::new();

    {
        let mut axes = fg.axes2d();
        axes.set_aspect_ratio(gnuplot::AutoOption::Fix(1.));

        let grid_opt = [gnuplot::PlotOption::LineStyle(gnuplot::DashType::DotDash)];

        for x in 0..n {
            axes.lines(&[x, x], &[0, n-1], &grid_opt);
            axes.lines(&[0, n-1], &[x, x], &grid_opt);
            axes.lines(&[0, x], &[n-1 - x, n-1], &grid_opt);
            axes.lines(&[x, n-1], &[0, n-1 - x], &grid_opt);
        }

        for &level in &[-0.1, 0., 0.1] {
            let verts = marching_triangles(u.as_slice().unwrap(), dim, level);

            for line in verts.chunks(2) {
                axes.lines(line.iter().map(|p| p[0]), line.iter().map(|p| p[1]), &[]);
            }
        }
    }
    fg.show();
}
<|endoftext|>


<commit_before>use std::collections::hash_map::HashMap;
use std::rc::Rc;

use automation::Automation;
use partial::Partial;
use tree::node::{ANode, NodeInputSlot, YNode};
use tree::send::{AASend, AYSend, Send, YYSend};
use tree::tree::Tree;

/// Tracks all the partials/automations that have ever entered the node.
/// This information is needed in order to evaluate the output whenever
/// a new input arrives.
struct ANodeState {
    left: Vec<Automation>,
    right: Vec<Automation>,
    aasends: Vec<AASend>,
    aysends: Vec<AYSend>
}

/// Tracks all the partials/automations that have ever entered the node.
/// This information is needed in order to evaluate the output whenever
/// a new input arrives.
struct YNodeState {
    left: Vec<Partial>,
    right: Vec<Automation>,
    yysends: Vec<YYSend>,
}

struct TreeRenderer {
    anode_states: HashMap<Rc<ANode>, ANodeState>,
    ynode_states: HashMap<Rc<YNode>, YNodeState>,
    output_nodes: Vec<Rc<YNode>>,
    output_buff: Vec<f32>,
}

impl TreeRenderer {
    pub fn new() -> TreeRenderer {
        TreeRenderer{
            anode_states: HashMap::new(),
            ynode_states: HashMap::new(),
            output_nodes: vec![],
            output_buff: vec![]
        }
    }
    /// Get the ANodeState associated with a node,
    /// and create it if it doesn't already exist.
    fn get_anode_state(&mut self, node: &Rc<ANode>) -> &mut ANodeState {
        self.anode_states.entry(node.clone()).or_insert_with(|| ANodeState::new())
        //&self.anode_states[node]
    }
    /// Get the YNodeState associated with a node,
    /// and create it if it doesn't already exist.
    fn get_ynode_state(&mut self, node: &Rc<YNode>) -> &mut YNodeState {
        self.ynode_states.entry(node.clone()).or_insert_with(|| YNodeState::new())
    }
    /// Send a partial to the input of any nodes connected to the output of the
    /// given node.
    fn broadcast_partial(&mut self, from: &Rc<YNode>, partial: Partial) {
        // need to clone the State's sends to avoid mutability problems
        let sends = self.get_ynode_state(from).yysends.clone();
        for ref send in sends.iter() {
            self.ynode_input_left(send.dest(), partial);
        }
    }
    /// Send an Automation to the input of any nodes connected to the output of
    /// the given node.
    fn broadcast_autom(&mut self, from: &Rc<ANode>, autom: Automation) {
        // need to clone the State's sends to avoid mutability problems
        let aasends = self.get_anode_state(from).aasends.clone();
        let aysends = self.get_anode_state(from).aysends.clone();
        // send automation input to the YNodes:
        for ref send in aysends.iter() {
            self.ynode_input_right(send.dest(), autom);
        }
        // send the automation to the other ANodes:
        for ref send in aasends.iter() {
            self.anode_input(send.dest(), send.dest_slot(), autom);
        }
    }
    /// Add a partial to the YNode's left slot
    fn ynode_input_left(&mut self, node: &Rc<YNode>, partial: Partial) {
        let right;
        {
            let mut state = self.get_ynode_state(node);
            state.left.push(partial);
            // need to clone the State's right-hand-side to avoid mut issues
            right = state.right.clone();
        }
        // compute any new outputs & broadcast them.
        for autom in right.iter() {
            self.broadcast_partial(node, autom.apply_to_partial(partial));
        }
    }
    fn ynode_input_right(&mut self, node: &Rc<YNode>, autom: Automation) {
        let left;
        {
            let mut state = self.get_ynode_state(node);
            state.right.push(autom);
            // need to clone the State's left-hand-side to avoid mut issues
            left = state.left.clone();
        }
        // compute any new outputs & broadcast them.
        for partial in left.iter() {
            self.broadcast_partial(node, autom.apply_to_partial(*partial));
        }
    }
    fn anode_input(&mut self, node: &Rc<ANode>, slot: NodeInputSlot,
      autom: Automation) {
        unimplemented!();
    }
}

impl Tree for TreeRenderer {
    /// Connect two nodes in the tree.
    /// If the send is ASrcSend / YSrcSend, this is the same as feeding
    /// external stimuli into the tree.
    fn add_send(&mut self, send: Send) {
        match send {
            Send::AASend(send) => {
                self.get_anode_state(send.src()).add_aasend(send);
            },
            Send::AYSend(send) => {
                self.get_anode_state(send.src()).add_aysend(send);
            },
            Send::YYSend(send) => {
                self.get_ynode_state(send.src()).add_yysend(send);
            },
            Send::ASrcSend(send) => {
                self.broadcast_autom(send.dest(), *send.src());
            },
            Send::YSrcSend(send) => {
                self.broadcast_partial(send.dest(), *send.src());
            },
        }
    }

    /// set the nodes for which we are interested in the output PCM signals.
    /// Future calls to `step()` will return an array of samples corresponding
    /// to these nodes.
    fn watch_nodes(&mut self, outputs: &[Rc<YNode>]) {
        self.output_nodes = outputs.to_vec();
    }
    /// Return the next buffer of samples related to the watched nodes.
    fn step(&mut self) -> &[f32] {
        unimplemented!();
        &self.output_buff
    }
}

impl ANodeState {
    fn new() -> ANodeState {
        ANodeState{ left:vec![], right: vec![], aasends: vec![], aysends:vec![] }
    }
    fn add_aasend(&mut self, send: AASend) {
        unimplemented!();
    }
    fn add_aysend(&mut self, send: AYSend) {
        unimplemented!();
    }
}

impl YNodeState {
    fn new() -> YNodeState {
        YNodeState{ left:vec![], right: vec![], yysends: vec![] }
    }
    fn add_yysend(&mut self, send: YYSend) {
        unimplemented!();
    }
}
<commit_msg>Implement anode_input()<commit_after>use std::collections::hash_map::HashMap;
use std::rc::Rc;

use automation::Automation;
use partial::Partial;
use tree::node::{ANode, NodeInputSlot, YNode};
use tree::send::{AASend, AYSend, Send, YYSend};
use tree::tree::Tree;

/// Tracks all the partials/automations that have ever entered the node.
/// This information is needed in order to evaluate the output whenever
/// a new input arrives.
struct ANodeState {
    left: Vec<Automation>,
    right: Vec<Automation>,
    aasends: Vec<AASend>,
    aysends: Vec<AYSend>
}

/// Tracks all the partials/automations that have ever entered the node.
/// This information is needed in order to evaluate the output whenever
/// a new input arrives.
struct YNodeState {
    left: Vec<Partial>,
    right: Vec<Automation>,
    yysends: Vec<YYSend>,
}

struct TreeRenderer {
    anode_states: HashMap<Rc<ANode>, ANodeState>,
    ynode_states: HashMap<Rc<YNode>, YNodeState>,
    output_nodes: Vec<Rc<YNode>>,
    output_buff: Vec<f32>,
}

impl TreeRenderer {
    pub fn new() -> TreeRenderer {
        TreeRenderer{
            anode_states: HashMap::new(),
            ynode_states: HashMap::new(),
            output_nodes: vec![],
            output_buff: vec![]
        }
    }
    /// Get the ANodeState associated with a node,
    /// and create it if it doesn't already exist.
    fn get_anode_state(&mut self, node: &Rc<ANode>) -> &mut ANodeState {
        self.anode_states.entry(node.clone()).or_insert_with(|| ANodeState::new())
    }
    /// Get the YNodeState associated with a node,
    /// and create it if it doesn't already exist.
    fn get_ynode_state(&mut self, node: &Rc<YNode>) -> &mut YNodeState {
        self.ynode_states.entry(node.clone()).or_insert_with(|| YNodeState::new())
    }
    /// Send a partial to the input of any nodes connected to the output of the
    /// given node.
    fn broadcast_partial(&mut self, from: &Rc<YNode>, partial: Partial) {
        // need to clone the State's sends to avoid mutability problems
        let sends = self.get_ynode_state(from).yysends.clone();
        for ref send in sends.iter() {
            self.ynode_input_left(send.dest(), partial);
        }
    }
    /// Send an Automation to the input of any nodes connected to the output of
    /// the given node.
    fn broadcast_autom(&mut self, from: &Rc<ANode>, autom: Automation) {
        // need to clone the State's sends to avoid mutability problems
        let aasends = self.get_anode_state(from).aasends.clone();
        let aysends = self.get_anode_state(from).aysends.clone();
        // send automation input to the YNodes:
        for ref send in aysends.iter() {
            self.ynode_input_right(send.dest(), autom);
        }
        // send the automation to the other ANodes:
        for ref send in aasends.iter() {
            self.anode_input(send.dest(), send.dest_slot(), autom);
        }
    }
    /// Add a partial to the YNode's left slot
    fn ynode_input_left(&mut self, node: &Rc<YNode>, partial: Partial) {
        let right;
        {
            let mut state = self.get_ynode_state(node);
            state.left.push(partial);
            // need to clone the State's right-hand-side to avoid mut issues
            right = state.right.clone();
        }
        // compute any new outputs & broadcast them.
        for autom in right.iter() {
            self.broadcast_partial(node, autom.apply_to_partial(partial));
        }
    }
    fn ynode_input_right(&mut self, node: &Rc<YNode>, autom: Automation) {
        let left;
        {
            let mut state = self.get_ynode_state(node);
            state.right.push(autom);
            // need to clone the State's left-hand-side to avoid mut issues
            left = state.left.clone();
        }
        // compute any new outputs & broadcast them.
        for partial in left.iter() {
            self.broadcast_partial(node, autom.apply_to_partial(*partial));
        }
    }
    fn anode_input(&mut self, node: &Rc<ANode>, slot: NodeInputSlot,
      autom: Automation) {
        match slot {
            NodeInputSlot::Left => {
                let right;
                {
                    let mut state = self.get_anode_state(node);
                    state.left.push(autom);
                    right = state.right.clone();
                }
                // all the automations in the right bin affect the new autom
                for autom_right in right.iter() {
                    self.broadcast_autom(node, autom_right.apply_to_autom(autom));
                }
            },
            NodeInputSlot::Right => {
                let left;
                {
                    let mut state = self.get_anode_state(node);
                    state.right.push(autom);
                    left = state.left.clone();
                }
                // this new autom affects all automations in the left bin
                for autom_left in left.iter() {
                    self.broadcast_autom(node, autom.apply_to_autom(*autom_left));
                }
            },
        };
    }
}

impl Tree for TreeRenderer {
    /// Connect two nodes in the tree.
    /// If the send is ASrcSend / YSrcSend, this is the same as feeding
    /// external stimuli into the tree.
    fn add_send(&mut self, send: Send) {
        match send {
            Send::AASend(send) => {
                self.get_anode_state(send.src()).add_aasend(send);
            },
            Send::AYSend(send) => {
                self.get_anode_state(send.src()).add_aysend(send);
            },
            Send::YYSend(send) => {
                self.get_ynode_state(send.src()).add_yysend(send);
            },
            Send::ASrcSend(send) => {
                self.broadcast_autom(send.dest(), *send.src());
            },
            Send::YSrcSend(send) => {
                self.broadcast_partial(send.dest(), *send.src());
            },
        }
    }

    /// set the nodes for which we are interested in the output PCM signals.
    /// Future calls to `step()` will return an array of samples corresponding
    /// to these nodes.
    fn watch_nodes(&mut self, outputs: &[Rc<YNode>]) {
        self.output_nodes = outputs.to_vec();
    }
    /// Return the next buffer of samples related to the watched nodes.
    fn step(&mut self) -> &[f32] {
        unimplemented!();
        &self.output_buff
    }
}

impl ANodeState {
    fn new() -> ANodeState {
        ANodeState{ left:vec![], right: vec![], aasends: vec![], aysends:vec![] }
    }
    fn add_aasend(&mut self, send: AASend) {
        self.aasends.push(send);
    }
    fn add_aysend(&mut self, send: AYSend) {
        self.aysends.push(send);
    }
}

impl YNodeState {
    fn new() -> YNodeState {
        YNodeState{ left:vec![], right: vec![], yysends: vec![] }
    }
    fn add_yysend(&mut self, send: YYSend) {
        self.yysends.push(send);
    }
}
<|endoftext|>