<commit_before>#![feature(libc, int_uint, core, unique)]

extern crate libc;

use std::ptr::{self, Unique};
use std::ffi::{CStr,CString};
use std::default::Default;
use std::mem::transmute;
use std::slice::SliceExt;
use std::raw::Slice;
use std::ops::Deref;
use std::str;
mod raw;

/// An iterator over devices that pcap is aware about on the system.
pub struct Devices {
    orig: Unique<raw::Struct_pcap_if>,
    device: Unique<raw::Struct_pcap_if>
}

impl Devices {
    /// Construct a new `Devices` iterator by internally using `pcap_findalldevs()`
    pub fn list_all() -> Result<Devices, String> {
        unsafe {
            let mut errbuf = [0i8; 256];
            let mut dev_buf: *mut raw::Struct_pcap_if = ptr::null_mut();

            match raw::pcap_findalldevs(&mut dev_buf, errbuf.as_mut_ptr()) {
                0 => {
                    Ok(Devices {
                        orig: Unique::new(dev_buf),
                        device: Unique::new(dev_buf)
                    })
                },
                _ => {
                    Err(
                        cstr_to_string(errbuf.as_ptr()).unwrap()
                    )
                }
            }
        }
    }
}

impl Drop for Devices {
    fn drop(&mut self) {
        unsafe {
            raw::pcap_freealldevs(*self.orig);
        }
    }
}

#[derive(Debug)]
/// A network device as constructed with `Device::new()` or returned from `Devices::list_all()`.
pub struct Device {
    pub name: String,
    pub desc: Option<String>
}

impl Device {
    /// Create a new device with a given name, useful when you know the name of the device already.
    pub fn new(name: &str) -> Device {
        Device {
            name: name.to_string(),
            desc: None
        }
    }

    /// Open a `Capture` for this network device.
    pub fn open(&self) -> Result<Capture, String> {
        let name = CString::new(&self.name[..]).unwrap();
        let mut errbuf = [0i8; 256];

        unsafe {
            let pcap_t = raw::pcap_open_live(name.as_ptr(), 65535, 1, 0, errbuf.as_mut_ptr());
            if pcap_t.is_null() {
                Err(
                    cstr_to_string(errbuf.as_ptr()).unwrap()
                )
            } else {
                Ok(Capture{
                    handle: Unique::new(pcap_t)
                })
            }
        }
    }
}

/// A packet obtained from a `Capture`.
///
/// This can be dereferenced to access the raw packet data.
pub enum Packet<'a> {
    Allocated(Vec<u8>),
    Borrowed(&'a [u8])
}

impl<'b> Deref for Packet<'b> {
    type Target = [u8];

    fn deref<'a>(&'a self) -> &'a [u8] {
        match *self {
            Packet::Allocated(ref v) => {
                v.as_slice()
            },
            Packet::Borrowed(x) => x
        }
    }
}

/// An iterator over packets obtained from a `Capture` in realtime.
///
/// This iterator will allocate a `Vec<u8>` for each packet it receives. If this
/// is not tolerable, try using `.next()` on `Capture` directly instead of this
/// iterator.
pub struct Packets<'a> {
    capture: &'a mut Capture
}

impl<'a, 'b> Iterator for Packets<'a> {
    type Item = Packet<'b>;

    fn next(&mut self) -> Option<Packet> {
        self.capture.next().map(|x| Packet::Allocated((*x).to_vec()))
    }
}

/// This represents an open capture handle obtained by calling `.open()` on a `Device`.
/// Internally it represents a `pcap_t` handle obtained by `pcap_open_live()`.
pub struct Capture {
    handle: Unique<raw::pcap_t>
}

impl Capture {
    /// Returns an iterator over packets received on this capture handle.
    pub fn listen<'a>(&'a mut self) -> Packets<'a> {
        Packets {
            capture: self
        }
    }

    /// Blocks until a packet is returned from the capture handle or an error occurs.
    pub fn next<'a>(&'a mut self) -> Option<Packet<'a>> {
        unsafe {
            let mut header: *mut raw::Struct_pcap_pkthdr = ptr::null_mut();
            let mut packet: *const libc::c_uchar = ptr::null_mut();
            match raw::pcap_next_ex(*self.handle, &mut header, &mut packet) {
                1 => {
                    // packet was read without issue
                    let packet = transmute::<_, &[u8]>(Slice {
                        data: packet,
                        len: (*header).len as usize
                    });

                    Some(Packet::Borrowed(packet))
                },
                _ => {
                    None
                }
            }
        }
    }

    /// Adds a filter to the capture using the given BPF program string. Internally
    /// this is compiled using `pcap_compile()`.
    ///
    /// See http://biot.com/capstats/bpf.html for more information about this syntax.
    pub fn filter(&mut self, program: &str) -> Result<(), String> {
        let program = CString::new(program).unwrap();

        unsafe {
            let mut bpf_program: raw::Struct_bpf_program = Default::default();

            if -1 == raw::pcap_compile(*self.handle, &mut bpf_program, program.as_ptr(), 0, 0) {
                return Err(cstr_to_string(raw::pcap_geterr(*self.handle)).unwrap());
            }

            if -1 == raw::pcap_setfilter(*self.handle, &mut bpf_program) {
                raw::pcap_freecode(&mut bpf_program);
                return Err(cstr_to_string(raw::pcap_geterr(*self.handle)).unwrap());
            }

            raw::pcap_freecode(&mut bpf_program);
            Ok(())
        }
    }
}

impl Drop for Capture {
    fn drop(&mut self) {
        unsafe {
            raw::pcap_close(*self.handle)
        }
    }
}

impl Iterator for Devices {
    type Item = Device;

    fn next(&mut self) -> Option<Device> {
        if self.device.is_null() {
            None
        } else {
            unsafe {
                let ret = Device {
                    name: cstr_to_string(self.device.get().name).unwrap(),
                    desc: {
                        if !self.device.get().description.is_null() {
                            Some(cstr_to_string(self.device.get().description).unwrap())
                        } else {
                            None
                        }
                    }
                };
                self.device = Unique::new(self.device.get().next);

                Some(ret)
            }
        }
    }
}

fn cstr_to_string(ptr: *const libc::c_char) -> Result<String, str::Utf8Error> {
    Ok(try!(str::from_utf8(unsafe{CStr::from_ptr(ptr)}.to_bytes())).to_string())
}<commit_msg>Don't expose packet internals.<commit_after>#![feature(libc, int_uint, core, unique)]

extern crate libc;

use std::ptr::{self, Unique};
use std::ffi::{CStr,CString};
use std::default::Default;
use std::mem::transmute;
use std::slice::SliceExt;
use std::raw::Slice;
use std::ops::Deref;
use std::str;
mod raw;

/// An iterator over devices that pcap is aware about on the system.
pub struct Devices {
    orig: Unique<raw::Struct_pcap_if>,
    device: Unique<raw::Struct_pcap_if>
}

impl Devices {
    /// Construct a new `Devices` iterator by internally using `pcap_findalldevs()`
    pub fn list_all() -> Result<Devices, String> {
        unsafe {
            let mut errbuf = [0i8; 256];
            let mut dev_buf: *mut raw::Struct_pcap_if = ptr::null_mut();

            match raw::pcap_findalldevs(&mut dev_buf, errbuf.as_mut_ptr()) {
                0 => {
                    Ok(Devices {
                        orig: Unique::new(dev_buf),
                        device: Unique::new(dev_buf)
                    })
                },
                _ => {
                    Err(
                        cstr_to_string(errbuf.as_ptr()).unwrap()
                    )
                }
            }
        }
    }
}

impl Drop for Devices {
    fn drop(&mut self) {
        unsafe {
            raw::pcap_freealldevs(*self.orig);
        }
    }
}

#[derive(Debug)]
/// A network device as constructed with `Device::new()` or returned from `Devices::list_all()`.
pub struct Device {
    pub name: String,
    pub desc: Option<String>
}

impl Device {
    /// Create a new device with a given name, useful when you know the name of the device already.
    pub fn new(name: &str) -> Device {
        Device {
            name: name.to_string(),
            desc: None
        }
    }

    /// Open a `Capture` for this network device.
    pub fn open(&self) -> Result<Capture, String> {
        let name = CString::new(&self.name[..]).unwrap();
        let mut errbuf = [0i8; 256];

        unsafe {
            let pcap_t = raw::pcap_open_live(name.as_ptr(), 65535, 1, 0, errbuf.as_mut_ptr());
            if pcap_t.is_null() {
                Err(
                    cstr_to_string(errbuf.as_ptr()).unwrap()
                )
            } else {
                Ok(Capture{
                    handle: Unique::new(pcap_t)
                })
            }
        }
    }
}

/// A packet obtained from a `Capture`.
///
/// This can be dereferenced to access the raw packet data.
pub struct Packet<'a> {
    data: PacketData<'a>
}

impl<'a> Packet<'a> {
    fn new(content: &'a [u8]) -> Packet<'a> {
        Packet {
            data: PacketData::Borrowed(content)
        }
    }

    fn alloc(mut self) -> Packet<'a> {
        self.data = PacketData::Allocated(self.to_vec());
        self
    }
}

enum PacketData<'a> {
    Allocated(Vec<u8>),
    Borrowed(&'a [u8])
}

impl<'b> Deref for Packet<'b> {
    type Target = [u8];

    fn deref<'a>(&'a self) -> &'a [u8] {
        match self.data {
            PacketData::Allocated(ref v) => {
                v.as_slice()
            },
            PacketData::Borrowed(x) => x
        }
    }
}

/// An iterator over packets obtained from a `Capture` in realtime.
///
/// This iterator will allocate a `Vec<u8>` for each packet it receives. If this
/// is not tolerable, try using `.next()` on `Capture` directly instead of this
/// iterator.
pub struct Packets<'a> {
    capture: &'a mut Capture
}

impl<'a, 'b> Iterator for Packets<'a> {
    type Item = Packet<'b>;

    fn next(&mut self) -> Option<Packet> {
        self.capture.next().map(|x| x.alloc())
    }
}

/// This represents an open capture handle obtained by calling `.open()` on a `Device`.
/// Internally it represents a `pcap_t` handle obtained by `pcap_open_live()`.
pub struct Capture {
    handle: Unique<raw::pcap_t>
}

impl Capture {
    /// Returns an iterator over packets received on this capture handle.
    pub fn listen<'a>(&'a mut self) -> Packets<'a> {
        Packets {
            capture: self
        }
    }

    /// Blocks until a packet is returned from the capture handle or an error occurs.
    pub fn next<'a>(&'a mut self) -> Option<Packet<'a>> {
        unsafe {
            let mut header: *mut raw::Struct_pcap_pkthdr = ptr::null_mut();
            let mut packet: *const libc::c_uchar = ptr::null_mut();
            match raw::pcap_next_ex(*self.handle, &mut header, &mut packet) {
                1 => {
                    // packet was read without issue
                    let packet = transmute::<_, &[u8]>(Slice {
                        data: packet,
                        len: (*header).len as usize
                    });

                    Some(Packet::new(packet))
                },
                _ => {
                    None
                }
            }
        }
    }

    /// Adds a filter to the capture using the given BPF program string. Internally
    /// this is compiled using `pcap_compile()`.
    ///
    /// See http://biot.com/capstats/bpf.html for more information about this syntax.
    pub fn filter(&mut self, program: &str) -> Result<(), String> {
        let program = CString::new(program).unwrap();

        unsafe {
            let mut bpf_program: raw::Struct_bpf_program = Default::default();

            if -1 == raw::pcap_compile(*self.handle, &mut bpf_program, program.as_ptr(), 0, 0) {
                return Err(cstr_to_string(raw::pcap_geterr(*self.handle)).unwrap());
            }

            if -1 == raw::pcap_setfilter(*self.handle, &mut bpf_program) {
                raw::pcap_freecode(&mut bpf_program);
                return Err(cstr_to_string(raw::pcap_geterr(*self.handle)).unwrap());
            }

            raw::pcap_freecode(&mut bpf_program);
            Ok(())
        }
    }
}

impl Drop for Capture {
    fn drop(&mut self) {
        unsafe {
            raw::pcap_close(*self.handle)
        }
    }
}

impl Iterator for Devices {
    type Item = Device;

    fn next(&mut self) -> Option<Device> {
        if self.device.is_null() {
            None
        } else {
            unsafe {
                let ret = Device {
                    name: cstr_to_string(self.device.get().name).unwrap(),
                    desc: {
                        if !self.device.get().description.is_null() {
                            Some(cstr_to_string(self.device.get().description).unwrap())
                        } else {
                            None
                        }
                    }
                };
                self.device = Unique::new(self.device.get().next);

                Some(ret)
            }
        }
    }
}

fn cstr_to_string(ptr: *const libc::c_char) -> Result<String, str::Utf8Error> {
    Ok(try!(str::from_utf8(unsafe{CStr::from_ptr(ptr)}.to_bytes())).to_string())
}<|endoftext|>


<commit_before>use std::cmp::Ord;
use std::option::{None, Option, Some};
use std::to_string::ToString;

/// FourNode
struct FourNode<V: ToString+Ord>(V, V, V, Option<(Box<Node<V>>, Box<Node<V>>, Box<Node<V>>, Box<Node<V>>)>);

impl <V: ToString+Ord> FourNode<V> {

    fn from_leaf_3node_and_value(node: Node<V>, value: V) -> FourNode<V> {
        match node {
            LeafThreeNode(value1, value2) =>
                if value > value2      { FourNode(value1, value2, value, None) }
                else if value < value1 { FourNode(value, value1, value2, None) }
                else                   { FourNode(value1, value, value2, None) },
            _ => fail!(""),
        }
    }

    /// Convert a Split into a TwoNode with the middle value as the value of the new parent node
    fn to_two_node(self) -> Node<V> {
        match self {
            FourNode(v1, v2, v3, None) =>
                TwoNode(v2,
                    box LeafTwoNode(v1),
                    box LeafTwoNode(v3)),
            FourNode(v1, v2, v3, Some((n1, n2, n3, n4))) =>
                TwoNode(v2,
                    box TwoNode(v1, n1, n2),
                    box TwoNode(v3, n3, n4)),
        }
    }
}

/// InsertResult
enum InsertResult<V: ToString+Ord> {
    Fit(Node<V>),  // box this node?
    Split(FourNode<V>),  // split should always contain a ThreeNode/LeafThreeNode. box this?
}

/// Direction
enum Direction {
    Left,
    Middle,
    Right,
    Leaf,
}

/// Node
pub enum Node<V: ToString+Ord> {
    LeafTwoNode(V),
    LeafThreeNode(V, V),
    TwoNode(V, Box<Node<V>>, Box<Node<V>>),
    ThreeNode(V, V, Box<Node<V>>, Box<Node<V>>, Box<Node<V>>),
}

impl <V: ToString+Ord> ToString for Node<V> {
    fn to_string(&self) -> String {
        match *self {
            LeafTwoNode(ref v) => format!("LeafTwoNode({:s})", v.to_string()),
            LeafThreeNode(ref v1, ref v2) => format!("LeafThreeNode({:s}, {:s})", v1.to_string(), v2.to_string()),
            TwoNode(ref v, ref left, ref middle) => format!("TwoNode({:s}, {:s}, {:s})", v.to_string(), left.to_string(), middle.to_string()),
            ThreeNode(_, _, ref left, ref middle, ref right) => format!("ThreeNode({:s}, {:s}, {:s})", left.to_string(), middle.to_string(), right.to_string()),
        }
    }
}

impl <V: ToString+Ord> Node<V> {
    // PRIVATE
    /// Extend this TwoNode with the provided value and child node to make it a ThreeNode
    fn extend(self, other_value: V, other_node: Box<Node<V>>) -> Node<V> {
        match self {
            TwoNode(self_value, self_left, self_middle) => {
                if self_value > other_value {
                    ThreeNode(other_value, self_value, other_node, self_left, self_middle)
                } else {
                    ThreeNode(self_value, other_value, self_left, self_middle, other_node)
                }
            }
            _ => fail!(""),
        }
    }

    fn extend4(self, other_value: V, other_node: Box<Node<V>>) -> FourNode<V> {
        match self {
            ThreeNode(self_value1, self_value2, self_left, self_middle, self_right) => {
                if other_value < self_value1 {
                    FourNode(other_value, self_value1, self_value2, Some((other_node, self_left, self_middle, self_right)))
                } else {
                    FourNode(self_value1, self_value2, other_value, Some((self_left, self_middle, self_right, other_node)))
                }
            }
            _ => fail!(""),
        }
    }

    fn next_direction(&self, to_insert: &V) -> Direction {
        match self {
            &TwoNode(ref value, _, _) =>
                if to_insert < value { Left }
                else                 { Middle },
            &ThreeNode(ref value1, ref value2, _, _, _) =>
                if      to_insert < value1 { Left }
                else if to_insert > value2 { Right }
                else                       { Middle },
            _ => Leaf,
        }
    }

    fn contains_node(&self, to_check: &V) -> bool {
        match self {
            &TwoNode(ref v, _, _) |
                &LeafTwoNode(ref v) if to_check == v => true,

            &ThreeNode(ref v1, ref v2, _, _, _) |
                &LeafThreeNode(ref v1, ref v2) if to_check == v1 || to_check == v2 => true,

            _ => false
        }
    }

    fn insert(self, to_insert: V) -> InsertResult<V> {
        // If value is already in this node, we're done (prevent duplicates)
        if self.contains_node(&to_insert) { return Fit(self); }

        let next_direction = self.next_direction(&to_insert);

        match self {
            // Insert if leaf TwoNode
            LeafTwoNode(value) => {
                let (smaller, larger) =
                    if value < to_insert { (value, to_insert) }
                    else                 { (to_insert, value) };
                let new_node = LeafThreeNode(smaller, larger);
                Fit(new_node)
            },

            // Split if leaf ThreeNode
            node @ LeafThreeNode(..) => {
                let four_node = FourNode::from_leaf_3node_and_value(node, to_insert);
                Split(four_node)
            },

            // Recurse down if internal Node and handle results
            TwoNode(value, box left, box middle) => {

                // Determine which node we'll recurse next
                let (next_node, other_node) = match next_direction {
                    Left => (left, middle),
                    Middle => (middle, left),
                    _ => fail!(""),
                };

                // Recurse, save the result of the insert
                let insert_result = next_node.insert(to_insert);

                // Handle the result of the insert
                let new_node = match insert_result {
                    Fit(returned_node) =>
                        match next_direction {
                            Left => TwoNode(value, box returned_node, box other_node),
                            Middle => TwoNode(value, box other_node, box returned_node),
                            _ => fail!(""),
                        },
                    Split(four_node) => four_node.to_two_node().extend(value, box other_node),
                };

                Fit(new_node)
            },

            // Recurse down if internal Node and handle results
            ThreeNode(value1, value2, left, middle, right) => {

                // Determine which node we'll recurse next
                let (next_node, other_node1, other_node2) = match next_direction {
                    Left => (left, middle, right),
                    Middle => (middle, left, right),
                    Right => (right, left, middle),
                    _ => fail!(""),
                };

                let insert_result = next_node.insert(to_insert);

                match insert_result {
                    Fit(returned_node) => {
                        let new_node = match next_direction {
                            Left => ThreeNode(value1, value2, box returned_node, other_node1, other_node2),
                            Middle => ThreeNode(value1, value2, other_node1, box returned_node, other_node2),
                            Right => ThreeNode(value1, value2, other_node1, other_node2, box returned_node),
                            _ => fail!(""),
                        };
                        Fit(new_node)
                    },
                    Split(four_node) => {
                        let new_node: FourNode<V> = match next_direction {
                            Left => four_node.to_two_node().extend(value1, other_node1).extend4(value2, other_node2),
                            Middle => four_node.to_two_node().extend(value1, other_node1).extend4(value2, other_node2),
                            Right => four_node.to_two_node().extend(value2, other_node2).extend4(value1, other_node1),
                            _ => fail!(""),
                        };
                        Split(new_node)
                    }
                }
            }
        }
    }
}

/// TTTree
pub struct TTTree<V: ToString+Ord> {
    pub root: Option<Node<V>>,
}

impl <V: ToString+Ord> ToString for TTTree<V> {
    fn to_string(&self) -> String {
        match self.root {
            Some(ref node) => node.to_string(),
            None => "TTTree(<empty>)".to_string(),
        }
    }
}

impl <V: ToString+Ord> TTTree<V> {
    pub fn new() -> TTTree<V> {
        TTTree { root: None }
    }

    pub fn insert(&mut self, value: V) -> () {
        let root: Option<Node<V>> = self.root.take();
        let new_root: Node<V> = match root {
            None => LeafTwoNode(value),
            Some(root) => {
                let result = root.insert(value);
                match result {
                    Fit(node) => node,
                    Split(node @ FourNode(..)) => node.to_two_node(),
                }
            }
        };
        self.root = Some(new_root);
    }
}

// TODO:
// Collection trait
// convert this to Key/Value K/V
// remove ToString debugging stuffs
<commit_msg>Add note about design decisions<commit_after>// Many of my decisions were based off the following document
// https://web.archive.org/web/20140727185616/http://algs4.cs.princeton.edu/33balanced/

use std::cmp::Ord;
use std::option::{None, Option, Some};
use std::to_string::ToString;

/// FourNode
struct FourNode<V: ToString+Ord>(V, V, V, Option<(Box<Node<V>>, Box<Node<V>>, Box<Node<V>>, Box<Node<V>>)>);

impl <V: ToString+Ord> FourNode<V> {

    fn from_leaf_3node_and_value(node: Node<V>, value: V) -> FourNode<V> {
        match node {
            LeafThreeNode(value1, value2) =>
                if value > value2      { FourNode(value1, value2, value, None) }
                else if value < value1 { FourNode(value, value1, value2, None) }
                else                   { FourNode(value1, value, value2, None) },
            _ => fail!(""),
        }
    }

    /// Convert a Split into a TwoNode with the middle value as the value of the new parent node
    fn to_two_node(self) -> Node<V> {
        match self {
            FourNode(v1, v2, v3, None) =>
                TwoNode(v2,
                    box LeafTwoNode(v1),
                    box LeafTwoNode(v3)),
            FourNode(v1, v2, v3, Some((n1, n2, n3, n4))) =>
                TwoNode(v2,
                    box TwoNode(v1, n1, n2),
                    box TwoNode(v3, n3, n4)),
        }
    }
}

/// InsertResult
enum InsertResult<V: ToString+Ord> {
    Fit(Node<V>),  // box this node?
    Split(FourNode<V>),  // split should always contain a ThreeNode/LeafThreeNode. box this?
}

/// Direction
enum Direction {
    Left,
    Middle,
    Right,
    Leaf,
}

/// Node
pub enum Node<V: ToString+Ord> {
    LeafTwoNode(V),
    LeafThreeNode(V, V),
    TwoNode(V, Box<Node<V>>, Box<Node<V>>),
    ThreeNode(V, V, Box<Node<V>>, Box<Node<V>>, Box<Node<V>>),
}

impl <V: ToString+Ord> ToString for Node<V> {
    fn to_string(&self) -> String {
        match *self {
            LeafTwoNode(ref v) => format!("LeafTwoNode({:s})", v.to_string()),
            LeafThreeNode(ref v1, ref v2) => format!("LeafThreeNode({:s}, {:s})", v1.to_string(), v2.to_string()),
            TwoNode(ref v, ref left, ref middle) => format!("TwoNode({:s}, {:s}, {:s})", v.to_string(), left.to_string(), middle.to_string()),
            ThreeNode(_, _, ref left, ref middle, ref right) => format!("ThreeNode({:s}, {:s}, {:s})", left.to_string(), middle.to_string(), right.to_string()),
        }
    }
}

impl <V: ToString+Ord> Node<V> {
    // PRIVATE
    /// Extend this TwoNode with the provided value and child node to make it a ThreeNode
    fn extend(self, other_value: V, other_node: Box<Node<V>>) -> Node<V> {
        match self {
            TwoNode(self_value, self_left, self_middle) => {
                if self_value > other_value {
                    ThreeNode(other_value, self_value, other_node, self_left, self_middle)
                } else {
                    ThreeNode(self_value, other_value, self_left, self_middle, other_node)
                }
            }
            _ => fail!(""),
        }
    }

    fn extend4(self, other_value: V, other_node: Box<Node<V>>) -> FourNode<V> {
        match self {
            ThreeNode(self_value1, self_value2, self_left, self_middle, self_right) => {
                if other_value < self_value1 {
                    FourNode(other_value, self_value1, self_value2, Some((other_node, self_left, self_middle, self_right)))
                } else {
                    FourNode(self_value1, self_value2, other_value, Some((self_left, self_middle, self_right, other_node)))
                }
            }
            _ => fail!(""),
        }
    }

    fn next_direction(&self, to_insert: &V) -> Direction {
        match self {
            &TwoNode(ref value, _, _) =>
                if to_insert < value { Left }
                else                 { Middle },
            &ThreeNode(ref value1, ref value2, _, _, _) =>
                if      to_insert < value1 { Left }
                else if to_insert > value2 { Right }
                else                       { Middle },
            _ => Leaf,
        }
    }

    fn contains_node(&self, to_check: &V) -> bool {
        match self {
            &TwoNode(ref v, _, _) |
                &LeafTwoNode(ref v) if to_check == v => true,

            &ThreeNode(ref v1, ref v2, _, _, _) |
                &LeafThreeNode(ref v1, ref v2) if to_check == v1 || to_check == v2 => true,

            _ => false
        }
    }

    fn insert(self, to_insert: V) -> InsertResult<V> {
        // If value is already in this node, we're done (prevent duplicates)
        if self.contains_node(&to_insert) { return Fit(self); }

        let next_direction = self.next_direction(&to_insert);

        match self {
            // Insert if leaf TwoNode
            LeafTwoNode(value) => {
                let (smaller, larger) =
                    if value < to_insert { (value, to_insert) }
                    else                 { (to_insert, value) };
                let new_node = LeafThreeNode(smaller, larger);
                Fit(new_node)
            },

            // Split if leaf ThreeNode
            node @ LeafThreeNode(..) => {
                let four_node = FourNode::from_leaf_3node_and_value(node, to_insert);
                Split(four_node)
            },

            // Recurse down if internal Node and handle results
            TwoNode(value, box left, box middle) => {

                // Determine which node we'll recurse next
                let (next_node, other_node) = match next_direction {
                    Left => (left, middle),
                    Middle => (middle, left),
                    _ => fail!(""),
                };

                // Recurse, save the result of the insert
                let insert_result = next_node.insert(to_insert);

                // Handle the result of the insert
                let new_node = match insert_result {
                    Fit(returned_node) =>
                        match next_direction {
                            Left => TwoNode(value, box returned_node, box other_node),
                            Middle => TwoNode(value, box other_node, box returned_node),
                            _ => fail!(""),
                        },
                    Split(four_node) => four_node.to_two_node().extend(value, box other_node),
                };

                Fit(new_node)
            },

            // Recurse down if internal Node and handle results
            ThreeNode(value1, value2, left, middle, right) => {

                // Determine which node we'll recurse next
                let (next_node, other_node1, other_node2) = match next_direction {
                    Left => (left, middle, right),
                    Middle => (middle, left, right),
                    Right => (right, left, middle),
                    _ => fail!(""),
                };

                let insert_result = next_node.insert(to_insert);

                match insert_result {
                    Fit(returned_node) => {
                        let new_node = match next_direction {
                            Left => ThreeNode(value1, value2, box returned_node, other_node1, other_node2),
                            Middle => ThreeNode(value1, value2, other_node1, box returned_node, other_node2),
                            Right => ThreeNode(value1, value2, other_node1, other_node2, box returned_node),
                            _ => fail!(""),
                        };
                        Fit(new_node)
                    },
                    Split(four_node) => {
                        let new_node: FourNode<V> = match next_direction {
                            Left => four_node.to_two_node().extend(value1, other_node1).extend4(value2, other_node2),
                            Middle => four_node.to_two_node().extend(value1, other_node1).extend4(value2, other_node2),
                            Right => four_node.to_two_node().extend(value2, other_node2).extend4(value1, other_node1),
                            _ => fail!(""),
                        };
                        Split(new_node)
                    }
                }
            }
        }
    }
}

/// TTTree
pub struct TTTree<V: ToString+Ord> {
    pub root: Option<Node<V>>,
}

impl <V: ToString+Ord> ToString for TTTree<V> {
    fn to_string(&self) -> String {
        match self.root {
            Some(ref node) => node.to_string(),
            None => "TTTree(<empty>)".to_string(),
        }
    }
}

impl <V: ToString+Ord> TTTree<V> {
    pub fn new() -> TTTree<V> {
        TTTree { root: None }
    }

    pub fn insert(&mut self, value: V) -> () {
        let root: Option<Node<V>> = self.root.take();
        let new_root: Node<V> = match root {
            None => LeafTwoNode(value),
            Some(root) => {
                let result = root.insert(value);
                match result {
                    Fit(node) => node,
                    Split(node @ FourNode(..)) => node.to_two_node(),
                }
            }
        };
        self.root = Some(new_root);
    }
}

// TODO:
// Collection trait
// convert this to Key/Value K/V
// remove ToString debugging stuffs
<|endoftext|>


<commit_before>// lib.rs
// AltOSRust
//
// Created by Daniel Seitz on 11/30/16

#![feature(lang_items)]
#![feature(core_intrinsics)]
#![feature(asm)]
#![feature(naked_functions)]
#![feature(const_fn)]
#![feature(alloc)]
#![feature(collections)]
#![feature(drop_types_in_const)] // Probably can come back and remove this later
#![no_std]

#[cfg(not(test))]
extern crate bump_allocator;
extern crate alloc;
#[macro_use]
extern crate collections;

mod exceptions;
mod peripheral;
mod math;
mod timer;
mod volatile;
mod arm;
mod interrupt;
mod task;
mod system_control;
mod atomic;

use peripheral::gpio;
use peripheral::rcc;
use peripheral::systick;

pub use math::{__aeabi_uidiv, __aeabi_uidivmod, __aeabi_lmul};
#[cfg(not(test))]
pub use vector_table::RESET;
#[cfg(not(test))]
pub use exceptions::EXCEPTIONS;
pub use task::{CURRENT_TASK, switch_context};

#[no_mangle]
pub fn start() -> ! {
  // TODO: set pendsv and systick interrupts to lowest priority
  init_data_segment();
  init_bss_segment();

  #[cfg(not(test))]
  bump_allocator::init_heap();

  init_led();
  init_clock();
  init_ticks();

  task::new_task(test_task_1, 512, task::Priority::Critical, "first task");
  task::new_task(test_task_2, 512, task::Priority::Critical, "second task");
  task::new_task(test_task_3, 512, task::Priority::Critical, "third task");
  task::start_first_task();

  loop { unsafe { arm::bkpt() }; }
}

fn test_task_1() {
  let pb3 = gpio::Port::new(3, gpio::Group::B);
  loop {
    for _ in 0..5 {
      pb3.set();
      timer::Timer::delay_ms(100);
      pb3.reset();
      timer::Timer::delay_ms(100);
    }
    task::yield_task();
  }
}

fn test_task_2() {
  let pb3 = gpio::Port::new(3, gpio::Group::B);
  loop {
    for _ in 0..3 {
      pb3.set();
      timer::Timer::delay_ms(500);
      pb3.reset();
      timer::Timer::delay_ms(500);
    }
    task::yield_task();
  }
}

fn test_task_3() {
  let pb3 = gpio::Port::new(3, gpio::Group::B);
  loop {
    for _ in 0..10 {
      pb3.set();
      timer::Timer::delay_ms(50);
      pb3.reset();
      timer::Timer::delay_ms(50);
    }
    task::yield_task();
  }

}

mod vector_table {
  #[cfg(not(test))]
  #[link_section = ".reset"]
  #[no_mangle]
  pub static RESET: fn() -> ! = ::start;
}

#[cfg(not(test))]
#[lang = "eh_personality"] extern fn eh_personality() {}
#[cfg(not(test))]
#[lang = "panic_fmt"] extern fn panic_fmt() -> ! {loop{}}

fn init_data_segment() {
  unsafe {
    #[cfg(target_arch="arm")]
    asm!(
      concat!(
        "ldr r1, =_sidata\n", /* start of data in flash */
        "ldr r2, =_sdata\n",  /* start of memory location in RAM */
        "ldr r3, =_edata\n",  /* end of memory location in RAM */
      "copy:\n",
        "cmp r2, r3\n", /* check if we've reached the end of our segment */
        "bpl d_done\n",
        "ldr r0, [r1]\n", /* if not, keep copying */
        "adds r1, #4\n",
        "str r0, [r2]\n",
        "adds r2, #4\n",
        "b copy\n", /* repeat until done */
      "d_done:\n")
    : /* no outputs */
    : /* no inputs */
    : "r0", "r1", "r2", "r3" /* clobbers */
    : "volatile");
  }
}

fn init_bss_segment() {
  unsafe {
    #[cfg(target_arch="arm")]
    asm!(
      concat!(
        "movs r0, #0\n", /* store zero for later */
        "ldr r1, =_sbss\n", /* start of bss in RAM */
        "ldr r2, =_ebss\n", /* end of bss in RAM */
      "loop:\n",
        "cmp r1, r2\n", /* check if we've reached the end of our segment */
        "bpl b_done\n",
        "str r0, [r1]\n", /* if not, zero out memory at current location */
        "adds r1, #4\n",
        "b loop\n", /* repeat until done */
      "b_done:\n")
    : /* no outputs */
    : /* no inputs */
    : "r0", "r1", "r2" /* clobbers */
    : "volatile");
  }
}

fn init_led() {
  gpio::GPIO::enable(gpio::Group::B);

  let mut pb3 = gpio::Port::new(3, gpio::Group::B);
  pb3.set_mode(gpio::Mode::Output);
  pb3.set_type(gpio::Type::PushPull);
}

fn init_clock() {
  let rcc = rcc::rcc();

  // 12 is the max we can go since our input clock is (8MHz / 2)
  let clock_multiplier: u8 = 12;

  // PLL must be off in order to configure
  rcc.disable_clock(rcc::Clock::PLL);

  // Make sure HSI is the PLL source clock
  rcc.set_pll_source(rcc::Clock::HSI);

  // Set the multiplier... DO NOT EXCEED 48 MHz
  rcc.set_pll_multiplier(clock_multiplier);

  // Enable the PLL clock
  rcc.enable_clock(rcc::Clock::PLL);

  // Wait for it to be ready
  while !rcc.clock_is_ready(rcc::Clock::PLL) {}
  // Switch over to the PLL for running the system
  rcc.set_system_clock_source(rcc::Clock::PLL);
}

fn init_ticks() {
  let systick = systick::systick();

  systick.use_processor_clock();
  systick.clear_current_value();
  systick.enable_counter();
  systick.enable_interrupts();

}
<commit_msg>apply cfg to entire unsafe block rather than asm macro<commit_after>// lib.rs
// AltOSRust
//
// Created by Daniel Seitz on 11/30/16

#![feature(lang_items)]
#![feature(core_intrinsics)]
#![feature(asm)]
#![feature(naked_functions)]
#![feature(const_fn)]
#![feature(alloc)]
#![feature(collections)]
#![feature(drop_types_in_const)] // Probably can come back and remove this later
#![no_std]

#[cfg(not(test))]
extern crate bump_allocator;
extern crate alloc;
#[macro_use]
extern crate collections;

mod exceptions;
mod peripheral;
mod math;
mod timer;
mod volatile;
mod arm;
mod interrupt;
mod task;
mod system_control;
mod atomic;

use peripheral::gpio;
use peripheral::rcc;
use peripheral::systick;

pub use math::{__aeabi_uidiv, __aeabi_uidivmod, __aeabi_lmul};
#[cfg(not(test))]
pub use vector_table::RESET;
#[cfg(not(test))]
pub use exceptions::EXCEPTIONS;
pub use task::{CURRENT_TASK, switch_context};

#[no_mangle]
pub fn start() -> ! {
  // TODO: set pendsv and systick interrupts to lowest priority
  init_data_segment();
  init_bss_segment();

  #[cfg(not(test))]
  bump_allocator::init_heap();

  init_led();
  init_clock();
  init_ticks();

  task::new_task(test_task_1, 512, task::Priority::Critical, "first task");
  task::new_task(test_task_2, 512, task::Priority::Critical, "second task");
  task::new_task(test_task_3, 512, task::Priority::Critical, "third task");
  task::start_first_task();

  loop { unsafe { arm::bkpt() }; }
}

fn test_task_1() {
  let pb3 = gpio::Port::new(3, gpio::Group::B);
  loop {
    for _ in 0..5 {
      pb3.set();
      timer::Timer::delay_ms(100);
      pb3.reset();
      timer::Timer::delay_ms(100);
    }
    task::yield_task();
  }
}

fn test_task_2() {
  let pb3 = gpio::Port::new(3, gpio::Group::B);
  loop {
    for _ in 0..3 {
      pb3.set();
      timer::Timer::delay_ms(500);
      pb3.reset();
      timer::Timer::delay_ms(500);
    }
    task::yield_task();
  }
}

fn test_task_3() {
  let pb3 = gpio::Port::new(3, gpio::Group::B);
  loop {
    for _ in 0..10 {
      pb3.set();
      timer::Timer::delay_ms(50);
      pb3.reset();
      timer::Timer::delay_ms(50);
    }
    task::yield_task();
  }

}

mod vector_table {
  #[cfg(not(test))]
  #[link_section = ".reset"]
  #[no_mangle]
  pub static RESET: fn() -> ! = ::start;
}

#[cfg(not(test))]
#[lang = "eh_personality"] extern fn eh_personality() {}
#[cfg(not(test))]
#[lang = "panic_fmt"] extern fn panic_fmt() -> ! {loop{}}

fn init_data_segment() {
  unsafe {
    #![cfg(target_arch="arm")]
    asm!(
      concat!(
        "ldr r1, =_sidata\n", /* start of data in flash */
        "ldr r2, =_sdata\n",  /* start of memory location in RAM */
        "ldr r3, =_edata\n",  /* end of memory location in RAM */
      "copy:\n",
        "cmp r2, r3\n", /* check if we've reached the end of our segment */
        "bpl d_done\n",
        "ldr r0, [r1]\n", /* if not, keep copying */
        "adds r1, #4\n",
        "str r0, [r2]\n",
        "adds r2, #4\n",
        "b copy\n", /* repeat until done */
      "d_done:\n")
    : /* no outputs */
    : /* no inputs */
    : "r0", "r1", "r2", "r3" /* clobbers */
    : "volatile");
  }
}

fn init_bss_segment() {
  unsafe {
    #![cfg(target_arch="arm")]
    asm!(
      concat!(
        "movs r0, #0\n", /* store zero for later */
        "ldr r1, =_sbss\n", /* start of bss in RAM */
        "ldr r2, =_ebss\n", /* end of bss in RAM */
      "loop:\n",
        "cmp r1, r2\n", /* check if we've reached the end of our segment */
        "bpl b_done\n",
        "str r0, [r1]\n", /* if not, zero out memory at current location */
        "adds r1, #4\n",
        "b loop\n", /* repeat until done */
      "b_done:\n")
    : /* no outputs */
    : /* no inputs */
    : "r0", "r1", "r2" /* clobbers */
    : "volatile");
  }
}

fn init_led() {
  gpio::GPIO::enable(gpio::Group::B);

  let mut pb3 = gpio::Port::new(3, gpio::Group::B);
  pb3.set_mode(gpio::Mode::Output);
  pb3.set_type(gpio::Type::PushPull);
}

fn init_clock() {
  let rcc = rcc::rcc();

  // 12 is the max we can go since our input clock is (8MHz / 2)
  let clock_multiplier: u8 = 12;

  // PLL must be off in order to configure
  rcc.disable_clock(rcc::Clock::PLL);

  // Make sure HSI is the PLL source clock
  rcc.set_pll_source(rcc::Clock::HSI);

  // Set the multiplier... DO NOT EXCEED 48 MHz
  rcc.set_pll_multiplier(clock_multiplier);

  // Enable the PLL clock
  rcc.enable_clock(rcc::Clock::PLL);

  // Wait for it to be ready
  while !rcc.clock_is_ready(rcc::Clock::PLL) {}
  // Switch over to the PLL for running the system
  rcc.set_system_clock_source(rcc::Clock::PLL);
}

fn init_ticks() {
  let systick = systick::systick();

  systick.use_processor_clock();
  systick.clear_current_value();
  systick.enable_counter();
  systick.enable_interrupts();

}
<|endoftext|>


<commit_before>#![recursion_limit = "1024"]

#[macro_use]
extern crate error_chain;
extern crate reqwest;
extern crate idna;

pub mod errors;

#[cfg(test)]
mod tests;

use std::io::Read;
use std::fs::File;
use std::path::Path;
use std::collections::HashMap;

use errors::*;
use reqwest::IntoUrl;
use idna::domain_to_unicode;

#[derive(Debug)]
struct Suffix {
    rule: String,
    typ: Type,
}

#[derive(Debug)]
pub struct List {
    rules: HashMap<String, Vec<Suffix>>,
}

#[derive(Debug, Clone, Copy, PartialEq)]
enum Type {
    Icann,
    Private,
}

#[derive(Debug, Clone)]
pub struct Domain {
    full: String,
    typ: Option<Type>,
    suffix: Option<String>,
}

const OFFICIAL_URL: &'static str = "https://publicsuffix.org/list/public_suffix_list.dat";

impl List {
    fn append(&mut self, rule: &str, typ: Type) -> Result<()> {
        rule.rsplit('.').next()
            .ok_or(ErrorKind::InvalidRule(rule.into()).into())
            .and_then(|tld| {
                if tld.is_empty() {
                    return Err(ErrorKind::InvalidRule(rule.into()).into());
                }
                Ok(tld)})
            .and_then(|tld| {
                self.rules.entry(tld.into()).or_insert(Vec::new())
                    .push(Suffix {
                        rule: rule.into(),
                        typ: typ,
                    });
                Ok(())
            })
    }

    fn build<R: Read>(mut reader: R) -> Result<List> {
        let mut res = String::new();
        reader.read_to_string(&mut res)?;

        let mut typ = Type::Icann;

        let mut list = List {
            rules: HashMap::new(),
        };

        for line in res.lines() {
            match line {
                line if line.contains("BEGIN ICANN DOMAINS") => { typ = Type::Icann; }
                line if line.contains("BEGIN PRIVATE DOMAINS") => { typ = Type::Private; }
                line if line.starts_with("//") => { continue; }
                line => {
                    let rule = line.trim();
                    if rule.is_empty() {
                        continue;
                    }
                    list.append(rule, typ)?;
                }
            }
        }

        list.rules.shrink_to_fit();
        Ok(list)
    }

    pub fn from_url<U: IntoUrl>(url: U) -> Result<List> {
        reqwest::get(url)
            .map_err(|err| ErrorKind::Request(err).into())
            .and_then(Self::build)
    }

    pub fn from_path<P: AsRef<Path>>(path: P) -> Result<List> {
        File::open(path)
            .map_err(|err| ErrorKind::Io(err).into())
            .and_then(Self::build)
    }

    pub fn fetch() -> Result<List> {
        Self::from_url(OFFICIAL_URL)
    }

    fn find_type(&self, typ: Type) -> Vec<&String> {
        self.rules.values()
            .fold(Vec::new(), |mut res, ref suffices| {
                for suffix in *suffices {
                    if suffix.typ == typ {
                        res.push(&suffix.rule);
                    }
                }
                res
            })
    }

    pub fn icann(&self) -> Vec<&String> {
        self.find_type(Type::Icann)
    }

    pub fn private(&self) -> Vec<&String> {
        self.find_type(Type::Private)
    }

    pub fn all(&self) -> Vec<&String> {
        self.rules.values()
            .fold(Vec::new(), |mut res, ref suffices| {
                for suffix in *suffices {
                    res.push(&suffix.rule);
                }
                res
            })
    }
}

impl Domain {
    fn possible_matches<'a>(domain: &str, list: &'a List) -> Result<Vec<&'a Suffix>> {
        domain.rsplit('.').next()
            .ok_or(ErrorKind::InvalidDomain(domain.to_string()).into())
            .and_then(|tld| {
                if tld.is_empty() {
                    return Err(ErrorKind::InvalidDomain(domain.to_string()).into());
                }
                Ok(tld)})
            .and_then(|tld| {
                let candidates = match list.rules.get(tld) {
                    Some(candidates) => candidates,
                    None => { return Ok(Vec::new()); },
                };
                let candidates = candidates.iter()
                    .fold(Vec::new(), |mut res, ref suffix| {
                        res.push(*suffix);
                        res
                    });
                Ok(candidates)
            })
    }

    fn find_match(domain: &str, candidates: Vec<&Suffix>) -> Result<Domain> {
        let d_labels: Vec<&str> = domain.split('.').rev().collect();

        let mut suffix = None;
        let mut typ = None;
        let mut num_labels = 0;

        for candidate in candidates {
            let s_labels: Vec<&str> = candidate.rule.split('.').rev().collect();
            if s_labels.len() > d_labels.len() { continue; }
            for (i, label) in s_labels.iter().enumerate() {
                if *label == d_labels[i] || *label == "*" || label.trim_right_matches('!') == d_labels[i] {
                    if i == s_labels.len()-1 {
                        if s_labels.len() > num_labels {
                            num_labels = s_labels.len();
                            typ = Some(candidate.typ);
                            let parts = if label.starts_with("!") {
                                &d_labels[..s_labels.len()-1]
                            } else {
                                &d_labels[..s_labels.len()]
                            };
                            suffix = Some(parts.iter().rev()
                                          .map(|part| *part)
                                          .collect::<Vec<_>>()
                                          .join("."));
                        }
                    }
                } else {
                    break;
                }
            }
        }

        Ok(Domain {
            full: domain.to_string(),
            typ: typ,
            suffix: suffix,
        })
    }

    pub fn parse(domain: &str, list: &List) -> Result<Domain> {
        let domain = domain.trim().trim_right_matches('.');
        let (domain, res) = domain_to_unicode(domain);
        if let Err(errors) = res {
            return Err(ErrorKind::Uts46(errors).into());
        }
        Self::possible_matches(&domain, list)
            .and_then(|res| Self::find_match(&domain, res))
    }

    pub fn suffix(&self) -> Option<&String> {
        match self.suffix {
            Some(ref suffix) => Some(suffix),
            None => None,
        }
    }

    pub fn is_private(&self) -> bool {
        match self.typ {
            Some(typ) => match typ {
                Type::Icann => false,
                Type::Private => true,
            },
            None => false,
        }
    }

    pub fn is_icann(&self) -> bool {
        match self.typ {
            Some(typ) => match typ {
                Type::Icann => true,
                Type::Private => false,
            },
            None => false,
        }
    }
}
<commit_msg>Implement domain parsing<commit_after>#![recursion_limit = "1024"]

#[macro_use]
extern crate error_chain;
extern crate reqwest;
extern crate idna;

pub mod errors;

#[cfg(test)]
mod tests;

use std::io::Read;
use std::fs::File;
use std::path::Path;
use std::collections::HashMap;

use errors::*;
use reqwest::IntoUrl;
use idna::domain_to_unicode;

#[derive(Debug)]
struct Suffix {
    rule: String,
    typ: Type,
}

#[derive(Debug)]
pub struct List {
    rules: HashMap<String, Vec<Suffix>>,
}

#[derive(Debug, Clone, Copy, PartialEq)]
enum Type {
    Icann,
    Private,
}

#[derive(Debug, Clone)]
pub struct Domain {
    full: String,
    typ: Option<Type>,
    suffix: Option<String>,
    registrable: Option<String>,
}

const OFFICIAL_URL: &'static str = "https://publicsuffix.org/list/public_suffix_list.dat";

impl List {
    fn append(&mut self, rule: &str, typ: Type) -> Result<()> {
        rule.rsplit('.').next()
            .ok_or(ErrorKind::InvalidRule(rule.into()).into())
            .and_then(|tld| {
                if tld.is_empty() {
                    return Err(ErrorKind::InvalidRule(rule.into()).into());
                }
                Ok(tld)})
            .and_then(|tld| {
                self.rules.entry(tld.into()).or_insert(Vec::new())
                    .push(Suffix {
                        rule: rule.into(),
                        typ: typ,
                    });
                Ok(())
            })
    }

    fn build<R: Read>(mut reader: R) -> Result<List> {
        let mut res = String::new();
        reader.read_to_string(&mut res)?;

        let mut typ = Type::Icann;

        let mut list = List {
            rules: HashMap::new(),
        };

        for line in res.lines() {
            match line {
                line if line.contains("BEGIN ICANN DOMAINS") => { typ = Type::Icann; }
                line if line.contains("BEGIN PRIVATE DOMAINS") => { typ = Type::Private; }
                line if line.starts_with("//") => { continue; }
                line => {
                    let rule = line.trim();
                    if rule.is_empty() {
                        continue;
                    }
                    list.append(rule, typ)?;
                }
            }
        }

        list.rules.shrink_to_fit();
        Ok(list)
    }

    pub fn from_url<U: IntoUrl>(url: U) -> Result<List> {
        reqwest::get(url)
            .map_err(|err| ErrorKind::Request(err).into())
            .and_then(Self::build)
    }

    pub fn from_path<P: AsRef<Path>>(path: P) -> Result<List> {
        File::open(path)
            .map_err(|err| ErrorKind::Io(err).into())
            .and_then(Self::build)
    }

    pub fn fetch() -> Result<List> {
        Self::from_url(OFFICIAL_URL)
    }

    fn find_type(&self, typ: Type) -> Vec<&String> {
        self.rules.values()
            .fold(Vec::new(), |mut res, ref suffices| {
                for suffix in *suffices {
                    if suffix.typ == typ {
                        res.push(&suffix.rule);
                    }
                }
                res
            })
    }

    pub fn icann(&self) -> Vec<&String> {
        self.find_type(Type::Icann)
    }

    pub fn private(&self) -> Vec<&String> {
        self.find_type(Type::Private)
    }

    pub fn all(&self) -> Vec<&String> {
        self.rules.values()
            .fold(Vec::new(), |mut res, ref suffices| {
                for suffix in *suffices {
                    res.push(&suffix.rule);
                }
                res
            })
    }
}

impl Domain {
    fn possible_matches<'a>(domain: &str, list: &'a List) -> Result<Vec<&'a Suffix>> {
        domain.rsplit('.').next()
            .ok_or(ErrorKind::InvalidDomain(domain.to_string()).into())
            .and_then(|tld| {
                if tld.is_empty() {
                    return Err(ErrorKind::InvalidDomain(domain.to_string()).into());
                }
                Ok(tld)})
            .and_then(|tld| {
                let candidates = match list.rules.get(tld) {
                    Some(candidates) => candidates,
                    None => { return Ok(Vec::new()); },
                };
                let candidates = candidates.iter()
                    .fold(Vec::new(), |mut res, ref suffix| {
                        res.push(*suffix);
                        res
                    });
                Ok(candidates)
            })
    }

    fn assemble(d_labels: &Vec<&str>, s_len: usize) -> String {
        d_labels[..s_len].iter().rev()
            .map(|part| *part)
            .collect::<Vec<_>>()
            .join(".")
    }

    fn find_match(domain: &str, candidates: Vec<&Suffix>) -> Result<Domain> {
        let d_labels: Vec<&str> = domain.split('.').rev().collect();

        let mut registrable = None;
        let mut suffix = None;
        let mut typ = None;
        let mut num_labels = 0;

        for candidate in candidates {
            let s_labels: Vec<&str> = candidate.rule.split('.').rev().collect();
            if s_labels.len() > d_labels.len() { continue; }
            for (i, label) in s_labels.iter().enumerate() {
                if *label == d_labels[i] || *label == "*" || label.trim_right_matches('!') == d_labels[i] {
                    if i == s_labels.len()-1 {
                        if s_labels.len() > num_labels {
                            num_labels = s_labels.len();
                            typ = Some(candidate.typ);
                            let s_len = if label.starts_with("!") {
                                s_labels.len()-1
                            } else {
                                s_labels.len()
                            };
                            suffix = Some(Self::assemble(&d_labels, s_len));
                            if d_labels.len() > s_len {
                                registrable = Some(Self::assemble(&d_labels, s_len+1));
                            }
                        }
                    }
                } else {
                    break;
                }
            }
        }

        Ok(Domain {
            full: domain.to_string(),
            typ: typ,
            suffix: suffix,
            registrable: registrable,
        })
    }

    pub fn parse(domain: &str, list: &List) -> Result<Domain> {
        let domain = domain.trim().trim_right_matches('.');
        let (domain, res) = domain_to_unicode(domain);
        if let Err(errors) = res {
            return Err(ErrorKind::Uts46(errors).into());
        }
        Self::possible_matches(&domain, list)
            .and_then(|res| Self::find_match(&domain, res))
    }

    pub fn root_domain(&self) -> Option<&String> {
        match self.registrable {
            Some(ref registrable) => Some(registrable),
            None => None,
        }
    }

    pub fn suffix(&self) -> Option<&String> {
        match self.suffix {
            Some(ref suffix) => Some(suffix),
            None => None,
        }
    }

    pub fn is_private(&self) -> bool {
        match self.typ {
            Some(typ) => match typ {
                Type::Icann => false,
                Type::Private => true,
            },
            None => false,
        }
    }

    pub fn is_icann(&self) -> bool {
        match self.typ {
            Some(typ) => match typ {
                Type::Icann => true,
                Type::Private => false,
            },
            None => false,
        }
    }
}
<|endoftext|>


<commit_before>#![no_std]

pub use elf_sections::{ElfSectionsTag, ElfSection, ElfSectionIter, ElfSectionType, ElfSectionFlags};
pub use elf_sections::{ELF_SECTION_WRITABLE, ELF_SECTION_ALLOCATED, ELF_SECTION_EXECUTABLE};
pub use memory_map::{MemoryMapTag, MemoryArea, MemoryAreaIter};

#[macro_use]
extern crate bitflags;

mod elf_sections;
mod memory_map;

pub unsafe fn load(address: usize) -> &'static BootInformation {
    let multiboot = &*(address as *const BootInformation);
    assert!(multiboot.has_valid_end_tag());
    multiboot
}

#[repr(C)]
pub struct BootInformation {
    pub total_size: u32,
    _reserved: u32,
    first_tag: Tag,
}

impl BootInformation {
    pub fn elf_sections_tag(&self) -> Option<&'static ElfSectionsTag> {
        self.get_tag(9).map(|tag| unsafe{&*(tag as *const Tag as *const ElfSectionsTag)})
    }

    pub fn memory_map_tag(&self) -> Option<&'static MemoryMapTag> {
        self.get_tag(6).map(|tag| unsafe{&*(tag as *const Tag as *const MemoryMapTag)})
    }

    fn has_valid_end_tag(&self) -> bool {
        const END_TAG: Tag = Tag{typ:0, size:8};

        let self_ptr = self as *const _;
        let end_tag_addr = self_ptr as usize + (self.total_size - END_TAG.size) as usize;
        let end_tag = unsafe{&*(end_tag_addr as *const Tag)};

        end_tag.typ == END_TAG.typ && end_tag.size == END_TAG.size
    }

    fn get_tag(&self, typ: u32) -> Option<&'static Tag> {
        self.tags().find(|tag| tag.typ == typ)
    }

    fn tags(&self) -> TagIter {
        TagIter{current: &self.first_tag as *const _}
    }
}

#[repr(C)]
struct Tag {
    typ: u32,
    size: u32,
    // tag specific fields
}

struct TagIter {
    current: *const Tag,
}

impl Iterator for TagIter {
    type Item = &'static Tag;

    fn next(&mut self) -> Option<&'static Tag> {
        match unsafe{&*self.current} {
            &Tag{typ:0, size:8} => None, // end tag
            tag => {
                // go to next tag
                let mut tag_addr = self.current as usize;
                tag_addr += tag.size as usize;
                tag_addr = ((tag_addr-1) & !0x7) + 0x8; //align at 8 byte
                self.current = tag_addr as *const _;

                Some(tag)
            },
        }
    }
}
<commit_msg>Add start_address and end_address methods<commit_after>#![no_std]

pub use elf_sections::{ElfSectionsTag, ElfSection, ElfSectionIter, ElfSectionType, ElfSectionFlags};
pub use elf_sections::{ELF_SECTION_WRITABLE, ELF_SECTION_ALLOCATED, ELF_SECTION_EXECUTABLE};
pub use memory_map::{MemoryMapTag, MemoryArea, MemoryAreaIter};

#[macro_use]
extern crate bitflags;

mod elf_sections;
mod memory_map;

pub unsafe fn load(address: usize) -> &'static BootInformation {
    let multiboot = &*(address as *const BootInformation);
    assert!(multiboot.has_valid_end_tag());
    multiboot
}

#[repr(C)]
pub struct BootInformation {
    pub total_size: u32,
    _reserved: u32,
    first_tag: Tag,
}

impl BootInformation {
    pub fn start_address(&self) -> usize {
        self as *const _ as usize
    }

    pub fn end_address(&self) -> usize {
        self.start_address() + self.total_size as usize
    }

    pub fn elf_sections_tag(&self) -> Option<&'static ElfSectionsTag> {
        self.get_tag(9).map(|tag| unsafe{&*(tag as *const Tag as *const ElfSectionsTag)})
    }

    pub fn memory_map_tag(&self) -> Option<&'static MemoryMapTag> {
        self.get_tag(6).map(|tag| unsafe{&*(tag as *const Tag as *const MemoryMapTag)})
    }

    fn has_valid_end_tag(&self) -> bool {
        const END_TAG: Tag = Tag{typ:0, size:8};

        let self_ptr = self as *const _;
        let end_tag_addr = self_ptr as usize + (self.total_size - END_TAG.size) as usize;
        let end_tag = unsafe{&*(end_tag_addr as *const Tag)};

        end_tag.typ == END_TAG.typ && end_tag.size == END_TAG.size
    }

    fn get_tag(&self, typ: u32) -> Option<&'static Tag> {
        self.tags().find(|tag| tag.typ == typ)
    }

    fn tags(&self) -> TagIter {
        TagIter{current: &self.first_tag as *const _}
    }
}

#[repr(C)]
struct Tag {
    typ: u32,
    size: u32,
    // tag specific fields
}

struct TagIter {
    current: *const Tag,
}

impl Iterator for TagIter {
    type Item = &'static Tag;

    fn next(&mut self) -> Option<&'static Tag> {
        match unsafe{&*self.current} {
            &Tag{typ:0, size:8} => None, // end tag
            tag => {
                // go to next tag
                let mut tag_addr = self.current as usize;
                tag_addr += tag.size as usize;
                tag_addr = ((tag_addr-1) & !0x7) + 0x8; //align at 8 byte
                self.current = tag_addr as *const _;

                Some(tag)
            },
        }
    }
}
<|endoftext|>


<commit_before>
//! Hubcaps wraps hyper with an interface for interacting with the Github API

extern crate hyper;
extern crate rustc_serialize;
extern crate url;

pub mod keys;
pub mod gists;
pub mod deployments;
pub mod errors;
pub mod issues;
pub mod labels;
pub mod rep;
pub mod releases;
pub mod repository;
pub mod statuses;
pub mod pullrequests;

use errors::Error;
use gists::{Gists, UserGists};
use hyper::Client;
use hyper::method::Method;
use hyper::header::{Authorization, UserAgent};
use hyper::status::StatusCode;
use repository::Repository;
use std::default::Default;
use std::fmt;
use std::io::Read;

/// alias for Result that infers hubcaps::Error as Err
pub type Result<T> = std::result::Result<T, Error>;

/// enum representation of github pull and issue state
pub enum State {
  Open,
  Closed,
  All
}

impl fmt::Display for State {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", match *self {
            State::Open   => "open",
            State::Closed => "closed",
            State::All    => "all"
        })
    }
}

impl Default for State {
    fn default() -> State {
        State::Open
    }
}

/// enum representation of Github list sorting options
pub enum SortDirection {
    Asc,
    Desc
}

impl fmt::Display for SortDirection {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", match *self {
            SortDirection::Asc => "asc",
            SortDirection::Desc => "desc"
        })
    }
}

impl Default for SortDirection {
    fn default() -> SortDirection {
        SortDirection::Asc
    }
}

/// Entry point interface for interacting with Github API
pub struct Github<'a> {
    host: &'static str,
    agent: &'static str,
    client: &'a Client,
    token: Option<&'static str>
}

impl<'a> Github<'a> {
    /// Create a new Github instance
    pub fn new(
        agent: &'static str, client: &'a Client, token: Option<&'static str>) -> Github<'a> {
        Github::host("https://api.github.com", agent, client, token)
    }

    /// Create a new Github instance hosted at a custom location
    pub fn host(
        host: &'static str, agent: &'static str,
        client: &'a Client, token: Option<&'static str>) -> Github<'a> {
        Github {
            host: host,
            agent: agent,
            client: client,
            token: token
        }
    }

    /// Return a reference to a Github reposistory
    pub fn repo(&self, owner: &'static str, repo: &'static str) -> Repository {
        Repository::new(self, owner, repo)
    }

    /// Return a reference to an interface that provides access to a user's gists
    pub fn user_gists(&self, owner: &'static str) -> UserGists {
        UserGists::new(self, owner)
    }

    /// Return a reference to an interface that provides access to the
    /// gists belonging to the owner of the token used to configure this client
    pub fn gists(&self) -> Gists {
        Gists::new(self)
    }

    fn request(
        &self, method: Method, uri: &str, body: Option<&'a [u8]>) -> Result<String> {
        let url = format!("{}{}", self.host, uri);
        let builder = self.client.request(method, &url).header(
            UserAgent(self.agent.to_owned())
        );
        let authenticated = match self.token {
            Some(token) =>
                builder.header(
                    Authorization(format!("token {}", token))
               ),
            _ =>
                builder
        };
        let mut res = match body {
            Some(ref bod) => authenticated.body(*bod).send().unwrap(),
            _ => authenticated.send().unwrap()
        };
        let mut body = String::new();
        res.read_to_string(&mut body).unwrap();
        match res.status {
            StatusCode::BadRequest
            | StatusCode::UnprocessableEntity
            | StatusCode::Unauthorized
            | StatusCode::NotFound
            | StatusCode::Forbidden => Err(
                Error::Fault { code: res.status, body: body }
            ),
            _ => Ok(body)
        }
    }

    fn get(&self, uri: &str) -> Result<String> {
        self.request(
            Method::Get,
            uri,
            None
        )
    }

    fn delete(&self, uri: &str) -> Result<()> {
        self.request(
            Method::Delete,
            uri,
            None
        ).map(|_| ())
    }

    fn post(&self, uri: &str, message: &[u8]) -> Result<String> {
        self.request(
            Method::Post,
            uri,
            Some(message)
        )
    }

    fn patch(&self, uri: &str, message: &[u8]) -> Result<String> {
        self.request(
            Method::Patch,
            uri,
            Some(message)
        )
    }

    fn put(&self, uri: &str, message: &[u8]) -> Result<String> {
        self.request(
            Method::Put,
            uri,
            Some(message)
        )
    }
}
<commit_msg>re-export rep type<commit_after>
//! Hubcaps wraps hyper with an interface for interacting with the Github API

extern crate hyper;
extern crate rustc_serialize;
extern crate url;

pub mod keys;
pub mod gists;
pub mod deployments;
pub mod errors;
pub mod issues;
pub mod labels;
pub mod rep;
pub mod releases;
pub mod repository;
pub mod statuses;
pub mod pullrequests;

pub use rep::*;
use errors::Error;
use gists::{Gists, UserGists};
use hyper::Client;
use hyper::method::Method;
use hyper::header::{Authorization, UserAgent};
use hyper::status::StatusCode;
use repository::Repository;
use std::default::Default;
use std::fmt;
use std::io::Read;

/// alias for Result that infers hubcaps::Error as Err
pub type Result<T> = std::result::Result<T, Error>;

/// enum representation of github pull and issue state
pub enum State {
  Open,
  Closed,
  All
}

impl fmt::Display for State {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", match *self {
            State::Open   => "open",
            State::Closed => "closed",
            State::All    => "all"
        })
    }
}

impl Default for State {
    fn default() -> State {
        State::Open
    }
}

/// enum representation of Github list sorting options
pub enum SortDirection {
    Asc,
    Desc
}

impl fmt::Display for SortDirection {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", match *self {
            SortDirection::Asc => "asc",
            SortDirection::Desc => "desc"
        })
    }
}

impl Default for SortDirection {
    fn default() -> SortDirection {
        SortDirection::Asc
    }
}

/// Entry point interface for interacting with Github API
pub struct Github<'a> {
    host: &'static str,
    agent: &'static str,
    client: &'a Client,
    token: Option<&'static str>
}

impl<'a> Github<'a> {
    /// Create a new Github instance
    pub fn new(
        agent: &'static str, client: &'a Client, token: Option<&'static str>) -> Github<'a> {
        Github::host("https://api.github.com", agent, client, token)
    }

    /// Create a new Github instance hosted at a custom location
    pub fn host(
        host: &'static str, agent: &'static str,
        client: &'a Client, token: Option<&'static str>) -> Github<'a> {
        Github {
            host: host,
            agent: agent,
            client: client,
            token: token
        }
    }

    /// Return a reference to a Github reposistory
    pub fn repo(&self, owner: &'static str, repo: &'static str) -> Repository {
        Repository::new(self, owner, repo)
    }

    /// Return a reference to an interface that provides access to a user's gists
    pub fn user_gists(&self, owner: &'static str) -> UserGists {
        UserGists::new(self, owner)
    }

    /// Return a reference to an interface that provides access to the
    /// gists belonging to the owner of the token used to configure this client
    pub fn gists(&self) -> Gists {
        Gists::new(self)
    }

    fn request(
        &self, method: Method, uri: &str, body: Option<&'a [u8]>) -> Result<String> {
        let url = format!("{}{}", self.host, uri);
        let builder = self.client.request(method, &url).header(
            UserAgent(self.agent.to_owned())
        );
        let authenticated = match self.token {
            Some(token) =>
                builder.header(
                    Authorization(format!("token {}", token))
               ),
            _ =>
                builder
        };
        let mut res = match body {
            Some(ref bod) => authenticated.body(*bod).send().unwrap(),
            _ => authenticated.send().unwrap()
        };
        let mut body = String::new();
        res.read_to_string(&mut body).unwrap();
        match res.status {
            StatusCode::BadRequest
            | StatusCode::UnprocessableEntity
            | StatusCode::Unauthorized
            | StatusCode::NotFound
            | StatusCode::Forbidden => Err(
                Error::Fault { code: res.status, body: body }
            ),
            _ => Ok(body)
        }
    }

    fn get(&self, uri: &str) -> Result<String> {
        self.request(
            Method::Get,
            uri,
            None
        )
    }

    fn delete(&self, uri: &str) -> Result<()> {
        self.request(
            Method::Delete,
            uri,
            None
        ).map(|_| ())
    }

    fn post(&self, uri: &str, message: &[u8]) -> Result<String> {
        self.request(
            Method::Post,
            uri,
            Some(message)
        )
    }

    fn patch(&self, uri: &str, message: &[u8]) -> Result<String> {
        self.request(
            Method::Patch,
            uri,
            Some(message)
        )
    }

    fn put(&self, uri: &str, message: &[u8]) -> Result<String> {
        self.request(
            Method::Put,
            uri,
            Some(message)
        )
    }
}
<|endoftext|>


<commit_before>/*!
This crate provides a number of conversion traits with more specific semantics than those provided by `as` or `From`/`Into`.

The goal with the traits provided here is to be more specific about what generic code can rely on, as well as provide reasonably self-describing alternatives to the standard `From`/`Into` traits.  For example, the although `T: From<U>` might be satisfied in generic code, this says nothing about what *kind* of conversion that represents.

In addition, `From`/`Into` provide no facility for a conversion failing, meaning that implementations may need to choose between conversions that may not be valid, or panicking; neither option is appealing in general.
*/

#![deny(missing_docs)]

// Exported macros.
pub mod macros;

pub use errors::{
    NoError, GeneralError, Unrepresentable,
    Underflow, Overflow,
    FloatError, RangeError,
    UnwrapOk, UnwrapOrInf, UnwrapOrInvalid, UnwrapOrSaturate,
};

/**
Publicly re-exports the most generally useful set of items.

Usage of the prelude should be considered **unstable**.  Although items will likely *not* be removed without bumping the major version, new items *may* be added, which could potentially cause name conflicts in user code.
*/
pub mod prelude {
    pub use super::{
        ApproxFrom, ApproxInto, ApproxWith,
        ValueFrom, ValueInto,
        UnwrapOk, UnwrapOrInf, UnwrapOrInvalid, UnwrapOrSaturate,
    };
}

macro_rules! as_item {
    ($($i:item)*) => {$($i)*};
}

macro_rules! item_for_each {
    (
        $( ($($arg:tt)*) ),* $(,)* => { $($exp:tt)* }
    ) => {
        macro_rules! body {
            $($exp)*
        }

        $(
            body! { $($arg)* }
        )*
    };
}

pub mod errors;
pub mod misc;

mod impls;

/**
This trait is used to perform a conversion that is permitted to approximate the result, but *not* to wrap or saturate the result to fit into the destination type's representable range.

# Details

All implementations of this trait must provide a conversion that can be separated into two logical steps: an approximation transform, and a representation transform.

The "approximation transform" step involves transforming the input value into an approximately equivalent value which is supported by the target type *without* taking the target type's representable range into account.  For example, this might involve rounding or truncating a floating point value to an integer, or reducing the accuracy of a floating point value.

The "representation transform" step *exactly* rewrites the value from the source type's binary representation into the destination type's binary representation.  This step *may not* transform the value in any way.  If the result of the approximation is not representable, the conversion *must* fail.

The major reason for this formulation is to exactly define what happens when converting between floating point and integer types.  Often, it is unclear what happens to floating point values beyond the range of the target integer type.  Do they saturate, wrap, or cause a failure?

With this formulation, it is well-defined: if a floating point value is outside the representable range, the conversion fails.  This allows users to distinguish between approximation and range violation, and act accordingly.
*/
pub trait ApproxFrom<Src, Scheme=DefaultApprox> where Scheme: ApproxScheme {
    /// The error type produced by a failed conversion.
    type Err;

    /// Convert the given value into an approximately equivalent representation.
    fn approx_from(src: Src) -> Result<Self, Self::Err>;
}

impl<Src, Scheme> ApproxFrom<Src, Scheme> for Src where Scheme: ApproxScheme {
    type Err = NoError;
    fn approx_from(src: Src) -> Result<Self, Self::Err> {
        Ok(src)
    }
}

/**
This is the dual of `ApproxFrom`; see that trait for information.
*/
pub trait ApproxInto<Dst, Scheme=DefaultApprox> where Scheme: ApproxScheme {
    /// The error type produced by a failed conversion.
    type Err;

    /// Convert the subject into an approximately equivalent representation.
    fn approx_into(self) -> Result<Dst, Self::Err>;
}

impl<Dst, Src, Scheme> ApproxInto<Dst, Scheme> for Src
where
    Dst: ApproxFrom<Src, Scheme>,
    Scheme: ApproxScheme,
{
    type Err = Dst::Err;
    fn approx_into(self) -> Result<Dst, Self::Err> {
        ApproxFrom::approx_from(self)
    }
}

/**
This extension trait exists to simplify using approximation implementations.

If there is more than one `ApproxFrom` implementation for a given type, a simple call to `approx_into` may not be uniquely resolvable.  Due to the position of the scheme parameter (on the trait itself), it is cumbersome to specify which scheme you wanted.

Hence this trait.
*/
pub trait ApproxWith<Dst> {
    /// Approximate the subject with the default scheme.
    fn approx(self) -> Result<Dst, Self::Err>
    where Self: Sized + ApproxInto<Dst> {
        self.approx_into()
    }

    /// Approximate the subject with a specific scheme.
    fn approx_with<Scheme=DefaultApprox>(self) -> Result<Dst, Self::Err>
    where
        Self: Sized + ApproxInto<Dst, Scheme>,
        Scheme: ApproxScheme,
    {
        self.approx_into()
    }
}

impl<T, Dst> ApproxWith<Dst> for T {}

/**
This trait is used to mark approximation scheme types.
*/
pub trait ApproxScheme {}

/**
The "default" approximation scheme.  This scheme does whatever would generally be expected of a lossy conversion, assuming no additional context or instruction is given.

This is a double-edged sword: it has the loosest semantics, but is far more likely to exist than more complicated approximation schemes.
*/
pub enum DefaultApprox {}
impl ApproxScheme for DefaultApprox {}

/**
This scheme is used to convert a value by "wrapping" it into a narrower range.

In abstract, this can be viewed as the opposite of rounding: rather than preserving the most significant bits of a value, it preserves the *least* significant bits of a value.
*/
pub enum Wrapping {}
impl ApproxScheme for Wrapping {}

// TODO: RoundToNearest, RoundToPosInf, RoundToNegInf, RoundToZero

/**
This trait is used to perform a conversion between different semantic types which might fail.

# Details

Typically, this should be used in cases where you are converting between values whose ranges and/or representations only partially overlap.  That the conversion may fail should be a reasonably expected outcome.  A standard example of this is converting from integers to enums of unitary variants.
*/
pub trait TryFrom<Src> {
    /// The error type produced by a failed conversion.
    type Err;

    /// Convert the given value into the subject type.
    fn try_from(src: Src) -> Result<Self, Self::Err>;
}

impl<Src> TryFrom<Src> for Src {
    type Err = NoError;
    fn try_from(src: Src) -> Result<Self, Self::Err> {
        Ok(src)
    }
}

/**
This is the dual of `TryFrom`; see that trait for information.
*/
pub trait TryInto<Dst> {
    /// The error type produced by a failed conversion.
    type Err;

    /// Convert the subject into the destination type.
    fn try_into(self) -> Result<Dst, Self::Err>;
}

impl<Src, Dst> TryInto<Dst> for Src where Dst: TryFrom<Src> {
    type Err = Dst::Err;
    fn try_into(self) -> Result<Dst, Self::Err> {
        TryFrom::try_from(self)
    }
}

/**
This trait is used to perform an exact, value-preserving conversion.

# Details

Implementations of this trait should be reflexive, associative and commutative (in the absence of conversion errors).  That is, all possible cycles of `ValueFrom` conversions (for which each "step" has a defined implementation) should produce the same result, with a given value either being "round-tripped" exactly, or an error being produced.
*/
pub trait ValueFrom<Src> {
    /// The error type produced by a failed conversion.
    type Err;

    /// Convert the given value into an exactly equivalent representation.
    fn value_from(src: Src) -> Result<Self, Self::Err>;
}

impl<Src> ValueFrom<Src> for Src {
    type Err = NoError;
    fn value_from(src: Src) -> Result<Self, Self::Err> {
        Ok(src)
    }
}

/**
This is the dual of `ValueFrom`; see that trait for information.
*/
pub trait ValueInto<Dst> {
    /// The error type produced by a failed conversion.
    type Err;

    /// Convert the subject into an exactly equivalent representation.
    fn value_into(self) -> Result<Dst, Self::Err>;
}

impl<Src, Dst> ValueInto<Dst> for Src where Dst: ValueFrom<Src> {
    type Err = Dst::Err;
    fn value_into(self) -> Result<Dst, Self::Err> {
        ValueFrom::value_from(self)
    }
}
<commit_msg>Added notice on possible future API changes.<commit_after>/*!
This crate provides a number of conversion traits with more specific semantics than those provided by `as` or `From`/`Into`.

The goal with the traits provided here is to be more specific about what generic code can rely on, as well as provide reasonably self-describing alternatives to the standard `From`/`Into` traits.  For example, the although `T: From<U>` might be satisfied in generic code, this says nothing about what *kind* of conversion that represents.

In addition, `From`/`Into` provide no facility for a conversion failing, meaning that implementations may need to choose between conversions that may not be valid, or panicking; neither option is appealing in general.

# API Stability Notice

The API of this crate is still not entirely decided.  In particular, errors may change in the future to carry the value that failed to convert (allowing it to be recovered).
*/

#![deny(missing_docs)]

// Exported macros.
pub mod macros;

pub use errors::{
    NoError, GeneralError, Unrepresentable,
    Underflow, Overflow,
    FloatError, RangeError,
    UnwrapOk, UnwrapOrInf, UnwrapOrInvalid, UnwrapOrSaturate,
};

/**
Publicly re-exports the most generally useful set of items.

Usage of the prelude should be considered **unstable**.  Although items will likely *not* be removed without bumping the major version, new items *may* be added, which could potentially cause name conflicts in user code.
*/
pub mod prelude {
    pub use super::{
        ApproxFrom, ApproxInto, ApproxWith,
        ValueFrom, ValueInto,
        UnwrapOk, UnwrapOrInf, UnwrapOrInvalid, UnwrapOrSaturate,
    };
}

macro_rules! as_item {
    ($($i:item)*) => {$($i)*};
}

macro_rules! item_for_each {
    (
        $( ($($arg:tt)*) ),* $(,)* => { $($exp:tt)* }
    ) => {
        macro_rules! body {
            $($exp)*
        }

        $(
            body! { $($arg)* }
        )*
    };
}

pub mod errors;
pub mod misc;

mod impls;

/**
This trait is used to perform a conversion that is permitted to approximate the result, but *not* to wrap or saturate the result to fit into the destination type's representable range.

# Details

All implementations of this trait must provide a conversion that can be separated into two logical steps: an approximation transform, and a representation transform.

The "approximation transform" step involves transforming the input value into an approximately equivalent value which is supported by the target type *without* taking the target type's representable range into account.  For example, this might involve rounding or truncating a floating point value to an integer, or reducing the accuracy of a floating point value.

The "representation transform" step *exactly* rewrites the value from the source type's binary representation into the destination type's binary representation.  This step *may not* transform the value in any way.  If the result of the approximation is not representable, the conversion *must* fail.

The major reason for this formulation is to exactly define what happens when converting between floating point and integer types.  Often, it is unclear what happens to floating point values beyond the range of the target integer type.  Do they saturate, wrap, or cause a failure?

With this formulation, it is well-defined: if a floating point value is outside the representable range, the conversion fails.  This allows users to distinguish between approximation and range violation, and act accordingly.
*/
pub trait ApproxFrom<Src, Scheme=DefaultApprox> where Scheme: ApproxScheme {
    /// The error type produced by a failed conversion.
    type Err;

    /// Convert the given value into an approximately equivalent representation.
    fn approx_from(src: Src) -> Result<Self, Self::Err>;
}

impl<Src, Scheme> ApproxFrom<Src, Scheme> for Src where Scheme: ApproxScheme {
    type Err = NoError;
    fn approx_from(src: Src) -> Result<Self, Self::Err> {
        Ok(src)
    }
}

/**
This is the dual of `ApproxFrom`; see that trait for information.
*/
pub trait ApproxInto<Dst, Scheme=DefaultApprox> where Scheme: ApproxScheme {
    /// The error type produced by a failed conversion.
    type Err;

    /// Convert the subject into an approximately equivalent representation.
    fn approx_into(self) -> Result<Dst, Self::Err>;
}

impl<Dst, Src, Scheme> ApproxInto<Dst, Scheme> for Src
where
    Dst: ApproxFrom<Src, Scheme>,
    Scheme: ApproxScheme,
{
    type Err = Dst::Err;
    fn approx_into(self) -> Result<Dst, Self::Err> {
        ApproxFrom::approx_from(self)
    }
}

/**
This extension trait exists to simplify using approximation implementations.

If there is more than one `ApproxFrom` implementation for a given type, a simple call to `approx_into` may not be uniquely resolvable.  Due to the position of the scheme parameter (on the trait itself), it is cumbersome to specify which scheme you wanted.

Hence this trait.
*/
pub trait ApproxWith<Dst> {
    /// Approximate the subject with the default scheme.
    fn approx(self) -> Result<Dst, Self::Err>
    where Self: Sized + ApproxInto<Dst> {
        self.approx_into()
    }

    /// Approximate the subject with a specific scheme.
    fn approx_with<Scheme=DefaultApprox>(self) -> Result<Dst, Self::Err>
    where
        Self: Sized + ApproxInto<Dst, Scheme>,
        Scheme: ApproxScheme,
    {
        self.approx_into()
    }
}

impl<T, Dst> ApproxWith<Dst> for T {}

/**
This trait is used to mark approximation scheme types.
*/
pub trait ApproxScheme {}

/**
The "default" approximation scheme.  This scheme does whatever would generally be expected of a lossy conversion, assuming no additional context or instruction is given.

This is a double-edged sword: it has the loosest semantics, but is far more likely to exist than more complicated approximation schemes.
*/
pub enum DefaultApprox {}
impl ApproxScheme for DefaultApprox {}

/**
This scheme is used to convert a value by "wrapping" it into a narrower range.

In abstract, this can be viewed as the opposite of rounding: rather than preserving the most significant bits of a value, it preserves the *least* significant bits of a value.
*/
pub enum Wrapping {}
impl ApproxScheme for Wrapping {}

// TODO: RoundToNearest, RoundToPosInf, RoundToNegInf, RoundToZero

/**
This trait is used to perform a conversion between different semantic types which might fail.

# Details

Typically, this should be used in cases where you are converting between values whose ranges and/or representations only partially overlap.  That the conversion may fail should be a reasonably expected outcome.  A standard example of this is converting from integers to enums of unitary variants.
*/
pub trait TryFrom<Src> {
    /// The error type produced by a failed conversion.
    type Err;

    /// Convert the given value into the subject type.
    fn try_from(src: Src) -> Result<Self, Self::Err>;
}

impl<Src> TryFrom<Src> for Src {
    type Err = NoError;
    fn try_from(src: Src) -> Result<Self, Self::Err> {
        Ok(src)
    }
}

/**
This is the dual of `TryFrom`; see that trait for information.
*/
pub trait TryInto<Dst> {
    /// The error type produced by a failed conversion.
    type Err;

    /// Convert the subject into the destination type.
    fn try_into(self) -> Result<Dst, Self::Err>;
}

impl<Src, Dst> TryInto<Dst> for Src where Dst: TryFrom<Src> {
    type Err = Dst::Err;
    fn try_into(self) -> Result<Dst, Self::Err> {
        TryFrom::try_from(self)
    }
}

/**
This trait is used to perform an exact, value-preserving conversion.

# Details

Implementations of this trait should be reflexive, associative and commutative (in the absence of conversion errors).  That is, all possible cycles of `ValueFrom` conversions (for which each "step" has a defined implementation) should produce the same result, with a given value either being "round-tripped" exactly, or an error being produced.
*/
pub trait ValueFrom<Src> {
    /// The error type produced by a failed conversion.
    type Err;

    /// Convert the given value into an exactly equivalent representation.
    fn value_from(src: Src) -> Result<Self, Self::Err>;
}

impl<Src> ValueFrom<Src> for Src {
    type Err = NoError;
    fn value_from(src: Src) -> Result<Self, Self::Err> {
        Ok(src)
    }
}

/**
This is the dual of `ValueFrom`; see that trait for information.
*/
pub trait ValueInto<Dst> {
    /// The error type produced by a failed conversion.
    type Err;

    /// Convert the subject into an exactly equivalent representation.
    fn value_into(self) -> Result<Dst, Self::Err>;
}

impl<Src, Dst> ValueInto<Dst> for Src where Dst: ValueFrom<Src> {
    type Err = Dst::Err;
    fn value_into(self) -> Result<Dst, Self::Err> {
        ValueFrom::value_from(self)
    }
}
<|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/.

//! Some utilities functions for processing texts.
//!
//! These functions were originally written for
//! [Crowbook](https://github.com/lise-henry/crowbook), but have
//! been published on a separate crate and under a less restrictive
//! license (MPL instead of LGPL) so they can be used elsewhere.
//!
//! # Example
//!
//! ```
//! use crowbook_text_processing::{
//!     FrenchFormatter,
//!     escape_html,
//!     escape_tex,
//!     remove_whitespaces,
//! };
//!
//! let s = " Some  string with  too much   whitespaces & around 1% \
//!          characters that might cause trouble to HTML or LaTeX.";
//! // Remove unnecessary whitespaces (but doesn't trim at is can have meaning)
//! let new_s = remove_whitespaces(s);
//! // Display to HTML
//! println!("for HTML: {}", escape_html(new_s.clone()));
//! // Display to LaTeX
//! println!("for LaTeX: {}", escape_tex(new_s));
//!
//! // Format whitespaces according to french typographic rules, using
//! // the appropriate non-breaking spaces where needed
//! let s = " Une chaîne en français ! On voudrait un résultat \
//!          « typographiquement correct ».";
//! let french = FrenchFormatter::new();
//! println!("for text: {}", french.format(s));
//! println!("for LaTeX: {}", escape_tex(french.format_tex(s)));
//! ```
//! # Requirements
//!
//! * `rustc >= 1.6.0`
//!
//! # Semantic versioning
//!
//! While not yet at version `1.0`, this crates tries to follows semantic
//! versioning in the following way:
//!
//! * an increase of `x` in `0.x.y` means breaking changes.
//! * an increase of `y` in `0.x.y` means non-breaking changes.
extern crate regex;
#[macro_use]
extern crate lazy_static;

pub mod escape;
pub mod clean;
pub mod french;

mod common;

pub use escape::{escape_html, escape_tex};
pub use clean::remove_whitespaces;
pub use clean::typographic_quotes;
pub use french::FrenchFormatter;
<commit_msg>Update lib.rs documentation<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/.

//! Some utilities functions for processing texts.
//!
//! These functions were originally written for
//! [Crowbook](https://github.com/lise-henry/crowbook), but have
//! been published on a separate crate and under a less restrictive
//! license (MPL instead of LGPL) so they can be used elsewhere.
//!
//! # Example
//!
//! ```
//! use crowbook_text_processing::{
//!     FrenchFormatter,
//!     escape_html,
//!     escape_tex,
//!     remove_whitespaces,
//!     typographic_quotes,
//! };
//!
//! let s = " Some  string with  too much   whitespaces & around 1% \
//!          characters that might cause trouble to HTML or LaTeX.";
//! // Remove unnecessary whitespaces (but doesn't trim at is can have meaning)
//! let new_s = remove_whitespaces(s);
//! // Display to HTML
//! println!("for HTML: {}", escape_html(new_s.clone()));
//! // Display to LaTeX
//! println!("for LaTeX: {}", escape_tex(new_s));
//!
//! // Replace quotes with typographic quotation marks
//! let s = r#"Some "quoted string" and 'another one'."#;
//! let new_s = typographic_quotes(s);
//! println!("for HTML: {}", escape_html(new_s));
//!
//!
//! // Format whitespaces according to french typographic rules, using
//! // the appropriate non-breaking spaces where needed
//! let s = " Une chaîne en français ! On voudrait un résultat \
//!          « typographiquement correct ».";
//! let french = FrenchFormatter::new();
//! println!("for text: {}", french.format(s));
//! println!("for LaTeX: {}", escape_tex(french.format_tex(s)));
//! ```
//! # Requirements
//!
//! * `rustc >= 1.6.0`
//!
//! # Semantic versioning
//!
//! While not yet at version `1.0`, this crates tries to follows semantic
//! versioning in the following way:
//!
//! * an increase of `x` in `0.x.y` means breaking changes.
//! * an increase of `y` in `0.x.y` means non-breaking changes.
extern crate regex;
#[macro_use]
extern crate lazy_static;

pub mod escape;
pub mod clean;
pub mod french;

mod common;

pub use escape::{escape_html, escape_tex};
pub use clean::remove_whitespaces;
pub use clean::typographic_quotes;
pub use french::FrenchFormatter;
<|endoftext|>