<commit_before>extern crate nalgebra;
extern crate rand;
use rand::*;
use nalgebra::*;

mod csv;
mod koe;
mod central_body;
mod tickable;
use std::f64::consts::PI;
use std::rc::*;
use central_body::*;
use csv::*;
use koe::*;

#[test]
fn koe_invariance() {
    let iterations = 10000;
    let eps = 1.0e-3;
    let mut a_ok = 0;
    let mut e_ok = 0;
    let mut inc_ok = 0;
    let mut lan_ok = 0;
    let mut ap_ok = 0;
    let mut m0_ok = 0;
    for _ in 0..iterations {
        let cb = get_random_cb();
        let koe0 = get_random_koe(Rc::<CentralBody>::new(cb));
        let csv0 = koe0.to_csv();
        let koe1 = csv0.to_koe();
        if approx_eq_eps(&koe0.a, &koe1.a, &eps) {
            a_ok += 1;
        }
        if approx_eq_eps(&koe0.e, &koe1.e, &eps) {
            e_ok += 1;
        }
        if approx_eq_eps(&koe0.inc, &koe1.inc, &eps) {
            inc_ok += 1;
        }
        if approx_eq_eps(&koe0.lan, &koe1.lan, &eps) {
            lan_ok += 1;
        }
        if approx_eq_eps(&koe0.ap, &koe1.ap, &eps) {
            ap_ok += 1;
        }
        if approx_eq_eps(&koe0.m0, &koe1.m0, &eps) {
            m0_ok += 1;
        }
    }
    let a_ok_f = a_ok as f32 / iterations as f32;
    let e_ok_f = e_ok as f32 / iterations as f32;
    let inc_ok_f = inc_ok as f32 / iterations as f32;
    let lan_ok_f = lan_ok as f32 / iterations as f32;
    let ap_ok_f = ap_ok as f32 / iterations as f32;
    let m0_ok_f = m0_ok as f32 / iterations as f32;
    let threshold = 0.99;
    let mut failed = false;

    println!("");
    println!("eps = {}", eps);
    println!("threshold = {}", threshold);
    if a_ok_f < threshold {
        println!("a_ok_f = {}", a_ok_f);
        if !failed {
            failed = true;
        }
    }
    if e_ok_f < threshold {
        println!("e_ok_f = {}", e_ok_f);
        if !failed {
            failed = true;
        }
    }
    if inc_ok_f < threshold {
        println!("inc_ok_f = {}", inc_ok_f);
        if !failed {
            failed = true;
        }
    }
    if ap_ok_f < threshold {
        println!("ap_ok_f = {}", ap_ok_f);
        if !failed {
            failed = true;
        }
    }
    if m0_ok_f < threshold {
        println!("m0_ok_f = {}", m0_ok_f);
        if !failed {
            failed = true;
        }
    }
    if failed {
        panic!("success rate for one of the parameters is below threshold");
    }
}

#[test]
fn csv_invariance() {
    let iterations = 10000;
    let eps = 1.0e-3;
    let mut r_ok = 0;
    let mut v_ok = 0;
    for _ in 0..iterations {
        let cb = get_random_cb();
        let koe0 = get_random_koe(Rc::<CentralBody>::new(cb));
        let csv0 = koe0.to_csv();
        let koe1 = csv0.to_koe();
        let csv1 = koe1.to_csv();
        if csv0.r.approx_eq_eps(&csv1.r, &eps) {
            r_ok += 1;
        }
        if csv0.v.approx_eq_eps(&csv1.v, &eps) {
            v_ok += 1;
        }
    }
    let r_ok_f = r_ok as f32 / iterations as f32;
    let v_ok_f = v_ok as f32 / iterations as f32;
    let threshold = 0.99;
    let mut failed = false;

    println!("");
    println!("eps = {}", eps);
    println!("threshold = {}", threshold);
    if r_ok_f < threshold {
        println!("r_ok_f = {}", r_ok_f);
        if !failed {
            failed = true;
        }
    }
    if v_ok_f < threshold {
        println!("v_ok_f = {}", v_ok_f);
        if !failed {
            failed = true;
        }
    }
    if failed {
        panic!("success rate for some of the parameters is below the threshold");
    }
}

fn get_random_cb() -> CentralBody {
    let mut rng = thread_rng();
    let up = normalize(
            &Vec3::new( // Up vector
                rng.gen_range(0.1, 1.0),
                rng.gen_range(0.1, 1.0),
                rng.gen_range(0.1, 1.0)
                )
        );
    let x_axis = Vec3::<f64>::new(1.0, 0.0, 0.0);
    let reference = normalize(&cross(&x_axis, &up));
    CentralBody::new(
        rng.gen_range(1.0e9, 1.0e25), // Standard Gravitational Parameter
        up,
        reference
    )
}

fn get_random_koe(cb: Rc<CentralBody>) -> KOE {
    let mut rng = thread_rng();
    let ecc = rng.gen_range(0.0, 1.0);
    let inc = rng.gen_range(0.0, PI);
    let mut lan = rng.gen_range(0.0, 2.0*PI);
    let mut ap = rng.gen_range(0.0, 2.0*PI);
    if approx_eq(&ecc, &0.0) {
        ap = 0.0;
    }
    if approx_eq(&inc, &0.0) {
        lan = 0.0;
        ap = 0.0;
        if !approx_eq(&ecc, &0.0) {
            ap = rng.gen_range(0.0, 2.0*PI);
        }
    }
    KOE::new(
        rng.gen_range(1.0, 1.0e10), // Semi major axis
        ecc, // Eccentricity
        inc, // Inclination
        lan, // Longitude of Ascending Node
        ap,  // Argument of Periapsis
        rng.gen_range(-PI, PI), // Mean anomaly
        cb
    )
}
<commit_msg>Minor fix to previous commit<commit_after>extern crate nalgebra;
extern crate rand;
use rand::*;
use nalgebra::*;

mod csv;
mod koe;
mod central_body;
mod tickable;
use std::f64::consts::PI;
use std::rc::*;
use central_body::*;
use csv::*;
use koe::*;
use tickable::*;

#[test]
fn koe_invariance() {
    let iterations = 10000;
    let eps = 1.0e-3;
    let mut a_ok = 0;
    let mut e_ok = 0;
    let mut inc_ok = 0;
    let mut lan_ok = 0;
    let mut ap_ok = 0;
    let mut m0_ok = 0;
    for _ in 0..iterations {
        let cb = get_random_cb();
        let koe0 = get_random_koe(Rc::<CentralBody>::new(cb));
        let csv0 = koe0.to_csv();
        let koe1 = csv0.to_koe();
        if approx_eq_eps(&koe0.a, &koe1.a, &eps) {
            a_ok += 1;
        }
        if approx_eq_eps(&koe0.e, &koe1.e, &eps) {
            e_ok += 1;
        }
        if approx_eq_eps(&koe0.inc, &koe1.inc, &eps) {
            inc_ok += 1;
        }
        if approx_eq_eps(&koe0.lan, &koe1.lan, &eps) {
            lan_ok += 1;
        }
        if approx_eq_eps(&koe0.ap, &koe1.ap, &eps) {
            ap_ok += 1;
        }
        if approx_eq_eps(&koe0.m0, &koe1.m0, &eps) {
            m0_ok += 1;
        }
    }
    let a_ok_f = a_ok as f32 / iterations as f32;
    let e_ok_f = e_ok as f32 / iterations as f32;
    let inc_ok_f = inc_ok as f32 / iterations as f32;
    let lan_ok_f = lan_ok as f32 / iterations as f32;
    let ap_ok_f = ap_ok as f32 / iterations as f32;
    let m0_ok_f = m0_ok as f32 / iterations as f32;
    let threshold = 0.99;
    let mut failed = false;

    println!("");
    println!("eps = {}", eps);
    println!("threshold = {}", threshold);
    if a_ok_f < threshold {
        println!("a_ok_f = {}", a_ok_f);
        if !failed {
            failed = true;
        }
    }
    if e_ok_f < threshold {
        println!("e_ok_f = {}", e_ok_f);
        if !failed {
            failed = true;
        }
    }
    if inc_ok_f < threshold {
        println!("inc_ok_f = {}", inc_ok_f);
        if !failed {
            failed = true;
        }
    }
    if ap_ok_f < threshold {
        println!("ap_ok_f = {}", ap_ok_f);
        if !failed {
            failed = true;
        }
    }
    if m0_ok_f < threshold {
        println!("m0_ok_f = {}", m0_ok_f);
        if !failed {
            failed = true;
        }
    }
    if failed {
        panic!("success rate for one of the parameters is below threshold");
    }
}

#[test]
fn csv_invariance() {
    let iterations = 10000;
    let eps = 1.0e-3;
    let mut r_ok = 0;
    let mut v_ok = 0;
    for _ in 0..iterations {
        let cb = get_random_cb();
        let koe0 = get_random_koe(Rc::<CentralBody>::new(cb));
        let csv0 = koe0.to_csv();
        let koe1 = csv0.to_koe();
        let csv1 = koe1.to_csv();
        if csv0.r.approx_eq_eps(&csv1.r, &eps) {
            r_ok += 1;
        }
        if csv0.v.approx_eq_eps(&csv1.v, &eps) {
            v_ok += 1;
        }
    }
    let r_ok_f = r_ok as f32 / iterations as f32;
    let v_ok_f = v_ok as f32 / iterations as f32;
    let threshold = 0.99;
    let mut failed = false;

    println!("");
    println!("eps = {}", eps);
    println!("threshold = {}", threshold);
    if r_ok_f < threshold {
        println!("r_ok_f = {}", r_ok_f);
        if !failed {
            failed = true;
        }
    }
    if v_ok_f < threshold {
        println!("v_ok_f = {}", v_ok_f);
        if !failed {
            failed = true;
        }
    }
    if failed {
        panic!("success rate for some of the parameters is below the threshold");
    }
}

fn get_random_cb() -> CentralBody {
    let mut rng = thread_rng();
    let up = normalize(
            &Vec3::new( // Up vector
                rng.gen_range(0.1, 1.0),
                rng.gen_range(0.1, 1.0),
                rng.gen_range(0.1, 1.0)
                )
        );
    let x_axis = Vec3::<f64>::new(1.0, 0.0, 0.0);
    let reference = normalize(&cross(&x_axis, &up));
    CentralBody::new(
        rng.gen_range(1.0e9, 1.0e25), // Standard Gravitational Parameter
        up,
        reference
    )
}

fn get_random_koe(cb: Rc<CentralBody>) -> KOE {
    let mut rng = thread_rng();
    let ecc = rng.gen_range(0.0, 1.0);
    let inc = rng.gen_range(0.0, PI);
    let mut lan = rng.gen_range(0.0, 2.0*PI);
    let mut ap = rng.gen_range(0.0, 2.0*PI);
    if approx_eq(&ecc, &0.0) {
        ap = 0.0;
    }
    if approx_eq(&inc, &0.0) {
        lan = 0.0;
        ap = 0.0;
        if !approx_eq(&ecc, &0.0) {
            ap = rng.gen_range(0.0, 2.0*PI);
        }
    }
    KOE::new(
        rng.gen_range(1.0, 1.0e10), // Semi major axis
        ecc, // Eccentricity
        inc, // Inclination
        lan, // Longitude of Ascending Node
        ap,  // Argument of Periapsis
        rng.gen_range(-PI, PI), // Mean anomaly
        cb
    )
}
<|endoftext|>


<commit_before>// Copyright 2016 Hroi Sigurdsson
//
// Licensed under the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>.
// This file may not be copied, modified, or distributed except according to those terms.

#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]

#![feature(test)]
#![feature(alloc)]

//! # Fast IP lookup table for IPv4/IPv6 prefixes
//!
//! This crate provides a datastructure for fast IP address lookups.
//! It aims at fast lookup times, and a small memory footprint.
//! A full IPv4 BGP table of more than 600k entries fits in less than 5 MB. A full IPv6 BGP table of more than 25k entries fits in less than 1 MB.
//!
//! Longest match lookups on full BGP IP tables take on the order of 100ns.
//!
//! The internal datastructure is based on the Tree-bitmap algorithm described by W. Eatherton, Z. Dittia, G. Varghes.
//!

#[macro_use]
#[cfg(test)]
extern crate lazy_static;
extern crate alloc; // for RawVec
extern crate test;
use std::net::{Ipv4Addr, Ipv6Addr};
use std::marker::PhantomData;

mod tree_bitmap;
use tree_bitmap::TreeBitmap;

mod address;
use address::Address;

///The operations defined on the lookup table.
pub trait IpLookupTableOps<Addr, T> {
    /// Insert a value for the prefix designated by ip and masklen. If prefix existed previously, the old value is returned.
    /// # Example
    /// ```
    /// use treebitmap::{IpLookupTable, IpLookupTableOps};
    /// use std::net::Ipv6Addr;
    ///
    /// let mut table: IpLookupTable<Ipv6Addr,&str> = IpLookupTable::new();
    /// let prefix = Ipv6Addr::new(0x2001, 0xdb8, 0xdead, 0xbeef, 0, 0, 0, 0);
    /// let masklen = 32;
    ///
    /// assert_eq!(table.insert(prefix, masklen, "foo"), None);
    /// // Insert duplicate
    /// assert_eq!(table.insert(prefix, masklen, "bar"), Some("foo"));
    /// ```
    fn insert(&mut self, ip: Addr, masklen: u32, value: T) -> Option<T>;

    /// Remove an entry from the lookup table. If the prefix existed previously, the value is returned.
    /// # Example
    /// ```
    /// use treebitmap::{IpLookupTable, IpLookupTableOps};
    /// use std::net::Ipv6Addr;
    ///
    /// let mut table: IpLookupTable<Ipv6Addr,&str> = IpLookupTable::new();
    /// let prefix = Ipv6Addr::new(0x2001, 0xdb8, 0xdead, 0xbeef, 0, 0, 0, 0);
    /// let masklen = 32;
    /// table.insert(prefix, masklen, "foo");
    ///
    /// assert_eq!(table.remove(prefix, masklen), Some("foo"));
    /// // Remove non-existant
    /// assert_eq!(table.remove(prefix, masklen), None);
    /// ```
    fn remove(&mut self, ip: Addr, masklen: u32) -> Option<T>;

    /// Perform exact match lookup of ```ip```/```masklen``` and return the value.
    /// # Example
    /// ```
    /// use treebitmap::{IpLookupTable, IpLookupTableOps};
    /// use std::net::Ipv6Addr;
    ///
    /// let mut table: IpLookupTable<Ipv6Addr,&str> = IpLookupTable::new();
    /// let prefix = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0);
    /// let masklen = 32;
    /// table.insert(prefix, masklen, "foo");
    ///
    /// assert_eq!(table.exact_match(prefix, masklen), Some(&"foo"));
    /// // differing mask
    /// assert_eq!(table.exact_match(prefix, 48), None);
    /// ```
    fn exact_match(&self, ip: Addr, masklen: u32) -> Option<&T>;

    /// Perform longest match lookup of ```ip``` and return the best matching prefix, designated by ip, masklen, along with its value.
    /// # Example
    /// ```
    /// use treebitmap::{IpLookupTable, IpLookupTableOps};
    /// use std::net::Ipv6Addr;
    ///
    /// let mut table: IpLookupTable<Ipv6Addr,&str> = IpLookupTable::new();
    /// let less_specific = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0);
    /// let more_specific = Ipv6Addr::new(0x2001, 0xdb8, 0xdead, 0, 0, 0, 0, 0);
    /// table.insert(less_specific, 32, "foo");
    /// table.insert(more_specific, 48, "bar");
    ///
    /// let lookupip = Ipv6Addr::new(0x2001, 0xdb8, 0xdead, 0xbeef, 0xcafe, 0xbabe, 0, 1);
    /// let result = table.longest_match(lookupip);
    /// assert_eq!(result, Some((more_specific, 48, &"bar")));
    ///
    /// let lookupip = Ipv6Addr::new(0x2001, 0xdb8, 0xcafe, 0xf00, 0xf00, 0xf00, 0, 1);
    /// let result = table.longest_match(lookupip);
    /// assert_eq!(result, Some((less_specific, 32, &"foo")));
    /// ```
    fn longest_match(&self, ip: Addr) -> Option<(Addr, u32, &T)>;

    /// Returns iterator over prefixes and values.
    /// # Example
    /// ```
    /// use treebitmap::{IpLookupTable, IpLookupTableOps};
    /// use std::net::Ipv6Addr;
    ///
    /// let mut table: IpLookupTable<Ipv6Addr,&str> = IpLookupTable::new();
    /// let less_specific = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0);
    /// let more_specific = Ipv6Addr::new(0x2001, 0xdb8, 0xdead, 0, 0, 0, 0, 0);
    /// table.insert(less_specific, 32, "foo");
    /// table.insert(more_specific, 48, "bar");
    ///
    /// let mut iter = table.iter();
    /// assert_eq!(iter.next(), Some((less_specific, 32, &"foo")));
    /// assert_eq!(iter.next(), Some((more_specific, 48, &"bar")));
    /// assert_eq!(iter.next(), None);
    /// ```
    fn iter(&self) -> Iter<Addr, T>;

    /// Mutable version of iter()
    fn iter_mut(&self) -> IterMut<Addr, T>;
}

/// A fast, compressed IP lookup table.
pub struct IpLookupTable<A, T> {
    inner: TreeBitmap<T>,
    _addrtype: PhantomData<A>,
}

impl<A, T> IpLookupTable<A, T> {
    /// Initialize an empty lookup table with no preallocation.
    pub fn new() -> Self {
        IpLookupTable {
            inner: TreeBitmap::new(),
            _addrtype: PhantomData,
        }
    }

    /// Initialize an empty lookup table with pre-allocated buffers.
    pub fn with_capacity(n: usize) -> Self {
        IpLookupTable {
            inner: TreeBitmap::with_capacity(n),
            _addrtype: PhantomData,
        }
    }

    /// Return the bytes used by nodes and results.
    pub fn mem_usage(&self) -> (usize, usize) {
        self.inner.mem_usage()
    }
}

/// Iterates over prefixes and associated values. The prefixes are returned in "tree"-order.
pub struct Iter<'a, A, T: 'a> {
    inner: tree_bitmap::Iter<'a, T>,
    _addrtype: PhantomData<A>,
}

/// Mutable iterates over prefixes and associated values. The prefixes are returned in "tree"-order.
pub struct IterMut<'a, A, T: 'a> {
    inner: tree_bitmap::IterMut<'a, T>,
    _addrtype: PhantomData<A>,
}

/// Converts ```IpLookupTable``` into an iterator. The prefixes are returned in "tree"-order.
pub struct IntoIter<A, T> {
    inner: tree_bitmap::IntoIter<T>,
    _addrtype: PhantomData<A>,
}

macro_rules! impl_ops {
    ($addr_type:ty) => {
        impl<T: Sized> IpLookupTableOps<$addr_type, T> for IpLookupTable<$addr_type, T> {

            fn insert(&mut self, ip: $addr_type, masklen: u32, value: T) -> Option<T>{
                self.inner.insert(&ip.nibbles(), masklen, value)
            }

            fn remove(&mut self, ip: $addr_type, masklen: u32) -> Option<T>{
                self.inner.remove(&ip.nibbles(), masklen)
            }

            fn exact_match(&self, ip: $addr_type, masklen: u32) -> Option<&T> {
                self.inner.exact_match(&ip.nibbles(), masklen)
            }

            fn longest_match(&self, ip: $addr_type) -> Option<($addr_type, u32, &T)> {
                match self.inner.longest_match(&ip.nibbles()) {
                    Some((bits_matched,value)) => Some((ip.mask(bits_matched), bits_matched, value)),
                    None => None
                }
            }

            fn iter(&self) -> Iter<$addr_type,T> {
                Iter{
                    inner: self.inner.iter(),
                    _addrtype: PhantomData,
                }
            }

            fn iter_mut(&self) -> IterMut<$addr_type,T> {
                IterMut{
                    inner: self.inner.iter_mut(),
                    _addrtype: PhantomData,
                }
            }
        }

        impl<'a, T: 'a> Iterator for Iter<'a, $addr_type, T> {
            type Item = ($addr_type, u32, &'a T);

            fn next(&mut self) -> Option<Self::Item> {
                match self.inner.next() {
                    Some((nibbles, masklen, value)) => {
                        Some((Address::from_nibbles(&nibbles[..]), masklen, value))
                    },
                    None => None,
                }
            }
        }

        impl<'a, T: 'a> Iterator for IterMut<'a, $addr_type, T> {
            type Item = ($addr_type, u32, &'a mut T);

            fn next(&mut self) -> Option<Self::Item> {
                match self.inner.next() {
                    Some((nibbles, masklen, value)) => {
                        Some((Address::from_nibbles(&nibbles[..]), masklen, value))
                    },
                    None => None,
                }
            }
        }

        impl<'a, T: 'a> Iterator for IntoIter<$addr_type, T> {
            type Item = ($addr_type, u32, T);

            fn next(&mut self) -> Option<Self::Item> {
                match self.inner.next() {
                    Some((nibbles, masklen, value)) => {
                        Some((Address::from_nibbles(&nibbles[..]), masklen, value))
                    },
                    None => None,
                }
            }
        }

        impl<T> IntoIterator for IpLookupTable<$addr_type, T> {
            type Item = ($addr_type, u32, T);
            type IntoIter = IntoIter<$addr_type,T>;

            fn into_iter(self) -> IntoIter<$addr_type,T> {
                IntoIter {
                    inner: self.inner.into_iter(),
                    _addrtype: PhantomData,
                }
            }
        }
    }
}

impl_ops!(Ipv4Addr);
impl_ops!(Ipv6Addr);

#[cfg(test)]
mod tests;
#[cfg(all(test, feature = "full-bgp-tests"))]
mod full_bgp_tests;

<commit_msg>wording<commit_after>// Copyright 2016 Hroi Sigurdsson
//
// Licensed under the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>.
// This file may not be copied, modified, or distributed except according to those terms.

#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]

#![feature(test)]
#![feature(alloc)]

//! # Fast IP lookup table for IPv4/IPv6 prefixes
//!
//! This crate provides a datastructure for fast IP address lookups.
//! It aims at fast lookup times, and a small memory footprint.
//! A full IPv4 BGP table of more than 600k entries fits in less than 5 MB. A full IPv6 BGP table of more than 25k entries fits in less than 1 MB.
//!
//! Longest match lookups on full BGP IP tables take on the order of 100ns.
//!
//! The internal datastructure is based on the Tree-bitmap algorithm described by W. Eatherton, Z. Dittia, G. Varghes.
//!

#[macro_use]
#[cfg(test)]
extern crate lazy_static;
extern crate alloc; // for RawVec
extern crate test;
use std::net::{Ipv4Addr, Ipv6Addr};
use std::marker::PhantomData;

mod tree_bitmap;
use tree_bitmap::TreeBitmap;

mod address;
use address::Address;

///The operations defined on the lookup table.
pub trait IpLookupTableOps<Addr, T> {
    /// Insert a value for the prefix designated by ip and masklen. If prefix existed previously, the old value is returned.
    /// # Example
    /// ```
    /// use treebitmap::{IpLookupTable, IpLookupTableOps};
    /// use std::net::Ipv6Addr;
    ///
    /// let mut table: IpLookupTable<Ipv6Addr,&str> = IpLookupTable::new();
    /// let prefix = Ipv6Addr::new(0x2001, 0xdb8, 0xdead, 0xbeef, 0, 0, 0, 0);
    /// let masklen = 32;
    ///
    /// assert_eq!(table.insert(prefix, masklen, "foo"), None);
    /// // Insert duplicate
    /// assert_eq!(table.insert(prefix, masklen, "bar"), Some("foo"));
    /// ```
    fn insert(&mut self, ip: Addr, masklen: u32, value: T) -> Option<T>;

    /// Remove an entry from the lookup table. If the prefix existed previously, the value is returned.
    /// # Example
    /// ```
    /// use treebitmap::{IpLookupTable, IpLookupTableOps};
    /// use std::net::Ipv6Addr;
    ///
    /// let mut table: IpLookupTable<Ipv6Addr,&str> = IpLookupTable::new();
    /// let prefix = Ipv6Addr::new(0x2001, 0xdb8, 0xdead, 0xbeef, 0, 0, 0, 0);
    /// let masklen = 32;
    /// table.insert(prefix, masklen, "foo");
    ///
    /// assert_eq!(table.remove(prefix, masklen), Some("foo"));
    /// // Remove non-existant
    /// assert_eq!(table.remove(prefix, masklen), None);
    /// ```
    fn remove(&mut self, ip: Addr, masklen: u32) -> Option<T>;

    /// Perform exact match lookup of ```ip```/```masklen``` and return the value.
    /// # Example
    /// ```
    /// use treebitmap::{IpLookupTable, IpLookupTableOps};
    /// use std::net::Ipv6Addr;
    ///
    /// let mut table: IpLookupTable<Ipv6Addr,&str> = IpLookupTable::new();
    /// let prefix = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0);
    /// let masklen = 32;
    /// table.insert(prefix, masklen, "foo");
    ///
    /// assert_eq!(table.exact_match(prefix, masklen), Some(&"foo"));
    /// // differing mask
    /// assert_eq!(table.exact_match(prefix, 48), None);
    /// ```
    fn exact_match(&self, ip: Addr, masklen: u32) -> Option<&T>;

    /// Perform longest match lookup of ```ip``` and return the best matching prefix, designated by ip, masklen, along with its value.
    /// # Example
    /// ```
    /// use treebitmap::{IpLookupTable, IpLookupTableOps};
    /// use std::net::Ipv6Addr;
    ///
    /// let mut table: IpLookupTable<Ipv6Addr,&str> = IpLookupTable::new();
    /// let less_specific = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0);
    /// let more_specific = Ipv6Addr::new(0x2001, 0xdb8, 0xdead, 0, 0, 0, 0, 0);
    /// table.insert(less_specific, 32, "foo");
    /// table.insert(more_specific, 48, "bar");
    ///
    /// let lookupip = Ipv6Addr::new(0x2001, 0xdb8, 0xdead, 0xbeef, 0xcafe, 0xbabe, 0, 1);
    /// let result = table.longest_match(lookupip);
    /// assert_eq!(result, Some((more_specific, 48, &"bar")));
    ///
    /// let lookupip = Ipv6Addr::new(0x2001, 0xdb8, 0xcafe, 0xf00, 0xf00, 0xf00, 0, 1);
    /// let result = table.longest_match(lookupip);
    /// assert_eq!(result, Some((less_specific, 32, &"foo")));
    /// ```
    fn longest_match(&self, ip: Addr) -> Option<(Addr, u32, &T)>;

    /// Returns iterator over prefixes and values.
    /// # Example
    /// ```
    /// use treebitmap::{IpLookupTable, IpLookupTableOps};
    /// use std::net::Ipv6Addr;
    ///
    /// let mut table: IpLookupTable<Ipv6Addr,&str> = IpLookupTable::new();
    /// let less_specific = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0);
    /// let more_specific = Ipv6Addr::new(0x2001, 0xdb8, 0xdead, 0, 0, 0, 0, 0);
    /// table.insert(less_specific, 32, "foo");
    /// table.insert(more_specific, 48, "bar");
    ///
    /// let mut iter = table.iter();
    /// assert_eq!(iter.next(), Some((less_specific, 32, &"foo")));
    /// assert_eq!(iter.next(), Some((more_specific, 48, &"bar")));
    /// assert_eq!(iter.next(), None);
    /// ```
    fn iter(&self) -> Iter<Addr, T>;

    /// Mutable version of iter()
    fn iter_mut(&self) -> IterMut<Addr, T>;
}

/// A fast, compressed IP lookup table.
pub struct IpLookupTable<A, T> {
    inner: TreeBitmap<T>,
    _addrtype: PhantomData<A>,
}

impl<A, T> IpLookupTable<A, T> {
    /// Initialize an empty lookup table with no preallocation.
    pub fn new() -> Self {
        IpLookupTable {
            inner: TreeBitmap::new(),
            _addrtype: PhantomData,
        }
    }

    /// Initialize an empty lookup table with pre-allocated buffers.
    pub fn with_capacity(n: usize) -> Self {
        IpLookupTable {
            inner: TreeBitmap::with_capacity(n),
            _addrtype: PhantomData,
        }
    }

    /// Return the bytes used by nodes and results.
    pub fn mem_usage(&self) -> (usize, usize) {
        self.inner.mem_usage()
    }
}

/// Iterator over prefixes and associated values. The prefixes are returned in "tree"-order.
pub struct Iter<'a, A, T: 'a> {
    inner: tree_bitmap::Iter<'a, T>,
    _addrtype: PhantomData<A>,
}

/// Mutable iterator over prefixes and associated values. The prefixes are returned in "tree"-order.
pub struct IterMut<'a, A, T: 'a> {
    inner: tree_bitmap::IterMut<'a, T>,
    _addrtype: PhantomData<A>,
}

/// Converts ```IpLookupTable``` into an iterator. The prefixes are returned in "tree"-order.
pub struct IntoIter<A, T> {
    inner: tree_bitmap::IntoIter<T>,
    _addrtype: PhantomData<A>,
}

macro_rules! impl_ops {
    ($addr_type:ty) => {
        impl<T: Sized> IpLookupTableOps<$addr_type, T> for IpLookupTable<$addr_type, T> {

            fn insert(&mut self, ip: $addr_type, masklen: u32, value: T) -> Option<T>{
                self.inner.insert(&ip.nibbles(), masklen, value)
            }

            fn remove(&mut self, ip: $addr_type, masklen: u32) -> Option<T>{
                self.inner.remove(&ip.nibbles(), masklen)
            }

            fn exact_match(&self, ip: $addr_type, masklen: u32) -> Option<&T> {
                self.inner.exact_match(&ip.nibbles(), masklen)
            }

            fn longest_match(&self, ip: $addr_type) -> Option<($addr_type, u32, &T)> {
                match self.inner.longest_match(&ip.nibbles()) {
                    Some((bits_matched,value)) => Some((ip.mask(bits_matched), bits_matched, value)),
                    None => None
                }
            }

            fn iter(&self) -> Iter<$addr_type,T> {
                Iter{
                    inner: self.inner.iter(),
                    _addrtype: PhantomData,
                }
            }

            fn iter_mut(&self) -> IterMut<$addr_type,T> {
                IterMut{
                    inner: self.inner.iter_mut(),
                    _addrtype: PhantomData,
                }
            }
        }

        impl<'a, T: 'a> Iterator for Iter<'a, $addr_type, T> {
            type Item = ($addr_type, u32, &'a T);

            fn next(&mut self) -> Option<Self::Item> {
                match self.inner.next() {
                    Some((nibbles, masklen, value)) => {
                        Some((Address::from_nibbles(&nibbles[..]), masklen, value))
                    },
                    None => None,
                }
            }
        }

        impl<'a, T: 'a> Iterator for IterMut<'a, $addr_type, T> {
            type Item = ($addr_type, u32, &'a mut T);

            fn next(&mut self) -> Option<Self::Item> {
                match self.inner.next() {
                    Some((nibbles, masklen, value)) => {
                        Some((Address::from_nibbles(&nibbles[..]), masklen, value))
                    },
                    None => None,
                }
            }
        }

        impl<'a, T: 'a> Iterator for IntoIter<$addr_type, T> {
            type Item = ($addr_type, u32, T);

            fn next(&mut self) -> Option<Self::Item> {
                match self.inner.next() {
                    Some((nibbles, masklen, value)) => {
                        Some((Address::from_nibbles(&nibbles[..]), masklen, value))
                    },
                    None => None,
                }
            }
        }

        impl<T> IntoIterator for IpLookupTable<$addr_type, T> {
            type Item = ($addr_type, u32, T);
            type IntoIter = IntoIter<$addr_type,T>;

            fn into_iter(self) -> IntoIter<$addr_type,T> {
                IntoIter {
                    inner: self.inner.into_iter(),
                    _addrtype: PhantomData,
                }
            }
        }
    }
}

impl_ops!(Ipv4Addr);
impl_ops!(Ipv6Addr);

#[cfg(test)]
mod tests;
#[cfg(all(test, feature = "full-bgp-tests"))]
mod full_bgp_tests;

<|endoftext|>


<commit_before>//! A simple and type agnostic dual-quaternion math library designed for reexporting

extern crate vecmath;
extern crate quaternion;

use quaternion::Quaternion;
use vecmath::Vector3;
use vecmath::traits::Float;

/// A dual-quaternion consists of a real component and a dual component,
/// and can be used to represent both rotation and translation
pub type DualQuaternion<T> = (Quaternion<T>, Quaternion<T>);

/// Constructs identity dual-quaternion, representing no rotation or translation.
#[inline(always)]
pub fn id<T: Float>() -> DualQuaternion<T> {
    let one = T::one();
    let zero = T::zero();
    (
        (one, [zero, zero, zero]),
        (zero, [zero, zero, zero])
    )
}

/// Construct a dual-quaternion from separate rotation and translation components
#[inline(always)]
pub fn from_rotation_and_translation<T: Float>(rotation: Quaternion<T>, translation: Vector3<T>) -> DualQuaternion<T> {
    let zero = T::zero();
    let half = T::from_f64(0.5);
    (
        rotation,
        quaternion::scale(
            quaternion::mul((zero, translation), rotation),
            half
        )
    )
}

/// Multiplies two dual-quaternions
#[inline(always)]
pub fn mul<T: Float>(a: DualQuaternion<T>, b: DualQuaternion<T>) -> DualQuaternion<T> {
    (
        quaternion::mul(b.0, a.0),
        quaternion::add(
            quaternion::mul(b.1, a.0),
            quaternion::mul(b.0, a.1)
        )
    )
}

/// Returns the dual-quaternion conjugate
#[inline(always)]
pub fn conj<T: Float>(q: DualQuaternion<T>) -> DualQuaternion<T> {
    (
        quaternion::conj(q.0),
        quaternion::conj(q.1)
    )
}

/// Extracts rotation component from a dual-quaternion
pub fn get_rotation<T: Float>(q: DualQuaternion<T>) -> Quaternion<T> {
    q.0
}

/// Extracts translation component from a dual-quaternion
pub fn get_translation<T: Float>(q: DualQuaternion<T>) -> Vector3<T> {
    let two = T::from_f64(2.0);
    let t = quaternion::mul(
        quaternion::scale(q.1, two),
        quaternion::conj(q.0)
    );
    t.1
}

/// Tests
#[cfg(test)]
mod test {

    use std::f32::consts::PI;
    use quaternion;
    use vecmath::Vector3;

    const EPSILON: f32 = 0.000001;

    #[test]
    fn test_construction_and_extraction() {
        let r = quaternion::euler_angles(PI, PI, PI);
        let t = [1.0, 2.0, 3.0];

        let dq = super::from_rotation_and_translation(r, t);

        let r_prime = super::get_rotation(dq);
        let t_prime = super::get_translation(dq);

        assert!((t_prime[0] - t[0]).abs() < EPSILON);
        assert!((t_prime[1] - t[1]).abs() < EPSILON);
        assert!((t_prime[2] - t[2]).abs() < EPSILON);

        assert!((r_prime.0 - r.0).abs() < EPSILON);
        assert!((r_prime.1[0] - r.1[0]).abs() < EPSILON);
        assert!((r_prime.1[1] - r.1[1]).abs() < EPSILON);
        assert!((r_prime.1[2] - r.1[2]).abs() < EPSILON);
    }

    #[test]
    fn test_mul_rotations() {

        let r1 = quaternion::euler_angles(PI / 2.0, PI, PI);
        let r2 = quaternion::euler_angles(PI / 2.0, -PI, 0.0);

        let t1 = [0.0, 0.0, 0.0];
        let t2 = [0.0, 0.0, 0.0];

        let dq1 = super::from_rotation_and_translation(r1, t1);
        let dq2 = super::from_rotation_and_translation(r2, t2);
        let dq3 = super::mul(dq1, dq2);

        let r_prime = super::get_rotation(dq3);
        let t_prime = super::get_translation(dq3);

        let r_expected = quaternion::euler_angles(PI, 0.0, PI);
        let t_expected = [0.0, 0.0, 0.0];

        assert!((t_prime[0] - t_expected[0]).abs() < EPSILON);
        assert!((t_prime[1] - t_expected[1]).abs() < EPSILON);
        assert!((t_prime[2] - t_expected[2]).abs() < EPSILON);

        let rotate_test_1 = quaternion::rotate_vector(r_prime, [1.0, 1.0, 1.0]);
        let rotate_test_2 = quaternion::rotate_vector(r_expected, [1.0, 1.0, 1.0]);

        assert!((rotate_test_1[0] - rotate_test_2[0]).abs() < EPSILON);
        assert!((rotate_test_1[1] - rotate_test_2[1]).abs() < EPSILON);
        assert!((rotate_test_1[2] - rotate_test_2[2]).abs() < EPSILON);

    }

    #[test]
    fn test_mul_translations() {

        let t1: Vector3<f32> = [1.0, 2.0, 3.0];
        let t2: Vector3<f32> = [1.0, -2.0, 0.0];

        let dq1 = super::from_rotation_and_translation(quaternion::id(), t1);
        let dq2 = super::from_rotation_and_translation(quaternion::id(), t2);
        let dq3 = super::mul(dq1, dq2);

        let r_prime = super::get_rotation(dq3);
        let t_prime = super::get_translation(dq3);

        let r_expected = quaternion::id();
        let t_expected = [2.0, 0.0, 3.0];

        assert!((t_prime[0] - t_expected[0]).abs() < EPSILON);
        assert!((t_prime[1] - t_expected[1]).abs() < EPSILON);
        assert!((t_prime[2] - t_expected[2]).abs() < EPSILON);

        let rotate_test_1 = quaternion::rotate_vector(r_prime, [1.0, 1.0, 1.0]);
        let rotate_test_2 = quaternion::rotate_vector(r_expected, [1.0, 1.0, 1.0]);

        assert!((rotate_test_1[0] - rotate_test_2[0]).abs() < EPSILON);
        assert!((rotate_test_1[1] - rotate_test_2[1]).abs() < EPSILON);
        assert!((rotate_test_1[2] - rotate_test_2[2]).abs() < EPSILON);

    }

    #[test]
    fn test_mul_conj() {
        let r = quaternion::euler_angles(PI, PI, PI);
        let t = [1.0, 2.0, 3.0];

        let dq = super::from_rotation_and_translation(r, t);
        let dq_conj = super::conj(dq);

        let dq_prime = super::mul(dq, dq_conj);
        let r_prime = super::get_rotation(dq_prime);
        let t_prime = super::get_translation(dq_prime);

        assert!((t_prime[0] - 0.0).abs() < EPSILON);
        assert!((t_prime[1] - 0.0).abs() < EPSILON);
        assert!((t_prime[2] - 0.0).abs() < EPSILON);

        assert!((r_prime.0 - 1.0).abs() < EPSILON);
        assert!((r_prime.1[0] - 0.0).abs() < EPSILON);
        assert!((r_prime.1[1] - 0.0).abs() < EPSILON);
        assert!((r_prime.1[2] - 0.0).abs() < EPSILON);
    }

}
<commit_msg>More dual-quaternion functions<commit_after>//! A simple and type agnostic dual-quaternion math library designed for reexporting

extern crate vecmath;
extern crate quaternion;

use quaternion::Quaternion;
use vecmath::Vector3;
use vecmath::traits::Float;

/// A dual-quaternion consists of a real component and a dual component,
/// and can be used to represent both rotation and translation
pub type DualQuaternion<T> = (Quaternion<T>, Quaternion<T>);

/// Constructs identity dual-quaternion, representing no rotation or translation.
#[inline(always)]
pub fn id<T: Float>() -> DualQuaternion<T> {
    let one = T::one();
    let zero = T::zero();
    (
        (one, [zero, zero, zero]),
        (zero, [zero, zero, zero])
    )
}

/// Construct a dual-quaternion from separate rotation and translation components
#[inline(always)]
pub fn from_rotation_and_translation<T: Float>(rotation: Quaternion<T>, translation: Vector3<T>) -> DualQuaternion<T> {
    let zero = T::zero();
    let half = T::from_f64(0.5);
    (
        rotation,
        quaternion::scale(
            quaternion::mul((zero, translation), rotation),
            half
        )
    )
}

/// Adds two dual-quaternions
#[inline(always)]
pub fn add<T: Float>(a: DualQuaternion<T>, b: DualQuaternion<T>) -> DualQuaternion<T> {
    (
        quaternion::add(a.0, b.0),
        quaternion::add(a.1, b.1)
    )
}

/// Multiplies two dual-quaternions
#[inline(always)]
pub fn mul<T: Float>(a: DualQuaternion<T>, b: DualQuaternion<T>) -> DualQuaternion<T> {
    (
        quaternion::mul(b.0, a.0),
        quaternion::add(
            quaternion::mul(b.1, a.0),
            quaternion::mul(b.0, a.1)
        )
    )
}

/// Scales a dual-quaternion (element-wise) by a scalar
#[inline(always)]
pub fn scale<T: Float>(q: DualQuaternion<T>, t: T) -> DualQuaternion<T>
{
    (quaternion::scale(q.0, t), quaternion::scale(q.1, t))
}

/// Returns the dual-quaternion conjugate
#[inline(always)]
pub fn conj<T: Float>(q: DualQuaternion<T>) -> DualQuaternion<T> {
    (
        quaternion::conj(q.0),
        quaternion::conj(q.1)
    )
}

/// Dot product of two dual-quaternions
#[inline(always)]
pub fn dot<T: Float>(a: DualQuaternion<T>, b: DualQuaternion<T>) -> T {
    quaternion::dot(a.0, b.0)
}

/// Normalizes a dual-quaternion
pub fn normalize<T: Float>(q: DualQuaternion<T>) -> DualQuaternion<T> {
    let _1 = T::one();
    let len = dot(q, q);
    (
        quaternion::scale(q.0, _1 / len),
        quaternion::scale(q.1, _1 / len),
    )
}

/// Extracts rotation component from a dual-quaternion
pub fn get_rotation<T: Float>(q: DualQuaternion<T>) -> Quaternion<T> {
    q.0
}

/// Extracts translation component from a dual-quaternion
pub fn get_translation<T: Float>(q: DualQuaternion<T>) -> Vector3<T> {
    let two = T::from_f64(2.0);
    let t = quaternion::mul(
        quaternion::scale(q.1, two),
        quaternion::conj(q.0)
    );
    t.1
}

/// Tests
#[cfg(test)]
mod test {

    use std::f32::consts::PI;
    use quaternion;
    use vecmath::Vector3;

    const EPSILON: f32 = 0.000001;

    #[test]
    fn test_construction_and_extraction() {
        let r = quaternion::euler_angles(PI, PI, PI);
        let t = [1.0, 2.0, 3.0];

        let dq = super::from_rotation_and_translation(r, t);

        let r_prime = super::get_rotation(dq);
        let t_prime = super::get_translation(dq);

        assert!((t_prime[0] - t[0]).abs() < EPSILON);
        assert!((t_prime[1] - t[1]).abs() < EPSILON);
        assert!((t_prime[2] - t[2]).abs() < EPSILON);

        assert!((r_prime.0 - r.0).abs() < EPSILON);
        assert!((r_prime.1[0] - r.1[0]).abs() < EPSILON);
        assert!((r_prime.1[1] - r.1[1]).abs() < EPSILON);
        assert!((r_prime.1[2] - r.1[2]).abs() < EPSILON);
    }

    #[test]
    fn test_mul_rotations() {

        let r1 = quaternion::euler_angles(PI / 2.0, PI, PI);
        let r2 = quaternion::euler_angles(PI / 2.0, -PI, 0.0);

        let t1 = [0.0, 0.0, 0.0];
        let t2 = [0.0, 0.0, 0.0];

        let dq1 = super::from_rotation_and_translation(r1, t1);
        let dq2 = super::from_rotation_and_translation(r2, t2);
        let dq3 = super::mul(dq1, dq2);

        let r_prime = super::get_rotation(dq3);
        let t_prime = super::get_translation(dq3);

        let r_expected = quaternion::euler_angles(PI, 0.0, PI);
        let t_expected = [0.0, 0.0, 0.0];

        assert!((t_prime[0] - t_expected[0]).abs() < EPSILON);
        assert!((t_prime[1] - t_expected[1]).abs() < EPSILON);
        assert!((t_prime[2] - t_expected[2]).abs() < EPSILON);

        let rotate_test_1 = quaternion::rotate_vector(r_prime, [1.0, 1.0, 1.0]);
        let rotate_test_2 = quaternion::rotate_vector(r_expected, [1.0, 1.0, 1.0]);

        assert!((rotate_test_1[0] - rotate_test_2[0]).abs() < EPSILON);
        assert!((rotate_test_1[1] - rotate_test_2[1]).abs() < EPSILON);
        assert!((rotate_test_1[2] - rotate_test_2[2]).abs() < EPSILON);

    }

    #[test]
    fn test_mul_translations() {

        let t1: Vector3<f32> = [1.0, 2.0, 3.0];
        let t2: Vector3<f32> = [1.0, -2.0, 0.0];

        let dq1 = super::from_rotation_and_translation(quaternion::id(), t1);
        let dq2 = super::from_rotation_and_translation(quaternion::id(), t2);
        let dq3 = super::mul(dq1, dq2);

        let r_prime = super::get_rotation(dq3);
        let t_prime = super::get_translation(dq3);

        let r_expected = quaternion::id();
        let t_expected = [2.0, 0.0, 3.0];

        assert!((t_prime[0] - t_expected[0]).abs() < EPSILON);
        assert!((t_prime[1] - t_expected[1]).abs() < EPSILON);
        assert!((t_prime[2] - t_expected[2]).abs() < EPSILON);

        let rotate_test_1 = quaternion::rotate_vector(r_prime, [1.0, 1.0, 1.0]);
        let rotate_test_2 = quaternion::rotate_vector(r_expected, [1.0, 1.0, 1.0]);

        assert!((rotate_test_1[0] - rotate_test_2[0]).abs() < EPSILON);
        assert!((rotate_test_1[1] - rotate_test_2[1]).abs() < EPSILON);
        assert!((rotate_test_1[2] - rotate_test_2[2]).abs() < EPSILON);

    }

    #[test]
    fn test_mul_conj() {
        let r = quaternion::euler_angles(PI, PI, PI);
        let t = [1.0, 2.0, 3.0];

        let dq = super::from_rotation_and_translation(r, t);
        let dq_conj = super::conj(dq);

        let dq_prime = super::mul(dq, dq_conj);
        let r_prime = super::get_rotation(dq_prime);
        let t_prime = super::get_translation(dq_prime);

        assert!((t_prime[0] - 0.0).abs() < EPSILON);
        assert!((t_prime[1] - 0.0).abs() < EPSILON);
        assert!((t_prime[2] - 0.0).abs() < EPSILON);

        assert!((r_prime.0 - 1.0).abs() < EPSILON);
        assert!((r_prime.1[0] - 0.0).abs() < EPSILON);
        assert!((r_prime.1[1] - 0.0).abs() < EPSILON);
        assert!((r_prime.1[2] - 0.0).abs() < EPSILON);
    }

}
<|endoftext|>


<commit_before>#[macro_use]
extern crate string_cache;
extern crate html5ever;
extern crate unicode_width;

use std::io;
use std::io::Write;
use std::cmp::max;
use html5ever::{parse_document};
use html5ever::driver::ParseOpts;
use html5ever::tree_builder::TreeBuilderOpts;
use html5ever::rcdom::{RcDom,Handle,Text,Element,Document,Comment};
use html5ever::tendril::TendrilSink;
use unicode_width::{UnicodeWidthStr,UnicodeWidthChar};

/// A dummy writer which does nothing
struct Discard {}
impl Write for Discard {
    fn write(&mut self, bytes: &[u8]) -> std::result::Result<usize, io::Error> { Ok(bytes.len()) }
    fn flush(&mut self) -> std::result::Result<(), io::Error> { Ok(()) }
}

fn wrap_text(text: &str, width: usize) -> String {
    let mut result = String::new();
    let mut xpos = 0usize;
    for word in text.split_whitespace() {
        if width <= (xpos + 1) {
            result.push('\n');
            xpos = 0;
        }
        let space_left = width - xpos - 1;
        let word_width = UnicodeWidthStr::width(word);
        if word_width <= space_left {
            /* It fits; no problem.  Add a space if not at the
             * start of line.*/
            if xpos > 0 {
                result.push(' ');
                xpos += 1;
            }
            result.push_str(word);
            xpos += word_width;
            continue;
        }

        /* It doesn't fit.  If we're not at the start of the line,
         * then go to a new line. */
        if xpos > 0 {
            result.push('\n');
            xpos = 0;
        }

        /* We're now at the start of a line. */
        if word_width > width {
            /* It doesn't fit at all on the line, so break it. */
            for c in word.chars() {
                let c_width = UnicodeWidthChar::width(c).unwrap();
                if c_width + xpos > width {
                    /* Break here */
                    result.push('\n');
                    xpos = 0;
                }
                /* This might happen with really narrow spaces... */
                assert!(c_width <= width);

                result.push(c);
                xpos += c_width;
            }
        } else {
            result.push_str(word);
            xpos += word_width;
        }
    }
    /* Terminate with a newline if needed. */
    if xpos > 0 {
        result.push('\n');
    }
    result
}

fn get_text(handle: Handle) -> String {
    let node = handle.borrow();
    let mut result = String::new();
    if let Text(ref tstr) = node.node {
        result.push_str(&tstr);
    } else {
        for child in node.children.iter() {
            result.push_str(&get_text(child.clone()));
        }
    }
    result
}

fn get_wrapped_text(handle: Handle, width: usize) -> String {
    let text = get_text(handle);
    wrap_text(&text, width)
}

fn dom_to_string<T:Write>(handle: Handle, err_out: &mut T, width: usize) -> String {
    let node = handle.borrow();
    let mut result = String::new();
    match node.node {
        Document => {},
        Element(ref name, _, _) => {
            match *name {
                qualname!(html, "html") |
                qualname!(html, "div") |
                qualname!(html, "span") |
                qualname!(html, "body") => {
                    /* process children, but don't add anything */
                },
                qualname!(html, "link") |
                qualname!(html, "meta") |
                qualname!(html, "hr") |
                qualname!(html, "script") |
                qualname!(html, "head") => {
                    /* Ignore the head and its children */
                    return result;
                },
                qualname!(html, "h1") |
                qualname!(html, "h2") |
                qualname!(html, "h3") |
                qualname!(html, "h4") |
                qualname!(html, "p") => {
                    return get_wrapped_text(handle.clone(), width) + "\n";
                },
                qualname!(html, "br") => {
                    result.push('\n');
                }
                qualname!(html, "table") => return table_to_string(handle.clone(), err_out, width),
                _ => {
                    write!(err_out, "Unhandled element: {:?}\n", name.local).unwrap();
                },
            }
          },
        Text(ref tstr) => {
            return wrap_text(tstr, width);
        }
        Comment(_) => {},
        _ => { write!(err_out, "Unhandled: {:?}\n", node).unwrap(); },
    }
    for child in node.children.iter() {
        result.push_str(&dom_to_string(child.clone(), err_out, width));
    }
    result
}

#[derive(Debug)]
struct TableCell {
    colspan: usize,
    content: Handle,
}

#[derive(Debug)]
struct TableRow {
    cells: Vec<TableCell>,
}

#[derive(Debug)]
struct Table {
    rows: Vec<TableRow>,
}

impl Table {
    pub fn new() -> Table {
        Table{ rows: Vec::new() }
    }
    pub fn push(&mut self, row: TableRow) {
        self.rows.push(row);
    }
    pub fn rows(&self) -> std::slice::Iter<TableRow> {
        self.rows.iter()
    }
}

impl TableRow {
    pub fn new() -> TableRow {
        TableRow{ cells: Vec::new() }
    }
    pub fn push(&mut self, cell: TableCell) {
        self.cells.push(cell);
    }
    pub fn cells(&self) -> std::slice::Iter<TableCell> {
        self.cells.iter()
    }
    /// Return an iterator over (column, &cell)s, which
    /// takes into account colspan.
    pub fn cell_columns(&self) -> Vec<(usize, &TableCell)> {
        let mut result = Vec::new();
        let mut colno = 0;
        for cell in &self.cells {
            result.push((colno, cell));
            colno += cell.colspan;
        }
        result
    }
    /// Count the number of cells in the row.
    /// Takes into account colspan.
    pub fn num_cells(&self) -> usize {
        self.cells.iter().map(|cell| cell.colspan).sum()
    }
}

impl TableCell {
    pub fn new(s: Handle) -> TableCell {
        if let Element(_, _, ref attrs) = s.borrow().node {
            let mut colspan = 1;
            for attr in attrs {
                if &attr.name.local == "colspan" {
                    let v:&str = &*attr.value;
                    colspan = v.parse().unwrap_or(1);
                } else {
                    //println!("Attr: {:?}", attr);
                }
            }
            TableCell{ content: s.clone(), colspan: colspan }
        } else {
            panic!("TableCell::new received a non-Element");
        }
    }
    pub fn render<T:Write>(&self, width: usize, err_out: &mut T) -> String
    {
        dom_to_string(self.content.clone(), err_out, width)
    }
}

fn handle_td(handle: Handle) -> TableCell {
    TableCell::new(handle)
}

fn handle_tr<T:Write>(handle: Handle, _: &mut T) -> TableRow {
    let node = handle.borrow();

    let mut row = TableRow::new();

    for child in node.children.iter() {
        match child.borrow().node {
            Element(ref name, _, _) => {
                match *name {
                    qualname!(html, "td") => {
                        row.push(handle_td(child.clone()));
                    },
                    _ => println!("  [[tr child: {:?}]]", name),
                }
            },
            Comment(_) => {},
            _ => { /*result.push_str(&format!("Unhandled in table: {:?}\n", node));*/ },
        }
    }

    row
}

fn handle_tbody<T:Write>(handle: Handle, err_out: &mut T, width: usize) -> String {
    let node = handle.borrow();

    let mut table = Table::new();

    for child in node.children.iter() {
        match child.borrow().node {
            Element(ref name, _, _) => {
                match *name {
                    qualname!(html, "tr") => {
                        table.push(handle_tr(child.clone(), err_out));
                    },
                    _ => println!("  [[tbody child: {:?}]]", name),
                }
            },
            Comment(_) => {},
            _ => { /*result.push_str(&format!("Unhandled in table: {:?}\n", node));*/ },
        }
    }

    /* Now lay out the table.  Use the simple option of giving each column
     * same width.  TODO: be cleverer, and handle multi-width cells, etc. */
    let num_columns = table.rows().map(|r| r.num_cells()).max().unwrap();

    let mut result = String::new();

    /* Heuristic: scale the column widths according to how much content there is. */
    let test_col_width = 1000;  // Render width for measurement; shouldn't make much difference.
    let min_width = 5;
    let mut col_sizes = vec![0usize; num_columns];

    for row in table.rows() {
        let mut colno = 0;
        for cell in row.cells() {
            let celldata = cell.render(test_col_width, &mut Discard{});
            // If the cell has a colspan>1, then spread its size between the
            // columns.
            let col_size = celldata.len() / cell.colspan;
            for i in 0..cell.colspan {
                col_sizes[colno + i] += col_size;
            }
            colno += cell.colspan;
        }
    }
    let tot_size: usize = col_sizes.iter().sum();
    let mut col_widths:Vec<usize> = col_sizes.iter()
                                         .map(|sz| {
                                             if *sz == 0 {
                                                 0
                                             } else {
                                                 max(sz * width / tot_size, min_width)
                                             }
                                          }).collect();
    /* The minimums may have put the total width too high */
    while col_widths.iter().cloned().sum::<usize>() > width {
        let (i, _) = col_widths.iter().cloned().enumerate().max_by_key(|k| k.1).unwrap();
        col_widths[i] -= 1;
    }
    if col_widths.len() > 0 {
        // Slight fudge; we're not drawing extreme edges, so one of the columns
        // can gets a free character cell from not having a border.
        // make it the last.
        let last = col_widths.len() - 1;
        col_widths[last] += 1;
    }

    let mut rowline = String::new();
    for width in col_widths.iter().cloned().filter(|w:&usize| *w > 0) {
        rowline.push_str(&(0..(width-1)).map(|_| '-').collect::<String>());
        rowline.push('+');
    }
    if rowline.len() > 0 {
        rowline.pop().unwrap();  // Remove the last '+'.
    }
    result.push_str(&rowline);
    result.push('\n');

    for row in table.rows() {
        let (used_widths, formatted_cells): (Vec<usize>, Vec<String>) = row.cell_columns()
                                              .into_iter()
                                              .flat_map(|(colno, cell)| {
                                                   let col_width:usize = col_widths[colno..colno+cell.colspan]
                                                                      .iter().sum();
                                                   if col_width > 0 {
                                                       Some((col_width, cell.render(col_width-1, err_out)))
                                                   } else {
                                                       None
                                                   }
                                               })
                                              .unzip();
        let line_sets: Vec<Vec<&str>> = formatted_cells.iter()
                                                       .map(|s| s.lines()
                                                                 .map(|line| line.trim_right())
                                                                 .collect())
                                                       .collect();
        let cell_height = line_sets.iter()
                                   .map(|v| v.len())
                                   .max().unwrap_or(0);
        for i in 0..cell_height {
            for (cellno, ls) in line_sets.iter().enumerate() {
                result.push_str(&format!("{: <width$}", ls.get(i).cloned().unwrap_or(""), width = used_widths[cellno]-1));
                if cellno == line_sets.len()-1 {
                    result.push('\n')
                } else {
                    result.push('|')
                }
            }
        }
        if cell_height > 0 {
            result.push_str(&rowline);
            result.push('\n');
        }
    }

    result
}

fn table_to_string<T:Write>(handle: Handle, err_out: &mut T, width: usize) -> String {
    let node = handle.borrow();
    let result = String::new();

    for child in node.children.iter() {
        match child.borrow().node {
            Element(ref name, _, _) => {
                match *name {
                    qualname!(html, "tbody") => return handle_tbody(child.clone(), err_out, width),
                    _ => { writeln!(err_out, "  [[table child: {:?}]]", name).unwrap();},
                }
            },
            Comment(_) => {},
            _ => { /*result.push_str(&format!("Unhandled in table: {:?}\n", node));*/ },
        }
    }

    result
}

pub fn from_read<R>(mut input: R, width: usize) -> String where R: io::Read {
    let opts = ParseOpts {
        tree_builder: TreeBuilderOpts {
            drop_doctype: true,
            ..Default::default()
        },
        ..Default::default()
    };
    let dom = parse_document(RcDom::default(), opts)
                   .from_utf8()
                   .read_from(&mut input)
                   .unwrap();

    dom_to_string(dom.document, &mut Discard{} /* &mut io::stderr()*/, width)
}

#[cfg(test)]
mod tests {
    use super::{from_read,wrap_text};
    #[test]
    fn test_table() {
        assert_eq!(from_read(&br##"

           1
           2
           3

"##[..], 12), r#"---+---+----
1  |2  |3
---+---+----
"#);
     }

     #[test]
     fn test_colspan() {
        assert_eq!(from_read(&br##"

           1
           2
           3

           12
           3

           1
           23

"##[..], 12), r#"---+---+----
1  |2  |3
---+---+----
12     |3
---+---+----
1  |23
---+---+----
"#);
     }

     #[test]
     fn test_para() {
        assert_eq!(from_read(&b"
Hello
"[..], 10),
                   "Hello\n\n");
     }

     #[test]
     fn test_wrap() {
        assert_eq!(wrap_text("Hello", 10), "Hello\n");
     }

     #[test]
     fn test_blockquote() {
        assert_eq!(from_read(&br#"
Hello

One, two, three

foo

"#[..], 12), r#"Hello

> One, two,
> three

foo
"#);
     }
}
<commit_msg>Implement blockquotes.<commit_after>#[macro_use]
extern crate string_cache;
extern crate html5ever;
extern crate unicode_width;

use std::io;
use std::io::Write;
use std::cmp::max;
use html5ever::{parse_document};
use html5ever::driver::ParseOpts;
use html5ever::tree_builder::TreeBuilderOpts;
use html5ever::rcdom::{RcDom,Handle,Text,Element,Document,Comment};
use html5ever::tendril::TendrilSink;
use unicode_width::{UnicodeWidthStr,UnicodeWidthChar};

/// A dummy writer which does nothing
struct Discard {}
impl Write for Discard {
    fn write(&mut self, bytes: &[u8]) -> std::result::Result<usize, io::Error> { Ok(bytes.len()) }
    fn flush(&mut self) -> std::result::Result<(), io::Error> { Ok(()) }
}

fn wrap_text(text: &str, width: usize) -> String {
    let mut result = String::new();
    let mut xpos = 0usize;
    for word in text.split_whitespace() {
        if width <= (xpos + 1) {
            result.push('\n');
            xpos = 0;
        }
        let space_left = width - xpos - 1;
        let word_width = UnicodeWidthStr::width(word);
        if word_width <= space_left {
            /* It fits; no problem.  Add a space if not at the
             * start of line.*/
            if xpos > 0 {
                result.push(' ');
                xpos += 1;
            }
            result.push_str(word);
            xpos += word_width;
            continue;
        }

        /* It doesn't fit.  If we're not at the start of the line,
         * then go to a new line. */
        if xpos > 0 {
            result.push('\n');
            xpos = 0;
        }

        /* We're now at the start of a line. */
        if word_width > width {
            /* It doesn't fit at all on the line, so break it. */
            for c in word.chars() {
                let c_width = UnicodeWidthChar::width(c).unwrap();
                if c_width + xpos > width {
                    /* Break here */
                    result.push('\n');
                    xpos = 0;
                }
                /* This might happen with really narrow spaces... */
                assert!(c_width <= width);

                result.push(c);
                xpos += c_width;
            }
        } else {
            result.push_str(word);
            xpos += word_width;
        }
    }
    /* Terminate with a newline if needed. */
    if xpos > 0 {
        result.push('\n');
    }
    result
}

fn get_text(handle: Handle) -> String {
    let node = handle.borrow();
    let mut result = String::new();
    if let Text(ref tstr) = node.node {
        result.push_str(&tstr);
    } else {
        for child in node.children.iter() {
            result.push_str(&get_text(child.clone()));
        }
    }
    result
}

fn render_block(handle: Handle, width: usize) -> String {
    let text = get_text(handle);
    wrap_text(&text, width)
}

fn dom_to_string<T:Write>(handle: Handle, err_out: &mut T, width: usize) -> String {
    let node = handle.borrow();
    let mut result = String::new();
    match node.node {
        Document => {},
        Element(ref name, _, _) => {
            match *name {
                qualname!(html, "html") |
                qualname!(html, "div") |
                qualname!(html, "span") |
                qualname!(html, "body") => {
                    /* process children, but don't add anything */
                },
                qualname!(html, "link") |
                qualname!(html, "meta") |
                qualname!(html, "hr") |
                qualname!(html, "script") |
                qualname!(html, "head") => {
                    /* Ignore the head and its children */
                    return result;
                },
                qualname!(html, "h1") |
                qualname!(html, "h2") |
                qualname!(html, "h3") |
                qualname!(html, "h4") |
                qualname!(html, "p") => {
                    return render_block(handle.clone(), width) + "\n";
                },
                qualname!(html, "br") => {
                    result.push('\n');
                }
                qualname!(html, "table") => return table_to_string(handle.clone(), err_out, width),
                qualname!(html, "blockquote") => return bq_to_string(handle.clone(), err_out, width) + "\n",
                _ => {
                    write!(err_out, "Unhandled element: {:?}\n", name.local).unwrap();
                },
            }
          },
        Text(ref tstr) => {
            return wrap_text(tstr, width);
        }
        Comment(_) => {},
        _ => { write!(err_out, "Unhandled: {:?}\n", node).unwrap(); },
    }
    for child in node.children.iter() {
        result.push_str(&dom_to_string(child.clone(), err_out, width));
    }
    result
}

#[derive(Debug)]
struct TableCell {
    colspan: usize,
    content: Handle,
}

#[derive(Debug)]
struct TableRow {
    cells: Vec<TableCell>,
}

#[derive(Debug)]
struct Table {
    rows: Vec<TableRow>,
}

impl Table {
    pub fn new() -> Table {
        Table{ rows: Vec::new() }
    }
    pub fn push(&mut self, row: TableRow) {
        self.rows.push(row);
    }
    pub fn rows(&self) -> std::slice::Iter<TableRow> {
        self.rows.iter()
    }
}

impl TableRow {
    pub fn new() -> TableRow {
        TableRow{ cells: Vec::new() }
    }
    pub fn push(&mut self, cell: TableCell) {
        self.cells.push(cell);
    }
    pub fn cells(&self) -> std::slice::Iter<TableCell> {
        self.cells.iter()
    }
    /// Return an iterator over (column, &cell)s, which
    /// takes into account colspan.
    pub fn cell_columns(&self) -> Vec<(usize, &TableCell)> {
        let mut result = Vec::new();
        let mut colno = 0;
        for cell in &self.cells {
            result.push((colno, cell));
            colno += cell.colspan;
        }
        result
    }
    /// Count the number of cells in the row.
    /// Takes into account colspan.
    pub fn num_cells(&self) -> usize {
        self.cells.iter().map(|cell| cell.colspan).sum()
    }
}

impl TableCell {
    pub fn new(s: Handle) -> TableCell {
        if let Element(_, _, ref attrs) = s.borrow().node {
            let mut colspan = 1;
            for attr in attrs {
                if &attr.name.local == "colspan" {
                    let v:&str = &*attr.value;
                    colspan = v.parse().unwrap_or(1);
                } else {
                    //println!("Attr: {:?}", attr);
                }
            }
            TableCell{ content: s.clone(), colspan: colspan }
        } else {
            panic!("TableCell::new received a non-Element");
        }
    }
    pub fn render<T:Write>(&self, width: usize, err_out: &mut T) -> String
    {
        dom_to_string(self.content.clone(), err_out, width)
    }
}

fn handle_td(handle: Handle) -> TableCell {
    TableCell::new(handle)
}

fn handle_tr<T:Write>(handle: Handle, _: &mut T) -> TableRow {
    let node = handle.borrow();

    let mut row = TableRow::new();

    for child in node.children.iter() {
        match child.borrow().node {
            Element(ref name, _, _) => {
                match *name {
                    qualname!(html, "td") => {
                        row.push(handle_td(child.clone()));
                    },
                    _ => println!("  [[tr child: {:?}]]", name),
                }
            },
            Comment(_) => {},
            _ => { /*result.push_str(&format!("Unhandled in table: {:?}\n", node));*/ },
        }
    }

    row
}

fn handle_tbody<T:Write>(handle: Handle, err_out: &mut T, width: usize) -> String {
    let node = handle.borrow();

    let mut table = Table::new();

    for child in node.children.iter() {
        match child.borrow().node {
            Element(ref name, _, _) => {
                match *name {
                    qualname!(html, "tr") => {
                        table.push(handle_tr(child.clone(), err_out));
                    },
                    _ => println!("  [[tbody child: {:?}]]", name),
                }
            },
            Comment(_) => {},
            _ => { /*result.push_str(&format!("Unhandled in table: {:?}\n", node));*/ },
        }
    }

    /* Now lay out the table.  Use the simple option of giving each column
     * same width.  TODO: be cleverer, and handle multi-width cells, etc. */
    let num_columns = table.rows().map(|r| r.num_cells()).max().unwrap();

    let mut result = String::new();

    /* Heuristic: scale the column widths according to how much content there is. */
    let test_col_width = 1000;  // Render width for measurement; shouldn't make much difference.
    let min_width = 5;
    let mut col_sizes = vec![0usize; num_columns];

    for row in table.rows() {
        let mut colno = 0;
        for cell in row.cells() {
            let celldata = cell.render(test_col_width, &mut Discard{});
            // If the cell has a colspan>1, then spread its size between the
            // columns.
            let col_size = celldata.len() / cell.colspan;
            for i in 0..cell.colspan {
                col_sizes[colno + i] += col_size;
            }
            colno += cell.colspan;
        }
    }
    let tot_size: usize = col_sizes.iter().sum();
    let mut col_widths:Vec<usize> = col_sizes.iter()
                                         .map(|sz| {
                                             if *sz == 0 {
                                                 0
                                             } else {
                                                 max(sz * width / tot_size, min_width)
                                             }
                                          }).collect();
    /* The minimums may have put the total width too high */
    while col_widths.iter().cloned().sum::<usize>() > width {
        let (i, _) = col_widths.iter().cloned().enumerate().max_by_key(|k| k.1).unwrap();
        col_widths[i] -= 1;
    }
    if col_widths.len() > 0 {
        // Slight fudge; we're not drawing extreme edges, so one of the columns
        // can gets a free character cell from not having a border.
        // make it the last.
        let last = col_widths.len() - 1;
        col_widths[last] += 1;
    }

    let mut rowline = String::new();
    for width in col_widths.iter().cloned().filter(|w:&usize| *w > 0) {
        rowline.push_str(&(0..(width-1)).map(|_| '-').collect::<String>());
        rowline.push('+');
    }
    if rowline.len() > 0 {
        rowline.pop().unwrap();  // Remove the last '+'.
    }
    result.push_str(&rowline);
    result.push('\n');

    for row in table.rows() {
        let (used_widths, formatted_cells): (Vec<usize>, Vec<String>) = row.cell_columns()
                                              .into_iter()
                                              .flat_map(|(colno, cell)| {
                                                   let col_width:usize = col_widths[colno..colno+cell.colspan]
                                                                      .iter().sum();
                                                   if col_width > 0 {
                                                       Some((col_width, cell.render(col_width-1, err_out)))
                                                   } else {
                                                       None
                                                   }
                                               })
                                              .unzip();
        let line_sets: Vec<Vec<&str>> = formatted_cells.iter()
                                                       .map(|s| s.lines()
                                                                 .map(|line| line.trim_right())
                                                                 .collect())
                                                       .collect();
        let cell_height = line_sets.iter()
                                   .map(|v| v.len())
                                   .max().unwrap_or(0);
        for i in 0..cell_height {
            for (cellno, ls) in line_sets.iter().enumerate() {
                result.push_str(&format!("{: <width$}", ls.get(i).cloned().unwrap_or(""), width = used_widths[cellno]-1));
                if cellno == line_sets.len()-1 {
                    result.push('\n')
                } else {
                    result.push('|')
                }
            }
        }
        if cell_height > 0 {
            result.push_str(&rowline);
            result.push('\n');
        }
    }

    result
}

fn table_to_string<T:Write>(handle: Handle, err_out: &mut T, width: usize) -> String {
    let node = handle.borrow();
    let result = String::new();

    for child in node.children.iter() {
        match child.borrow().node {
            Element(ref name, _, _) => {
                match *name {
                    qualname!(html, "tbody") => return handle_tbody(child.clone(), err_out, width),
                    _ => { writeln!(err_out, "  [[table child: {:?}]]", name).unwrap();},
                }
            },
            Comment(_) => {},
            _ => { /*result.push_str(&format!("Unhandled in table: {:?}\n", node));*/ },
        }
    }

    result
}

fn prepend_block(block: &str, prefix: &str) -> String {
    let mut result = String::new();
    for line in block.lines() {
        result.push_str(prefix);
        result.push_str(line);
        result.push('\n');
    }
    result
}

fn bq_to_string<T:Write>(handle: Handle, err_out: &mut T, width: usize) -> String {

    let subblock = render_block(handle, width-2);

    prepend_block(&subblock, "> ")
}

pub fn from_read<R>(mut input: R, width: usize) -> String where R: io::Read {
    let opts = ParseOpts {
        tree_builder: TreeBuilderOpts {
            drop_doctype: true,
            ..Default::default()
        },
        ..Default::default()
    };
    let dom = parse_document(RcDom::default(), opts)
                   .from_utf8()
                   .read_from(&mut input)
                   .unwrap();

    dom_to_string(dom.document, &mut Discard{} /* &mut io::stderr()*/, width)
}

#[cfg(test)]
mod tests {
    use super::{from_read,wrap_text};
    #[test]
    fn test_table() {
        assert_eq!(from_read(&br##"

           1
           2
           3

"##[..], 12), r#"---+---+----
1  |2  |3
---+---+----
"#);
     }

     #[test]
     fn test_colspan() {
        assert_eq!(from_read(&br##"

           1
           2
           3

           12
           3

           1
           23

"##[..], 12), r#"---+---+----
1  |2  |3
---+---+----
12     |3
---+---+----
1  |23
---+---+----
"#);
     }

     #[test]
     fn test_para() {
        assert_eq!(from_read(&b"
Hello
"[..], 10),
                   "Hello\n\n");
     }

     #[test]
     fn test_wrap() {
        assert_eq!(wrap_text("Hello", 10), "Hello\n");
     }

     #[test]
     fn test_blockquote() {
        assert_eq!(from_read(&br#"
Hello

One, two, three

foo

"#[..], 12), r#"Hello

> One, two,
> three

foo

"#);
     }
}
<|endoftext|>


<commit_before>#![cfg_attr(test, deny(missing_docs, warnings))]
#![forbid(unused_variables)]

use std::{fmt, mem};
use std::borrow::{Borrow, ToOwned};
use std::default::Default;
use std::hash::{Hash, Hasher};
use std::iter::FromIterator;
use std::ops::{Deref, Index, Range, RangeFrom, RangeFull, RangeTo};

/// An owned sequence of Unicode scalar values, equivalent to `String`.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct UString(Vec<char>);

/// A Unicode string slice, equivalent to `str`.
pub struct UStr([char]);

impl UString {
    pub fn remove(&mut self, idx: usize) -> char {
        self.0.remove(idx)
    }
}

impl UStr {
    /// Returns the number of Unicode scalar values in this string.
    pub fn len(&self) -> usize {
        self.0.len()
    }

    /// Retrieves the first character from a `&UStr` and returns it.
    ///
    /// This does not allocate a new string; instead, it returns a slice that points one character beyond the character that was shifted.
    ///
    /// If the slice does not contain any characters, None is returned instead.
    pub fn slice_shift_char(&self) -> Option<(char, &UStr)> {
        if self.len() == 0 {
            None
        } else {
            let ch = self[0];
            let next_s = &self[1..];
            Some((ch, next_s))
        }
    }
}

impl Borrow<UStr> for UString {
    fn borrow(&self) -> &UStr {
        &self
    }
}

impl Default for UString {
    fn default() -> UString {
        UString(Vec::new())
    }
}

impl Deref for UString {
    type Target = UStr;

    fn deref(&self) -> &UStr {
        unsafe {
            mem::transmute(&*self.0)
            // just so you can be clear what it is:
            //mem::transmute::<&[char], &UStr>(&*self.0)
        }
    }
}

impl From<String> for UString {
    fn from(string: String) -> UString {
        UString(string.chars().collect())
    }
}

impl From<Vec<char>> for UString {
    fn from(chars: Vec<char>) -> UString {
        UString(chars)
    }
}

impl<'a> From<&'a str> for UString {
    fn from(string: &'a str) -> UString {
        UString(string.chars().collect())
    }
}

impl<'a> From<&'a [char]> for UString {
    fn from(slice: &[char]) -> UString {
        UString(slice.to_vec())
    }
}

impl From<UString> for String {
    fn from(string: UString) -> String {
        String::from_iter(string)
    }
}

impl<'a> From<&'a UString> for String {
    fn from(string: &UString) -> String {
        String::from_iter(string.into_iter().cloned())
    }
}

impl<'a> From<&'a UStr> for String {
    fn from(slice: &UStr) -> String {
        String::from_iter(slice.into_iter().cloned())
    }
}

impl<C: Into<char>> FromIterator<C> for UString {
    fn from_iter<T>(iterator: T) -> UString where T: IntoIterator<Item=C> {
        UString(iterator.into_iter().map(C::into).collect())
    }
}

impl Hash for UString {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.0.hash(state);
    }
}

impl Index<usize> for UStr {
    type Output = char;

    fn index(&self, idx: usize) -> &char {
        &self.0[idx]
    }
}

impl Index<Range<usize>> for UStr {
    type Output = UStr;

    fn index(&self, idx: Range<usize>) -> &UStr {
        unsafe { mem::transmute(&self.0[idx]) }
    }
}

impl Index<RangeFrom<usize>> for UStr {
    type Output = UStr;

    fn index(&self, idx: RangeFrom<usize>) -> &UStr {
        unsafe { mem::transmute(&self.0[idx]) }
    }
}

impl Index<RangeFull> for UStr {
    type Output = UStr;

    fn index(&self, _: RangeFull) -> &UStr {
        self
    }
}

impl Index<RangeTo<usize>> for UStr {
    type Output = UStr;

    fn index(&self, idx: RangeTo<usize>) -> &UStr {
        unsafe { mem::transmute(&self.0[idx]) }
    }
}

impl ToOwned for UStr {
    type Owned = UString;

    fn to_owned(&self) -> UString {
        UString::from(self.0.to_owned())
    }
}

impl fmt::Display for UStr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for c in &self.0 {
            try!(write!(f, "{}", c));
        }
        Ok(())
    }
}

#[derive(Debug)]
pub struct Iter<'a>(&'a [char]);

#[derive(Debug)]
pub struct IntoIter(Vec<char>);

impl<'a> Iterator for Iter<'a> {
    type Item = &'a char;

    fn next(&mut self) -> Option<&'a char> {
        if self.0.len() > 0 {
            let result = &self.0[0];
            self.0 = &self.0[1..];
            Some(result)
        } else {
            None
        }
    }
}

impl Iterator for IntoIter {
    type Item = char;

    fn next(&mut self) -> Option<char> {
        if self.0.len() > 0 {
            Some(self.0.remove(0))
        } else {
            None
        }
    }
}

impl IntoIterator for UString {
    type Item = char;
    type IntoIter = IntoIter;

    fn into_iter(self) -> IntoIter {
        IntoIter(self.0)
    }
}

impl<'a> IntoIterator for &'a UString {
    type Item = &'a char;
    type IntoIter = Iter<'a>;

    fn into_iter(self) -> Iter<'a> {
        Iter(&self.0)
    }
}

impl<'a> IntoIterator for &'a UStr {
    type Item = &'a char;
    type IntoIter = Iter<'a>;

    fn into_iter(self) -> Iter<'a> {
        Iter(&self.0)
    }
}
<commit_msg>Implement From<char> and {starts,ends}_with<commit_after>#![cfg_attr(test, deny(missing_docs, warnings))]
#![forbid(unused_variables)]

use std::{fmt, mem};
use std::borrow::{Borrow, ToOwned};
use std::default::Default;
use std::hash::{Hash, Hasher};
use std::iter::FromIterator;
use std::ops::{Deref, Index, Range, RangeFrom, RangeFull, RangeTo};

/// An owned sequence of Unicode scalar values, equivalent to `String`.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct UString(Vec<char>);

/// A Unicode string slice, equivalent to `str`.
pub struct UStr([char]);

impl UString {
    pub fn remove(&mut self, idx: usize) -> char {
        self.0.remove(idx)
    }
}

impl UStr {
    /// Returns the number of Unicode scalar values in this string.
    pub fn len(&self) -> usize {
        self.0.len()
    }

    /// Retrieves the first character from a `&UStr` and returns it.
    ///
    /// This does not allocate a new string; instead, it returns a slice that points one character beyond the character that was shifted.
    ///
    /// If the slice does not contain any characters, None is returned instead.
    pub fn slice_shift_char(&self) -> Option<(char, &UStr)> {
        if self.len() == 0 {
            None
        } else {
            let ch = self[0];
            let next_s = &self[1..];
            Some((ch, next_s))
        }
    }

    pub fn starts_with<'a, T: AsRef<UStr>>(&self, prefix: &'a T) -> bool {
        self.0.starts_with(&prefix.as_ref().0)
    }

    pub fn ends_with<'a, T: AsRef<UStr>>(&self, suffix: &'a T) -> bool {
        self.0.ends_with(&suffix.as_ref().0)
    }
}

impl Borrow<UStr> for UString {
    fn borrow(&self) -> &UStr {
        &self
    }
}

impl Default for UString {
    fn default() -> UString {
        UString(Vec::new())
    }
}

impl Deref for UString {
    type Target = UStr;

    fn deref(&self) -> &UStr {
        unsafe {
            mem::transmute(&*self.0)
            // just so you can be clear what it is:
            //mem::transmute::<&[char], &UStr>(&*self.0)
        }
    }
}

impl From<String> for UString {
    fn from(string: String) -> UString {
        UString(string.chars().collect())
    }
}

impl From<Vec<char>> for UString {
    fn from(chars: Vec<char>) -> UString {
        UString(chars)
    }
}

impl<'a> From<&'a str> for UString {
    fn from(string: &'a str) -> UString {
        UString(string.chars().collect())
    }
}

impl<'a> From<&'a [char]> for UString {
    fn from(slice: &[char]) -> UString {
        UString(slice.to_vec())
    }
}

impl From<char> for UString {
    fn from(c: char) -> UString {
        UString(vec![c])
    }
}

impl From<UString> for String {
    fn from(string: UString) -> String {
        String::from_iter(string)
    }
}

impl<'a> From<&'a UString> for String {
    fn from(string: &UString) -> String {
        String::from_iter(string.into_iter().cloned())
    }
}

impl<'a> From<&'a UStr> for String {
    fn from(slice: &UStr) -> String {
        String::from_iter(slice.into_iter().cloned())
    }
}

impl<C: Into<char>> FromIterator<C> for UString {
    fn from_iter<T>(iterator: T) -> UString where T: IntoIterator<Item=C> {
        UString(iterator.into_iter().map(C::into).collect())
    }
}

impl Hash for UString {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.0.hash(state);
    }
}

impl Index<usize> for UStr {
    type Output = char;

    fn index(&self, idx: usize) -> &char {
        &self.0[idx]
    }
}

impl Index<Range<usize>> for UStr {
    type Output = UStr;

    fn index(&self, idx: Range<usize>) -> &UStr {
        unsafe { mem::transmute(&self.0[idx]) }
    }
}

impl Index<RangeFrom<usize>> for UStr {
    type Output = UStr;

    fn index(&self, idx: RangeFrom<usize>) -> &UStr {
        unsafe { mem::transmute(&self.0[idx]) }
    }
}

impl Index<RangeFull> for UStr {
    type Output = UStr;

    fn index(&self, _: RangeFull) -> &UStr {
        self
    }
}

impl Index<RangeTo<usize>> for UStr {
    type Output = UStr;

    fn index(&self, idx: RangeTo<usize>) -> &UStr {
        unsafe { mem::transmute(&self.0[idx]) }
    }
}

impl ToOwned for UStr {
    type Owned = UString;

    fn to_owned(&self) -> UString {
        UString::from(self.0.to_owned())
    }
}

impl fmt::Display for UStr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for c in &self.0 {
            try!(write!(f, "{}", c));
        }
        Ok(())
    }
}

#[derive(Debug)]
pub struct Iter<'a>(&'a [char]);

#[derive(Debug)]
pub struct IntoIter(Vec<char>);

impl<'a> Iterator for Iter<'a> {
    type Item = &'a char;

    fn next(&mut self) -> Option<&'a char> {
        if self.0.len() > 0 {
            let result = &self.0[0];
            self.0 = &self.0[1..];
            Some(result)
        } else {
            None
        }
    }
}

impl Iterator for IntoIter {
    type Item = char;

    fn next(&mut self) -> Option<char> {
        if self.0.len() > 0 {
            Some(self.0.remove(0))
        } else {
            None
        }
    }
}

impl IntoIterator for UString {
    type Item = char;
    type IntoIter = IntoIter;

    fn into_iter(self) -> IntoIter {
        IntoIter(self.0)
    }
}

impl<'a> IntoIterator for &'a UString {
    type Item = &'a char;
    type IntoIter = Iter<'a>;

    fn into_iter(self) -> Iter<'a> {
        Iter(&self.0)
    }
}

impl<'a> IntoIterator for &'a UStr {
    type Item = &'a char;
    type IntoIter = Iter<'a>;

    fn into_iter(self) -> Iter<'a> {
        Iter(&self.0)
    }
}
<|endoftext|>