<commit_before>use libc::{c_int, c_uint, c_ulonglong};
use num::{ToPrimitive, FromPrimitive};

pub enum HwlocTopology {}

#[repr(u32)]
#[derive(Debug,PartialEq)]
pub enum ObjectType {
	/// The whole system that is accessible to hwloc. That may comprise several
	/// machines in SSI systems like Kerrighed.
	System,
	/// The typical root object type. A set of processors and memory with cache
	/// coherency.
	Machine,
	/// A set of processors around memory which the processors can directly
	/// access.
	NUMANode,
	/// Physical package, what goes into a socket. In the physical meaning,
	/// i.e. that you can add or remove physically.
	Package,
	/// The Cache. Can be L1i, L1d, L2, L3,...
	Cache,
	/// A computation unit (may be shared by several logical processors).
	Core,
	/// Processing Unit, or (Logical) Processor.
	///
	/// An execution unit (may share a core with some other logical
	/// processors, e.g. in the case of an SMT core). Objects of this kind
	/// are always reported and can thus be used as fallback when others are
	/// not.
	PU,
	/// Group objects.
	///	Objects which do not fit in the above but are detected by hwloc and
	/// are useful to take into account for affinity. For instance, some
	/// operating systems expose their arbitrary processors aggregation this
	/// way. And hwloc may insert such objects to group NUMA nodes according
	/// to their distances.
	///
	/// These objects are ignored when they do not bring any structure.
	Group,
	/// Miscellaneous objects.
	///
	/// Objects without particular meaning, that can e.g. be
	/// added by the application for its own use, or by hwloc
	/// for miscellaneous objects such as MemoryModule (DIMMs).
	Misc,
	/// Any bridge that connects the host or an I/O bus, to another I/O bus.
	///
	/// Bridge objects have neither CPU sets nor node sets.
	/// They are not added to the topology unless I/O discovery
	/// is enabled through the custom flags.
	Bridge,
	/// PCI device.
	///
	/// These objects have neither CPU sets nor node sets.
	/// They are not added to the topology unless I/O discovery
	/// is enabled through the custom flags.
	PCIDevice,
	/// Operating system device.
	///
	/// These objects have neither CPU sets nor node sets. They are not
	/// added to the topology unless I/O discovery is enabled
	/// through the custom flags.
	OSDevice,
	/// An internal sentinel value.
	TypeMax,
}

#[derive(Debug,PartialEq)]
pub enum TypeDepthError {
	/// HWLOC returned a depth error which is not known to the rust binding.
	UnkownTypeDepthError,
	/// No object of given type exists in the topology.
	TypeDepthUnknown,
	/// Objects of given type exist at different depth in the topology.
	TypeDepthMultiple,
	/// Virtual depth for bridge object level.
	TypeDepthBridge,
	/// Virtual depth for PCI device object level.
	TypeDepthPCIDevice,
	/// Virtual depth for software device object level.
	TypeDepthOSDevice,
}

#[derive(Debug,PartialEq)]
pub enum TopologyFlag {
	WholeSystem,
	IsThisSystem,
	IoDevices,
	IoBridges,
	WholeIo,
	ICaches,
}

impl ToPrimitive for TopologyFlag {

	fn to_i64(&self) -> Option<i64> {
		match *self {
			TopologyFlag::WholeSystem => Some(1),
			TopologyFlag::IsThisSystem => Some(2),
			TopologyFlag::IoDevices => Some(4),
			TopologyFlag::IoBridges => Some(8),
			TopologyFlag::WholeIo => Some(16),
			TopologyFlag::ICaches => Some(32),
		}
	}

	fn to_u64(&self) -> Option<u64> {
		self.to_i64().and_then(|x| x.to_u64())
	}

}

impl FromPrimitive for TopologyFlag {

	fn from_i64(n: i64) -> Option<Self> {
		match n {
			1 => Some(TopologyFlag::WholeSystem),
			2 => Some(TopologyFlag::IsThisSystem),
			4 => Some(TopologyFlag::IoDevices),
			8 => Some(TopologyFlag::IoBridges),
			16 => Some(TopologyFlag::WholeIo),
			32 => Some(TopologyFlag::ICaches),
			_ => None,
		}
	}

    fn from_u64(n: u64) -> Option<Self> {
    	FromPrimitive::from_i64(n as i64)
    }
}

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

	// === Topology Creation and Destruction ===

	pub fn hwloc_topology_init(topology: *mut *mut HwlocTopology) -> c_int;
	pub fn hwloc_topology_load(topology: *mut HwlocTopology) -> c_int;
	pub fn hwloc_topology_destroy(topology: *mut HwlocTopology);

	// === Topology Detection Configuration and Query ===

	pub fn hwloc_topology_set_flags(topology: *mut HwlocTopology, flags: c_ulonglong) -> c_int;
	pub fn hwloc_topology_get_flags(topology: *mut HwlocTopology) -> c_ulonglong;

	// === Object levels, depths and types ===

	pub fn hwloc_topology_get_depth(topology: *mut HwlocTopology) -> c_uint;
	pub fn hwloc_get_type_depth(topology: *mut HwlocTopology, object_type: ObjectType) -> c_int;
	pub fn hwloc_get_depth_type(topology: *mut HwlocTopology, depth: c_uint) -> ObjectType;
	pub fn hwloc_get_nbobjs_by_depth(topology: *mut HwlocTopology, depth: c_uint) -> c_uint;
	pub fn hwloc_get_obj_by_depth(topology: *mut HwlocTopology, depth: c_uint, idx: c_uint) -> ObjectType;
}<commit_msg>fix docblock with weird formatting<commit_after>use libc::{c_int, c_uint, c_ulonglong};
use num::{ToPrimitive, FromPrimitive};

pub enum HwlocTopology {}

#[repr(u32)]
#[derive(Debug,PartialEq)]
pub enum ObjectType {
	/// The whole system that is accessible to hwloc. That may comprise several
	/// machines in SSI systems like Kerrighed.
	System,
	/// The typical root object type. A set of processors and memory with cache
	/// coherency.
	Machine,
	/// A set of processors around memory which the processors can directly
	/// access.
	NUMANode,
	/// Physical package, what goes into a socket. In the physical meaning,
	/// i.e. that you can add or remove physically.
	Package,
	/// The Cache. Can be L1i, L1d, L2, L3,...
	Cache,
	/// A computation unit (may be shared by several logical processors).
	Core,
	/// Processing Unit, or (Logical) Processor.
	///
	/// An execution unit (may share a core with some other logical
	/// processors, e.g. in the case of an SMT core). Objects of this kind
	/// are always reported and can thus be used as fallback when others are
	/// not.
	PU,
	/// Group objects.
	///
	/// Objects which do not fit in the above but are detected by hwloc and
	/// are useful to take into account for affinity. For instance, some
	/// operating systems expose their arbitrary processors aggregation this
	/// way. And hwloc may insert such objects to group NUMA nodes according
	/// to their distances.
	///
	/// These objects are ignored when they do not bring any structure.
	Group,
	/// Miscellaneous objects.
	///
	/// Objects without particular meaning, that can e.g. be
	/// added by the application for its own use, or by hwloc
	/// for miscellaneous objects such as MemoryModule (DIMMs).
	Misc,
	/// Any bridge that connects the host or an I/O bus, to another I/O bus.
	///
	/// Bridge objects have neither CPU sets nor node sets.
	/// They are not added to the topology unless I/O discovery
	/// is enabled through the custom flags.
	Bridge,
	/// PCI device.
	///
	/// These objects have neither CPU sets nor node sets.
	/// They are not added to the topology unless I/O discovery
	/// is enabled through the custom flags.
	PCIDevice,
	/// Operating system device.
	///
	/// These objects have neither CPU sets nor node sets. They are not
	/// added to the topology unless I/O discovery is enabled
	/// through the custom flags.
	OSDevice,
	/// An internal sentinel value.
	TypeMax,
}

#[derive(Debug,PartialEq)]
pub enum TypeDepthError {
	/// HWLOC returned a depth error which is not known to the rust binding.
	UnkownTypeDepthError,
	/// No object of given type exists in the topology.
	TypeDepthUnknown,
	/// Objects of given type exist at different depth in the topology.
	TypeDepthMultiple,
	/// Virtual depth for bridge object level.
	TypeDepthBridge,
	/// Virtual depth for PCI device object level.
	TypeDepthPCIDevice,
	/// Virtual depth for software device object level.
	TypeDepthOSDevice,
}

#[derive(Debug,PartialEq)]
pub enum TopologyFlag {
	WholeSystem,
	IsThisSystem,
	IoDevices,
	IoBridges,
	WholeIo,
	ICaches,
}

impl ToPrimitive for TopologyFlag {

	fn to_i64(&self) -> Option<i64> {
		match *self {
			TopologyFlag::WholeSystem => Some(1),
			TopologyFlag::IsThisSystem => Some(2),
			TopologyFlag::IoDevices => Some(4),
			TopologyFlag::IoBridges => Some(8),
			TopologyFlag::WholeIo => Some(16),
			TopologyFlag::ICaches => Some(32),
		}
	}

	fn to_u64(&self) -> Option<u64> {
		self.to_i64().and_then(|x| x.to_u64())
	}

}

impl FromPrimitive for TopologyFlag {

	fn from_i64(n: i64) -> Option<Self> {
		match n {
			1 => Some(TopologyFlag::WholeSystem),
			2 => Some(TopologyFlag::IsThisSystem),
			4 => Some(TopologyFlag::IoDevices),
			8 => Some(TopologyFlag::IoBridges),
			16 => Some(TopologyFlag::WholeIo),
			32 => Some(TopologyFlag::ICaches),
			_ => None,
		}
	}

    fn from_u64(n: u64) -> Option<Self> {
    	FromPrimitive::from_i64(n as i64)
    }
}

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

	// === Topology Creation and Destruction ===

	pub fn hwloc_topology_init(topology: *mut *mut HwlocTopology) -> c_int;
	pub fn hwloc_topology_load(topology: *mut HwlocTopology) -> c_int;
	pub fn hwloc_topology_destroy(topology: *mut HwlocTopology);

	// === Topology Detection Configuration and Query ===

	pub fn hwloc_topology_set_flags(topology: *mut HwlocTopology, flags: c_ulonglong) -> c_int;
	pub fn hwloc_topology_get_flags(topology: *mut HwlocTopology) -> c_ulonglong;

	// === Object levels, depths and types ===

	pub fn hwloc_topology_get_depth(topology: *mut HwlocTopology) -> c_uint;
	pub fn hwloc_get_type_depth(topology: *mut HwlocTopology, object_type: ObjectType) -> c_int;
	pub fn hwloc_get_depth_type(topology: *mut HwlocTopology, depth: c_uint) -> ObjectType;
	pub fn hwloc_get_nbobjs_by_depth(topology: *mut HwlocTopology, depth: c_uint) -> c_uint;
	pub fn hwloc_get_obj_by_depth(topology: *mut HwlocTopology, depth: c_uint, idx: c_uint) -> ObjectType;
}<|endoftext|>


<commit_before>use std::fmt;
use std::str::FromStr;

use super::rfc5322::{Rfc5322Parser, MIME_LINE_LENGTH};
use super::header::{FromHeader, ToFoldedHeader};
use super::results::{ParsingResult,ParsingError};

/// Represents an RFC 5322 Address
#[derive(PartialEq, Eq, Debug)]
#[stable]
pub enum Address {
    /// A "regular" email address
    Mailbox(Mailbox),
    /// A named group of mailboxes
    Group(String, Vec<Mailbox>),
}

impl Address {
    /// Shortcut function to make a new Mailbox with the given address
    #[unstable]
    pub fn new_mailbox(address: String) -> Address {
        Address::Mailbox(Mailbox::new(address))
    }

    /// Shortcut function to make a new Mailbox with the address and given-name
    #[unstable]
    pub fn new_mailbox_with_name(name: String, address: String) -> Address {
        Address::Mailbox(Mailbox::new_with_name(name, address))
    }

    /// Shortcut function to make a new Group with a collection of mailboxes
    #[unstable]
    pub fn new_group(name: String, mailboxes: Vec<Mailbox>) -> Address {
        Address::Group(name, mailboxes)
    }
}

impl fmt::Display for Address {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Address::Mailbox(ref mbox) => mbox.fmt(fmt),
            Address::Group(ref name, ref mboxes) => {
                let mut mailbox_list = String::new();
                for mbox in mboxes.iter() {
                    if mailbox_list.len() > 0 {
                        // Insert the separator if there's already things in this list
                        mailbox_list.push_str(", ");
                    }
                    mailbox_list.push_str(mbox.to_string().as_slice());
                }
                write!(fmt, "{}: {};", name, mailbox_list)
            }
        }
    }
}

/// Represents an RFC 5322 mailbox
#[derive(PartialEq, Eq, Debug)]
#[stable]
pub struct Mailbox {
    /// The given name for this address
    pub name: Option<String>,
    /// The mailbox address
    pub address: String,
}

impl Mailbox {
    /// Create a new Mailbox without a display name
    #[stable]
    pub fn new(address: String) -> Mailbox {
        Mailbox {
            name: None,
            address: address
        }
    }

    /// Create a new Mailbox with a display name
    #[stable]
    pub fn new_with_name(name: String, address: String) -> Mailbox {
        Mailbox {
            name: Some(name),
            address: address
        }
    }
}

impl fmt::Display for Mailbox {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match self.name {
            Some(ref name) => write!(fmt, "\"{}\" <{}>", name, self.address),
            None => write!(fmt, "<{}>", self.address),
        }
    }
}

impl FromStr for Mailbox {
    type Err = ParsingError;

    fn from_str(s: &str) -> ParsingResult<Mailbox> {
        AddressParser::new(s).parse_mailbox()
    }
}

impl FromHeader for Vec<Address> {
    fn from_header(value: String) -> ParsingResult<Vec<Address>> {
        AddressParser::new(value.as_slice()).parse_address_list()
    }
}

impl ToFoldedHeader for Vec<Address> {
    fn to_folded_header(start_pos: usize, value: Vec<Address>) -> ParsingResult<String> {
        let mut header = String::new();

        let mut line_len = start_pos;

        for addr in value.iter() {
            let addr_str = format!("{}, ", addr);

            if line_len + addr_str.len() > MIME_LINE_LENGTH {
                // Adding this would cause a wrap, so wrap before!
                header.push_str("\r\n\t");
                line_len = 0;
            }
            line_len += addr_str.len();
            header.push_str(addr_str.as_slice());
        }

        // Clear up the final ", "
        let real_len = header.len() - 2;
        header.truncate(real_len);

        Ok(header)
    }
}

#[stable]
pub struct AddressParser<'s> {
    p: Rfc5322Parser<'s>,
}

impl<'s> AddressParser<'s> {
    #[stable]
    pub fn new(s: &str) -> AddressParser {
        AddressParser {
            p: Rfc5322Parser::new(s)
        }
    }

    #[stable]
    pub fn parse_address_list(&mut self) -> ParsingResult<Vec<Address>> {
        let mut result = Vec::new();

        while !self.p.eof() {
            self.p.push_position();

            match self.parse_group() {
                Ok(x) => result.push(x),
                Err(e) => {
                    // If we failed to parse as group, try again as mailbox
                    self.p.pop_position();
                    result.push(Address::Mailbox(match self.parse_mailbox() {
                        Ok(x) => x,
                        Err(e2) => return Err(ParsingError::new(
                            format!("Failed to parse as group: {}\n\
                                     Failed to parse as mailbox: {}", e, e2)
                        ))
                    }));
                }
            };

            self.p.consume_linear_whitespace();
            if !self.p.eof() && self.p.peek() == ',' {
                // Clear the separator
                self.p.consume_char();
            }
        }

        Ok(result)
    }

    #[stable]
    pub fn parse_group(&mut self) -> ParsingResult<Address> {
        let name = match self.p.consume_phrase(false) {
            Some(x) => x,
            None => return Err(ParsingError::new(format!("Couldn't find group name: {}", self.p.peek_to_end())))
        };

        if !self.p.eof() && self.p.peek() != ':' {
            return Err(ParsingError::new(format!("Expected ':', found {}.",
                                                 self.p.peek())));
        };

        self.p.consume_char();
        let mut mailboxes = Vec::new();

        while !self.p.eof() && self.p.peek() != ';' {
            mailboxes.push(try!(self.parse_mailbox()));

            if !self.p.eof() && self.p.peek() == ',' {
                self.p.consume_char();
            }
        };

        Ok(Address::Group(name, mailboxes))
    }

    #[stable]
    pub fn parse_mailbox(&mut self) -> ParsingResult<Mailbox> {
        // Push the current position of the parser so we can back out later
        self.p.push_position();
        match self.parse_name_addr() {
            Ok(result) => Ok(result),
            Err(_) => {
                // Revert back to our original position to try to parse an addr-spec
                self.p.pop_position();
                Ok(Mailbox::new(try!(self.parse_addr_spec())))
            }
        }
    }

    fn parse_name_addr(&mut self) -> ParsingResult<Mailbox> {
        // Find display-name
        let display_name = self.p.consume_phrase(false);
        self.p.consume_linear_whitespace();
        if self.p.eof() {
            return Err(ParsingError::new("Reached EOF while parsing address header.".to_string()));
        };

        // Find angle-addr
        if self.p.peek() != '<' {
            return Err(ParsingError::new("Could only find display name while parsing address header.".to_string()));
        } else {
            self.p.consume_char();
        };

        let addr = try!(self.parse_addr_spec());
        if self.p.consume_char() != '>' {
            // Fail because we should have a closing RANGLE here (to match the opening one)
            Err(ParsingError::new("Missing '>' at end while parsing address header.".to_string()))
        } else {
            Ok(match display_name {
                Some(name) => Mailbox::new_with_name(name, addr),
                None => Mailbox::new(addr)
            })
        }
    }

    fn parse_addr_spec(&mut self) -> ParsingResult<String> {
        // local-part is a phrase, but allows dots in atoms
        let local_part = match self.p.consume_phrase(true) {
            Some(x) => x,
            None => return Err(ParsingError::new(format!("Couldn't find local part while parsing address.")))
        };

        if self.p.eof() {
            return Err(ParsingError::new("Reached EOF while parsing address.".to_string()));
        };

        let at_char = self.p.consume_char();
        if at_char != '@' {
            return Err(ParsingError::new(format!("Expected @, found {} instead.", at_char)));
        };

        let domain = try!(self.parse_domain());
        Ok(format!("{}@{}", local_part, domain))
    }

    fn parse_domain(&mut self) -> ParsingResult<String> {
        // TODO: support domain-literal
        match self.p.consume_atom(true) {
            Some(x) => Ok(x),
            None => Err(ParsingError::new("Failed to parse domain.".to_string()))
        }
    }
}

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

    use super::super::header::Header;

    #[test]
    fn test_address_to_string() {
        let addr = Mailbox::new("foo@example.org".to_string());
        assert_eq!(addr.to_string(), "<foo@example.org>".to_string());

        let name_addr = Mailbox::new_with_name("Joe Blogs".to_string(), "foo@example.org".to_string());
        assert_eq!(name_addr.to_string(), "\"Joe Blogs\" <foo@example.org>".to_string());
    }

    #[test]
    fn test_address_from_string() {
        let addr = "\"Joe Blogs\" <joe@example.org>".parse::<Mailbox>().unwrap();
        assert_eq!(addr.name.unwrap(), "Joe Blogs".to_string());
        assert_eq!(addr.address, "joe@example.org".to_string());

        assert!("Not an address".parse::<Mailbox>().is_err());
    }

    #[test]
    fn test_address_parsing() {
        let mut parser = AddressParser::new("\"Joe Blogs\" <joe@example.org>");
        let mut addr = parser.parse_mailbox().unwrap();
        assert_eq!(addr.name.unwrap(), "Joe Blogs".to_string());
        assert_eq!(addr.address, "joe@example.org".to_string());

        parser = AddressParser::new("joe@example.org");
        addr = parser.parse_mailbox().unwrap();
        assert_eq!(addr.name, None);
        assert_eq!(addr.address, "joe@example.org".to_string());
    }

    #[test]
    fn test_address_group_to_string() {
        let addr = Address::new_group("undisclosed recipients".to_string(), vec![]);
        assert_eq!(addr.to_string(), "undisclosed recipients: ;".to_string());

        let addr = Address::new_group("group test".to_string(), vec![
            Mailbox::new("joe@example.org".to_string()),
            Mailbox::new_with_name("John Doe".to_string(), "john@example.org".to_string()),
        ]);
        assert_eq!(addr.to_string(), "group test: <joe@example.org>, \"John Doe\" <john@example.org>;".to_string());
    }

    #[test]
    fn test_address_group_parsing() {
        let mut parser = AddressParser::new("A Group:\"Joe Blogs\" <joe@example.org>,john@example.org;");
        let addr = parser.parse_group().unwrap();
        match addr {
            Address::Group(name, mboxes) => {
                assert_eq!(name, "A Group".to_string());
                assert_eq!(mboxes, vec![
                    Mailbox::new_with_name("Joe Blogs".to_string(), "joe@example.org".to_string()),
                    Mailbox::new("john@example.org".to_string()),
                ]);
            },
            _ => assert!(false),
        }
    }

    #[test]
    fn test_address_list_parsing() {
        let mut parser = AddressParser::new("\"Joe Blogs\" <joe@example.org>, \"John Doe\" <john@example.org>");
        assert_eq!(parser.parse_address_list().unwrap(), vec![
            Address::new_mailbox_with_name("Joe Blogs".to_string(), "joe@example.org".to_string()),
            Address::new_mailbox_with_name("John Doe".to_string(), "john@example.org".to_string()),
        ]);
    }

    #[test]
    fn test_address_list_parsing_groups() {
        let mut parser = AddressParser::new("A Group:\"Joe Blogs\" <joe@example.org>, \"John Doe\" <john@example.org>; <third@example.org>, <fourth@example.org>");
        assert_eq!(parser.parse_address_list().unwrap(), vec![
            Address::new_group("A Group".to_string(), vec![
                    Mailbox::new_with_name("Joe Blogs".to_string(), "joe@example.org".to_string()),
                    Mailbox::new_with_name("John Doe".to_string(), "john@example.org".to_string()),
            ]),
            Address::new_mailbox("third@example.org".to_string()),
            Address::new_mailbox("fourth@example.org".to_string()),
        ]);
    }

    #[test]
    fn test_from_header_parsing() {
        let header = Header::new(
            "From:".to_string(),
            "\"Joe Blogs\" <joe@example.org>, \"John Doe\" <john@example.org>".to_string());
        let addresses: Vec<Address> = header.get_value().unwrap();
        assert_eq!(addresses, vec![
            Address::new_mailbox_with_name("Joe Blogs".to_string(), "joe@example.org".to_string()),
            Address::new_mailbox_with_name("John Doe".to_string(), "john@example.org".to_string()),
        ]);
    }

    #[test]
    fn test_to_header_generation() {
        let addresses = vec![
            Address::new_mailbox_with_name("Joe Blogs".to_string(), "joe@example.org".to_string()),
            Address::new_mailbox_with_name("John Doe".to_string(), "john@example.org".to_string()),
        ];

        let header = Header::new_with_value("From:".to_string(), addresses).unwrap();
        assert_eq!(header.get_value::<String>().unwrap(),
                   "\"Joe Blogs\" <joe@example.org>, \"John Doe\" <john@example.org>".to_string());
    }

    #[test]
    fn test_to_header_line_wrap() {
        let addresses = vec![
            Address::new_mailbox_with_name("Joe Blogs".to_string(), "joe@example.org".to_string()),
            Address::new_mailbox_with_name("John Doe".to_string(), "john@example.org".to_string()),
            Address::new_mailbox_with_name("Mr Black".to_string(), "mafia_black@example.org".to_string()),
        ];

        let header = Header::new_with_value("To".to_string(), addresses).unwrap();
        assert_eq!(header.to_string().as_slice(),
                   "To: \"Joe Blogs\" <joe@example.org>, \"John Doe\" <john@example.org>, \r\n\
                   \t\"Mr Black\" <mafia_black@example.org>");
    }
}
<commit_msg>Fix mailbox group parsing bug<commit_after>use std::fmt;
use std::str::FromStr;

use super::rfc5322::{Rfc5322Parser, MIME_LINE_LENGTH};
use super::header::{FromHeader, ToFoldedHeader};
use super::results::{ParsingResult,ParsingError};

/// Represents an RFC 5322 Address
#[derive(PartialEq, Eq, Debug)]
#[stable]
pub enum Address {
    /// A "regular" email address
    Mailbox(Mailbox),
    /// A named group of mailboxes
    Group(String, Vec<Mailbox>),
}

impl Address {
    /// Shortcut function to make a new Mailbox with the given address
    #[unstable]
    pub fn new_mailbox(address: String) -> Address {
        Address::Mailbox(Mailbox::new(address))
    }

    /// Shortcut function to make a new Mailbox with the address and given-name
    #[unstable]
    pub fn new_mailbox_with_name(name: String, address: String) -> Address {
        Address::Mailbox(Mailbox::new_with_name(name, address))
    }

    /// Shortcut function to make a new Group with a collection of mailboxes
    #[unstable]
    pub fn new_group(name: String, mailboxes: Vec<Mailbox>) -> Address {
        Address::Group(name, mailboxes)
    }
}

impl fmt::Display for Address {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Address::Mailbox(ref mbox) => mbox.fmt(fmt),
            Address::Group(ref name, ref mboxes) => {
                let mut mailbox_list = String::new();
                for mbox in mboxes.iter() {
                    if mailbox_list.len() > 0 {
                        // Insert the separator if there's already things in this list
                        mailbox_list.push_str(", ");
                    }
                    mailbox_list.push_str(mbox.to_string().as_slice());
                }
                write!(fmt, "{}: {};", name, mailbox_list)
            }
        }
    }
}

/// Represents an RFC 5322 mailbox
#[derive(PartialEq, Eq, Debug)]
#[stable]
pub struct Mailbox {
    /// The given name for this address
    pub name: Option<String>,
    /// The mailbox address
    pub address: String,
}

impl Mailbox {
    /// Create a new Mailbox without a display name
    #[stable]
    pub fn new(address: String) -> Mailbox {
        Mailbox {
            name: None,
            address: address
        }
    }

    /// Create a new Mailbox with a display name
    #[stable]
    pub fn new_with_name(name: String, address: String) -> Mailbox {
        Mailbox {
            name: Some(name),
            address: address
        }
    }
}

impl fmt::Display for Mailbox {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match self.name {
            Some(ref name) => write!(fmt, "\"{}\" <{}>", name, self.address),
            None => write!(fmt, "<{}>", self.address),
        }
    }
}

impl FromStr for Mailbox {
    type Err = ParsingError;

    fn from_str(s: &str) -> ParsingResult<Mailbox> {
        AddressParser::new(s).parse_mailbox()
    }
}

impl FromHeader for Vec<Address> {
    fn from_header(value: String) -> ParsingResult<Vec<Address>> {
        AddressParser::new(value.as_slice()).parse_address_list()
    }
}

impl ToFoldedHeader for Vec<Address> {
    fn to_folded_header(start_pos: usize, value: Vec<Address>) -> ParsingResult<String> {
        let mut header = String::new();

        let mut line_len = start_pos;

        for addr in value.iter() {
            let addr_str = format!("{}, ", addr);

            if line_len + addr_str.len() > MIME_LINE_LENGTH {
                // Adding this would cause a wrap, so wrap before!
                header.push_str("\r\n\t");
                line_len = 0;
            }
            line_len += addr_str.len();
            header.push_str(addr_str.as_slice());
        }

        // Clear up the final ", "
        let real_len = header.len() - 2;
        header.truncate(real_len);

        Ok(header)
    }
}

#[stable]
pub struct AddressParser<'s> {
    p: Rfc5322Parser<'s>,
}

impl<'s> AddressParser<'s> {
    #[stable]
    pub fn new(s: &str) -> AddressParser {
        AddressParser {
            p: Rfc5322Parser::new(s)
        }
    }

    #[stable]
    pub fn parse_address_list(&mut self) -> ParsingResult<Vec<Address>> {
        let mut result = Vec::new();
        let mut expected_separator = ';';

        while !self.p.eof() {
            self.p.push_position();

            match self.parse_group() {
                Ok(x) => {
                    // Is a group
                    result.push(x);
                    expected_separator = ';';
                },
                Err(e) => {
                    // If we failed to parse as group, try again as mailbox
                    self.p.pop_position();
                    result.push(Address::Mailbox(match self.parse_mailbox() {
                        Ok(x) => x,
                        Err(e2) => return Err(ParsingError::new(
                            format!("Failed to parse as group: {}\n\
                                     Failed to parse as mailbox: {}", e, e2)
                        ))
                    }));
                    expected_separator = ',';
                }
            };

            self.p.consume_linear_whitespace();
            if !self.p.eof() && self.p.peek() == expected_separator {
                // Clear the separator
                self.p.consume_char();
            }
        }

        Ok(result)
    }

    #[stable]
    pub fn parse_group(&mut self) -> ParsingResult<Address> {
        let name = match self.p.consume_phrase(false) {
            Some(x) => x,
            None => return Err(ParsingError::new(format!("Couldn't find group name: {}", self.p.peek_to_end())))
        };

        if !self.p.eof() && self.p.peek() != ':' {
            return Err(ParsingError::new(format!("Expected ':', found {}.",
                                                 self.p.peek())));
        };

        self.p.consume_char();
        let mut mailboxes = Vec::new();

        while !self.p.eof() && self.p.peek() != ';' {
            mailboxes.push(try!(self.parse_mailbox()));

            if !self.p.eof() && self.p.peek() == ',' {
                self.p.consume_char();
            }
        };

        Ok(Address::Group(name, mailboxes))
    }

    #[stable]
    pub fn parse_mailbox(&mut self) -> ParsingResult<Mailbox> {
        // Push the current position of the parser so we can back out later
        self.p.push_position();
        match self.parse_name_addr() {
            Ok(result) => Ok(result),
            Err(_) => {
                // Revert back to our original position to try to parse an addr-spec
                self.p.pop_position();
                Ok(Mailbox::new(try!(self.parse_addr_spec())))
            }
        }
    }

    fn parse_name_addr(&mut self) -> ParsingResult<Mailbox> {
        // Find display-name
        let display_name = self.p.consume_phrase(false);
        self.p.consume_linear_whitespace();
        if self.p.eof() {
            return Err(ParsingError::new("Reached EOF while parsing address header.".to_string()));
        };

        // Find angle-addr
        if self.p.peek() != '<' {
            return Err(ParsingError::new("Could only find display name while parsing address header.".to_string()));
        } else {
            self.p.consume_char();
        };

        let addr = try!(self.parse_addr_spec());
        if self.p.consume_char() != '>' {
            // Fail because we should have a closing RANGLE here (to match the opening one)
            Err(ParsingError::new("Missing '>' at end while parsing address header.".to_string()))
        } else {
            Ok(match display_name {
                Some(name) => Mailbox::new_with_name(name, addr),
                None => Mailbox::new(addr)
            })
        }
    }

    fn parse_addr_spec(&mut self) -> ParsingResult<String> {
        // local-part is a phrase, but allows dots in atoms
        let local_part = match self.p.consume_phrase(true) {
            Some(x) => x,
            None => return Err(ParsingError::new(format!("Couldn't find local part while parsing address.")))
        };

        if self.p.eof() {
            return Err(ParsingError::new("Reached EOF while parsing address.".to_string()));
        };

        let at_char = self.p.consume_char();
        if at_char != '@' {
            return Err(ParsingError::new(format!("Expected @, found {} instead.", at_char)));
        };

        let domain = try!(self.parse_domain());
        Ok(format!("{}@{}", local_part, domain))
    }

    fn parse_domain(&mut self) -> ParsingResult<String> {
        // TODO: support domain-literal
        match self.p.consume_atom(true) {
            Some(x) => Ok(x),
            None => Err(ParsingError::new("Failed to parse domain.".to_string()))
        }
    }
}

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

    use super::super::header::Header;

    #[test]
    fn test_address_to_string() {
        let addr = Mailbox::new("foo@example.org".to_string());
        assert_eq!(addr.to_string(), "<foo@example.org>".to_string());

        let name_addr = Mailbox::new_with_name("Joe Blogs".to_string(), "foo@example.org".to_string());
        assert_eq!(name_addr.to_string(), "\"Joe Blogs\" <foo@example.org>".to_string());
    }

    #[test]
    fn test_address_from_string() {
        let addr = "\"Joe Blogs\" <joe@example.org>".parse::<Mailbox>().unwrap();
        assert_eq!(addr.name.unwrap(), "Joe Blogs".to_string());
        assert_eq!(addr.address, "joe@example.org".to_string());

        assert!("Not an address".parse::<Mailbox>().is_err());
    }

    #[test]
    fn test_address_parsing() {
        let mut parser = AddressParser::new("\"Joe Blogs\" <joe@example.org>");
        let mut addr = parser.parse_mailbox().unwrap();
        assert_eq!(addr.name.unwrap(), "Joe Blogs".to_string());
        assert_eq!(addr.address, "joe@example.org".to_string());

        parser = AddressParser::new("joe@example.org");
        addr = parser.parse_mailbox().unwrap();
        assert_eq!(addr.name, None);
        assert_eq!(addr.address, "joe@example.org".to_string());
    }

    #[test]
    fn test_address_group_to_string() {
        let addr = Address::new_group("undisclosed recipients".to_string(), vec![]);
        assert_eq!(addr.to_string(), "undisclosed recipients: ;".to_string());

        let addr = Address::new_group("group test".to_string(), vec![
            Mailbox::new("joe@example.org".to_string()),
            Mailbox::new_with_name("John Doe".to_string(), "john@example.org".to_string()),
        ]);
        assert_eq!(addr.to_string(), "group test: <joe@example.org>, \"John Doe\" <john@example.org>;".to_string());
    }

    #[test]
    fn test_address_group_parsing() {
        let mut parser = AddressParser::new("A Group:\"Joe Blogs\" <joe@example.org>,john@example.org;");
        let addr = parser.parse_group().unwrap();
        match addr {
            Address::Group(name, mboxes) => {
                assert_eq!(name, "A Group".to_string());
                assert_eq!(mboxes, vec![
                    Mailbox::new_with_name("Joe Blogs".to_string(), "joe@example.org".to_string()),
                    Mailbox::new("john@example.org".to_string()),
                ]);
            },
            _ => assert!(false),
        }
    }

    #[test]
    fn test_address_list_parsing() {
        let mut parser = AddressParser::new("\"Joe Blogs\" <joe@example.org>, \"John Doe\" <john@example.org>");
        assert_eq!(parser.parse_address_list().unwrap(), vec![
            Address::new_mailbox_with_name("Joe Blogs".to_string(), "joe@example.org".to_string()),
            Address::new_mailbox_with_name("John Doe".to_string(), "john@example.org".to_string()),
        ]);
    }

    #[test]
    fn test_address_list_parsing_groups() {
        let mut parser = AddressParser::new("A Group:\"Joe Blogs\" <joe@example.org>, \"John Doe\" <john@example.org>; <third@example.org>, <fourth@example.org>");
        assert_eq!(parser.parse_address_list().unwrap(), vec![
            Address::new_group("A Group".to_string(), vec![
                    Mailbox::new_with_name("Joe Blogs".to_string(), "joe@example.org".to_string()),
                    Mailbox::new_with_name("John Doe".to_string(), "john@example.org".to_string()),
            ]),
            Address::new_mailbox("third@example.org".to_string()),
            Address::new_mailbox("fourth@example.org".to_string()),
        ]);
    }

    #[test]
    fn test_from_header_parsing() {
        let header = Header::new(
            "From:".to_string(),
            "\"Joe Blogs\" <joe@example.org>, \"John Doe\" <john@example.org>".to_string());
        let addresses: Vec<Address> = header.get_value().unwrap();
        assert_eq!(addresses, vec![
            Address::new_mailbox_with_name("Joe Blogs".to_string(), "joe@example.org".to_string()),
            Address::new_mailbox_with_name("John Doe".to_string(), "john@example.org".to_string()),
        ]);
    }

    #[test]
    fn test_to_header_generation() {
        let addresses = vec![
            Address::new_mailbox_with_name("Joe Blogs".to_string(), "joe@example.org".to_string()),
            Address::new_mailbox_with_name("John Doe".to_string(), "john@example.org".to_string()),
        ];

        let header = Header::new_with_value("From:".to_string(), addresses).unwrap();
        assert_eq!(header.get_value::<String>().unwrap(),
                   "\"Joe Blogs\" <joe@example.org>, \"John Doe\" <john@example.org>".to_string());
    }

    #[test]
    fn test_to_header_line_wrap() {
        let addresses = vec![
            Address::new_mailbox_with_name("Joe Blogs".to_string(), "joe@example.org".to_string()),
            Address::new_mailbox_with_name("John Doe".to_string(), "john@example.org".to_string()),
            Address::new_mailbox_with_name("Mr Black".to_string(), "mafia_black@example.org".to_string()),
        ];

        let header = Header::new_with_value("To".to_string(), addresses).unwrap();
        assert_eq!(header.to_string().as_slice(),
                   "To: \"Joe Blogs\" <joe@example.org>, \"John Doe\" <john@example.org>, \r\n\
                   \t\"Mr Black\" <mafia_black@example.org>");
    }
}
<|endoftext|>


<commit_before>#[allow(unused)]
pub mod entity;
pub mod http;
pub mod response;
pub mod postparams;

extern crate hyper;
extern crate serde_json;
extern crate urlencoded;

use hyper::client;
use hyper::mime::Mime;
use std;
use std::collections::HashMap;
use std::fmt::Debug;
use std::io::Read;
use std::option::Option;
use std::process::exit;
use std::result::Result;

#[derive(Debug)]
pub struct Api {
    base_uri: &'static str,
    api_key: String,
    login_token: String,
    client: hyper::client::Client,
    user_agent: String,
}

#[allow(unused)]
impl Api {

    /// Create a new api client
    pub fn new(api_key: String) -> Api {
        let crates_version = &std::env::var("CARGO_PKG_VERSION")
            .unwrap_or("unknown".to_string());
        let crates_name = std::env::var("CARGO_PKG_NAME").
            unwrap_or("unknown".to_string());

        let ua = format!("libproxer-rust({}/v{})", crates_name, crates_version);

        Api {
            base_uri:    "http://proxer.me/api/v1/",
            api_key:     api_key,
            login_token: "None".to_string(),
            client:      hyper::client::Client::new(),
            user_agent:  ua,
        }
    }

    pub fn info_get_full_info(self, id: u32) -> Result<client::response::Response, hyper::Error> {
        use api::entity::response::*;
        let url = "info/fullentry";

        let mut post = postparams::Postparams::new();
        post.add("id", id);

        response::Response::new::<info::fullinfo::FullInfo>(self.http_req(url, post))
    }

    fn http_req(self, url: &str, data: postparams::Postparams) -> Result<client::response::Response, hyper::Error> {
        let uri = self.base_uri.to_string()+url;
        let hyper_url = hyper::Url::parse(&uri).unwrap();

        let mut headers = hyper::header::Headers::new();
        header! {(ProxerApiKeyHeader, "proxer-api-key") => [String]}
        header! {(UserAgent, "User-Agent") => [String]}
        headers.set(ProxerApiKeyHeader(self.api_key));
        headers.set(UserAgent(self.user_agent));
        headers.set(hyper::header::ContentType::form_url_encoded());

        self.client
            .post(hyper_url)
            .headers(headers)
            .body(&data.to_string())
            .send()
    }

    pub fn read_json(json: String) -> std::result::Result<serde_json::Value, serde_json::Error> {
        serde_json::from_str(&json)
    }
}
<commit_msg>implement 2 more api's<commit_after>#[allow(unused)]
pub mod entity;
pub mod http;
pub mod response;
pub mod postparams;

extern crate hyper;
extern crate serde_json;
extern crate urlencoded;

use hyper::client;
use hyper::mime::Mime;
use std;
use std::collections::HashMap;
use std::fmt::Debug;
use std::io::Read;
use std::option::Option;
use std::process::exit;
use std::result::Result;

#[derive(Debug)]
pub struct Api {
    base_uri: &'static str,
    api_key: String,
    login_token: String,
    client: hyper::client::Client,
    user_agent: String,
}

#[allow(unused)]
impl Api {

    /// Create a new api client
    pub fn new(api_key: String) -> Api {
        let crates_version = &std::env::var("CARGO_PKG_VERSION")
            .unwrap_or("unknown".to_string());
        let crates_name = std::env::var("CARGO_PKG_NAME").
            unwrap_or("unknown".to_string());

        let ua = format!("libproxer-rust({}/v{})", crates_name, crates_version);

        Api {
            base_uri:    "http://proxer.me/api/v1/",
            api_key:     api_key,
            login_token: "None".to_string(),
            client:      hyper::client::Client::new(),
            user_agent:  ua,
        }
    }

    /// Get the full information for an anime or manga
    ///
    /// See [Proxer wiki](http://proxer.me/wiki/Proxer_API/v1/Info#Get_Full_Entry)

    pub fn info_get_full_info(self, id: u32) -> Result<client::response::Response, hyper::Error> {
        use api::entity::response::*;
        let url = "info/fullentry";

        let mut post = postparams::Postparams::new();
        post.add("id", id);

        let response = self.http_req(url, &post);

        response
    }

    /// Get basic anime or manga information
    ///
    /// See [Proxer wiki](http://proxer.me/wiki/Proxer_API/v1/Info#Get_Entry)
    pub fn info_get_entry(self, id: u32) -> Result<client::response::Response, hyper::Error> {
        use api::entity::response::*;
        let url = "info/entry";

        let mut post = postparams::Postparams::new();
        post.add("id", id);

        let response = self.http_req(url, &post);

        response
    }

    /// Get the different names of an anime or manga
    ///
    /// See [Proxer wiki](http://proxer.me/wiki/Proxer_API/v1/Info#Get_Names)
    pub fn info_get_names(self, id: u32) -> Result<client::response::Response, hyper::Error> {
        use api::entity::response::*;
        let url = "info/names";

        let mut post = postparams::Postparams::new();
        post.add("id", id);

        let response = self.http_req(url, &post);

        response
    }

    fn http_req(self, url: &str, data: &postparams::Postparams) -> Result<client::response::Response, hyper::Error> {
        let uri = self.base_uri.to_string()+url;
        let hyper_url = hyper::Url::parse(&uri).unwrap();

        let mut headers = hyper::header::Headers::new();
        header! {(ProxerApiKeyHeader, "proxer-api-key") => [String]}
        header! {(UserAgent, "User-Agent") => [String]}
        headers.set(ProxerApiKeyHeader(self.api_key));
        headers.set(UserAgent(self.user_agent));
        headers.set(hyper::header::ContentType::form_url_encoded());

        self.client
            .post(hyper_url)
            .headers(headers)
            .body(&data.to_string())
            .send()
    }

    pub fn read_json(json: String) -> std::result::Result<serde_json::Value, serde_json::Error> {
        serde_json::from_str(&json)
    }
}
<|endoftext|>


<commit_before>use crate::{generate::*, inner::*, norm::Norm, types::*};
use ndarray::*;
use num_traits::Zero;

#[derive(Debug, Clone)]
pub struct MGS<A> {
    dim: usize,
    q: Vec<Array1<A>>,
    r: Vec<Array1<A>>,
}

pub enum Dependence<A: Scalar> {
    Orthogonal(A::Real),
    Coefficient(Array1<A>),
}

impl<A: Scalar + Lapack> MGS<A> {
    pub fn new(dim: usize) -> Self {
        Self {
            dim,
            q: Vec::new(),
            r: Vec::new(),
        }
    }

    pub fn dim(&self) -> usize {
        self.dim
    }

    pub fn len(&self) -> usize {
        self.q.len()
    }

    /// Add new vector, return residual norm
    pub fn append<S>(&mut self, a: ArrayBase<S, Ix1>) -> A::Real
    where
        S: Data<Elem = A>,
    {
        self.append_if(a, A::Real::zero()).unwrap()
    }

    /// Add new vector if the residual is larger than relative tolerance
    pub fn append_if<S>(&mut self, a: ArrayBase<S, Ix1>, rtol: A::Real) -> Option<A::Real>
    where
        S: Data<Elem = A>,
    {
        assert_eq!(a.len(), self.dim());
        let mut a = a.into_owned();
        let mut coef = Array1::zeros(self.len() + 1);
        for i in 0..self.len() {
            let q = &self.q[i];
            let c = q.inner(&a);
            azip!(mut a, q (q) in { *a = *a - c * q } );
            coef[i] = c;
        }
        let nrm = a.norm_l2();
        if nrm < rtol {
            return None;
        }
        coef[self.len()] = A::from_real(nrm);
        self.r.push(coef);
        azip!(mut a in { *a = *a / A::from_real(nrm) });
        self.q.push(a);
        Some(nrm)
    }

    /// Get orthogonal basis as Q matrix
    pub fn get_q(&self) -> Array2<A> {
        hstack(&self.q).unwrap()
    }

    /// Get each vector norm and coefficients as R matrix
    pub fn get_r(&self) -> Array2<A> {
        let len = self.len();
        let mut r = Array2::zeros((len, len));
        for i in 0..len {
            for j in 0..=i {
                r[(j, i)] = self.r[i][j];
            }
        }
        r
    }
}

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

    const N: usize = 5;

    #[test]
    fn new() {
        let mgs: MGS<f32> = MGS::new(N);
        assert_eq!(mgs.dim(), N);
        assert_eq!(mgs.len(), 0);
    }

    fn test_append<A: Scalar + Lapack>(rtol: A::Real) {
        let mut mgs: MGS<A> = MGS::new(N);
        let a: Array2<A> = crate::generate::random((N, 3));
        dbg!(&a);
        for col in a.axis_iter(Axis(1)) {
            let res = mgs.append(col);
            dbg!(res);
        }
        let q = mgs.get_q();
        dbg!(&q);
        let r = mgs.get_r();
        dbg!(&r);

        dbg!(q.dot(&r));
        close_l2(&q.dot(&r), &a, rtol).unwrap();

        let qt: Array2<_> = conjugate(&q);
        dbg!(qt.dot(&q));
        close_l2(&qt.dot(&q), &Array2::eye(3), rtol).unwrap();
    }

    #[test]
    fn append() {
        test_append::<f32>(1e-5);
        test_append::<c32>(1e-5);
        test_append::<f64>(1e-9);
        test_append::<c64>(1e-9);
    }

    fn test_append_if<A: Scalar + Lapack>(rtol: A::Real) {
        let mut mgs: MGS<A> = MGS::new(N);
        let a: Array2<A> = crate::generate::random((N, 8));
        dbg!(&a);
        for col in a.axis_iter(Axis(1)) {
            match mgs.append_if(col, rtol) {
                Some(res) => {
                    dbg!(res);
                }
                None => break,
            }
        }
        let q = mgs.get_q();
        dbg!(&q);
        let r = mgs.get_r();
        dbg!(&r);

        dbg!(q.dot(&r));
        close_l2(&q.dot(&r), &a.slice(s![.., 0..N]), rtol).unwrap();

        let qt: Array2<_> = conjugate(&q);
        dbg!(qt.dot(&q));
        close_l2(&qt.dot(&q), &Array2::eye(N), rtol).unwrap();
    }

    #[test]
    fn append_if() {
        test_append_if::<f32>(1e-5);
        test_append_if::<c32>(1e-5);
        test_append_if::<f64>(1e-9);
        test_append_if::<c64>(1e-9);
    }
}
<commit_msg>Do not manage R matrix in MGS<commit_after>use crate::{generate::*, inner::*, norm::Norm, types::*};
use ndarray::*;

/// Iterative orthogonalizer using modified Gram-Schmit procedure
#[derive(Debug, Clone)]
pub struct MGS<A> {
    /// Dimension of base space
    dimension: usize,
    /// Basis of spanned space
    q: Vec<Array1<A>>,
}

pub type Residual<S> = ArrayBase<S, Ix1>;
pub type Coefficient<A> = Array1<A>;

impl<A: Scalar + Lapack> MGS<A> {
    pub fn new(dimension: usize) -> Self {
        Self {
            dimension,
            q: Vec::new(),
        }
    }

    pub fn dim(&self) -> usize {
        self.dimension
    }

    pub fn len(&self) -> usize {
        self.q.len()
    }

    /// Orthogonalize given vector using current basis
    ///
    /// Panic
    /// -------
    /// - if the size of the input array mismaches to the dimension
    pub fn orthogonalize<S>(&self, mut a: ArrayBase<S, Ix1>) -> (Residual<S>, Coefficient<A>)
    where
        S: DataMut<Elem = A>,
    {
        assert_eq!(a.len(), self.dim());
        let mut coef = Array1::zeros(self.len() + 1);
        for i in 0..self.len() {
            let q = &self.q[i];
            let c = q.inner(&a);
            azip!(mut a, q (q) in { *a = *a - c * q } );
            coef[i] = c;
        }
        let nrm = a.norm_l2();
        coef[self.len()] = A::from_real(nrm);
        (a, coef)
    }

    /// Add new vector if the residual is larger than relative tolerance
    ///
    /// Panic
    /// -------
    /// - if the size of the input array mismaches to the dimension
    pub fn append_if_independent<S>(&mut self, a: ArrayBase<S, Ix1>, rtol: A::Real) -> Option<Coefficient<A>>
    where
        S: Data<Elem = A>,
    {
        let a = a.into_owned();
        let (mut a, coef) = self.orthogonalize(a);
        let nrm = coef[coef.len()].re();
        if nrm < rtol {
            // Linearly dependent
            return None;
        }
        azip!(mut a in { *a = *a / A::from_real(nrm) });
        self.q.push(a);
        Some(coef)
    }

    /// Get orthogonal basis as Q matrix
    pub fn get_q(&self) -> Array2<A> {
        hstack(&self.q).unwrap()
    }
}

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

    const N: usize = 5;

    #[test]
    fn new() {
        let mgs: MGS<f32> = MGS::new(N);
        assert_eq!(mgs.dim(), N);
        assert_eq!(mgs.len(), 0);
    }

    fn test_append<A: Scalar + Lapack>(rtol: A::Real) {
        let mut mgs: MGS<A> = MGS::new(N);
        let a: Array2<A> = crate::generate::random((N, 3));
        dbg!(&a);
        for col in a.axis_iter(Axis(1)) {
            let res = mgs.append(col);
            dbg!(res);
        }
        let q = mgs.get_q();
        dbg!(&q);
        let r = mgs.get_r();
        dbg!(&r);

        dbg!(q.dot(&r));
        close_l2(&q.dot(&r), &a, rtol).unwrap();

        let qt: Array2<_> = conjugate(&q);
        dbg!(qt.dot(&q));
        close_l2(&qt.dot(&q), &Array2::eye(3), rtol).unwrap();
    }

    #[test]
    fn append() {
        test_append::<f32>(1e-5);
        test_append::<c32>(1e-5);
        test_append::<f64>(1e-9);
        test_append::<c64>(1e-9);
    }

    fn test_append_if<A: Scalar + Lapack>(rtol: A::Real) {
        let mut mgs: MGS<A> = MGS::new(N);
        let a: Array2<A> = crate::generate::random((N, 8));
        dbg!(&a);
        for col in a.axis_iter(Axis(1)) {
            match mgs.append_if(col, rtol) {
                Some(res) => {
                    dbg!(res);
                }
                None => break,
            }
        }
        let q = mgs.get_q();
        dbg!(&q);
        let r = mgs.get_r();
        dbg!(&r);

        dbg!(q.dot(&r));
        close_l2(&q.dot(&r), &a.slice(s![.., 0..N]), rtol).unwrap();

        let qt: Array2<_> = conjugate(&q);
        dbg!(qt.dot(&q));
        close_l2(&qt.dot(&q), &Array2::eye(N), rtol).unwrap();
    }

    #[test]
    fn append_if() {
        test_append_if::<f32>(1e-5);
        test_append_if::<c32>(1e-5);
        test_append_if::<f64>(1e-9);
        test_append_if::<c64>(1e-9);
    }
}
<|endoftext|>


<commit_before>/*
 *
 * Computer-graphics specific implementations.
 * Currently, it is mostly implemented for homogeneous matrices in 2- and 3-space.
 *
 */

use num::One;

use base::allocator::Allocator;
use base::dimension::{DimName, DimNameDiff, DimNameSub, U1};
use base::storage::{Storage, StorageMut};
use base::{
    DefaultAllocator, Matrix3, Matrix4, MatrixN, Scalar, SquareMatrix, Unit, Vector, Vector3,
    VectorN,
};
use geometry::{
    Isometry, IsometryMatrix3, Orthographic3, Perspective3, Point, Point3, Rotation2, Rotation3,
};

use alga::general::{Real, Ring};
use alga::linear::Transformation;

impl<N, D: DimName> MatrixN<N, D>
where
    N: Scalar + Ring,
    DefaultAllocator: Allocator<N, D, D>,
{
    /// Creates a new homogeneous matrix that applies the same scaling factor on each dimension.
    #[inline]
    pub fn new_scaling(scaling: N) -> Self {
        let mut res = Self::from_diagonal_element(scaling);
        res[(D::dim() - 1, D::dim() - 1)] = N::one();

        res
    }

    /// Creates a new homogeneous matrix that applies a distinct scaling factor for each dimension.
    #[inline]
    pub fn new_nonuniform_scaling<SB>(scaling: &Vector<N, DimNameDiff<D, U1>, SB>) -> Self
    where
        D: DimNameSub<U1>,
        SB: Storage<N, DimNameDiff<D, U1>>,
    {
        let mut res = Self::one();
        for i in 0..scaling.len() {
            res[(i, i)] = scaling[i];
        }

        res
    }

    /// Creates a new homogeneous matrix that applies a pure translation.
    #[inline]
    pub fn new_translation<SB>(translation: &Vector<N, DimNameDiff<D, U1>, SB>) -> Self
    where
        D: DimNameSub<U1>,
        SB: Storage<N, DimNameDiff<D, U1>>,
    {
        let mut res = Self::one();
        res.fixed_slice_mut::<DimNameDiff<D, U1>, U1>(0, D::dim() - 1)
            .copy_from(translation);

        res
    }
}

impl<N: Real> Matrix3<N> {
    /// Builds a 2 dimensional homogeneous rotation matrix from an angle in radian.
    #[inline]
    pub fn new_rotation(angle: N) -> Self {
        Rotation2::new(angle).to_homogeneous()
    }
}

impl<N: Real> Matrix4<N> {
    /// Builds a 3D homogeneous rotation matrix from an axis and an angle (multiplied together).
    ///
    /// Returns the identity matrix if the given argument is zero.
    #[inline]
    pub fn new_rotation(axisangle: Vector3<N>) -> Self {
        Rotation3::new(axisangle).to_homogeneous()
    }

    /// Builds a 3D homogeneous rotation matrix from an axis and an angle (multiplied together).
    ///
    /// Returns the identity matrix if the given argument is zero.
    #[inline]
    pub fn new_rotation_wrt_point(axisangle: Vector3<N>, pt: Point3<N>) -> Self {
        let rot = Rotation3::from_scaled_axis(axisangle);
        Isometry::rotation_wrt_point(rot, pt).to_homogeneous()
    }

    /// Builds a 3D homogeneous rotation matrix from an axis and an angle (multiplied together).
    ///
    /// Returns the identity matrix if the given argument is zero.
    /// This is identical to `Self::new_rotation`.
    #[inline]
    pub fn from_scaled_axis(axisangle: Vector3<N>) -> Self {
        Rotation3::from_scaled_axis(axisangle).to_homogeneous()
    }

    /// Creates a new rotation from Euler angles.
    ///
    /// The primitive rotations are applied in order: 1 roll − 2 pitch − 3 yaw.
    pub fn from_euler_angles(roll: N, pitch: N, yaw: N) -> Self {
        Rotation3::from_euler_angles(roll, pitch, yaw).to_homogeneous()
    }

    /// Builds a 3D homogeneous rotation matrix from an axis and a rotation angle.
    pub fn from_axis_angle(axis: &Unit<Vector3<N>>, angle: N) -> Self {
        Rotation3::from_axis_angle(axis, angle).to_homogeneous()
    }

    /// Creates a new homogeneous matrix for an orthographic projection.
    #[inline]
    pub fn new_orthographic(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> Self {
        Orthographic3::new(left, right, bottom, top, znear, zfar).unwrap()
    }

    /// Creates a new homogeneous matrix for a perspective projection.
    #[inline]
    pub fn new_perspective(aspect: N, fovy: N, znear: N, zfar: N) -> Self {
        Perspective3::new(aspect, fovy, znear, zfar).unwrap()
    }

    /// Creates an isometry that corresponds to the local frame of an observer standing at the
    /// point `eye` and looking toward `target`.
    ///
    /// It maps the view direction `target - eye` to the positive `z` axis and the origin to the
    /// `eye`.
    #[inline]
    pub fn new_observer_frame(eye: &Point3<N>, target: &Point3<N>, up: &Vector3<N>) -> Self {
        IsometryMatrix3::new_observer_frame(eye, target, up).to_homogeneous()
    }

    /// Builds a right-handed look-at view matrix.
    #[inline]
    pub fn look_at_rh(eye: &Point3<N>, target: &Point3<N>, up: &Vector3<N>) -> Self {
        IsometryMatrix3::look_at_rh(eye, target, up).to_homogeneous()
    }

    /// Builds a left-handed look-at view matrix.
    #[inline]
    pub fn look_at_lh(eye: &Point3<N>, target: &Point3<N>, up: &Vector3<N>) -> Self {
        IsometryMatrix3::look_at_lh(eye, target, up).to_homogeneous()
    }
}

impl<N: Scalar + Ring, D: DimName, S: Storage<N, D, D>> SquareMatrix<N, D, S> {
    /// Computes the transformation equal to `self` followed by an uniform scaling factor.
    #[inline]
    pub fn append_scaling(&self, scaling: N) -> MatrixN<N, D>
    where
        D: DimNameSub<U1>,
        DefaultAllocator: Allocator<N, D, D>,
    {
        let mut res = self.clone_owned();
        res.append_scaling_mut(scaling);
        res
    }

    /// Computes the transformation equal to an uniform scaling factor followed by `self`.
    #[inline]
    pub fn prepend_scaling(&self, scaling: N) -> MatrixN<N, D>
    where
        D: DimNameSub<U1>,
        DefaultAllocator: Allocator<N, D, D>,
    {
        let mut res = self.clone_owned();
        res.prepend_scaling_mut(scaling);
        res
    }

    /// Computes the transformation equal to `self` followed by a non-uniform scaling factor.
    #[inline]
    pub fn append_nonuniform_scaling<SB>(
        &self,
        scaling: &Vector<N, DimNameDiff<D, U1>, SB>,
    ) -> MatrixN<N, D>
    where
        D: DimNameSub<U1>,
        SB: Storage<N, DimNameDiff<D, U1>>,
        DefaultAllocator: Allocator<N, D, D>,
    {
        let mut res = self.clone_owned();
        res.append_nonuniform_scaling_mut(scaling);
        res
    }

    /// Computes the transformation equal to a non-uniform scaling factor followed by `self`.
    #[inline]
    pub fn prepend_nonuniform_scaling<SB>(
        &self,
        scaling: &Vector<N, DimNameDiff<D, U1>, SB>,
    ) -> MatrixN<N, D>
    where
        D: DimNameSub<U1>,
        SB: Storage<N, DimNameDiff<D, U1>>,
        DefaultAllocator: Allocator<N, D, D>,
    {
        let mut res = self.clone_owned();
        res.prepend_nonuniform_scaling_mut(scaling);
        res
    }

    /// Computes the transformation equal to `self` followed by a translation.
    #[inline]
    pub fn append_translation<SB>(&self, shift: &Vector<N, DimNameDiff<D, U1>, SB>) -> MatrixN<N, D>
    where
        D: DimNameSub<U1>,
        SB: Storage<N, DimNameDiff<D, U1>>,
        DefaultAllocator: Allocator<N, D, D>,
    {
        let mut res = self.clone_owned();
        res.append_translation_mut(shift);
        res
    }

    /// Computes the transformation equal to a translation followed by `self`.
    #[inline]
    pub fn prepend_translation<SB>(
        &self,
        shift: &Vector<N, DimNameDiff<D, U1>, SB>,
    ) -> MatrixN<N, D>
    where
        D: DimNameSub<U1>,
        SB: Storage<N, DimNameDiff<D, U1>>,
        DefaultAllocator: Allocator<N, D, D> + Allocator<N, DimNameDiff<D, U1>>,
    {
        let mut res = self.clone_owned();
        res.prepend_translation_mut(shift);
        res
    }
}

impl<N: Scalar + Ring, D: DimName, S: StorageMut<N, D, D>> SquareMatrix<N, D, S> {
    /// Computes in-place the transformation equal to `self` followed by an uniform scaling factor.
    #[inline]
    pub fn append_scaling_mut(&mut self, scaling: N)
    where D: DimNameSub<U1> {
        let mut to_scale = self.fixed_rows_mut::<DimNameDiff<D, U1>>(0);
        to_scale *= scaling;
    }

    /// Computes in-place the transformation equal to an uniform scaling factor followed by `self`.
    #[inline]
    pub fn prepend_scaling_mut(&mut self, scaling: N)
    where D: DimNameSub<U1> {
        let mut to_scale = self.fixed_columns_mut::<DimNameDiff<D, U1>>(0);
        to_scale *= scaling;
    }

    /// Computes in-place the transformation equal to `self` followed by a non-uniform scaling factor.
    #[inline]
    pub fn append_nonuniform_scaling_mut<SB>(&mut self, scaling: &Vector<N, DimNameDiff<D, U1>, SB>)
    where
        D: DimNameSub<U1>,
        SB: Storage<N, DimNameDiff<D, U1>>,
    {
        for i in 0..scaling.len() {
            let mut to_scale = self.fixed_rows_mut::<U1>(i);
            to_scale *= scaling[i];
        }
    }

    /// Computes in-place the transformation equal to a non-uniform scaling factor followed by `self`.
    #[inline]
    pub fn prepend_nonuniform_scaling_mut<SB>(
        &mut self,
        scaling: &Vector<N, DimNameDiff<D, U1>, SB>,
    ) where
        D: DimNameSub<U1>,
        SB: Storage<N, DimNameDiff<D, U1>>,
    {
        for i in 0..scaling.len() {
            let mut to_scale = self.fixed_columns_mut::<U1>(i);
            to_scale *= scaling[i];
        }
    }

    /// Computes the transformation equal to `self` followed by a translation.
    #[inline]
    pub fn append_translation_mut<SB>(&mut self, shift: &Vector<N, DimNameDiff<D, U1>, SB>)
    where
        D: DimNameSub<U1>,
        SB: Storage<N, DimNameDiff<D, U1>>,
    {
        for i in 0..D::dim() {
            for j in 0..D::dim() - 1 {
                self[(j, i)] += shift[j] * self[(D::dim() - 1, i)];
            }
        }
    }

    /// Computes the transformation equal to a translation followed by `self`.
    #[inline]
    pub fn prepend_translation_mut<SB>(&mut self, shift: &Vector<N, DimNameDiff<D, U1>, SB>)
    where
        D: DimNameSub<U1>,
        SB: Storage<N, DimNameDiff<D, U1>>,
        DefaultAllocator: Allocator<N, DimNameDiff<D, U1>>,
    {
        let scale = self
            .fixed_slice::<U1, DimNameDiff<D, U1>>(D::dim() - 1, 0)
            .tr_dot(&shift);
        let post_translation =
            self.fixed_slice::<DimNameDiff<D, U1>, DimNameDiff<D, U1>>(0, 0) * shift;

        self[(D::dim() - 1, D::dim() - 1)] += scale;

        let mut translation = self.fixed_slice_mut::<DimNameDiff<D, U1>, U1>(0, D::dim() - 1);
        translation += post_translation;
    }
}

impl<N: Real, D: DimNameSub<U1>, S: Storage<N, D, D>> SquareMatrix<N, D, S>
where DefaultAllocator: Allocator<N, D, D>
        + Allocator<N, DimNameDiff<D, U1>>
        + Allocator<N, DimNameDiff<D, U1>, DimNameDiff<D, U1>>
{
    /// Transforms the given vector, assuming the matrix `self` uses homogeneous coordinates.
    #[inline]
    fn transform_vector(
        &self,
        v: &VectorN<N, DimNameDiff<D, U1>>,
    ) -> VectorN<N, DimNameDiff<D, U1>>
    {
        let transform = self.fixed_slice::<DimNameDiff<D, U1>, DimNameDiff<D, U1>>(0, 0);
        let normalizer = self.fixed_slice::<U1, DimNameDiff<D, U1>>(D::dim() - 1, 0);
        let n = normalizer.tr_dot(&v);

        if !n.is_zero() {
            return transform * (v / n);
        }

        transform * v
    }

    /// Transforms the given point, assuming the matrix `self` uses homogeneous coordinates.
    #[inline]
    fn transform_point(&self, pt: &Point<N, DimNameDiff<D, U1>>) -> Point<N, DimNameDiff<D, U1>> {
        let transform = self.fixed_slice::<DimNameDiff<D, U1>, DimNameDiff<D, U1>>(0, 0);
        let translation = self.fixed_slice::<DimNameDiff<D, U1>, U1>(0, D::dim() - 1);
        let normalizer = self.fixed_slice::<U1, DimNameDiff<D, U1>>(D::dim() - 1, 0);
        let n = normalizer.tr_dot(&pt.coords)
            + unsafe { *self.get_unchecked(D::dim() - 1, D::dim() - 1) };

        if !n.is_zero() {
            return transform * (pt / n) + translation;
        }

        transform * pt + translation
    }
}

impl<N: Real, D: DimNameSub<U1>> Transformation<Point<N, DimNameDiff<D, U1>>> for MatrixN<N, D>
where DefaultAllocator: Allocator<N, D, D>
        + Allocator<N, DimNameDiff<D, U1>>
        + Allocator<N, DimNameDiff<D, U1>, DimNameDiff<D, U1>>
{
    #[inline]
    fn transform_vector(
        &self,
        v: &VectorN<N, DimNameDiff<D, U1>>,
    ) -> VectorN<N, DimNameDiff<D, U1>>
    {
        self.transform_vector(v)
    }

    #[inline]
    fn transform_point(&self, pt: &Point<N, DimNameDiff<D, U1>>) -> Point<N, DimNameDiff<D, U1>> {
        self.transform_point(pt)
    }
}
<commit_msg>Make transform_vector and transform_point public.<commit_after>/*
 *
 * Computer-graphics specific implementations.
 * Currently, it is mostly implemented for homogeneous matrices in 2- and 3-space.
 *
 */

use num::One;

use base::allocator::Allocator;
use base::dimension::{DimName, DimNameDiff, DimNameSub, U1};
use base::storage::{Storage, StorageMut};
use base::{
    DefaultAllocator, Matrix3, Matrix4, MatrixN, Scalar, SquareMatrix, Unit, Vector, Vector3,
    VectorN,
};
use geometry::{
    Isometry, IsometryMatrix3, Orthographic3, Perspective3, Point, Point3, Rotation2, Rotation3,
};

use alga::general::{Real, Ring};
use alga::linear::Transformation;

impl<N, D: DimName> MatrixN<N, D>
where
    N: Scalar + Ring,
    DefaultAllocator: Allocator<N, D, D>,
{
    /// Creates a new homogeneous matrix that applies the same scaling factor on each dimension.
    #[inline]
    pub fn new_scaling(scaling: N) -> Self {
        let mut res = Self::from_diagonal_element(scaling);
        res[(D::dim() - 1, D::dim() - 1)] = N::one();

        res
    }

    /// Creates a new homogeneous matrix that applies a distinct scaling factor for each dimension.
    #[inline]
    pub fn new_nonuniform_scaling<SB>(scaling: &Vector<N, DimNameDiff<D, U1>, SB>) -> Self
    where
        D: DimNameSub<U1>,
        SB: Storage<N, DimNameDiff<D, U1>>,
    {
        let mut res = Self::one();
        for i in 0..scaling.len() {
            res[(i, i)] = scaling[i];
        }

        res
    }

    /// Creates a new homogeneous matrix that applies a pure translation.
    #[inline]
    pub fn new_translation<SB>(translation: &Vector<N, DimNameDiff<D, U1>, SB>) -> Self
    where
        D: DimNameSub<U1>,
        SB: Storage<N, DimNameDiff<D, U1>>,
    {
        let mut res = Self::one();
        res.fixed_slice_mut::<DimNameDiff<D, U1>, U1>(0, D::dim() - 1)
            .copy_from(translation);

        res
    }
}

impl<N: Real> Matrix3<N> {
    /// Builds a 2 dimensional homogeneous rotation matrix from an angle in radian.
    #[inline]
    pub fn new_rotation(angle: N) -> Self {
        Rotation2::new(angle).to_homogeneous()
    }
}

impl<N: Real> Matrix4<N> {
    /// Builds a 3D homogeneous rotation matrix from an axis and an angle (multiplied together).
    ///
    /// Returns the identity matrix if the given argument is zero.
    #[inline]
    pub fn new_rotation(axisangle: Vector3<N>) -> Self {
        Rotation3::new(axisangle).to_homogeneous()
    }

    /// Builds a 3D homogeneous rotation matrix from an axis and an angle (multiplied together).
    ///
    /// Returns the identity matrix if the given argument is zero.
    #[inline]
    pub fn new_rotation_wrt_point(axisangle: Vector3<N>, pt: Point3<N>) -> Self {
        let rot = Rotation3::from_scaled_axis(axisangle);
        Isometry::rotation_wrt_point(rot, pt).to_homogeneous()
    }

    /// Builds a 3D homogeneous rotation matrix from an axis and an angle (multiplied together).
    ///
    /// Returns the identity matrix if the given argument is zero.
    /// This is identical to `Self::new_rotation`.
    #[inline]
    pub fn from_scaled_axis(axisangle: Vector3<N>) -> Self {
        Rotation3::from_scaled_axis(axisangle).to_homogeneous()
    }

    /// Creates a new rotation from Euler angles.
    ///
    /// The primitive rotations are applied in order: 1 roll − 2 pitch − 3 yaw.
    pub fn from_euler_angles(roll: N, pitch: N, yaw: N) -> Self {
        Rotation3::from_euler_angles(roll, pitch, yaw).to_homogeneous()
    }

    /// Builds a 3D homogeneous rotation matrix from an axis and a rotation angle.
    pub fn from_axis_angle(axis: &Unit<Vector3<N>>, angle: N) -> Self {
        Rotation3::from_axis_angle(axis, angle).to_homogeneous()
    }

    /// Creates a new homogeneous matrix for an orthographic projection.
    #[inline]
    pub fn new_orthographic(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> Self {
        Orthographic3::new(left, right, bottom, top, znear, zfar).unwrap()
    }

    /// Creates a new homogeneous matrix for a perspective projection.
    #[inline]
    pub fn new_perspective(aspect: N, fovy: N, znear: N, zfar: N) -> Self {
        Perspective3::new(aspect, fovy, znear, zfar).unwrap()
    }

    /// Creates an isometry that corresponds to the local frame of an observer standing at the
    /// point `eye` and looking toward `target`.
    ///
    /// It maps the view direction `target - eye` to the positive `z` axis and the origin to the
    /// `eye`.
    #[inline]
    pub fn new_observer_frame(eye: &Point3<N>, target: &Point3<N>, up: &Vector3<N>) -> Self {
        IsometryMatrix3::new_observer_frame(eye, target, up).to_homogeneous()
    }

    /// Builds a right-handed look-at view matrix.
    #[inline]
    pub fn look_at_rh(eye: &Point3<N>, target: &Point3<N>, up: &Vector3<N>) -> Self {
        IsometryMatrix3::look_at_rh(eye, target, up).to_homogeneous()
    }

    /// Builds a left-handed look-at view matrix.
    #[inline]
    pub fn look_at_lh(eye: &Point3<N>, target: &Point3<N>, up: &Vector3<N>) -> Self {
        IsometryMatrix3::look_at_lh(eye, target, up).to_homogeneous()
    }
}

impl<N: Scalar + Ring, D: DimName, S: Storage<N, D, D>> SquareMatrix<N, D, S> {
    /// Computes the transformation equal to `self` followed by an uniform scaling factor.
    #[inline]
    pub fn append_scaling(&self, scaling: N) -> MatrixN<N, D>
    where
        D: DimNameSub<U1>,
        DefaultAllocator: Allocator<N, D, D>,
    {
        let mut res = self.clone_owned();
        res.append_scaling_mut(scaling);
        res
    }

    /// Computes the transformation equal to an uniform scaling factor followed by `self`.
    #[inline]
    pub fn prepend_scaling(&self, scaling: N) -> MatrixN<N, D>
    where
        D: DimNameSub<U1>,
        DefaultAllocator: Allocator<N, D, D>,
    {
        let mut res = self.clone_owned();
        res.prepend_scaling_mut(scaling);
        res
    }

    /// Computes the transformation equal to `self` followed by a non-uniform scaling factor.
    #[inline]
    pub fn append_nonuniform_scaling<SB>(
        &self,
        scaling: &Vector<N, DimNameDiff<D, U1>, SB>,
    ) -> MatrixN<N, D>
    where
        D: DimNameSub<U1>,
        SB: Storage<N, DimNameDiff<D, U1>>,
        DefaultAllocator: Allocator<N, D, D>,
    {
        let mut res = self.clone_owned();
        res.append_nonuniform_scaling_mut(scaling);
        res
    }

    /// Computes the transformation equal to a non-uniform scaling factor followed by `self`.
    #[inline]
    pub fn prepend_nonuniform_scaling<SB>(
        &self,
        scaling: &Vector<N, DimNameDiff<D, U1>, SB>,
    ) -> MatrixN<N, D>
    where
        D: DimNameSub<U1>,
        SB: Storage<N, DimNameDiff<D, U1>>,
        DefaultAllocator: Allocator<N, D, D>,
    {
        let mut res = self.clone_owned();
        res.prepend_nonuniform_scaling_mut(scaling);
        res
    }

    /// Computes the transformation equal to `self` followed by a translation.
    #[inline]
    pub fn append_translation<SB>(&self, shift: &Vector<N, DimNameDiff<D, U1>, SB>) -> MatrixN<N, D>
    where
        D: DimNameSub<U1>,
        SB: Storage<N, DimNameDiff<D, U1>>,
        DefaultAllocator: Allocator<N, D, D>,
    {
        let mut res = self.clone_owned();
        res.append_translation_mut(shift);
        res
    }

    /// Computes the transformation equal to a translation followed by `self`.
    #[inline]
    pub fn prepend_translation<SB>(
        &self,
        shift: &Vector<N, DimNameDiff<D, U1>, SB>,
    ) -> MatrixN<N, D>
    where
        D: DimNameSub<U1>,
        SB: Storage<N, DimNameDiff<D, U1>>,
        DefaultAllocator: Allocator<N, D, D> + Allocator<N, DimNameDiff<D, U1>>,
    {
        let mut res = self.clone_owned();
        res.prepend_translation_mut(shift);
        res
    }
}

impl<N: Scalar + Ring, D: DimName, S: StorageMut<N, D, D>> SquareMatrix<N, D, S> {
    /// Computes in-place the transformation equal to `self` followed by an uniform scaling factor.
    #[inline]
    pub fn append_scaling_mut(&mut self, scaling: N)
    where D: DimNameSub<U1> {
        let mut to_scale = self.fixed_rows_mut::<DimNameDiff<D, U1>>(0);
        to_scale *= scaling;
    }

    /// Computes in-place the transformation equal to an uniform scaling factor followed by `self`.
    #[inline]
    pub fn prepend_scaling_mut(&mut self, scaling: N)
    where D: DimNameSub<U1> {
        let mut to_scale = self.fixed_columns_mut::<DimNameDiff<D, U1>>(0);
        to_scale *= scaling;
    }

    /// Computes in-place the transformation equal to `self` followed by a non-uniform scaling factor.
    #[inline]
    pub fn append_nonuniform_scaling_mut<SB>(&mut self, scaling: &Vector<N, DimNameDiff<D, U1>, SB>)
    where
        D: DimNameSub<U1>,
        SB: Storage<N, DimNameDiff<D, U1>>,
    {
        for i in 0..scaling.len() {
            let mut to_scale = self.fixed_rows_mut::<U1>(i);
            to_scale *= scaling[i];
        }
    }

    /// Computes in-place the transformation equal to a non-uniform scaling factor followed by `self`.
    #[inline]
    pub fn prepend_nonuniform_scaling_mut<SB>(
        &mut self,
        scaling: &Vector<N, DimNameDiff<D, U1>, SB>,
    ) where
        D: DimNameSub<U1>,
        SB: Storage<N, DimNameDiff<D, U1>>,
    {
        for i in 0..scaling.len() {
            let mut to_scale = self.fixed_columns_mut::<U1>(i);
            to_scale *= scaling[i];
        }
    }

    /// Computes the transformation equal to `self` followed by a translation.
    #[inline]
    pub fn append_translation_mut<SB>(&mut self, shift: &Vector<N, DimNameDiff<D, U1>, SB>)
    where
        D: DimNameSub<U1>,
        SB: Storage<N, DimNameDiff<D, U1>>,
    {
        for i in 0..D::dim() {
            for j in 0..D::dim() - 1 {
                self[(j, i)] += shift[j] * self[(D::dim() - 1, i)];
            }
        }
    }

    /// Computes the transformation equal to a translation followed by `self`.
    #[inline]
    pub fn prepend_translation_mut<SB>(&mut self, shift: &Vector<N, DimNameDiff<D, U1>, SB>)
    where
        D: DimNameSub<U1>,
        SB: Storage<N, DimNameDiff<D, U1>>,
        DefaultAllocator: Allocator<N, DimNameDiff<D, U1>>,
    {
        let scale = self
            .fixed_slice::<U1, DimNameDiff<D, U1>>(D::dim() - 1, 0)
            .tr_dot(&shift);
        let post_translation =
            self.fixed_slice::<DimNameDiff<D, U1>, DimNameDiff<D, U1>>(0, 0) * shift;

        self[(D::dim() - 1, D::dim() - 1)] += scale;

        let mut translation = self.fixed_slice_mut::<DimNameDiff<D, U1>, U1>(0, D::dim() - 1);
        translation += post_translation;
    }
}

impl<N: Real, D: DimNameSub<U1>, S: Storage<N, D, D>> SquareMatrix<N, D, S>
where DefaultAllocator: Allocator<N, D, D>
        + Allocator<N, DimNameDiff<D, U1>>
        + Allocator<N, DimNameDiff<D, U1>, DimNameDiff<D, U1>>
{
    /// Transforms the given vector, assuming the matrix `self` uses homogeneous coordinates.
    #[inline]
    pub fn transform_vector(
        &self,
        v: &VectorN<N, DimNameDiff<D, U1>>,
    ) -> VectorN<N, DimNameDiff<D, U1>>
    {
        let transform = self.fixed_slice::<DimNameDiff<D, U1>, DimNameDiff<D, U1>>(0, 0);
        let normalizer = self.fixed_slice::<U1, DimNameDiff<D, U1>>(D::dim() - 1, 0);
        let n = normalizer.tr_dot(&v);

        if !n.is_zero() {
            return transform * (v / n);
        }

        transform * v
    }

    /// Transforms the given point, assuming the matrix `self` uses homogeneous coordinates.
    #[inline]
    pub fn transform_point(
        &self,
        pt: &Point<N, DimNameDiff<D, U1>>,
    ) -> Point<N, DimNameDiff<D, U1>>
    {
        let transform = self.fixed_slice::<DimNameDiff<D, U1>, DimNameDiff<D, U1>>(0, 0);
        let translation = self.fixed_slice::<DimNameDiff<D, U1>, U1>(0, D::dim() - 1);
        let normalizer = self.fixed_slice::<U1, DimNameDiff<D, U1>>(D::dim() - 1, 0);
        let n = normalizer.tr_dot(&pt.coords)
            + unsafe { *self.get_unchecked(D::dim() - 1, D::dim() - 1) };

        if !n.is_zero() {
            return transform * (pt / n) + translation;
        }

        transform * pt + translation
    }
}

impl<N: Real, D: DimNameSub<U1>> Transformation<Point<N, DimNameDiff<D, U1>>> for MatrixN<N, D>
where DefaultAllocator: Allocator<N, D, D>
        + Allocator<N, DimNameDiff<D, U1>>
        + Allocator<N, DimNameDiff<D, U1>, DimNameDiff<D, U1>>
{
    #[inline]
    fn transform_vector(
        &self,
        v: &VectorN<N, DimNameDiff<D, U1>>,
    ) -> VectorN<N, DimNameDiff<D, U1>>
    {
        self.transform_vector(v)
    }

    #[inline]
    fn transform_point(&self, pt: &Point<N, DimNameDiff<D, U1>>) -> Point<N, DimNameDiff<D, U1>> {
        self.transform_point(pt)
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;

use crate::types::BodyStructure;
/// An utility parser helping to find the appropriate
/// section part from a FETCH response.
pub struct BodyStructParser<'a> {
    root: &'a BodyStructure<'a>,
    prefix: Vec<u32>,
    iter: u32,
    map: HashMap<Vec<u32>, &'a BodyStructure<'a>>,
}

impl<'a> BodyStructParser<'a> {
    /// Returns a new parser
    ///
    /// # Arguments
    ///
    /// * `root` - The root of the `BodyStructure response.
    pub fn new(root: &'a BodyStructure<'a>) -> Self {
        let mut parser = BodyStructParser {
            root,
            prefix: vec![],
            iter: 1,
            map: HashMap::new(),
        };

        parser.parse(parser.root);
        parser
    }

    /// Search particular element within the bodystructure.
    ///
    /// # Arguments
    ///
    /// * `func` - The filter used to search elements within the bodystructure.
    pub fn search<F>(&self, func: F) -> Option<Vec<u32>>
    where
        F: Fn(&'a BodyStructure<'a>) -> bool,
    {
        let elem: Vec<_> = self
            .map
            .iter()
            .filter_map(|(k, v)| {
                if func(*v) {
                    let slice: &[u32] = k;
                    Some(slice)
                } else {
                    None
                }
            })
            .collect();
        elem.first().map(|a| a.to_vec())
    }

    /// Reetr
    fn parse(&mut self, node: &'a BodyStructure) {
        match node {
            BodyStructure::Multipart { bodies, .. } => {
                let vec = self.prefix.clone();
                self.map.insert(vec, node);

                for (i, n) in bodies.iter().enumerate() {
                    self.iter += i as u32;
                    self.prefix.push(self.iter);
                    self.parse(n);
                    self.prefix.pop();
                }
                self.iter = 1;
            }
            _ => {
                let vec = self.prefix.clone();
                self.map.insert(vec, node);
            }
        };
    }
}
<commit_msg>chore: apply clippy suggestions for 1.65<commit_after>use std::collections::HashMap;

use crate::types::BodyStructure;
/// An utility parser helping to find the appropriate
/// section part from a FETCH response.
pub struct BodyStructParser<'a> {
    root: &'a BodyStructure<'a>,
    prefix: Vec<u32>,
    iter: u32,
    map: HashMap<Vec<u32>, &'a BodyStructure<'a>>,
}

impl<'a> BodyStructParser<'a> {
    /// Returns a new parser
    ///
    /// # Arguments
    ///
    /// * `root` - The root of the `BodyStructure response.
    pub fn new(root: &'a BodyStructure<'a>) -> Self {
        let mut parser = BodyStructParser {
            root,
            prefix: vec![],
            iter: 1,
            map: HashMap::new(),
        };

        parser.parse(parser.root);
        parser
    }

    /// Search particular element within the bodystructure.
    ///
    /// # Arguments
    ///
    /// * `func` - The filter used to search elements within the bodystructure.
    pub fn search<F>(&self, func: F) -> Option<Vec<u32>>
    where
        F: Fn(&'a BodyStructure<'a>) -> bool,
    {
        let elem: Vec<_> = self
            .map
            .iter()
            .filter_map(|(k, v)| {
                if func(v) {
                    let slice: &[u32] = k;
                    Some(slice)
                } else {
                    None
                }
            })
            .collect();
        elem.first().map(|a| a.to_vec())
    }

    /// Reetr
    fn parse(&mut self, node: &'a BodyStructure) {
        match node {
            BodyStructure::Multipart { bodies, .. } => {
                let vec = self.prefix.clone();
                self.map.insert(vec, node);

                for (i, n) in bodies.iter().enumerate() {
                    self.iter += i as u32;
                    self.prefix.push(self.iter);
                    self.parse(n);
                    self.prefix.pop();
                }
                self.iter = 1;
            }
            _ => {
                let vec = self.prefix.clone();
                self.map.insert(vec, node);
            }
        };
    }
}
<|endoftext|>


<commit_before>use std::str::from_utf8;
use bencoded::*;
use parse::*;
use token::*;
use dict::*;
use list::*;

impl<'a> BEncoded<'a> {
    /// Is the remaining `data` a dict?
    pub fn is_dict(&self) -> bool {
        match parse_token(self.data) {
            Some((Token::DictStart, _)) => true,
            _ => false,
        }
    }

    /// Is the remaining `data` a list?
    pub fn is_list(&self) -> bool {
        match parse_token(self.data) {
            Some((Token::ListStart, _)) => true,
            _ => false,
        }
    }

    /// Is the remaining `data` a string? Then get it as a cheap slice.
    pub fn get_byte_string(&self) -> Option<&'a [u8]> {
        match parse_token(self.data) {
            Some((Token::ByteString(s), _)) => Some(s),
            _ => None,
        }
    }

    /// Is the remaining `data` a string? Then get it as checked UTF-8.
    pub fn get_utf8_string(&self) -> Option<&'a str> {
        self.get_byte_string()
            .and_then(|s| match from_utf8(s) {
                Ok(s) => Some(s),
                Err(_) => None,
            })
    }

    /// Is the remaining `data` an integer? If so, parse and return it.
    pub fn get_integer(&self) -> Option<i64> {
        let s = match parse_token(self.data) {
            Some((Token::Integer(bs), _)) => bs,
            _ => return None
        };

        let mut sig = 1;
        let mut position = 0;
        match s[0] as char {
            '-' => {
                sig = -1;
                position += 1;
            },
            _ => (),
        }

        let mut value = 0;
        for ch in &s[position..] {
            match *ch as char {
                '0'...'9' =>
                    value = (value * 10) + *ch as i64 - '0' as i64,
                _ =>
                    return None
            }
        }
        Some(sig * value)
    }

    /// Used by [`dict()`](#method.dict) and [`list()`](#method.list)
    ///
    /// Restricts the `BEncoded<'a>` to a single item (string,
    /// integer, list, or dict). Also returns the trailing data.
    pub fn this_and_rest(mut self) -> Option<(BEncoded<'a>, &'a [u8])> {
        let data = &self.data[..];
        while self.depth >= 0 {
            match self.next() {
                None => return None,
                _ => (),
            }
        }

        let this = BEncoded::new(&data[0..(data.len() - self.data.len())]);
        Some((this, self.data))
    }

    /// If the remaining data is a list, return value fulfills
    /// `Iterator<Item=BEncoded<'a>>`
    pub fn list(&self) -> ListIterator {
        ListIterator::new(self.data)
    }

    /// If the remaining data is a dict, return value fulfills
    /// `Iterator<Item=(BEncoded<'a>, BEncoded<'a>)>`
    pub fn dict(&self) -> DictIterator {
        DictIterator::new(self.data)
    }

    /// From a [`dict()`](#method.dict), get the value of key
    /// `wanted_key`.
    ///
    /// In case the key is not present, we return an empty
    /// instance. This allows chaining these calls conveniently:
    ///
    /// ```
    /// # use self::lazy_bencoding::*;
    /// let bencoded = BEncoded::new(b"d1:ad1:ad1:a4:spame1:bd1:a4:eggseee");
    /// assert_eq!(bencoded.get(b"a").get(b"b").get(b"a").get_utf8_string(),
    ///            Some("eggs"));
    /// ```
    pub fn get(&'a self, wanted_key: &'a [u8]) -> Self {
        for (mut key, value) in self.dict() {
            match (key.next(), key.next()) {
                (Some(Token::ByteString(s)), None) if s == wanted_key => return value,
                _ => (),
            }
        }

        // Default value:
        BEncoded::empty()
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_is_dict() {
        let bencoded = ::BEncoded::new(b"de");
        assert!(bencoded.is_dict(), "is_dict");
    }

    #[test]
    fn test_is_list() {
        let bencoded = ::BEncoded::new(b"le");
        assert!(bencoded.is_list(), "is_list");
    }

    #[test]
    fn test_get_byte_string() {
        let bencoded = ::BEncoded::new(b"4:spam");
        let expected: &'static [u8] = b"spam";
        assert_eq!(bencoded.get_byte_string(), Some(expected));
    }

    #[test]
    fn test_get_utf8_string() {
        let bencoded = ::BEncoded::new(b"4:spam");
        assert_eq!(bencoded.get_utf8_string(), Some("spam"));
    }

    #[test]
    fn test_get_integer() {
        let bencoded = ::BEncoded::new(b"i23e");
        assert_eq!(bencoded.get_integer(), Some(23));
    }

    #[test]
    fn test_get_negative_integer() {
        let bencoded = ::BEncoded::new(b"i-5e");
        assert_eq!(bencoded.get_integer(), Some(-5));
    }

    #[test]
    fn test_this_and_rest1() {
        let bencoded = ::BEncoded::new(b"4:spam4:eggs");
        let result = bencoded.this_and_rest().map(|(bencoded, rest)| (bencoded.data, rest));

        let expected_this: &'static [u8] = b"4:spam";
        let expected_rest: &'static [u8] = b"4:eggs";
        assert_eq!(result, Some((expected_this, expected_rest)));
    }

    #[test]
    fn test_this_and_rest2() {
        let bencoded = ::BEncoded::new(b"l4:spam4:eggseli23ee");
        let result = bencoded.this_and_rest().map(|(bencoded, rest)| (bencoded.data, rest));

        let expected_this: &'static [u8] = b"l4:spam4:eggse";
        let expected_rest: &'static [u8] = b"li23ee";
        assert_eq!(result, Some((expected_this, expected_rest)));
    }

    #[test]
    fn test_get_key1() {
        let bencoded = ::BEncoded::new(b"d1:a4:spame");
        let a_bencoded = bencoded.get(b"a");
        let mut a = Vec::new();
        for token in a_bencoded {
            a.push(token);
        }
        assert_eq!(a, vec![::Token::ByteString(b"spam")]);
    }

    #[test]
    fn test_get_key2() {
        let bencoded = ::BEncoded::new(b"d1:a4:spam1:b4:eggs1:ci42ee");
        assert_eq!(bencoded.get(b"a").get_utf8_string(), Some("spam"));
        assert_eq!(bencoded.get(b"b").get_utf8_string(), Some("eggs"));
        assert_eq!(bencoded.get(b"c").get_integer(), Some(42));
    }

    #[test]
    fn test_get_key_nested() {
        let bencoded = ::BEncoded::new(b"d1:ad1:ad1:a4:spame1:bd1:a4:eggseee");
        assert_eq!(bencoded.get(b"a").get(b"a").get(b"a").get_utf8_string(),
                   Some("spam"));
        assert_eq!(bencoded.get(b"a").get(b"b").get(b"a").get_utf8_string(),
                   Some("eggs"));
    }
}
<commit_msg>traverse: add test_get_key_not_found<commit_after>use std::str::from_utf8;
use bencoded::*;
use parse::*;
use token::*;
use dict::*;
use list::*;

impl<'a> BEncoded<'a> {
    /// Is the remaining `data` a dict?
    pub fn is_dict(&self) -> bool {
        match parse_token(self.data) {
            Some((Token::DictStart, _)) => true,
            _ => false,
        }
    }

    /// Is the remaining `data` a list?
    pub fn is_list(&self) -> bool {
        match parse_token(self.data) {
            Some((Token::ListStart, _)) => true,
            _ => false,
        }
    }

    /// Is the remaining `data` a string? Then get it as a cheap slice.
    pub fn get_byte_string(&self) -> Option<&'a [u8]> {
        match parse_token(self.data) {
            Some((Token::ByteString(s), _)) => Some(s),
            _ => None,
        }
    }

    /// Is the remaining `data` a string? Then get it as checked UTF-8.
    pub fn get_utf8_string(&self) -> Option<&'a str> {
        self.get_byte_string()
            .and_then(|s| match from_utf8(s) {
                Ok(s) => Some(s),
                Err(_) => None,
            })
    }

    /// Is the remaining `data` an integer? If so, parse and return it.
    pub fn get_integer(&self) -> Option<i64> {
        let s = match parse_token(self.data) {
            Some((Token::Integer(bs), _)) => bs,
            _ => return None
        };

        let mut sig = 1;
        let mut position = 0;
        match s[0] as char {
            '-' => {
                sig = -1;
                position += 1;
            },
            _ => (),
        }

        let mut value = 0;
        for ch in &s[position..] {
            match *ch as char {
                '0'...'9' =>
                    value = (value * 10) + *ch as i64 - '0' as i64,
                _ =>
                    return None
            }
        }
        Some(sig * value)
    }

    /// Used by [`dict()`](#method.dict) and [`list()`](#method.list)
    ///
    /// Restricts the `BEncoded<'a>` to a single item (string,
    /// integer, list, or dict). Also returns the trailing data.
    pub fn this_and_rest(mut self) -> Option<(BEncoded<'a>, &'a [u8])> {
        let data = &self.data[..];
        while self.depth >= 0 {
            match self.next() {
                None => return None,
                _ => (),
            }
        }

        let this = BEncoded::new(&data[0..(data.len() - self.data.len())]);
        Some((this, self.data))
    }

    /// If the remaining data is a list, return value fulfills
    /// `Iterator<Item=BEncoded<'a>>`
    pub fn list(&self) -> ListIterator {
        ListIterator::new(self.data)
    }

    /// If the remaining data is a dict, return value fulfills
    /// `Iterator<Item=(BEncoded<'a>, BEncoded<'a>)>`
    pub fn dict(&self) -> DictIterator {
        DictIterator::new(self.data)
    }

    /// From a [`dict()`](#method.dict), get the value of key
    /// `wanted_key`.
    ///
    /// In case the key is not present, we return an empty
    /// instance. This allows chaining these calls conveniently:
    ///
    /// ```
    /// # use self::lazy_bencoding::*;
    /// let bencoded = BEncoded::new(b"d1:ad1:ad1:a4:spame1:bd1:a4:eggseee");
    /// assert_eq!(bencoded.get(b"a").get(b"b").get(b"a").get_utf8_string(),
    ///            Some("eggs"));
    /// ```
    pub fn get(&'a self, wanted_key: &'a [u8]) -> Self {
        for (mut key, value) in self.dict() {
            match (key.next(), key.next()) {
                (Some(Token::ByteString(s)), None) if s == wanted_key => return value,
                _ => (),
            }
        }

        // Default value:
        BEncoded::empty()
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_is_dict() {
        let bencoded = ::BEncoded::new(b"de");
        assert!(bencoded.is_dict(), "is_dict");
    }

    #[test]
    fn test_is_list() {
        let bencoded = ::BEncoded::new(b"le");
        assert!(bencoded.is_list(), "is_list");
    }

    #[test]
    fn test_get_byte_string() {
        let bencoded = ::BEncoded::new(b"4:spam");
        let expected: &'static [u8] = b"spam";
        assert_eq!(bencoded.get_byte_string(), Some(expected));
    }

    #[test]
    fn test_get_utf8_string() {
        let bencoded = ::BEncoded::new(b"4:spam");
        assert_eq!(bencoded.get_utf8_string(), Some("spam"));
    }

    #[test]
    fn test_get_integer() {
        let bencoded = ::BEncoded::new(b"i23e");
        assert_eq!(bencoded.get_integer(), Some(23));
    }

    #[test]
    fn test_get_negative_integer() {
        let bencoded = ::BEncoded::new(b"i-5e");
        assert_eq!(bencoded.get_integer(), Some(-5));
    }

    #[test]
    fn test_this_and_rest1() {
        let bencoded = ::BEncoded::new(b"4:spam4:eggs");
        let result = bencoded.this_and_rest().map(|(bencoded, rest)| (bencoded.data, rest));

        let expected_this: &'static [u8] = b"4:spam";
        let expected_rest: &'static [u8] = b"4:eggs";
        assert_eq!(result, Some((expected_this, expected_rest)));
    }

    #[test]
    fn test_this_and_rest2() {
        let bencoded = ::BEncoded::new(b"l4:spam4:eggseli23ee");
        let result = bencoded.this_and_rest().map(|(bencoded, rest)| (bencoded.data, rest));

        let expected_this: &'static [u8] = b"l4:spam4:eggse";
        let expected_rest: &'static [u8] = b"li23ee";
        assert_eq!(result, Some((expected_this, expected_rest)));
    }

    #[test]
    fn test_get_key_not_found() {
        let bencoded = ::BEncoded::new(b"d1:a4:spam1:b4:eggs1:ci42ee");
        assert_eq!(bencoded.get(b"x").data, b"");
    }

    #[test]
    fn test_get_key1() {
        let bencoded = ::BEncoded::new(b"d1:a4:spame");
        let a_bencoded = bencoded.get(b"a");
        let mut a = Vec::new();
        for token in a_bencoded {
            a.push(token);
        }
        assert_eq!(a, vec![::Token::ByteString(b"spam")]);
    }

    #[test]
    fn test_get_key2() {
        let bencoded = ::BEncoded::new(b"d1:a4:spam1:b4:eggs1:ci42ee");
        assert_eq!(bencoded.get(b"a").get_utf8_string(), Some("spam"));
        assert_eq!(bencoded.get(b"b").get_utf8_string(), Some("eggs"));
        assert_eq!(bencoded.get(b"c").get_integer(), Some(42));
    }

    #[test]
    fn test_get_key_nested() {
        let bencoded = ::BEncoded::new(b"d1:ad1:ad1:a4:spame1:bd1:a4:eggseee");
        assert_eq!(bencoded.get(b"a").get(b"a").get(b"a").get_utf8_string(),
                   Some("spam"));
        assert_eq!(bencoded.get(b"a").get(b"b").get(b"a").get_utf8_string(),
                   Some("eggs"));
    }
}
<|endoftext|>