<commit_before>#![feature(no_panic_pow)]
#![feature(test)]

extern crate test;

use codegen::{Const, Enum, Function, Struct, Scope, Impl};
use can_dbc::{DBC, ByteOrder, Message, MessageId, Signal, ValueDescription};
use std::fmt::Write;
use heck::{CamelCase, ShoutySnakeCase};

#[cfg(test)]
mod tests {
    use test::{Bencher, black_box};
    use byteorder;
    use byteorder::{ByteOrder, LE};

    #[bench]
    fn bench_read_signal(b: &mut Bencher) {
        const byte_payload: &[u8] = &[0x4, 0x2, 0xA, 0xA, 0xF, 0xF, 0xE, 0xE, 0xD, 0xD, 0xA, 0xA, 0xF, 0xF, 0xD, 0xD];

        b.iter(|| {
            let frame_payload: u64 = LE::read_u64(byte_payload);
            let bit_msk_const = 2u64.saturating_pow(8 as u32) - 1;
            let factor: f64 = test::black_box(2.0);
            let start_bit: u64 = test::black_box(8);
            let offset: f64 = test::black_box(10.0);

            (((frame_payload >> start_bit) & bit_msk_const) as f64) * factor + offset
        });
    }
}

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

fn to_enum_name(message_id: &MessageId, signal_name: &str) -> String {
     format!("{}{}", &signal_name.to_camel_case(), message_id.0)
}

pub fn signal_enum(val_desc: &ValueDescription) -> Option<Enum> {
    if let ValueDescription::Signal{ ref message_id, ref signal_name, ref value_descriptions } = val_desc {

        let mut sig_enum = Enum::new(&to_enum_name(message_id, signal_name));
        sig_enum.vis("pub");
        sig_enum.repr("u64");
        sig_enum.derive("Debug");
        sig_enum.derive("Clone");
        sig_enum.derive("Copy");
        sig_enum.derive("PartialEq");
        sig_enum.derive("Eq");
        for desc in value_descriptions {
            sig_enum.new_variant(&desc.b().to_camel_case());
        }
        sig_enum.new_variant("XValue(u64)");
        return Some(sig_enum);
    }
    None
}

pub fn signal_enum_impl(val_desc: &ValueDescription) -> Option<Impl> {
    if let ValueDescription::Signal{ ref message_id, ref signal_name, ref value_descriptions } = val_desc {
        let enum_name = to_enum_name(message_id, signal_name);
        let mut enum_impl = Impl::new(codegen::Type::new(&enum_name));
        enum_impl.impl_trait("From<u64>");

        let new_fn = enum_impl.new_fn("from");
        new_fn.arg("val", codegen::Type::new("u64"));

        let mut matching = String::new();
        write!(&mut matching, "match val {{\n").unwrap();
        for value_description in value_descriptions {
            write!(&mut matching, "    {} => {}::{},\n", value_description.a(), enum_name, value_description.b().to_camel_case()).unwrap();
        }
        write!(&mut matching, "    value => {}::XValue(value),\n", enum_name).unwrap();
        write!(&mut matching, "}}").unwrap();

        new_fn.line(matching);
        new_fn.ret(codegen::Type::new("Self"));

        return Some(enum_impl);
    }
    None
}

pub fn signal_fn(dbc: &DBC, signal: &Signal, message_id: &MessageId) -> Result<Function> {
    let mut signal_fn = codegen::Function::new(&signal.name().to_lowercase());
    signal_fn.vis("pub");
    signal_fn.arg_ref_self();

    // Attempt to find a matching enum return type, default to `f64` otherwise
    let ret_enum_type = dbc.value_descriptions_for_signal(message_id, signal.name()).map(|_| codegen::Type::new(&to_enum_name(message_id, signal.name())));
    signal_fn.ret(ret_enum_type.clone().unwrap_or_else(|| codegen::Type::new("f64")));

    let default_signal_comment = format!("Read {} signal from can frame", signal.name());
    let signal_comment = dbc.signal_comment(message_id, signal.name()).unwrap_or(&default_signal_comment);
    signal_fn.doc(signal_comment);

    let read_byte_order = match signal.byte_order() {
        ByteOrder::LittleEndian => "let frame_payload: u64 = LE::read_u64(self.frame_payload);",
        ByteOrder::BigEndian => "let  frame_payload: u64 = BE::read_u64(self.frame_payload);",
    };
    signal_fn.line(read_byte_order);

    let bit_msk_const = 2u64.saturating_pow(*signal.signal_size() as u32) - 1;
    let mut calc = String::new();

    if ret_enum_type.is_some() {
       write!(&mut calc, "{}::from((", to_enum_name(message_id, signal.name()))?; // TODO to_valid_upper_case called multiple times
    }

    // No shift required if start_bit == 0
    let shift = if *signal.start_bit() != 0 {
        format!("(frame_payload >> {})", signal.start_bit())
    } else {
        format!("frame_payload")
    };

    write!(&mut calc, "({} & {:#X}) as f64", shift, bit_msk_const)?;

    if *signal.factor() != 1.0 {
        write!(&mut calc, " * {:.6}", signal.factor())?;
    }

    if *signal.offset() != 0.0 {
        write!(&mut calc, " + {} as f64", signal.offset())?;
    }

    if ret_enum_type.is_some() {
        write!(&mut calc, ") as u64)")?;
    }

    signal_fn.line(calc);
    Ok(signal_fn)
}

fn message_const(message: &Message) -> Const {
    let const_name = format!("MESSAGE_ID_{}", message.message_name().to_shouty_snake_case());
    let mut c = Const::new(&const_name, codegen::Type::new("u32"), message.message_id().0.to_string());
    c.vis("pub");
    c
}

fn message_struct(dbc: &DBC, message: &Message) -> Struct {
    let mut message_struct = Struct::new(&message.message_name().to_camel_case());
    if let Some(message_comment) = dbc.message_comment(message.message_id()) {
        message_struct.doc(message_comment);
    }
    message_struct.derive("Debug");
    message_struct.vis("pub");
    message_struct.generic("'a");
    message_struct.field("frame_payload", "&'a[u8]");
    message_struct
}

fn message_impl(dbc: &DBC, message: &Message) -> Result<Impl> {

    let mut msg_impl = Impl::new(codegen::Type::new(&message.message_name().to_camel_case()));
    msg_impl.generic("'a");
    msg_impl.target_generic("'a");
    let new_fn = msg_impl.new_fn("new");
    new_fn.vis("pub");
    new_fn.arg("frame_payload", codegen::Type::new("&[u8]"));

    new_fn.line(format!("{} {{ frame_payload }}", message.message_name().to_camel_case()));
    new_fn.ret(codegen::Type::new(&message.message_name().to_camel_case()));

    for signal in message.signals() {
        msg_impl.push_fn(signal_fn(dbc, signal, message.message_id())?);
    }

    Ok(msg_impl)
}

pub fn can_reader(dbc: &DBC) -> Result<Scope> {

    let mut scope = Scope::new();
    scope.raw("#[allow(dead_code, unused_imports)]\n");
    scope.import("byteorder", "{ByteOrder, LE, BE}");

    for message in dbc.messages() {
        scope.push_const(message_const(message));
    }

    for value_description in dbc.value_descriptions() {
        if let Some(signal_enum) = signal_enum(value_description) {
            scope.push_enum(signal_enum);
        }

        if let Some(enum_impl) = signal_enum_impl(value_description) {
            scope.push_impl(enum_impl);
        }
    }

    for message in dbc.messages() {
        scope.push_struct(message_struct(&dbc, message));
        scope.push_impl(message_impl(&dbc, message)?);
    }

    Ok(scope)
}<commit_msg>Add allow code lints to generated code<commit_after>#![feature(no_panic_pow)]
#![feature(test)]

extern crate test;

use codegen::{Const, Enum, Function, Struct, Scope, Impl};
use can_dbc::{DBC, ByteOrder, Message, MessageId, Signal, ValueDescription};
use std::fmt::Write;
use heck::{CamelCase, ShoutySnakeCase};

#[cfg(test)]
mod tests {
    use test::{Bencher, black_box};
    use byteorder;
    use byteorder::{ByteOrder, LE};

    #[bench]
    fn bench_read_signal(b: &mut Bencher) {
        const byte_payload: &[u8] = &[0x4, 0x2, 0xA, 0xA, 0xF, 0xF, 0xE, 0xE, 0xD, 0xD, 0xA, 0xA, 0xF, 0xF, 0xD, 0xD];

        b.iter(|| {
            let frame_payload: u64 = LE::read_u64(byte_payload);
            let bit_msk_const = 2u64.saturating_pow(8 as u32) - 1;
            let factor: f64 = test::black_box(2.0);
            let start_bit: u64 = test::black_box(8);
            let offset: f64 = test::black_box(10.0);

            (((frame_payload >> start_bit) & bit_msk_const) as f64) * factor + offset
        });
    }
}

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

fn to_enum_name(message_id: &MessageId, signal_name: &str) -> String {
     format!("{}{}", &signal_name.to_camel_case(), message_id.0)
}

pub fn signal_enum(val_desc: &ValueDescription) -> Option<Enum> {
    if let ValueDescription::Signal{ ref message_id, ref signal_name, ref value_descriptions } = val_desc {

        let mut sig_enum = Enum::new(&to_enum_name(message_id, signal_name));
        sig_enum.allow("dead_code");
        sig_enum.vis("pub");
        sig_enum.repr("u64");
        sig_enum.derive("Debug");
        sig_enum.derive("Clone");
        sig_enum.derive("Copy");
        sig_enum.derive("PartialEq");
        sig_enum.derive("Eq");
        for desc in value_descriptions {
            sig_enum.new_variant(&desc.b().to_camel_case());
        }
        sig_enum.new_variant("XValue(u64)");
        return Some(sig_enum);
    }
    None
}

pub fn signal_enum_impl(val_desc: &ValueDescription) -> Option<Impl> {
    if let ValueDescription::Signal{ ref message_id, ref signal_name, ref value_descriptions } = val_desc {
        let enum_name = to_enum_name(message_id, signal_name);
        let mut enum_impl = Impl::new(codegen::Type::new(&enum_name));
        enum_impl.impl_trait("From<u64>");

        let from_fn = enum_impl.new_fn("from");
        from_fn.allow("dead_code");
        from_fn.arg("val", codegen::Type::new("u64"));

        let mut matching = String::new();
        write!(&mut matching, "match val {{\n").unwrap();
        for value_description in value_descriptions {
            write!(&mut matching, "    {} => {}::{},\n", value_description.a(), enum_name, value_description.b().to_camel_case()).unwrap();
        }
        write!(&mut matching, "    value => {}::XValue(value),\n", enum_name).unwrap();
        write!(&mut matching, "}}").unwrap();

        from_fn.line(matching);
        from_fn.ret(codegen::Type::new("Self"));

        return Some(enum_impl);
    }
    None
}

pub fn signal_fn(dbc: &DBC, signal: &Signal, message_id: &MessageId) -> Result<Function> {
    let mut signal_fn = codegen::Function::new(&signal.name().to_lowercase());
    signal_fn.allow("dead_code");
    signal_fn.vis("pub");
    signal_fn.arg_ref_self();

    // Attempt to find a matching enum return type, default to `f64` otherwise
    let ret_enum_type = dbc.value_descriptions_for_signal(message_id, signal.name()).map(|_| codegen::Type::new(&to_enum_name(message_id, signal.name())));
    signal_fn.ret(ret_enum_type.clone().unwrap_or_else(|| codegen::Type::new("f64")));

    let default_signal_comment = format!("Read {} signal from can frame", signal.name());
    let signal_comment = dbc.signal_comment(message_id, signal.name()).unwrap_or(&default_signal_comment);
    signal_fn.doc(signal_comment);

    let read_byte_order = match signal.byte_order() {
        ByteOrder::LittleEndian => "let frame_payload: u64 = LE::read_u64(self.frame_payload);",
        ByteOrder::BigEndian => "let  frame_payload: u64 = BE::read_u64(self.frame_payload);",
    };
    signal_fn.line(read_byte_order);

    let bit_msk_const = 2u64.saturating_pow(*signal.signal_size() as u32) - 1;
    let mut calc = String::new();

    if ret_enum_type.is_some() {
       write!(&mut calc, "{}::from((", to_enum_name(message_id, signal.name()))?; // TODO to_valid_upper_case called multiple times
    }

    // No shift required if start_bit == 0
    let shift = if *signal.start_bit() != 0 {
        format!("(frame_payload >> {})", signal.start_bit())
    } else {
        format!("frame_payload")
    };

    write!(&mut calc, "({} & {:#X}) as f64", shift, bit_msk_const)?;

    if *signal.factor() != 1.0 {
        write!(&mut calc, " * {:.6}", signal.factor())?;
    }

    if *signal.offset() != 0.0 {
        write!(&mut calc, " + {}f64", signal.offset())?;
    }

    if ret_enum_type.is_some() {
        write!(&mut calc, ") as u64)")?;
    }

    signal_fn.line(calc);
    Ok(signal_fn)
}

fn message_const(message: &Message) -> Const {
    let const_name = format!("MESSAGE_ID_{}", message.message_name().to_shouty_snake_case());
    let mut c = Const::new(&const_name, codegen::Type::new("u32"), message.message_id().0.to_string());
    c.allow("dead_code");
    c.vis("pub");
    c
}

fn message_struct(dbc: &DBC, message: &Message) -> Struct {
    let mut message_struct = Struct::new(&message.message_name().to_camel_case());
    if let Some(message_comment) = dbc.message_comment(message.message_id()) {
        message_struct.doc(message_comment);
    }
    message_struct.allow("dead_code");
    message_struct.derive("Debug");
    message_struct.vis("pub");
    message_struct.generic("'a");
    message_struct.field("frame_payload", "&'a[u8]");
    message_struct
}

fn message_impl(dbc: &DBC, message: &Message) -> Result<Impl> {

    let mut msg_impl = Impl::new(codegen::Type::new(&message.message_name().to_camel_case()));
    msg_impl.generic("'a");
    msg_impl.target_generic("'a");
    let new_fn = msg_impl.new_fn("new");
    new_fn.allow("dead_code");
    new_fn.vis("pub");
    new_fn.arg("frame_payload", codegen::Type::new("&[u8]"));

    new_fn.line(format!("{} {{ frame_payload }}", message.message_name().to_camel_case()));
    new_fn.ret(codegen::Type::new(&message.message_name().to_camel_case()));

    for signal in message.signals() {
        msg_impl.push_fn(signal_fn(dbc, signal, message.message_id())?);
    }

    Ok(msg_impl)
}

pub fn can_reader(dbc: &DBC) -> Result<Scope> {

    let mut scope = Scope::new();
    scope.import("byteorder", "{ByteOrder, LE, BE}");

    for message in dbc.messages() {
        scope.push_const(message_const(message));
    }

    for value_description in dbc.value_descriptions() {
        if let Some(signal_enum) = signal_enum(value_description) {
            scope.push_enum(signal_enum);
        }

        if let Some(enum_impl) = signal_enum_impl(value_description) {
            scope.push_impl(enum_impl);
        }
    }

    for message in dbc.messages() {
        scope.push_struct(message_struct(&dbc, message));
        scope.push_impl(message_impl(&dbc, message)?);
    }

    Ok(scope)
}<|endoftext|>


<commit_before>//! Memory primitives.

use core::{ops, cmp};
use core::ptr::Unique;

/// A contigious memory block.
pub struct Block {
    /// The size of this block, in bytes.
    pub size: usize,
    /// The pointer to the start of this block.
    pub ptr: Unique<u8>,
}

impl Block {
    /// Get a pointer to the end of this block, not inclusive.
    pub fn end(&self) -> Unique<u8> {
        unsafe {
            Unique::new((self.size + *self.ptr as usize) as *mut _)
        }
    }

    /// Is this block is left to `to`?
    pub fn left_to(&self, to: &Block) -> bool {
        self.size + *self.ptr as usize == *to.ptr as usize
    }
}

impl PartialOrd for Block {
    fn partial_cmp(&self, other: &Block) -> Option<cmp::Ordering> {
        self.ptr.partial_cmp(&other.ptr)
    }
}

impl Ord for Block {
    fn cmp(&self, other: &Block) -> cmp::Ordering {
        self.ptr.cmp(&other.ptr)
    }
}

impl cmp::PartialEq for Block {
    fn eq(&self, other: &Block) -> bool {
        self.size == other.size && *self.ptr == *other.ptr
    }
}

impl cmp::Eq for Block {}

/// A block entry.
///
/// A block entry is a wrapper around `Block` containing an extra field telling if this block is
/// free or not.
#[derive(PartialEq, Eq)]
pub struct BlockEntry {
    /// The underlying block.
    block: Block,
    /// Is this block free?
    pub free: bool,
}

impl ops::Deref for BlockEntry {
    type Target = Block;

    fn deref(&self) -> &Block {
        &self.block
    }
}

impl ops::DerefMut for BlockEntry {
    fn deref_mut(&mut self) -> &mut Block {
        &mut self.block
    }
}

impl PartialOrd for BlockEntry {
    fn partial_cmp(&self, other: &BlockEntry) -> Option<cmp::Ordering> {
        self.block.partial_cmp(other)
    }
}

impl Ord for BlockEntry {
    fn cmp(&self, other: &BlockEntry) -> cmp::Ordering {
        self.block.cmp(other)
    }
}

impl From<Block> for BlockEntry {
    fn from(block: Block) -> BlockEntry {
        BlockEntry {
            block: block,
            free: true,
        }
    }
}

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

    #[test]
    fn test_end() {
        let a = Block {
            size: 10,
            ptr: unsafe { Unique::new(10 as *mut _) },
        };
        let b = Block {
            size: 15,
            ptr: unsafe { Unique::new(25 as *mut _) },
        };
        let c = Block {
            size: 75,
            ptr: unsafe { Unique::new(40 as *mut _) },
        };

        assert_eq!(*a.end(), *b.ptr);
        assert_eq!(*b.end(), *c.ptr);
    }

    #[test]
    fn test_from() {
        let ent: BlockEntry = Block {
            size: 10,
            ptr: unsafe { Unique::new(10 as *mut _) },
        }.into();
        assert!(ent.free)
    }

    #[test]
    fn test_left_to() {
        let a = Block {
            size: 10,
            ptr: unsafe { Unique::new(10 as *mut _) },
        };
        let b = Block {
            size: 15,
            ptr: unsafe { Unique::new(25 as *mut _) },
        };
        let c = Block {
            size: 75,
            ptr: unsafe { Unique::new(40 as *mut _) },
        };

        assert!(a.left_to(&b));
        assert!(b.left_to(&c));
        assert!(!c.left_to(&a));
        assert!(!a.left_to(&c));
        assert!(!b.left_to(&b));
        assert!(!b.left_to(&a));
    }

    #[test]
    fn test_cmp() {
        let a = Block {
            size: 10,
            ptr: unsafe { Unique::new(10 as *mut _) },
        };
        let b = Block {
            size: 15,
            ptr: unsafe { Unique::new(25 as *mut _) },
        };
        let c = Block {
            size: 75,
            ptr: unsafe { Unique::new(40 as *mut _) },
        };

        assert!(a < b);
        assert!(b < c);
        assert!(c > a);
        assert!(a == a);
        assert!(b == b);
        assert!(c == c);
        assert!(c >= c);
        assert!(c <= c);
        assert!(a <= c);
        assert!(b >= a);
    }
}
<commit_msg>Fix Block tests<commit_after>//! Memory primitives.

use core::{ops, cmp};
use core::ptr::Unique;

/// A contigious memory block.
pub struct Block {
    /// The size of this block, in bytes.
    pub size: usize,
    /// The pointer to the start of this block.
    pub ptr: Unique<u8>,
}

impl Block {
    /// Get a pointer to the end of this block, not inclusive.
    pub fn end(&self) -> Unique<u8> {
        unsafe {
            Unique::new((self.size + *self.ptr as usize) as *mut _)
        }
    }

    /// Is this block is left to `to`?
    pub fn left_to(&self, to: &Block) -> bool {
        self.size + *self.ptr as usize == *to.ptr as usize
    }
}

impl PartialOrd for Block {
    fn partial_cmp(&self, other: &Block) -> Option<cmp::Ordering> {
        self.ptr.partial_cmp(&other.ptr)
    }
}

impl Ord for Block {
    fn cmp(&self, other: &Block) -> cmp::Ordering {
        self.ptr.cmp(&other.ptr)
    }
}

impl cmp::PartialEq for Block {
    fn eq(&self, other: &Block) -> bool {
        self.size == other.size && *self.ptr == *other.ptr
    }
}

impl cmp::Eq for Block {}

/// A block entry.
///
/// A block entry is a wrapper around `Block` containing an extra field telling if this block is
/// free or not.
#[derive(PartialEq, Eq)]
pub struct BlockEntry {
    /// The underlying block.
    block: Block,
    /// Is this block free?
    pub free: bool,
}

impl ops::Deref for BlockEntry {
    type Target = Block;

    fn deref(&self) -> &Block {
        &self.block
    }
}

impl ops::DerefMut for BlockEntry {
    fn deref_mut(&mut self) -> &mut Block {
        &mut self.block
    }
}

impl PartialOrd for BlockEntry {
    fn partial_cmp(&self, other: &BlockEntry) -> Option<cmp::Ordering> {
        self.block.partial_cmp(other)
    }
}

impl Ord for BlockEntry {
    fn cmp(&self, other: &BlockEntry) -> cmp::Ordering {
        self.block.cmp(other)
    }
}

impl From<Block> for BlockEntry {
    fn from(block: Block) -> BlockEntry {
        BlockEntry {
            block: block,
            free: true,
        }
    }
}

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

    #[test]
    fn test_end() {
        let a = Block {
            size: 10,
            ptr: unsafe { Unique::new(15 as *mut _) },
        };
        let b = Block {
            size: 15,
            ptr: unsafe { Unique::new(25 as *mut _) },
        };
        let c = Block {
            size: 75,
            ptr: unsafe { Unique::new(40 as *mut _) },
        };

        assert_eq!(*a.end(), *b.ptr);
        assert_eq!(*b.end(), *c.ptr);
    }

    #[test]
    fn test_from() {
        let ent: BlockEntry = Block {
            size: 10,
            ptr: unsafe { Unique::new(10 as *mut _) },
        }.into();
        assert!(ent.free)
    }

    #[test]
    fn test_left_to() {
        let a = Block {
            size: 10,
            ptr: unsafe { Unique::new(15 as *mut _) },
        };
        let b = Block {
            size: 15,
            ptr: unsafe { Unique::new(25 as *mut _) },
        };
        let c = Block {
            size: 75,
            ptr: unsafe { Unique::new(40 as *mut _) },
        };

        assert!(a.left_to(&b));
        assert!(b.left_to(&c));
        assert!(!c.left_to(&a));
        assert!(!a.left_to(&c));
        assert!(!b.left_to(&b));
        assert!(!b.left_to(&a));
    }

    #[test]
    fn test_cmp() {
        let a = Block {
            size: 10,
            ptr: unsafe { Unique::new(10 as *mut _) },
        };
        let b = Block {
            size: 15,
            ptr: unsafe { Unique::new(25 as *mut _) },
        };
        let c = Block {
            size: 75,
            ptr: unsafe { Unique::new(40 as *mut _) },
        };

        assert!(a < b);
        assert!(b < c);
        assert!(c > a);
        assert!(a == a);
        assert!(b == b);
        assert!(c == c);
        assert!(c >= c);
        assert!(c <= c);
        assert!(a <= c);
        assert!(b >= a);
    }
}
<|endoftext|>


<commit_before>pub use bindings::*;

pub struct Error {
  code: i32,
  string: &'static str
}

impl Error {
  pub fn new(err: i32) -> Error {
    Error { code: err, string: Error::error_to_string(err) }
  }

  // TODO: Finish for all errors.
  pub fn error_to_string(err: i32) -> &'static str {
    match err {
      MPI_SUCCESS => "SUCCESS",
      MPI_ERR_BUFFER => "ERR BUFFER",
      MPI_ERR_COMM => "ERR COMM",
      MPI_ERR_RANK => "ERR RANK",
      _ => "ERR OTHER"
    }
  }
}

pub const MPI_SUCCESS: i32 = 0;
pub const MPI_ERR_BUFFER: i32 = 1;
pub const MPI_ERR_COUNT: i32 = 2;
pub const MPI_ERR_TYPE: i32 = 3;
pub const MPI_ERR_TAG: i32 = 4;
pub const MPI_ERR_COMM: i32 = 5;
pub const MPI_ERR_RANK: i32 = 6;
pub const MPI_ERR_REQUEST: i32 = 7;
pub const MPI_ERR_ROOT: i32 = 8;
pub const MPI_ERR_GROUP: i32 = 9;
pub const MPI_ERR_OP: i32 = 10;
pub const MPI_ERR_TOPOLOGY: i32 = 11;
pub const MPI_ERR_DIMS: i32 = 12;
pub const MPI_ERR_ARG: i32 = 13;
pub const MPI_ERR_UNKNOWN: i32 = 14;
pub const MPI_ERR_TRUNCATE: i32 = 15;
pub const MPI_ERR_OTHER: i32 = 16;
pub const MPI_ERR_INTERN: i32 = 17;
pub const MPI_ERR_IN_STATUS: i32 = 18;
pub const MPI_ERR_PENDING: i32 = 19;
pub const MPI_ERR_ACCESS: i32 = 20;
pub const MPI_ERR_AMODE: i32 = 21;
pub const MPI_ERR_ASSERT: i32 = 22;
pub const MPI_ERR_BAD_FILE: i32 = 23;
pub const MPI_ERR_BASE: i32 = 24;
pub const MPI_ERR_CONVERSION: i32 = 25;
pub const MPI_ERR_DISP: i32 = 26;
pub const MPI_ERR_DUP_DATAREP: i32 = 27;
pub const MPI_ERR_FILE_EXISTS: i32 = 28;
pub const MPI_ERR_FILE_IN_USE: i32 = 29;
pub const MPI_ERR_FILE: i32 = 30;
pub const MPI_ERR_INFO_KEY: i32 = 31;
pub const MPI_ERR_INFO_NOKEY: i32 = 32;
pub const MPI_ERR_INFO_VALUE: i32 = 33;
pub const MPI_ERR_INFO: i32 = 34;
pub const MPI_ERR_IO: i32 = 35;
pub const MPI_ERR_KEYVAL: i32 = 36;
pub const MPI_ERR_LOCKTYPE: i32 = 37;
pub const MPI_ERR_NAME: i32 = 38;
pub const MPI_ERR_NO_MEM: i32 = 39;
pub const MPI_ERR_NOT_SAME: i32 = 40;
pub const MPI_ERR_NO_SPACE: i32 = 41;
pub const MPI_ERR_NO_SUCH_FILE: i32 = 42;
pub const MPI_ERR_PORT: i32 = 43;
pub const MPI_ERR_QUOTA: i32 = 44;
pub const MPI_ERR_READ_ONLY: i32 = 45;
pub const MPI_ERR_RMA_CONFLICT: i32 = 46;
pub const MPI_ERR_RMA_SYNC: i32 = 47;
pub const MPI_ERR_SERVICE: i32 = 48;
pub const MPI_ERR_SIZE: i32 = 49;
pub const MPI_ERR_SPAWN: i32 = 50;
pub const MPI_ERR_UNSUPPORTED_DATAREP: i32 = 51;
pub const MPI_ERR_UNSUPPORTED_OPERATION: i32 = 52;
pub const MPI_ERR_WIN: i32 = 53;
pub const MPI_T_ERR_MEMORY: i32 = 54;
pub const MPI_T_ERR_NOT_INITIALIZED: i32 = 55;
pub const MPI_T_ERR_CANNOT_INIT: i32 = 56;
pub const MPI_T_ERR_INVALID_INDEX: i32 = 57;
pub const MPI_T_ERR_INVALID_ITEM: i32 = 58;
pub const MPI_T_ERR_INVALID_HANDLE: i32 = 59;
pub const MPI_T_ERR_OUT_OF_HANDLES: i32 = 60;
pub const MPI_T_ERR_OUT_OF_SESSIONS: i32 = 61;
pub const MPI_T_ERR_INVALID_SESSION: i32 = 62;
pub const MPI_T_ERR_CVAR_SET_NOT_NOW: i32 = 63;
pub const MPI_T_ERR_CVAR_SET_NEVER: i32 = 64;
pub const MPI_T_ERR_PVAR_NO_STARTSTOP: i32 = 65;
pub const MPI_T_ERR_PVAR_NO_WRITE: i32 = 66;
pub const MPI_T_ERR_PVAR_NO_ATOMIC: i32 = 67;
pub const MPI_ERR_RMA_RANGE: i32 = 68;
pub const MPI_ERR_RMA_ATTACH: i32 = 69;
pub const MPI_ERR_RMA_FLAVOR: i32 = 70;
pub const MPI_ERR_RMA_SHARED: i32 = 71;
pub const MPI_ERR_LASTCODE: i32 = MPI_ERR_RMA_SHARED;
pub const MPI_ERR_SYSRESOURCE: i32 = -2;
<commit_msg>Remove bindings import from error mod.<commit_after>pub struct Error {
  code: i32,
  string: &'static str
}

impl Error {
  pub fn new(err: i32) -> Error {
    Error { code: err, string: Error::error_to_string(err) }
  }

  // TODO: Finish for all errors.
  pub fn error_to_string(err: i32) -> &'static str {
    match err {
      MPI_SUCCESS => "SUCCESS",
      MPI_ERR_BUFFER => "ERR BUFFER",
      MPI_ERR_COMM => "ERR COMM",
      MPI_ERR_RANK => "ERR RANK",
      _ => "ERR OTHER"
    }
  }
}

pub const MPI_SUCCESS: i32 = 0;
pub const MPI_ERR_BUFFER: i32 = 1;
pub const MPI_ERR_COUNT: i32 = 2;
pub const MPI_ERR_TYPE: i32 = 3;
pub const MPI_ERR_TAG: i32 = 4;
pub const MPI_ERR_COMM: i32 = 5;
pub const MPI_ERR_RANK: i32 = 6;
pub const MPI_ERR_REQUEST: i32 = 7;
pub const MPI_ERR_ROOT: i32 = 8;
pub const MPI_ERR_GROUP: i32 = 9;
pub const MPI_ERR_OP: i32 = 10;
pub const MPI_ERR_TOPOLOGY: i32 = 11;
pub const MPI_ERR_DIMS: i32 = 12;
pub const MPI_ERR_ARG: i32 = 13;
pub const MPI_ERR_UNKNOWN: i32 = 14;
pub const MPI_ERR_TRUNCATE: i32 = 15;
pub const MPI_ERR_OTHER: i32 = 16;
pub const MPI_ERR_INTERN: i32 = 17;
pub const MPI_ERR_IN_STATUS: i32 = 18;
pub const MPI_ERR_PENDING: i32 = 19;
pub const MPI_ERR_ACCESS: i32 = 20;
pub const MPI_ERR_AMODE: i32 = 21;
pub const MPI_ERR_ASSERT: i32 = 22;
pub const MPI_ERR_BAD_FILE: i32 = 23;
pub const MPI_ERR_BASE: i32 = 24;
pub const MPI_ERR_CONVERSION: i32 = 25;
pub const MPI_ERR_DISP: i32 = 26;
pub const MPI_ERR_DUP_DATAREP: i32 = 27;
pub const MPI_ERR_FILE_EXISTS: i32 = 28;
pub const MPI_ERR_FILE_IN_USE: i32 = 29;
pub const MPI_ERR_FILE: i32 = 30;
pub const MPI_ERR_INFO_KEY: i32 = 31;
pub const MPI_ERR_INFO_NOKEY: i32 = 32;
pub const MPI_ERR_INFO_VALUE: i32 = 33;
pub const MPI_ERR_INFO: i32 = 34;
pub const MPI_ERR_IO: i32 = 35;
pub const MPI_ERR_KEYVAL: i32 = 36;
pub const MPI_ERR_LOCKTYPE: i32 = 37;
pub const MPI_ERR_NAME: i32 = 38;
pub const MPI_ERR_NO_MEM: i32 = 39;
pub const MPI_ERR_NOT_SAME: i32 = 40;
pub const MPI_ERR_NO_SPACE: i32 = 41;
pub const MPI_ERR_NO_SUCH_FILE: i32 = 42;
pub const MPI_ERR_PORT: i32 = 43;
pub const MPI_ERR_QUOTA: i32 = 44;
pub const MPI_ERR_READ_ONLY: i32 = 45;
pub const MPI_ERR_RMA_CONFLICT: i32 = 46;
pub const MPI_ERR_RMA_SYNC: i32 = 47;
pub const MPI_ERR_SERVICE: i32 = 48;
pub const MPI_ERR_SIZE: i32 = 49;
pub const MPI_ERR_SPAWN: i32 = 50;
pub const MPI_ERR_UNSUPPORTED_DATAREP: i32 = 51;
pub const MPI_ERR_UNSUPPORTED_OPERATION: i32 = 52;
pub const MPI_ERR_WIN: i32 = 53;
pub const MPI_T_ERR_MEMORY: i32 = 54;
pub const MPI_T_ERR_NOT_INITIALIZED: i32 = 55;
pub const MPI_T_ERR_CANNOT_INIT: i32 = 56;
pub const MPI_T_ERR_INVALID_INDEX: i32 = 57;
pub const MPI_T_ERR_INVALID_ITEM: i32 = 58;
pub const MPI_T_ERR_INVALID_HANDLE: i32 = 59;
pub const MPI_T_ERR_OUT_OF_HANDLES: i32 = 60;
pub const MPI_T_ERR_OUT_OF_SESSIONS: i32 = 61;
pub const MPI_T_ERR_INVALID_SESSION: i32 = 62;
pub const MPI_T_ERR_CVAR_SET_NOT_NOW: i32 = 63;
pub const MPI_T_ERR_CVAR_SET_NEVER: i32 = 64;
pub const MPI_T_ERR_PVAR_NO_STARTSTOP: i32 = 65;
pub const MPI_T_ERR_PVAR_NO_WRITE: i32 = 66;
pub const MPI_T_ERR_PVAR_NO_ATOMIC: i32 = 67;
pub const MPI_ERR_RMA_RANGE: i32 = 68;
pub const MPI_ERR_RMA_ATTACH: i32 = 69;
pub const MPI_ERR_RMA_FLAVOR: i32 = 70;
pub const MPI_ERR_RMA_SHARED: i32 = 71;
pub const MPI_ERR_LASTCODE: i32 = MPI_ERR_RMA_SHARED;
pub const MPI_ERR_SYSRESOURCE: i32 = -2;
<|endoftext|>


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

// Functions for dealing with devices.

use std::collections::HashMap;
use std::fs::File;
use std::io::{BufWriter, Seek, Write, SeekFrom};
use std::fs::OpenOptions;
use std::os::linux::fs::MetadataExt;
use std::os::unix::prelude::AsRawFd;
use std::path::Path;

use nix::sys::stat::{S_IFBLK, S_IFMT};

use devicemapper::{Bytes, Device, IEC, SECTOR_SIZE, Sectors};

use super::super::errors::{EngineResult, EngineError, ErrorEnum};

ioctl!(read blkgetsize64 with 0x12, 114; u64);

pub fn blkdev_size(file: &File) -> EngineResult<Bytes> {
    let mut val: u64 = 0;

    match unsafe { blkgetsize64(file.as_raw_fd(), &mut val) } {
        Err(x) => Err(EngineError::Nix(x)),
        Ok(_) => Ok(Bytes(val)),
    }
}

/// Write buf at offset length times.
pub fn write_sectors<P: AsRef<Path>>(path: P,
                                     offset: Sectors,
                                     length: Sectors,
                                     buf: &[u8; SECTOR_SIZE])
                                     -> EngineResult<()> {
    let mut f = BufWriter::with_capacity(IEC::Mi as usize,
                                         OpenOptions::new().write(true).open(path)?);

    f.seek(SeekFrom::Start(*offset))?;
    for _ in 0..*length {
        f.write_all(buf)?;
    }

    f.flush()?;
    Ok(())
}

/// Zero sectors at the given offset for length sectors.
pub fn wipe_sectors<P: AsRef<Path>>(path: P, offset: Sectors, length: Sectors) -> EngineResult<()> {
    write_sectors(path, offset, length, &[0u8; SECTOR_SIZE])
}

/// Get a device number from a device node.
/// Return None if the device is not a block device; devicemapper is not
/// interested in other sorts of devices.
pub fn devnode_to_devno(path: &Path) -> EngineResult<Option<u64>> {
    match path.metadata() {
        Ok(metadata) => {
            Ok(if metadata.st_mode() & S_IFMT.bits() == S_IFBLK.bits() {
                   Some(metadata.st_rdev())
               } else {
                   None
               })
        }
        Err(err) => Err(err)?,
    }
}

/// Resolve a list of Paths of some sort to a set of unique Devices.
/// Return an IOError if there was a problem resolving any particular device.
/// The set of devices maps each device to one of the paths passed.
/// Returns an error if any path does not correspond to a block device.
pub fn resolve_devices<'a>(paths: &'a [&Path]) -> EngineResult<HashMap<Device, &'a Path>> {
    let mut map = HashMap::new();
    for path in paths {
        match devnode_to_devno(path)? {
            Some(devno) => {
                let _ = map.insert(Device::from(devno), *path);
            }
            None => {
                let err_msg = format!("path {} does not refer to a block device", path.display());
                return Err(EngineError::Engine(ErrorEnum::Invalid, err_msg.into()));
            }
        }
    }
    Ok(map)
}
<commit_msg>Update devnode_to_devno() to return None for NotFound errors<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

// Functions for dealing with devices.

use std::collections::HashMap;
use std::fs::File;
use std::io::{BufWriter, ErrorKind, Seek, SeekFrom, Write};
use std::fs::OpenOptions;
use std::os::linux::fs::MetadataExt;
use std::os::unix::prelude::AsRawFd;
use std::path::Path;

use nix::sys::stat::{S_IFBLK, S_IFMT};

use devicemapper::{Bytes, Device, IEC, SECTOR_SIZE, Sectors};

use super::super::errors::{EngineResult, EngineError, ErrorEnum};

ioctl!(read blkgetsize64 with 0x12, 114; u64);

pub fn blkdev_size(file: &File) -> EngineResult<Bytes> {
    let mut val: u64 = 0;

    match unsafe { blkgetsize64(file.as_raw_fd(), &mut val) } {
        Err(x) => Err(EngineError::Nix(x)),
        Ok(_) => Ok(Bytes(val)),
    }
}

/// Write buf at offset length times.
pub fn write_sectors<P: AsRef<Path>>(path: P,
                                     offset: Sectors,
                                     length: Sectors,
                                     buf: &[u8; SECTOR_SIZE])
                                     -> EngineResult<()> {
    let mut f = BufWriter::with_capacity(IEC::Mi as usize,
                                         OpenOptions::new().write(true).open(path)?);

    f.seek(SeekFrom::Start(*offset))?;
    for _ in 0..*length {
        f.write_all(buf)?;
    }

    f.flush()?;
    Ok(())
}

/// Zero sectors at the given offset for length sectors.
pub fn wipe_sectors<P: AsRef<Path>>(path: P, offset: Sectors, length: Sectors) -> EngineResult<()> {
    write_sectors(path, offset, length, &[0u8; SECTOR_SIZE])
}

/// Get a device number from a device node.
/// Return None if the device is not a block device; devicemapper is not
/// interested in other sorts of devices.
pub fn devnode_to_devno(path: &Path) -> EngineResult<Option<u64>> {
    match path.metadata() {
        Ok(metadata) => {
            Ok(if metadata.st_mode() & S_IFMT.bits() == S_IFBLK.bits() {
                   Some(metadata.st_rdev())
               } else {
                   None
               })
        }
        Err(err) => {
            if err.kind() == ErrorKind::NotFound {
                return Ok(None);
            }
            Err(err)?
        }
    }
}

/// Resolve a list of Paths of some sort to a set of unique Devices.
/// Return an IOError if there was a problem resolving any particular device.
/// The set of devices maps each device to one of the paths passed.
/// Returns an error if any path does not correspond to a block device.
pub fn resolve_devices<'a>(paths: &'a [&Path]) -> EngineResult<HashMap<Device, &'a Path>> {
    let mut map = HashMap::new();
    for path in paths {
        match devnode_to_devno(path)? {
            Some(devno) => {
                let _ = map.insert(Device::from(devno), *path);
            }
            None => {
                let err_msg = format!("path {} does not refer to a block device", path.display());
                return Err(EngineError::Engine(ErrorEnum::Invalid, err_msg.into()));
            }
        }
    }
    Ok(map)
}
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with
// this file, You can obtain one at https://mozilla.org/MPL/2.0/.

use common::is_whitespace;

use regex::Regex;
use std::borrow::Cow;

/// Removes unnecessary whitespaces from a String.
///
/// # Example
///
/// ```
/// use crowbook_text_processing::clean::remove_whitespaces;
/// let s = remove_whitespaces("  A  string   with   more   whitespaces  than  needed   ");
/// assert_eq!(&s, " A string with more whitespaces than needed ");
/// ```
pub fn remove_whitespaces<'a, S: Into<Cow<'a, str>>>(input: S) -> Cow<'a, str> {
    lazy_static! {
        static ref REGEX: Regex = Regex::new(r"[  \x{202F}\x{2002}]{2,}?").unwrap();
    }
    let input = input.into();
    let first = REGEX.find(&input);
    if let Some((first, _)) = first {
        let mut new_s = String::with_capacity(input.len());
        new_s.push_str(&input[0..first]);
        let mut previous_space = false;
        for c in input[first..].chars() {
            if is_whitespace(c) {
                if previous_space {
                    // previous char already a space, don't copy it
                } else {
                    new_s.push(c);
                    previous_space = true;
                }
            } else {
                previous_space = false;
                new_s.push(c);
            }
        }
        Cow::Owned(new_s)
    } else {
        input
    }
}

/// Class of a character
#[derive(Debug, PartialEq, Eq, PartialOrd, Clone, Copy)]
enum CharClass {
    Whitespace = 0,
    Punctuation,
    Alphanumeric
}

/// Get class of a character
fn char_class(c: char) -> CharClass {
    if c.is_alphanumeric() {
        CharClass::Alphanumeric
    } else if c.is_whitespace() {
        CharClass::Whitespace
    } else {
        CharClass::Punctuation
    }
}

/// Replace quotes with more typographic variants
///
/// While it should work pretty well for double quotes (`"`), the rules for single
/// quote (`'`) are more ambiguous, as it can be a quote, or an apostrophe and it's not
/// that easy to get right.
///
/// # Example
///
/// ```
/// use crowbook_text_processing::typographic_quotes;
/// let s = typographic_quotes("\"foo\"");
/// assert_eq!(&s, "“foo”");
/// let s = typographic_quotes("'foo'");
/// assert_eq!(&s, "‘foo’");
/// ```
pub fn typographic_quotes<'a, S: Into<Cow<'a, str>>>(input: S) -> Cow<'a, str> {
    /// Custom whitespace-detection function, including `,`, `;`, `.`, `!`, `?`, and `:`
    fn is_whitespace(c: char) -> bool {
        match c {
            ',' | '.' | ';' | '!' | '?' | ':' | '"'
                | '(' | ')' => true,
            _ => c.is_whitespace()
        }
    }

    lazy_static! {
        static ref REGEX: Regex = Regex::new("[\"\']").unwrap();
    }
    let input = input.into();
    let first = REGEX.find(&input);
    if let Some((mut first, _)) = first {
        let mut new_s = String::with_capacity(input.len());
        if first > 0 {
            // Move one step backward since we might need to know if previous char was
            // a letter or not
            first -= 1;
        }
        new_s.push_str(&input[0..first]);
        let mut chars = input[first..].chars().collect::<Vec<_>>();
        let mut closing_quote = None;
        let mut opened_doubles = 0;
        for i in 0..chars.len() {
            let c = chars[i];
            let has_opened_quote = if let Some(n) = closing_quote {
                i <= n
            } else {
                false
            };
            match c {
                '"' => {
                    let prev = if i > 0 {
                        char_class(chars[i-1])
                    } else {
                        CharClass::Whitespace
                    };
                    let next = if i < chars.len() - 1 {
                        char_class(chars[i+1])
                    } else {
                        CharClass::Whitespace
                    };

                    if prev < next {
                        opened_doubles += 1;
                        new_s.push('“');
                    } else {
                        if opened_doubles > 0 {
                            opened_doubles -= 1;
                            new_s.push('”');
                        } else {
                            new_s.push('"');
                        }
                    }
                },
                '\'' => {
                    let prev = if i > 0 {
                        char_class(chars[i - 1])
                    } else {
                        CharClass::Whitespace
                    };
                    let next = if i < chars.len() - 1 {
                        char_class(chars[i + 1])
                    } else {
                        CharClass::Whitespace
                    };

                    let replacement = match (prev, next) {
                        // Elision or possessive
                        (CharClass::Alphanumeric, CharClass::Alphanumeric)
//                            | (CharClass::Punctuation, CharClass::Alphanumeric)
                            => '’',

                        // Beginning of word, it's opening (not always though)
                        (x, y) if x < y
                            => {
                                let mut is_next_closing = false;
                                for j in (i + 1)..chars.len() {
                                    if chars[j] == '\'' {
                                        if chars[j-1].is_whitespace() {
                                            continue;
                                        } else {
                                            if j >= chars.len() - 1
                                                || char_class(chars[j+1]) != CharClass::Alphanumeric {
                                                    is_next_closing = true;
                                                    closing_quote = Some(j);
                                                    chars[j] = '’';
                                                    break;
                                                }
                                        }
                                    }
                                }
                                if is_next_closing && !has_opened_quote {
                                    '‘'
                                } else {
                                    '’'
                                }
                            }

                        // Apostrophe at end of word, it's closing
                        (x, y) if x > y
                            => {
                                '’'
                            },
                        _ => '\'',
                    };
                    new_s.push(replacement);
                    // if i > 0 && !chars[i - 1].is_whitespace() {
                    //     new_s.push('’');
                    // } else if i < chars.len() - 1 && !chars[i + 1].is_whitespace() {
                    //     new_s.push('‘');
                    // } else {
                    //     new_s.push('\'');
                    // }
                },
                _ => new_s.push(c)
            }
        }
        Cow::Owned(new_s)
    } else {
        input
    }
}

#[test]
fn remove_whitespaces_1() {
    let s = "   Remove    supplementary   spaces    but    don't    trim     either   ";
    let res = remove_whitespaces(s);
    assert_eq!(&res, " Remove supplementary spaces but don't trim either ");
}

#[test]
fn typographic_quotes_1() {
    let s = "Some string without ' typographic ' quotes";
    let res = typographic_quotes(s);
    assert_eq!(&res, s);
}

#[test]
fn typographic_quotes_2() {
    let s = typographic_quotes("\"foo\"");
    assert_eq!(&s, "“foo”");
    let s = typographic_quotes("'foo'");
    assert_eq!(&s, "‘foo’");
}

#[test]
fn typographic_quotes_3() {
    let s = typographic_quotes("\'mam, how are you?");
    assert_eq!(&s, "’mam, how are you?");
}

#[test]
fn typographic_quotes_4() {
    let s = typographic_quotes("some char: 'c', '4', '&'");
    assert_eq!(&s, "some char: ‘c’, ‘4’, ‘&’");
}

#[test]
fn typographic_quotes_5() {
    let s = typographic_quotes("It's a good day to say 'hi'");
    assert_eq!(&s, "It’s a good day to say ‘hi’");
}

#[test]
fn typographic_quotes_6() {
    let s = typographic_quotes("The '60s were nice, weren't they?");
    assert_eq!(&s, "The ’60s were nice, weren’t they?");
}

#[test]
fn typographic_quotes_7() {
    let s = typographic_quotes("Plurals' possessive");
    assert_eq!(&s, "Plurals’ possessive");
}

#[test]
fn typographic_quotes_8() {
    let s = typographic_quotes("\"I like 'That '70s show'\", she said");
    assert_eq!(&s, "“I like ‘That ’70s show’”, she said");
}

#[test]
fn typographic_quotes_9() {
    let s = typographic_quotes("some char: '!', '?', ','");
    assert_eq!(&s, "some char: ‘!’, ‘?’, ‘,’");
}

#[test]
fn typographic_quotes_10() {
    let s = typographic_quotes("\"'Let's try \"nested\" quotes,' he said.\"");
    assert_eq!(&s, "“‘Let’s try “nested” quotes,’ he said.”");
}
<commit_msg>Add more test and remove correct is_whitespace function<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with
// this file, You can obtain one at https://mozilla.org/MPL/2.0/.

use common::is_whitespace;

use regex::Regex;
use std::borrow::Cow;

/// Removes unnecessary whitespaces from a String.
///
/// # Example
///
/// ```
/// use crowbook_text_processing::clean::remove_whitespaces;
/// let s = remove_whitespaces("  A  string   with   more   whitespaces  than  needed   ");
/// assert_eq!(&s, " A string with more whitespaces than needed ");
/// ```
pub fn remove_whitespaces<'a, S: Into<Cow<'a, str>>>(input: S) -> Cow<'a, str> {
    lazy_static! {
        static ref REGEX: Regex = Regex::new(r"[  \x{202F}\x{2002}]{2,}?").unwrap();
    }
    let input = input.into();
    let first = REGEX.find(&input);
    if let Some((first, _)) = first {
        let mut new_s = String::with_capacity(input.len());
        new_s.push_str(&input[0..first]);
        let mut previous_space = false;
        for c in input[first..].chars() {
            if is_whitespace(c) {
                if previous_space {
                    // previous char already a space, don't copy it
                } else {
                    new_s.push(c);
                    previous_space = true;
                }
            } else {
                previous_space = false;
                new_s.push(c);
            }
        }
        Cow::Owned(new_s)
    } else {
        input
    }
}

/// Class of a character
#[derive(Debug, PartialEq, Eq, PartialOrd, Clone, Copy)]
enum CharClass {
    Whitespace = 0,
    Punctuation,
    Alphanumeric
}

/// Get class of a character
fn char_class(c: char) -> CharClass {
    if c.is_alphanumeric() {
        CharClass::Alphanumeric
    } else if c.is_whitespace() {
        CharClass::Whitespace
    } else {
        CharClass::Punctuation
    }
}

/// Replace quotes with more typographic variants
///
/// While it should work pretty well for double quotes (`"`), the rules for single
/// quote (`'`) are more ambiguous, as it can be a quote, or an apostrophe and it's not
/// that easy to get right.
///
/// # Example
///
/// ```
/// use crowbook_text_processing::typographic_quotes;
/// let s = typographic_quotes("\"foo\"");
/// assert_eq!(&s, "“foo”");
/// let s = typographic_quotes("'foo'");
/// assert_eq!(&s, "‘foo’");
/// ```
pub fn typographic_quotes<'a, S: Into<Cow<'a, str>>>(input: S) -> Cow<'a, str> {
    lazy_static! {
        static ref REGEX: Regex = Regex::new("[\"\']").unwrap();
    }
    let input = input.into();
    let first = REGEX.find(&input);
    if let Some((mut first, _)) = first {
        let mut new_s = String::with_capacity(input.len());
        if first > 0 {
            // Move one step backward since we might need to know if previous char was
            // a letter or not
            first -= 1;
        }
        new_s.push_str(&input[0..first]);
        let mut chars = input[first..].chars().collect::<Vec<_>>();
        let mut closing_quote = None;
        let mut opened_doubles = 0;
        for i in 0..chars.len() {
            let c = chars[i];
            let has_opened_quote = if let Some(n) = closing_quote {
                i <= n
            } else {
                false
            };
            match c {
                '"' => {
                    let prev = if i > 0 {
                        char_class(chars[i-1])
                    } else {
                        CharClass::Whitespace
                    };
                    let next = if i < chars.len() - 1 {
                        char_class(chars[i+1])
                    } else {
                        CharClass::Whitespace
                    };

                    if prev < next {
                        opened_doubles += 1;
                        new_s.push('“');
                    } else {
                        if opened_doubles > 0 {
                            opened_doubles -= 1;
                            new_s.push('”');
                        } else {
                            new_s.push('"');
                        }
                    }
                },
                '\'' => {
                    let prev = if i > 0 {
                        char_class(chars[i - 1])
                    } else {
                        CharClass::Whitespace
                    };
                    let next = if i < chars.len() - 1 {
                        char_class(chars[i + 1])
                    } else {
                        CharClass::Whitespace
                    };

                    let replacement = match (prev, next) {
                        // Elision or possessive
                        (CharClass::Alphanumeric, CharClass::Alphanumeric)
//                            | (CharClass::Punctuation, CharClass::Alphanumeric)
                            => '’',

                        // Beginning of word, it's opening (not always though)
                        (x, y) if x < y
                            => {
                                let mut is_next_closing = false;
                                for j in (i + 1)..chars.len() {
                                    if chars[j] == '\'' {
                                        if chars[j-1].is_whitespace() {
                                            continue;
                                        } else {
                                            if j >= chars.len() - 1
                                                || char_class(chars[j+1]) != CharClass::Alphanumeric {
                                                    is_next_closing = true;
                                                    closing_quote = Some(j);
                                                    chars[j] = '’';
                                                    break;
                                                }
                                        }
                                    }
                                }
                                if is_next_closing && !has_opened_quote {
                                    '‘'
                                } else {
                                    '’'
                                }
                            }

                        // Apostrophe at end of word, it's closing
                        (x, y) if x > y
                            => {
                                '’'
                            },
                        _ => '\'',
                    };
                    new_s.push(replacement);
                    // if i > 0 && !chars[i - 1].is_whitespace() {
                    //     new_s.push('’');
                    // } else if i < chars.len() - 1 && !chars[i + 1].is_whitespace() {
                    //     new_s.push('‘');
                    // } else {
                    //     new_s.push('\'');
                    // }
                },
                _ => new_s.push(c)
            }
        }
        Cow::Owned(new_s)
    } else {
        input
    }
}

#[test]
fn remove_whitespaces_1() {
    let s = "   Remove    supplementary   spaces    but    don't    trim     either   ";
    let res = remove_whitespaces(s);
    assert_eq!(&res, " Remove supplementary spaces but don't trim either ");
}

#[test]
fn typographic_quotes_1() {
    let s = "Some string without ' typographic ' quotes";
    let res = typographic_quotes(s);
    assert_eq!(&res, s);
}

#[test]
fn typographic_quotes_2() {
    let s = typographic_quotes("\"foo\"");
    assert_eq!(&s, "“foo”");
    let s = typographic_quotes("'foo'");
    assert_eq!(&s, "‘foo’");
}

#[test]
fn typographic_quotes_3() {
    let s = typographic_quotes("\'mam, how are you?");
    assert_eq!(&s, "’mam, how are you?");
}

#[test]
fn typographic_quotes_4() {
    let s = typographic_quotes("some char: 'c', '4', '&'");
    assert_eq!(&s, "some char: ‘c’, ‘4’, ‘&’");
}

#[test]
fn typographic_quotes_5() {
    let s = typographic_quotes("It's a good day to say 'hi'");
    assert_eq!(&s, "It’s a good day to say ‘hi’");
}

#[test]
fn typographic_quotes_6() {
    let s = typographic_quotes("The '60s were nice, weren't they?");
    assert_eq!(&s, "The ’60s were nice, weren’t they?");
}

#[test]
fn typographic_quotes_7() {
    let s = typographic_quotes("Plurals' possessive");
    assert_eq!(&s, "Plurals’ possessive");
}

#[test]
fn typographic_quotes_8() {
    let s = typographic_quotes("\"I like 'That '70s show'\", she said");
    assert_eq!(&s, "“I like ‘That ’70s show’”, she said");
}

#[test]
fn typographic_quotes_9() {
    let s = typographic_quotes("some char: '!', '?', ','");
    assert_eq!(&s, "some char: ‘!’, ‘?’, ‘,’");
}

#[test]
fn typographic_quotes_10() {
    let s = typographic_quotes("\"'Let's try \"nested\" quotes,' he said.\"");
    assert_eq!(&s, "“‘Let’s try “nested” quotes,’ he said.”");
}

#[test]
fn typographic_quotes_11() {
    let s = typographic_quotes("Enhanced \"typographic_quotes\"'s heuristics");
    assert_eq!(&s, "Enhanced “typographic_quotes”’s heuristics");
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::rc::Rc;
use std::hash;
use digit_slice::DigitSlice;

pub enum Shape<'a, N: 'a + Noun> {
    // A natural number represented as a little-endian sequence of 8-bit
    // digits.
    Atom(&'a [u8]),
    // An ordered pair of nouns.
    Cell(&'a N, &'a N),
}

/// A Nock noun, the basic unit of representation.
///
/// A noun is an atom or a cell. An atom is any natural number. A cell is any
/// ordered pair of nouns.
pub trait Noun: Sized+Clone {
    fn get<'a>(&'a self) -> Shape<'a, Self>;

    /// Memory address or other unique identifier for the noun.
    fn addr(&self) -> usize;

    /// Run a memoizing fold over the noun
    fn fold<'a, F, G, T: Clone>(&'a self, mut leaf: F, mut branch: G) -> T
        where F: FnMut(&[u8]) -> T,
              G: FnMut(&T, &T) -> T
    {
        fn h<'a, S, F, G, T>(noun: &'a S,
                             memo: &mut HashMap<usize, T>,
                             leaf: &mut F,
                             branch: &mut G)
                             -> T
            where S: Noun,
                  F: FnMut(&[u8]) -> T,
                  G: FnMut(&T, &T) -> T,
                  T: Clone
        {
            let key = noun.addr();

            if memo.contains_key(&key) {
                memo.get(&key).unwrap().clone()
            } else {
                let ret = match noun.get() {
                    Shape::Atom(x) => leaf(x),
                    Shape::Cell(ref a, ref b) => {
                        let a = h(*a, memo, leaf, branch);
                        let b = h(*b, memo, leaf, branch);
                        branch(&a, &b)
                    }
                };
                memo.insert(key, ret.clone());
                ret
            }
        }

        h(self, &mut HashMap::new(), &mut leaf, &mut branch)
    }
}

pub trait Context: Sized {
    type Noun: Noun;

    /// Build a new atom noun from a little-endian 8-bit digit sequence.
    fn atom(&mut self, digits: &[u8]) -> Self::Noun;

    /// Build a new cell noun from two existing nouns.
    fn cell(&mut self, a: Self::Noun, b: Self::Noun) -> Self::Noun;

    fn noun<T: ToNoun>(&mut self, item: T) -> Self::Noun {
        item.to_noun(self)
    }
}

/// Trait for types that can convert themselves to a noun.
pub trait ToNoun {
    fn to_noun<C: Context>(self, &mut C) -> C::Noun;
}

impl<T> ToNoun for T where T: DigitSlice
{
    fn to_noun<C: Context>(self, ctx: &mut C) -> C::Noun {
        ctx.atom(self.as_digits())
    }
}

#[derive(Clone, PartialEq, Eq)]
enum HeapNounInner {
    Atom(Vec<u8>),
    Cell(Rc<HeapNoun>, Rc<HeapNoun>),
}

#[derive(Clone, PartialEq, Eq)]
pub struct HeapNoun(HeapNounInner);

impl Noun for HeapNoun {
    fn get<'a>(&'a self) -> Shape<'a, Self> {
        match self.0 {
            HeapNounInner::Atom(ref v) => Shape::Atom(&v),
            HeapNounInner::Cell(ref a, ref b) => Shape::Cell(&*a, &*b),
        }
    }

    fn addr(&self) -> usize {
        &*self as *const _ as usize
    }
}

#[derive(Default)]
pub struct Heap;

impl Context for Heap {
    type Noun = HeapNoun;

    /// Build a new atom noun.
    fn atom(&mut self, digits: &[u8]) -> Self::Noun {
        HeapNoun(HeapNounInner::Atom(digits.to_vec()))
    }

    /// Build a new cell noun from two existing nouns.
    fn cell(&mut self, a: Self::Noun, b: Self::Noun) -> Self::Noun {
        HeapNoun(HeapNounInner::Cell(Rc::new(a), Rc::new(b)))
    }
}

#[cfg(test)]
mod tests {
    use super::{Context, Heap};

    #[test]
    fn scratch() {
        let x = Heap.noun(123u32);
        assert!(x == Heap.noun(123u8));
    }
}
<commit_msg>Simplify new API, no more impl genericity<commit_after>use std::collections::HashMap;
use std::rc::Rc;
use std::hash;
use digit_slice::DigitSlice;

pub enum Shape<'a> {
    /// A natural number represented as a little-endian sequence of 8-bit
    /// digits.
    Atom(&'a [u8]),
    /// An ordered pair of nouns.
    Cell(&'a Noun, &'a Noun),
}

/// A Nock noun, the basic unit of representation.
///
/// A noun is an atom or a cell. An atom is any natural number. A cell is any
/// ordered pair of nouns.
#[derive(Clone, PartialEq, Eq)]
pub struct Noun(Inner);

#[derive(Clone, PartialEq, Eq)]
enum Inner {
    Atom(Rc<Vec<u8>>),
    Cell(Rc<Noun>, Rc<Noun>),
}

impl Noun {
    fn get<'a>(&'a self) -> Shape<'a> {
        match self.0 {
            Inner::Atom(ref v) => Shape::Atom(&v),
            Inner::Cell(ref a, ref b) => Shape::Cell(&*a, &*b),
        }
    }

    /// Memory address or other unique identifier for the noun.
    fn addr(&self) -> usize {
        &*self as *const _ as usize
    }

    /// Run a memoizing fold over the noun
    fn fold<'a, F, G, T: Clone>(&'a self, mut leaf: F, mut branch: G) -> T
        where F: FnMut(&[u8]) -> T,
              G: FnMut(&T, &T) -> T
    {
        fn h<'a, F, G, T>(noun: &'a Noun,
                          memo: &mut HashMap<usize, T>,
                          leaf: &mut F,
                          branch: &mut G)
                          -> T
            where F: FnMut(&[u8]) -> T,
                  G: FnMut(&T, &T) -> T,
                  T: Clone
        {
            let key = noun.addr();

            if memo.contains_key(&key) {
                memo.get(&key).unwrap().clone()
            } else {
                let ret = match noun.get() {
                    Shape::Atom(x) => leaf(x),
                    Shape::Cell(ref a, ref b) => {
                        let a = h(*a, memo, leaf, branch);
                        let b = h(*b, memo, leaf, branch);
                        branch(&a, &b)
                    }
                };
                memo.insert(key, ret.clone());
                ret
            }
        }

        h(self, &mut HashMap::new(), &mut leaf, &mut branch)
    }

    /// Build a new atom noun from a little-endian 8-bit digit sequence.
    fn atom(digits: &[u8]) -> Noun {
        Noun(Inner::Atom(Rc::new(digits.to_vec())))
    }

    /// Build a new cell noun from two existing nouns.
    fn cell(&mut self, a: &Noun, b: &Noun) -> Noun {
        Noun(Inner::Cell(Rc::new(a.clone()), Rc::new(b.clone())))
    }

    fn noun<T: ToNoun>(item: T) -> Noun {
        item.to_noun()
    }
}

/// Trait for types that can convert themselves to a noun.
pub trait ToNoun {
    fn to_noun(&self) -> Noun;
}

impl<T> ToNoun for T where T: DigitSlice
{
    fn to_noun(&self) -> Noun {
        Noun::atom(self.as_digits())
    }
}

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

    #[test]
    fn scratch() {
        let x = Noun::noun(123u32);
        assert!(x == Noun::noun(123u8));
    }
}
<|endoftext|>


<commit_before>use std::io::Error as IoError;
use std::error::Error as StdError;
use std::fmt::Display;
use hyper::Error as HyperError;
use serde_json::Error as JsonError;
use serde_json::Value;
use websocket::result::WebSocketError;
use chrono::ParseError as ChronoError;
#[cfg(feature="voice")]
use opus::Error as OpusError;

/// Discord API `Result` alias type.
pub type Result<T> = ::std::result::Result<T, Error>;

/// Discord API error type.
#[derive(Debug)]
pub enum Error {
	/// A `hyper` crate error
	Hyper(HyperError),
	/// A `chrono` crate error
	Chrono(ChronoError),
	/// A `serde_json` crate error
	Json(JsonError),
	/// A `websocket` crate error
	WebSocket(WebSocketError),
	/// A `std::io` module error
	Io(IoError),
	/// An error in the Opus library, with the function name and error code
	#[cfg(feature="voice")]
	Opus(OpusError),
	/// A websocket connection was closed, possibly with a message
	Closed(Option<u16>, String),
	/// A json decoding error, with a description and the offending value
	Decode(&'static str, Value),
	/// A generic non-success response from the REST API
	Status(::hyper::status::StatusCode, Option<Value>),
	/// A rate limit error, with how many milliseconds to wait before retrying
	RateLimited(u64),
	/// A Discord protocol error, with a description
	Protocol(&'static str),
	/// A command execution failure, with a command name and output
	Command(&'static str, ::std::process::Output),
	/// A miscellaneous error, with a description
	Other(&'static str),
}

impl Error {
	#[doc(hidden)]
	pub fn from_response(response: ::hyper::client::Response) -> Error {
		let status = response.status;
		let value = ::serde_json::from_reader(response).ok();
		if status == ::hyper::status::StatusCode::TooManyRequests {
			if let Some(Value::Object(ref map)) = value {
				if let Some(delay) = map.get("retry_after").and_then(|v| v.as_u64()) {
					return Error::RateLimited(delay);
				}
			}
		}
		Error::Status(status, value)
	}
}

impl From<IoError> for Error {
	fn from(err: IoError) -> Error {
		Error::Io(err)
	}
}

impl From<HyperError> for Error {
	fn from(err: HyperError) -> Error {
		Error::Hyper(err)
	}
}

impl From<ChronoError> for Error {
	fn from(err: ChronoError) -> Error {
		Error::Chrono(err)
	}
}

impl From<JsonError> for Error {
	fn from(err: JsonError) -> Error {
		Error::Json(err)
	}
}

impl From<WebSocketError> for Error {
	fn from(err: WebSocketError) -> Error {
		Error::WebSocket(err)
	}
}

#[cfg(feature="voice")]
impl From<OpusError> for Error {
	fn from(err: OpusError) -> Error {
		Error::Opus(err)
	}
}

impl Display for Error {
	fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
		match *self {
			Error::Hyper(ref inner) => inner.fmt(f),
			Error::Chrono(ref inner) => inner.fmt(f),
			Error::Json(ref inner) => inner.fmt(f),
			Error::WebSocket(ref inner) => inner.fmt(f),
			Error::Io(ref inner) => inner.fmt(f),
			#[cfg(feature="voice")]
			Error::Opus(ref inner) => inner.fmt(f),
			Error::Command(cmd, _) => write!(f, "Command failed: {}", cmd),
			_ => f.write_str(self.description()),
		}
	}
}

impl StdError for Error {
	fn description(&self) -> &str {
		match *self {
			Error::Hyper(ref inner) => inner.description(),
			Error::Chrono(ref inner) => inner.description(),
			Error::Json(ref inner) => inner.description(),
			Error::WebSocket(ref inner) => inner.description(),
			Error::Io(ref inner) => inner.description(),
			#[cfg(feature="voice")]
			Error::Opus(ref inner) => inner.description(),
			Error::Closed(_, _) => "Connection closed",
			Error::Decode(msg, _) |
			Error::Protocol(msg) |
			Error::Other(msg) => msg,
			Error::Status(status, _) => status.canonical_reason().unwrap_or("Unknown bad HTTP status"),
			Error::RateLimited(_) => "Rate limited",
			Error::Command(_, _) => "Command failed",
		}
	}

	fn cause(&self) -> Option<&StdError> {
		match *self {
			Error::Hyper(ref inner) => Some(inner),
			Error::Chrono(ref inner) => Some(inner),
			Error::Json(ref inner) => Some(inner),
			Error::WebSocket(ref inner) => Some(inner),
			Error::Io(ref inner) => Some(inner),
			#[cfg(feature="voice")]
			Error::Opus(ref inner) => Some(inner),
			_ => None,
		}
	}
}
<commit_msg>Update timestamps to use chrono types (#117)<commit_after>use std::io::Error as IoError;
use std::error::Error as StdError;
use std::fmt::Display;
use hyper::Error as HyperError;
use serde_json::Error as JsonError;
use serde_json::Value;
use websocket::result::WebSocketError;
use chrono::ParseError as ChronoError;
#[cfg(feature="voice")]
use opus::Error as OpusError;

/// Discord API `Result` alias type.
pub type Result<T> = ::std::result::Result<T, Error>;

/// Discord API error type.
#[derive(Debug)]
pub enum Error {
	/// A `hyper` crate error
	Hyper(HyperError),
	/// A `chrono` crate error
	Chrono(ChronoError),
	/// A `serde_json` crate error
	Json(JsonError),
	/// A `websocket` crate error
	WebSocket(WebSocketError),
	/// A `std::io` module error
	Io(IoError),
	/// An error in the Opus library, with the function name and error code
	#[cfg(feature="voice")]
	Opus(OpusError),
	/// A websocket connection was closed, possibly with a message
	Closed(Option<u16>, String),
	/// A json decoding error, with a description and the offending value
	Decode(&'static str, Value),
	/// A generic non-success response from the REST API
	Status(::hyper::status::StatusCode, Option<Value>),
	/// A rate limit error, with how many milliseconds to wait before retrying
	RateLimited(u64),
	/// A Discord protocol error, with a description
	Protocol(&'static str),
	/// A command execution failure, with a command name and output
	Command(&'static str, ::std::process::Output),
	/// A miscellaneous error, with a description
	Other(&'static str),
}

impl Error {
	#[doc(hidden)]
	pub fn from_response(response: ::hyper::client::Response) -> Error {
		let status = response.status;
		let value = ::serde_json::from_reader(response).ok();
		if status == ::hyper::status::StatusCode::TooManyRequests {
			if let Some(Value::Object(ref map)) = value {
				if let Some(delay) = map.get("retry_after").and_then(|v| v.as_u64()) {
					return Error::RateLimited(delay)
				}
			}
		}
		Error::Status(status, value)
	}
}

impl From<IoError> for Error {
	fn from(err: IoError) -> Error {
		Error::Io(err)
	}
}

impl From<HyperError> for Error {
	fn from(err: HyperError) -> Error {
		Error::Hyper(err)
	}
}

impl From<ChronoError> for Error {
	fn from(err: ChronoError) -> Error {
		Error::Chrono(err)
	}
}

impl From<JsonError> for Error {
	fn from(err: JsonError) -> Error {
		Error::Json(err)
	}
}

impl From<WebSocketError> for Error {
	fn from(err: WebSocketError) -> Error {
		Error::WebSocket(err)
	}
}

#[cfg(feature="voice")]
impl From<OpusError> for Error {
	fn from(err: OpusError) -> Error {
		Error::Opus(err)
	}
}

impl Display for Error {
	fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
		match *self {
			Error::Hyper(ref inner) => inner.fmt(f),
			Error::Chrono(ref inner) => inner.fmt(f),
			Error::Json(ref inner) => inner.fmt(f),
			Error::WebSocket(ref inner) => inner.fmt(f),
			Error::Io(ref inner) => inner.fmt(f),
			#[cfg(feature="voice")]
			Error::Opus(ref inner) => inner.fmt(f),
			Error::Command(cmd, _) => write!(f, "Command failed: {}", cmd),
			_ => f.write_str(self.description()),
		}
	}
}

impl StdError for Error {
	fn description(&self) -> &str {
		match *self {
			Error::Hyper(ref inner) => inner.description(),
			Error::Chrono(ref inner) => inner.description(),
			Error::Json(ref inner) => inner.description(),
			Error::WebSocket(ref inner) => inner.description(),
			Error::Io(ref inner) => inner.description(),
			#[cfg(feature="voice")]
			Error::Opus(ref inner) => inner.description(),
			Error::Closed(_, _) => "Connection closed",
			Error::Decode(msg, _) |
			Error::Protocol(msg) |
			Error::Other(msg) => msg,
			Error::Status(status, _) => status.canonical_reason().unwrap_or("Unknown bad HTTP status"),
			Error::RateLimited(_) => "Rate limited",
			Error::Command(_, _) => "Command failed",
		}
	}

	fn cause(&self) -> Option<&StdError> {
		match *self {
			Error::Hyper(ref inner) => Some(inner),
			Error::Chrono(ref inner) => Some(inner),
			Error::Json(ref inner) => Some(inner),
			Error::WebSocket(ref inner) => Some(inner),
			Error::Io(ref inner) => Some(inner),
			#[cfg(feature="voice")]
			Error::Opus(ref inner) => Some(inner),
			_ => None,
		}
	}
}
<|endoftext|>


<commit_before>use std::str::FromStr;
use std::io::IoError;
use std::error::{Error, FromError};
use std::collections::enum_set::CLike;
use rustc_serialize::{Encoder, Encodable};

#[derive(Show, Copy, RustcEncodable)]
pub enum MpdErrorCode {
    NotList,
    Argument,
    Password,
    Permission,
    UnknownCmd,
    NoExist,
    PlaylistMax,
    System,
    PlaylistLoad,
    UpdateAlready,
    PlayerSync,
    Exist,
    Other(uint)
}

impl FromStr for MpdErrorCode {
    fn from_str(s: &str) -> Option<MpdErrorCode> {
        match s {
            "1" => Some(MpdErrorCode::NotList),
            "2" => Some(MpdErrorCode::Argument),
            "3" => Some(MpdErrorCode::Password),
            "4" => Some(MpdErrorCode::Permission),
            "5" => Some(MpdErrorCode::UnknownCmd),

            "50" => Some(MpdErrorCode::NoExist),
            "51" => Some(MpdErrorCode::PlaylistMax),
            "52" => Some(MpdErrorCode::System),
            "53" => Some(MpdErrorCode::PlaylistLoad),
            "54" => Some(MpdErrorCode::UpdateAlready),
            "55" => Some(MpdErrorCode::PlayerSync),
            "56" => Some(MpdErrorCode::Exist),

            _ => s.parse().map(|v| MpdErrorCode::Other(v))
        }
    }
}

impl CLike for MpdErrorCode {
    fn to_uint(&self) -> uint {
        match *self {
            MpdErrorCode::NotList => 1,
            MpdErrorCode::Argument => 2,
            MpdErrorCode::Password => 3,
            MpdErrorCode::Permission => 4,
            MpdErrorCode::UnknownCmd => 5,
            MpdErrorCode::NoExist => 50,
            MpdErrorCode::PlaylistMax => 51,
            MpdErrorCode::System => 52,
            MpdErrorCode::PlaylistLoad => 53,
            MpdErrorCode::UpdateAlready => 54,
            MpdErrorCode::PlayerSync => 55,
            MpdErrorCode::Exist => 56,
            MpdErrorCode::Other(num) => num
        }
    }

    fn from_uint(v: uint) -> MpdErrorCode {
        match v {
            1 => MpdErrorCode::NotList,
            2 => MpdErrorCode::Argument,
            3 => MpdErrorCode::Password,
            4 => MpdErrorCode::Permission,
            5 => MpdErrorCode::UnknownCmd,
            50 => MpdErrorCode::NoExist,
            51 => MpdErrorCode::PlaylistMax,
            52 => MpdErrorCode::System,
            53 => MpdErrorCode::PlaylistLoad,
            54 => MpdErrorCode::UpdateAlready,
            55 => MpdErrorCode::PlayerSync,
            56 => MpdErrorCode::Exist,
            _ => MpdErrorCode::Other(v)
        }
    }
}

#[derive(Show, RustcEncodable)]
pub struct MpdServerError {
    pub code: MpdErrorCode,
    pub pos: uint,
    pub command: String,
    pub detail: String
}

#[derive(Show)]
pub enum MpdError {
    Mpd(MpdServerError),
    Io(IoError),
}

impl<S, E> Encodable<S, E> for MpdError where S: Encoder<E> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        match *self {
            MpdError::Mpd(ref err) => err.encode(s),
            MpdError::Io(ref err) => {
                s.emit_struct("IoError", 3, |s| {
                    s.emit_struct_field("kind", 0, |s| err.kind.to_string().encode(s)).and_then(|_|
                    s.emit_struct_field("desc", 1, |s| err.desc.encode(s))).and_then(|_|
                    s.emit_struct_field("detail", 2, |s| err.detail.encode(s)))
                })
            }
        }
    }
}

impl Error for MpdServerError {
    fn description(&self) -> &str {
        match self.code {
            MpdErrorCode::NotList => "not a list",
            MpdErrorCode::Argument => "invalid argument",
            MpdErrorCode::Password => "invalid password",
            MpdErrorCode::Permission => "access denied",
            MpdErrorCode::UnknownCmd => "unknown command",
            MpdErrorCode::NoExist => "object not found",
            MpdErrorCode::PlaylistMax => "playlist overflow",
            MpdErrorCode::System => "system error",
            MpdErrorCode::PlaylistLoad => "playlist load error",
            MpdErrorCode::UpdateAlready => "database already updating",
            MpdErrorCode::PlayerSync => "player sync error",
            MpdErrorCode::Exist => "object already exists",
            MpdErrorCode::Other(_) => "unknown error",
        }
    }
}

impl Error for MpdError {
    fn description(&self) -> &str {
        match *self {
            MpdError::Io(ref err) => err.description(),
            MpdError::Mpd(ref err) => err.description(),
        }
    }

    fn detail(&self) -> Option<String> {
        match *self {
            MpdError::Mpd(ref err) => err.detail(),
            MpdError::Io(ref err) => err.detail(),
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            MpdError::Io(ref err) => Some(err as &Error),
            MpdError::Mpd(ref err) => Some(err as &Error),
        }
    }
}

impl FromError<IoError> for MpdError {
    fn from_error(err: IoError) -> MpdError {
        MpdError::Io(err)
    }
}

impl FromError<MpdServerError> for MpdError {
    fn from_error(err: MpdServerError) -> MpdError {
        MpdError::Mpd(err)
    }
}

impl FromStr for MpdServerError {
    fn from_str(s: &str) -> Option<MpdServerError> {
        // ACK [<code>@<index>] {<command>} <description>
        if s.starts_with("ACK [") {
            let s = s[5..];
            if let (Some(atsign), Some(right_bracket)) = (s.find('@'), s.find(']')) {
                if let (Some(code), Some(pos)) = (s[..atsign].parse(), s[atsign + 1..right_bracket].parse()) {
                    let s = s[right_bracket + 1..];
                    if let (Some(left_brace), Some(right_brace)) = (s.find('{'), s.find('}')) {
                        let command = s[left_brace + 1..right_brace].to_string();
                        let detail = s[right_brace + 1..].trim().to_string();
                        return Some(MpdServerError {
                            code: code,
                            pos: pos,
                            command: command,
                            detail: detail
                        });
                    }
                }
            }
        }
        None
    }
}

pub type MpdResult<T> = Result<T, MpdError>;

impl<S, E, T> Encodable<S, E> for MpdResult<T>
    where S: Encoder<E>, T: Encodable<S, E> {

    fn encode(&self, s: &mut S) -> Result<(), E> {
        match *self {
            Ok(ref v) => v.encode(s),
            Err(ref e) => e.encode(s)
        }
    }
}
<commit_msg>remove clike impl<commit_after>use std::str::FromStr;
use std::io::IoError;
use std::error::{Error, FromError};
use rustc_serialize::{Encoder, Encodable};

#[derive(Show, Copy, RustcEncodable)]
pub enum MpdErrorCode {
    NotList,
    Argument,
    Password,
    Permission,
    UnknownCmd,
    NoExist,
    PlaylistMax,
    System,
    PlaylistLoad,
    UpdateAlready,
    PlayerSync,
    Exist,
    Other(uint)
}

impl FromStr for MpdErrorCode {
    fn from_str(s: &str) -> Option<MpdErrorCode> {
        match s {
            "1" => Some(MpdErrorCode::NotList),
            "2" => Some(MpdErrorCode::Argument),
            "3" => Some(MpdErrorCode::Password),
            "4" => Some(MpdErrorCode::Permission),
            "5" => Some(MpdErrorCode::UnknownCmd),

            "50" => Some(MpdErrorCode::NoExist),
            "51" => Some(MpdErrorCode::PlaylistMax),
            "52" => Some(MpdErrorCode::System),
            "53" => Some(MpdErrorCode::PlaylistLoad),
            "54" => Some(MpdErrorCode::UpdateAlready),
            "55" => Some(MpdErrorCode::PlayerSync),
            "56" => Some(MpdErrorCode::Exist),

            _ => s.parse().map(|v| MpdErrorCode::Other(v))
        }
    }
}

#[derive(Show, RustcEncodable)]
pub struct MpdServerError {
    pub code: MpdErrorCode,
    pub pos: uint,
    pub command: String,
    pub detail: String
}

#[derive(Show)]
pub enum MpdError {
    Mpd(MpdServerError),
    Io(IoError),
}

impl<S, E> Encodable<S, E> for MpdError where S: Encoder<E> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        match *self {
            MpdError::Mpd(ref err) => err.encode(s),
            MpdError::Io(ref err) => {
                s.emit_struct("IoError", 3, |s| {
                    s.emit_struct_field("kind", 0, |s| err.kind.to_string().encode(s)).and_then(|_|
                    s.emit_struct_field("desc", 1, |s| err.desc.encode(s))).and_then(|_|
                    s.emit_struct_field("detail", 2, |s| err.detail.encode(s)))
                })
            }
        }
    }
}

impl Error for MpdServerError {
    fn description(&self) -> &str {
        match self.code {
            MpdErrorCode::NotList => "not a list",
            MpdErrorCode::Argument => "invalid argument",
            MpdErrorCode::Password => "invalid password",
            MpdErrorCode::Permission => "access denied",
            MpdErrorCode::UnknownCmd => "unknown command",
            MpdErrorCode::NoExist => "object not found",
            MpdErrorCode::PlaylistMax => "playlist overflow",
            MpdErrorCode::System => "system error",
            MpdErrorCode::PlaylistLoad => "playlist load error",
            MpdErrorCode::UpdateAlready => "database already updating",
            MpdErrorCode::PlayerSync => "player sync error",
            MpdErrorCode::Exist => "object already exists",
            MpdErrorCode::Other(_) => "unknown error",
        }
    }
}

impl Error for MpdError {
    fn description(&self) -> &str {
        match *self {
            MpdError::Io(ref err) => err.description(),
            MpdError::Mpd(ref err) => err.description(),
        }
    }

    fn detail(&self) -> Option<String> {
        match *self {
            MpdError::Mpd(ref err) => err.detail(),
            MpdError::Io(ref err) => err.detail(),
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            MpdError::Io(ref err) => Some(err as &Error),
            MpdError::Mpd(ref err) => Some(err as &Error),
        }
    }
}

impl FromError<IoError> for MpdError {
    fn from_error(err: IoError) -> MpdError {
        MpdError::Io(err)
    }
}

impl FromError<MpdServerError> for MpdError {
    fn from_error(err: MpdServerError) -> MpdError {
        MpdError::Mpd(err)
    }
}

impl FromStr for MpdServerError {
    fn from_str(s: &str) -> Option<MpdServerError> {
        // ACK [<code>@<index>] {<command>} <description>
        if s.starts_with("ACK [") {
            let s = s[5..];
            if let (Some(atsign), Some(right_bracket)) = (s.find('@'), s.find(']')) {
                if let (Some(code), Some(pos)) = (s[..atsign].parse(), s[atsign + 1..right_bracket].parse()) {
                    let s = s[right_bracket + 1..];
                    if let (Some(left_brace), Some(right_brace)) = (s.find('{'), s.find('}')) {
                        let command = s[left_brace + 1..right_brace].to_string();
                        let detail = s[right_brace + 1..].trim().to_string();
                        return Some(MpdServerError {
                            code: code,
                            pos: pos,
                            command: command,
                            detail: detail
                        });
                    }
                }
            }
        }
        None
    }
}

pub type MpdResult<T> = Result<T, MpdError>;

impl<S, E, T> Encodable<S, E> for MpdResult<T>
    where S: Encoder<E>, T: Encodable<S, E> {

    fn encode(&self, s: &mut S) -> Result<(), E> {
        match *self {
            Ok(ref v) => v.encode(s),
            Err(ref e) => e.encode(s)
        }
    }
}
<|endoftext|>