<commit_before>use crate::event::Source;
use crate::net::UnixStream;
#[cfg(debug_assertions)]
use crate::poll::SelectorId;
use crate::unix::SocketAddr;
use crate::{sys, Interests, Registry, Token};

use std::io;
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use std::os::unix::net;
use std::path::Path;

/// A non-blocking Unix domain socket server.
#[derive(Debug)]
pub struct UnixListener {
    sys: sys::UnixListener,
    #[cfg(debug_assertions)]
    selector_id: SelectorId,
}

impl UnixListener {
    fn new(sys: sys::UnixListener) -> UnixListener {
        UnixListener {
            sys,
            #[cfg(debug_assertions)]
            selector_id: SelectorId::new(),
        }
    }

    /// Creates a new `UnixListener` bound to the specified socket.
    pub fn bind<P: AsRef<Path>>(path: P) -> io::Result<UnixListener> {
        let sys = sys::UnixListener::bind(path.as_ref())?;
        Ok(UnixListener::new(sys))
    }

    /// Creates a new `UnixListener` from a standard `net::UnixListener`.
    ///
    /// This function is intended to be used to wrap a Unix listener from the
    /// standard library in the Mio equivalent. The conversion assumes nothing
    /// about the underlying listener; it is left up to the user to set it in
    /// non-blocking mode.
    pub fn from_std(listener: net::UnixListener) -> UnixListener {
        let sys = sys::UnixListener::from_std(listener);
        UnixListener {
            sys,
            #[cfg(debug_assertions)]
            selector_id: SelectorId::new(),
        }
    }

    /// Accepts a new incoming connection to this listener.
    ///
    /// The call is responsible for ensuring that the listening socket is in
    /// non-blocking mode.
    pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> {
        let (sys, sockaddr) = self.sys.accept()?;
        Ok((UnixStream::new(sys), sockaddr))
    }

    /// Creates a new independently owned handle to the underlying socket.
    ///
    /// The returned `UnixListener` is a reference to the same socket that this
    /// object references. Both handles can be used to accept incoming
    /// connections and options set on one listener will affect the other.
    pub fn try_clone(&self) -> io::Result<UnixListener> {
        let sys = self.sys.try_clone()?;
        Ok(UnixListener::new(sys))
    }

    /// Returns the local socket address of this listener.
    pub fn local_addr(&self) -> io::Result<sys::SocketAddr> {
        self.sys.local_addr()
    }

    /// Returns the value of the `SO_ERROR` option.
    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
        self.sys.take_error()
    }
}

impl Source for UnixListener {
    fn register(&self, registry: &Registry, token: Token, interests: Interests) -> io::Result<()> {
        #[cfg(debug_assertions)]
        self.selector_id.associate_selector(registry)?;
        self.sys.reregister(registry, token, interests)
    }

    fn reregister(
        &self,
        registry: &Registry,
        token: Token,
        interests: Interests,
    ) -> io::Result<()> {
        self.sys.reregister(registry, token, interests)
    }

    fn deregister(&self, registry: &Registry) -> io::Result<()> {
        self.sys.deregister(registry)
    }
}

#[cfg(unix)]
impl AsRawFd for UnixListener {
    fn as_raw_fd(&self) -> RawFd {
        self.sys.as_raw_fd()
    }
}

#[cfg(unix)]
impl IntoRawFd for UnixListener {
    fn into_raw_fd(self) -> RawFd {
        self.sys.into_raw_fd()
    }
}

#[cfg(unix)]
impl FromRawFd for UnixListener {
    /// Converts a `std` `RawFd` to a `mio` `UnixListener`.
    ///
    /// The caller is responsible for ensuring that the socket is in
    /// non-blocking mode.
    unsafe fn from_raw_fd(fd: RawFd) -> UnixListener {
        UnixListener::new(FromRawFd::from_raw_fd(fd))
    }
}
<commit_msg>Fix UnixListener registration<commit_after>use crate::event::Source;
use crate::net::UnixStream;
#[cfg(debug_assertions)]
use crate::poll::SelectorId;
use crate::unix::SocketAddr;
use crate::{sys, Interests, Registry, Token};

use std::io;
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use std::os::unix::net;
use std::path::Path;

/// A non-blocking Unix domain socket server.
#[derive(Debug)]
pub struct UnixListener {
    sys: sys::UnixListener,
    #[cfg(debug_assertions)]
    selector_id: SelectorId,
}

impl UnixListener {
    fn new(sys: sys::UnixListener) -> UnixListener {
        UnixListener {
            sys,
            #[cfg(debug_assertions)]
            selector_id: SelectorId::new(),
        }
    }

    /// Creates a new `UnixListener` bound to the specified socket.
    pub fn bind<P: AsRef<Path>>(path: P) -> io::Result<UnixListener> {
        let sys = sys::UnixListener::bind(path.as_ref())?;
        Ok(UnixListener::new(sys))
    }

    /// Creates a new `UnixListener` from a standard `net::UnixListener`.
    ///
    /// This function is intended to be used to wrap a Unix listener from the
    /// standard library in the Mio equivalent. The conversion assumes nothing
    /// about the underlying listener; it is left up to the user to set it in
    /// non-blocking mode.
    pub fn from_std(listener: net::UnixListener) -> UnixListener {
        let sys = sys::UnixListener::from_std(listener);
        UnixListener {
            sys,
            #[cfg(debug_assertions)]
            selector_id: SelectorId::new(),
        }
    }

    /// Accepts a new incoming connection to this listener.
    ///
    /// The call is responsible for ensuring that the listening socket is in
    /// non-blocking mode.
    pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> {
        let (sys, sockaddr) = self.sys.accept()?;
        Ok((UnixStream::new(sys), sockaddr))
    }

    /// Creates a new independently owned handle to the underlying socket.
    ///
    /// The returned `UnixListener` is a reference to the same socket that this
    /// object references. Both handles can be used to accept incoming
    /// connections and options set on one listener will affect the other.
    pub fn try_clone(&self) -> io::Result<UnixListener> {
        let sys = self.sys.try_clone()?;
        Ok(UnixListener::new(sys))
    }

    /// Returns the local socket address of this listener.
    pub fn local_addr(&self) -> io::Result<sys::SocketAddr> {
        self.sys.local_addr()
    }

    /// Returns the value of the `SO_ERROR` option.
    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
        self.sys.take_error()
    }
}

impl Source for UnixListener {
    fn register(&self, registry: &Registry, token: Token, interests: Interests) -> io::Result<()> {
        #[cfg(debug_assertions)]
        self.selector_id.associate_selector(registry)?;
        self.sys.register(registry, token, interests)
    }

    fn reregister(
        &self,
        registry: &Registry,
        token: Token,
        interests: Interests,
    ) -> io::Result<()> {
        self.sys.reregister(registry, token, interests)
    }

    fn deregister(&self, registry: &Registry) -> io::Result<()> {
        self.sys.deregister(registry)
    }
}

#[cfg(unix)]
impl AsRawFd for UnixListener {
    fn as_raw_fd(&self) -> RawFd {
        self.sys.as_raw_fd()
    }
}

#[cfg(unix)]
impl IntoRawFd for UnixListener {
    fn into_raw_fd(self) -> RawFd {
        self.sys.into_raw_fd()
    }
}

#[cfg(unix)]
impl FromRawFd for UnixListener {
    /// Converts a `std` `RawFd` to a `mio` `UnixListener`.
    ///
    /// The caller is responsible for ensuring that the socket is in
    /// non-blocking mode.
    unsafe fn from_raw_fd(fd: RawFd) -> UnixListener {
        UnixListener::new(FromRawFd::from_raw_fd(fd))
    }
}
<|endoftext|>


<commit_before>use scroll::{self, Pread};
use error;

#[repr(C)]
#[derive(Debug, PartialEq, Copy, Clone, Default)]
pub struct SectionTable {
    pub name: [u8; 8],
    pub virtual_size: u32,
    pub virtual_address: u32,
    pub size_of_raw_data: u32,
    pub pointer_to_raw_data: u32,
    pub pointer_to_relocations: u32,
    pub pointer_to_linenumbers: u32,
    pub number_of_relocations: u16,
    pub number_of_linenumbers: u16,
    pub characteristics: u32,
}

pub const SIZEOF_SECTION_TABLE: usize = 8 * 5;

impl SectionTable {
    pub fn parse(bytes: &[u8], offset: &mut usize) -> error::Result<Self> {
        let mut table = SectionTable::default();
        let mut name = [0u8; 8];
        for i in 0..8 {
            name[i] = bytes.gread_with(offset, scroll::LE)?;
        }
        table.name = name;
        table.virtual_size = bytes.gread_with(offset, scroll::LE)?;
        table.virtual_address = bytes.gread_with(offset, scroll::LE)?;
        table.size_of_raw_data = bytes.gread_with(offset, scroll::LE)?;
        table.pointer_to_raw_data = bytes.gread_with(offset, scroll::LE)?;
        table.pointer_to_relocations = bytes.gread_with(offset, scroll::LE)?;
        table.pointer_to_linenumbers = bytes.gread_with(offset, scroll::LE)?;
        table.number_of_relocations = bytes.gread_with(offset, scroll::LE)?;
        table.number_of_linenumbers = bytes.gread_with(offset, scroll::LE)?;
        table.characteristics = bytes.gread_with(offset, scroll::LE)?;
        Ok(table)
    }
    pub fn name(&self) -> error::Result<&str> {
        Ok(self.name.pread(0)?)
    }
}
<commit_msg>Add flags for PE section characteristics (#65)<commit_after>use scroll::{self, Pread};
use error;

#[repr(C)]
#[derive(Debug, PartialEq, Copy, Clone, Default)]
pub struct SectionTable {
    pub name: [u8; 8],
    pub virtual_size: u32,
    pub virtual_address: u32,
    pub size_of_raw_data: u32,
    pub pointer_to_raw_data: u32,
    pub pointer_to_relocations: u32,
    pub pointer_to_linenumbers: u32,
    pub number_of_relocations: u16,
    pub number_of_linenumbers: u16,
    pub characteristics: u32,
}

pub const SIZEOF_SECTION_TABLE: usize = 8 * 5;

impl SectionTable {
    pub fn parse(bytes: &[u8], offset: &mut usize) -> error::Result<Self> {
        let mut table = SectionTable::default();
        let mut name = [0u8; 8];
        for i in 0..8 {
            name[i] = bytes.gread_with(offset, scroll::LE)?;
        }
        table.name = name;
        table.virtual_size = bytes.gread_with(offset, scroll::LE)?;
        table.virtual_address = bytes.gread_with(offset, scroll::LE)?;
        table.size_of_raw_data = bytes.gread_with(offset, scroll::LE)?;
        table.pointer_to_raw_data = bytes.gread_with(offset, scroll::LE)?;
        table.pointer_to_relocations = bytes.gread_with(offset, scroll::LE)?;
        table.pointer_to_linenumbers = bytes.gread_with(offset, scroll::LE)?;
        table.number_of_relocations = bytes.gread_with(offset, scroll::LE)?;
        table.number_of_linenumbers = bytes.gread_with(offset, scroll::LE)?;
        table.characteristics = bytes.gread_with(offset, scroll::LE)?;
        Ok(table)
    }
    pub fn name(&self) -> error::Result<&str> {
        Ok(self.name.pread(0)?)
    }
}

/// The section should not be padded to the next boundary. This flag is obsolete and is replaced
/// by `IMAGE_SCN_ALIGN_1BYTES`. This is valid only for object files.
pub const IMAGE_SCN_TYPE_NO_PAD: u32 = 0x00000008;
/// The section contains executable code.
pub const IMAGE_SCN_CNT_CODE: u32 = 0x00000020;
/// The section contains initialized data.
pub const IMAGE_SCN_CNT_INITIALIZED_DATA: u32 = 0x00000040;
///  The section contains uninitialized data.
pub const IMAGE_SCN_CNT_UNINITIALIZED_DATA: u32 = 0x00000080;
pub const IMAGE_SCN_LNK_OTHER: u32 = 0x00000100;
/// The section contains comments or other information. The .drectve section has this type.
/// This is valid for object files only.
pub const IMAGE_SCN_LNK_INFO: u32 = 0x00000200;
/// The section will not become part of the image. This is valid only for object files.
pub const IMAGE_SCN_LNK_REMOVE: u32 = 0x00000800;
/// The section contains COMDAT data. This is valid only for object files.
pub const IMAGE_SCN_LNK_COMDAT: u32 = 0x00001000;
/// The section contains data referenced through the global pointer (GP).
pub const IMAGE_SCN_GPREL: u32 = 0x00008000;
pub const IMAGE_SCN_MEM_PURGEABLE: u32 = 0x00020000;
pub const IMAGE_SCN_MEM_16BIT: u32 = 0x00020000;
pub const IMAGE_SCN_MEM_LOCKED: u32 = 0x00040000;
pub const IMAGE_SCN_MEM_PRELOAD: u32 = 0x00080000;

pub const IMAGE_SCN_ALIGN_1BYTES: u32 = 0x00100000;
pub const IMAGE_SCN_ALIGN_2BYTES: u32 = 0x00200000;
pub const IMAGE_SCN_ALIGN_4BYTES: u32 = 0x00300000;
pub const IMAGE_SCN_ALIGN_8BYTES: u32 = 0x00400000;
pub const IMAGE_SCN_ALIGN_16BYTES: u32 = 0x00500000;
pub const IMAGE_SCN_ALIGN_32BYTES: u32 = 0x00600000;
pub const IMAGE_SCN_ALIGN_64BYTES: u32 = 0x00700000;
pub const IMAGE_SCN_ALIGN_128BYTES: u32 = 0x00800000;
pub const IMAGE_SCN_ALIGN_256BYTES: u32 = 0x00900000;
pub const IMAGE_SCN_ALIGN_512BYTES: u32 = 0x00A00000;
pub const IMAGE_SCN_ALIGN_1024BYTES: u32 = 0x00B00000;
pub const IMAGE_SCN_ALIGN_2048BYTES: u32 = 0x00C00000;
pub const IMAGE_SCN_ALIGN_4096BYTES: u32 = 0x00D00000;
pub const IMAGE_SCN_ALIGN_8192BYTES: u32 = 0x00E00000;
pub const IMAGE_SCN_ALIGN_MASK: u32 = 0x00F00000;

/// The section contains extended relocations.
pub const IMAGE_SCN_LNK_NRELOC_OVFL: u32 = 0x01000000;
/// The section can be discarded as needed.
pub const IMAGE_SCN_MEM_DISCARDABLE: u32 = 0x02000000;
/// The section cannot be cached.
pub const IMAGE_SCN_MEM_NOT_CACHED: u32 = 0x04000000;
/// The section is not pageable.
pub const IMAGE_SCN_MEM_NOT_PAGED: u32 = 0x08000000;
/// The section can be shared in memory.
pub const IMAGE_SCN_MEM_SHARED: u32 = 0x10000000;
/// The section can be executed as code.
pub const IMAGE_SCN_MEM_EXECUTE: u32 = 0x20000000;
/// The section can be read.
pub const IMAGE_SCN_MEM_READ: u32 = 0x40000000;
/// The section can be written to.
pub const IMAGE_SCN_MEM_WRITE: u32 = 0x80000000;
<|endoftext|>


<commit_before>// Options
// Space before /
// Quote style
// Ordering of attributes

use std::io::IoResult;

use super::{ElementElementChild,TextElementChild,CommentElementChild,PIElementChild};
use super::{ElementRootChild,CommentRootChild,PIRootChild};

enum Content {
    Element(super::Element),
    ElementEnd(String),
    Text(super::Text),
    Comment(super::Comment),
    ProcessingInstruction(super::ProcessingInstruction),
}

fn format_element<W : Writer>(element: super::Element, todo: &mut Vec<Content>, writer: &mut W) -> IoResult<()> {
    try!(write!(writer, "<{}", element.name()));

    for attr in element.attributes().iter() {
        try!(write!(writer, " {}='{}'", attr.name(), attr.value()));
    }

    let mut children = element.children();
    if children.is_empty() {
        writer.write_str("/>")
    } else {
        try!(writer.write_str(">"));

        todo.push(ElementEnd(element.name()));
        children.reverse();
        let x = children.move_iter().map(|c| match c {
            ElementElementChild(element) => Element(element),
            TextElementChild(t)          => Text(t),
            CommentElementChild(c)       => Comment(c),
            PIElementChild(p)            => ProcessingInstruction(p),
        }).collect();
        todo.push_all_move(x);

        Ok(())
    }
}

fn format_comment<W : Writer>(comment: super::Comment, writer: &mut W) -> IoResult<()> {
    write!(writer, "<!--{}-->", comment.text())
}

fn format_processing_instruction<W : Writer>(pi: super::ProcessingInstruction, writer: &mut W) -> IoResult<()> {
    match pi.value() {
        None    => write!(writer, "<?{}?>", pi.target()),
        Some(v) => write!(writer, "<?{} {}?>", pi.target(), v),
    }
}

fn format_one<W : Writer>(content: Content, todo: &mut Vec<Content>, writer: &mut W) -> IoResult<()> {
    match content {
        Element(e)               => format_element(e, todo, writer),
        ElementEnd(name)         => write!(writer, "</{}>", name),
        Text(t)                  => writer.write_str(t.text().as_slice()),
        Comment(c)               => format_comment(c, writer),
        ProcessingInstruction(p) => format_processing_instruction(p, writer),
    }
}

fn format_body<W : Writer>(element: super::Element, writer: &mut W) -> IoResult<()> {
    let mut todo = vec![Element(element)];

    while ! todo.is_empty() {
        try!(format_one(todo.pop().unwrap(), &mut todo, writer));
    }

    Ok(())
}

pub fn format_document<W : Writer>(doc: &super::Document, writer: &mut W) -> IoResult<()> {
    try!(writer.write_str("<?xml version='1.0'?>"));

    for child in doc.root().children().move_iter() {
        try!(match child {
            ElementRootChild(e) => format_body(e, writer),
            CommentRootChild(c) => format_comment(c, writer),
            PIRootChild(p)      => format_processing_instruction(p, writer),
        })
    }

    Ok(())
}

#[cfg(test)]
mod test {
    use std::io::MemWriter;

    use super::super::Document;
    use super::format_document;

    macro_rules! assert_str_eq(
        ($l:expr, $r:expr) => (assert_eq!($l.as_slice(), $r.as_slice()));
    )

    fn format_xml(doc: &Document) -> String {
        let mut w = MemWriter::new();
        format_document(doc, &mut w).ok().expect("Not formatted");
        String::from_utf8(w.unwrap()).ok().expect("Not a string")
    }

    #[test]
    fn top_element() {
        let d = Document::new();
        let e = d.new_element("hello".to_string());
        d.root().append_child(e);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello/>");
    }

    #[test]
    fn element_with_attributes() {
        let d = Document::new();
        let e = d.new_element("hello".to_string());
        e.set_attribute("a".to_string(), "b".to_string());
        d.root().append_child(e);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello a='b'/>");
    }

    #[test]
    fn nested_element() {
        let d = Document::new();
        let hello = d.new_element("hello".to_string());
        let world = d.new_element("world".to_string());
        hello.append_child(world);
        d.root().append_child(hello);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello><world/></hello>");
    }

    #[test]
    fn nested_text() {
        let d = Document::new();
        let hello = d.new_element("hello".to_string());
        let text = d.new_text("A fine day to you!".to_string());
        hello.append_child(text);
        d.root().append_child(hello);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello>A fine day to you!</hello>");
    }

    #[test]
    fn nested_comment() {
        let d = Document::new();
        let hello = d.new_element("hello".to_string());
        let comment = d.new_comment(" Fill this in ".to_string());
        hello.append_child(comment);
        d.root().append_child(hello);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello><!-- Fill this in --></hello>");
    }

    #[test]
    fn nested_processing_instruction_without_value() {
        let d = Document::new();
        let hello = d.new_element("hello".to_string());
        let pi = d.new_processing_instruction("display".to_string(), None);
        hello.append_child(pi);
        d.root().append_child(hello);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello><?display?></hello>");
    }

    #[test]
    fn nested_processing_instruction_with_value() {
        let d = Document::new();
        let hello = d.new_element("hello".to_string());
        let pi = d.new_processing_instruction("display".to_string(), Some("screen".to_string()));
        hello.append_child(pi);
        d.root().append_child(hello);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello><?display screen?></hello>");
    }

    #[test]
    fn top_level_comment() {
        let d = Document::new();
        let comment = d.new_comment(" Fill this in ".to_string());
        d.root().append_child(comment);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><!-- Fill this in -->");
    }

    #[test]
    fn top_level_processing_instruction() {
        let d = Document::new();
        let pi = d.new_processing_instruction("display".to_string(), None);
        d.root().append_child(pi);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><?display?>");
    }
}
<commit_msg>Document the writer<commit_after>//! Formats a DOM structure to a Writer
//!
//! ### Known issues
//!
//! Output is not escaped in any way,
//! it's very easy to create malformed XML!
//!
//! ### Potential options to support
//!
//! - Space before `/>`
//! - Single vs double quotes
//! - Fixed ordering of attributes

use std::io::IoResult;

use super::{ElementElementChild,TextElementChild,CommentElementChild,PIElementChild};
use super::{ElementRootChild,CommentRootChild,PIRootChild};

enum Content {
    Element(super::Element),
    ElementEnd(String),
    Text(super::Text),
    Comment(super::Comment),
    ProcessingInstruction(super::ProcessingInstruction),
}

fn format_element<W : Writer>(element: super::Element, todo: &mut Vec<Content>, writer: &mut W) -> IoResult<()> {
    try!(write!(writer, "<{}", element.name()));

    for attr in element.attributes().iter() {
        try!(write!(writer, " {}='{}'", attr.name(), attr.value()));
    }

    let mut children = element.children();
    if children.is_empty() {
        writer.write_str("/>")
    } else {
        try!(writer.write_str(">"));

        todo.push(ElementEnd(element.name()));
        children.reverse();
        let x = children.move_iter().map(|c| match c {
            ElementElementChild(element) => Element(element),
            TextElementChild(t)          => Text(t),
            CommentElementChild(c)       => Comment(c),
            PIElementChild(p)            => ProcessingInstruction(p),
        }).collect();
        todo.push_all_move(x);

        Ok(())
    }
}

fn format_comment<W : Writer>(comment: super::Comment, writer: &mut W) -> IoResult<()> {
    write!(writer, "<!--{}-->", comment.text())
}

fn format_processing_instruction<W : Writer>(pi: super::ProcessingInstruction, writer: &mut W) -> IoResult<()> {
    match pi.value() {
        None    => write!(writer, "<?{}?>", pi.target()),
        Some(v) => write!(writer, "<?{} {}?>", pi.target(), v),
    }
}

fn format_one<W : Writer>(content: Content, todo: &mut Vec<Content>, writer: &mut W) -> IoResult<()> {
    match content {
        Element(e)               => format_element(e, todo, writer),
        ElementEnd(name)         => write!(writer, "</{}>", name),
        Text(t)                  => writer.write_str(t.text().as_slice()),
        Comment(c)               => format_comment(c, writer),
        ProcessingInstruction(p) => format_processing_instruction(p, writer),
    }
}

fn format_body<W : Writer>(element: super::Element, writer: &mut W) -> IoResult<()> {
    let mut todo = vec![Element(element)];

    while ! todo.is_empty() {
        try!(format_one(todo.pop().unwrap(), &mut todo, writer));
    }

    Ok(())
}

/// Formats a document into a Writer
pub fn format_document<W : Writer>(doc: &super::Document, writer: &mut W) -> IoResult<()> {
    try!(writer.write_str("<?xml version='1.0'?>"));

    for child in doc.root().children().move_iter() {
        try!(match child {
            ElementRootChild(e) => format_body(e, writer),
            CommentRootChild(c) => format_comment(c, writer),
            PIRootChild(p)      => format_processing_instruction(p, writer),
        })
    }

    Ok(())
}

#[cfg(test)]
mod test {
    use std::io::MemWriter;

    use super::super::Document;
    use super::format_document;

    macro_rules! assert_str_eq(
        ($l:expr, $r:expr) => (assert_eq!($l.as_slice(), $r.as_slice()));
    )

    fn format_xml(doc: &Document) -> String {
        let mut w = MemWriter::new();
        format_document(doc, &mut w).ok().expect("Not formatted");
        String::from_utf8(w.unwrap()).ok().expect("Not a string")
    }

    #[test]
    fn top_element() {
        let d = Document::new();
        let e = d.new_element("hello".to_string());
        d.root().append_child(e);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello/>");
    }

    #[test]
    fn element_with_attributes() {
        let d = Document::new();
        let e = d.new_element("hello".to_string());
        e.set_attribute("a".to_string(), "b".to_string());
        d.root().append_child(e);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello a='b'/>");
    }

    #[test]
    fn nested_element() {
        let d = Document::new();
        let hello = d.new_element("hello".to_string());
        let world = d.new_element("world".to_string());
        hello.append_child(world);
        d.root().append_child(hello);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello><world/></hello>");
    }

    #[test]
    fn nested_text() {
        let d = Document::new();
        let hello = d.new_element("hello".to_string());
        let text = d.new_text("A fine day to you!".to_string());
        hello.append_child(text);
        d.root().append_child(hello);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello>A fine day to you!</hello>");
    }

    #[test]
    fn nested_comment() {
        let d = Document::new();
        let hello = d.new_element("hello".to_string());
        let comment = d.new_comment(" Fill this in ".to_string());
        hello.append_child(comment);
        d.root().append_child(hello);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello><!-- Fill this in --></hello>");
    }

    #[test]
    fn nested_processing_instruction_without_value() {
        let d = Document::new();
        let hello = d.new_element("hello".to_string());
        let pi = d.new_processing_instruction("display".to_string(), None);
        hello.append_child(pi);
        d.root().append_child(hello);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello><?display?></hello>");
    }

    #[test]
    fn nested_processing_instruction_with_value() {
        let d = Document::new();
        let hello = d.new_element("hello".to_string());
        let pi = d.new_processing_instruction("display".to_string(), Some("screen".to_string()));
        hello.append_child(pi);
        d.root().append_child(hello);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello><?display screen?></hello>");
    }

    #[test]
    fn top_level_comment() {
        let d = Document::new();
        let comment = d.new_comment(" Fill this in ".to_string());
        d.root().append_child(comment);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><!-- Fill this in -->");
    }

    #[test]
    fn top_level_processing_instruction() {
        let d = Document::new();
        let pi = d.new_processing_instruction("display".to_string(), None);
        d.root().append_child(pi);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><?display?>");
    }
}
<|endoftext|>


<commit_before>// Copyright 2017-2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// https://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! ISAAC helper functions for 256-element arrays.

// Terrible workaround because arrays with more than 32 elements do not
// implement `AsRef`, `Default`, `Serialize`, `Deserialize`, or any other
// traits for that matter.

#[cfg(feature="serde-1")] use serde::{Serialize, Deserialize};

const RAND_SIZE_LEN: usize = 8;
const RAND_SIZE: usize = 1 << RAND_SIZE_LEN;

#[derive(Copy, Clone)]
#[allow(missing_debug_implementations)]
#[cfg_attr(feature="serde-1", derive(Serialize, Deserialize))]
pub struct IsaacArray<T> where T: Default + Copy {
    #[cfg_attr(feature="serde-1",serde(with="isaac_array_serde"))]
    #[cfg_attr(feature="serde-1", serde(bound(
        serialize = "T: Serialize",
        deserialize = "T: Deserialize<'de>")))]
    inner: [T; RAND_SIZE]
}

impl<T> ::core::convert::AsRef<[T]> for IsaacArray<T> where T: Default + Copy {
    #[inline(always)]
    fn as_ref(&self) -> &[T] {
        &self.inner[..]
    }
}

impl<T> ::core::ops::Deref for IsaacArray<T> where T: Default + Copy {
    type Target = [T; RAND_SIZE];
    #[inline(always)]
    fn deref(&self) -> &Self::Target {
        &self.inner
    }
}

impl<T> ::core::ops::DerefMut for IsaacArray<T> where T: Default + Copy {
    #[inline(always)]
    fn deref_mut(&mut self) -> &mut [T; RAND_SIZE] {
        &mut self.inner
    }
}

impl<T> ::core::default::Default for IsaacArray<T> where T: Default + Copy {
    fn default() -> IsaacArray<T> {
        IsaacArray { inner: [T::default(); RAND_SIZE] }
    }
}

#[cfg(feature="serde-1")]
pub(super) mod isaac_array_serde {
    const RAND_SIZE_LEN: usize = 8;
    const RAND_SIZE: usize = 1 << RAND_SIZE_LEN;

    use serde::{Deserialize, Deserializer, Serialize, Serializer};
    use serde::de::{Visitor,SeqAccess};
    use serde::de;

    use core::fmt;

    pub fn serialize<T, S>(arr: &[T;RAND_SIZE], ser: S) -> Result<S::Ok, S::Error>
    where
        T: Serialize,
        S: Serializer
    {
        use serde::ser::SerializeTuple;

        let mut seq = ser.serialize_tuple(RAND_SIZE)?;

        for e in arr.iter() {
            seq.serialize_element(&e)?;
        }

        seq.end()
    }

    #[inline]
    pub fn deserialize<'de, T, D>(de: D) -> Result<[T;RAND_SIZE], D::Error>
    where
        T: Deserialize<'de>+Default+Copy,
        D: Deserializer<'de>,
    {
        use core::marker::PhantomData;
        struct ArrayVisitor<T> {
            _pd: PhantomData<T>,
        };
        impl<'de,T> Visitor<'de> for ArrayVisitor<T>
        where
            T: Deserialize<'de>+Default+Copy
        {
            type Value = [T; RAND_SIZE];

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("Isaac state array")
            }

            #[inline]
            fn visit_seq<A>(self, mut seq: A) -> Result<[T; RAND_SIZE], A::Error>
            where
                A: SeqAccess<'de>,
            {
                let mut out = [Default::default();RAND_SIZE];

                for i in 0..RAND_SIZE {
                    match seq.next_element()? {
                        Some(val) => out[i] = val,
                        None => return Err(de::Error::invalid_length(i, &self)),
                    };
                }

                Ok(out)
            }
        }

        de.deserialize_tuple(RAND_SIZE, ArrayVisitor{_pd: PhantomData})
    }
}
<commit_msg>Don't put bounds on a data structure<commit_after>// Copyright 2017-2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// https://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! ISAAC helper functions for 256-element arrays.

// Terrible workaround because arrays with more than 32 elements do not
// implement `AsRef`, `Default`, `Serialize`, `Deserialize`, or any other
// traits for that matter.

#[cfg(feature="serde-1")] use serde::{Serialize, Deserialize};

const RAND_SIZE_LEN: usize = 8;
const RAND_SIZE: usize = 1 << RAND_SIZE_LEN;

#[derive(Copy, Clone)]
#[allow(missing_debug_implementations)]
#[cfg_attr(feature="serde-1", derive(Serialize, Deserialize))]
pub struct IsaacArray<T> {
    #[cfg_attr(feature="serde-1",serde(with="isaac_array_serde"))]
    #[cfg_attr(feature="serde-1", serde(bound(
        serialize = "T: Serialize",
        deserialize = "T: Deserialize<'de> + Copy + Default")))]
    inner: [T; RAND_SIZE]
}

impl<T> ::core::convert::AsRef<[T]> for IsaacArray<T> {
    #[inline(always)]
    fn as_ref(&self) -> &[T] {
        &self.inner[..]
    }
}

impl<T> ::core::ops::Deref for IsaacArray<T> {
    type Target = [T; RAND_SIZE];
    #[inline(always)]
    fn deref(&self) -> &Self::Target {
        &self.inner
    }
}

impl<T> ::core::ops::DerefMut for IsaacArray<T> {
    #[inline(always)]
    fn deref_mut(&mut self) -> &mut [T; RAND_SIZE] {
        &mut self.inner
    }
}

impl<T> ::core::default::Default for IsaacArray<T> where T: Copy + Default {
    fn default() -> IsaacArray<T> {
        IsaacArray { inner: [T::default(); RAND_SIZE] }
    }
}

#[cfg(feature="serde-1")]
pub(super) mod isaac_array_serde {
    const RAND_SIZE_LEN: usize = 8;
    const RAND_SIZE: usize = 1 << RAND_SIZE_LEN;

    use serde::{Deserialize, Deserializer, Serialize, Serializer};
    use serde::de::{Visitor,SeqAccess};
    use serde::de;

    use core::fmt;

    pub fn serialize<T, S>(arr: &[T;RAND_SIZE], ser: S) -> Result<S::Ok, S::Error>
    where
        T: Serialize,
        S: Serializer
    {
        use serde::ser::SerializeTuple;

        let mut seq = ser.serialize_tuple(RAND_SIZE)?;

        for e in arr.iter() {
            seq.serialize_element(&e)?;
        }

        seq.end()
    }

    #[inline]
    pub fn deserialize<'de, T, D>(de: D) -> Result<[T;RAND_SIZE], D::Error>
    where
        T: Deserialize<'de>+Default+Copy,
        D: Deserializer<'de>,
    {
        use core::marker::PhantomData;
        struct ArrayVisitor<T> {
            _pd: PhantomData<T>,
        };
        impl<'de,T> Visitor<'de> for ArrayVisitor<T>
        where
            T: Deserialize<'de>+Default+Copy
        {
            type Value = [T; RAND_SIZE];

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("Isaac state array")
            }

            #[inline]
            fn visit_seq<A>(self, mut seq: A) -> Result<[T; RAND_SIZE], A::Error>
            where
                A: SeqAccess<'de>,
            {
                let mut out = [Default::default();RAND_SIZE];

                for i in 0..RAND_SIZE {
                    match seq.next_element()? {
                        Some(val) => out[i] = val,
                        None => return Err(de::Error::invalid_length(i, &self)),
                    };
                }

                Ok(out)
            }
        }

        de.deserialize_tuple(RAND_SIZE, ArrayVisitor{_pd: PhantomData})
    }
}
<|endoftext|>


<commit_before>use crate::StrError;

/// Implements the shape(N) time scalar(S) time gradient(G) integration case with different shapes (e.g., coupling matrix)
///
/// Coupling vectors:
///
/// ```text
/// →     ⌠       →
/// Kᵐⁿ = │ NBᵐ s Gⁿ dΩ
///       ⌡
///       Ωₑ
/// ```
pub fn mat_coupling_nsg() -> Result<(), StrError> {
    Err("mat_coupling_nsg: TODO")
}

/// Implements the gradient(G) time tensor(T) time shape(N) integration case with different shapes (e.g., coupling matrix)
///
/// Coupling vectors:
///
/// ```text
/// →     ⌠ →
/// Kᵐⁿ = │ GBᵐ ⋅ T Nⁿ dΩ
///       ⌡       ▔
///       Ωₑ
/// ```
pub fn mat_coupling_gtn() -> Result<(), StrError> {
    Err("mat_coupling_gtn: TODO")
}

/// Implements the shape(N) time vector(V) time shape(N) integration case with different shapes (e.g., coupling matrix)
///
/// Coupling vectors:
///
/// ```text
/// →     ⌠    →
/// Kᵐⁿ = │ Nᵐ v NBⁿ dΩ
///       ⌡
///       Ωₑ
/// ```
pub fn mat_coupling_nvn() -> Result<(), StrError> {
    Err("mat_coupling_nvn: TODO")
}

/// Implements the gradient(G) time scalar(S) time shape(N) integration case with different shapes (e.g., coupling matrix)
///
/// Coupling vectors:
///
/// ```text
/// →     ⌠ →
/// Kᵐⁿ = │ Gᵐ s NBⁿ dΩ
///       ⌡
///       Ωₑ
/// ```
pub fn mat_coupling_gsn() -> Result<(), StrError> {
    Err("mat_coupling_gsn: TODO")
}
<commit_msg>Add tests<commit_after>use crate::StrError;

/// Implements the shape(N) time scalar(S) time gradient(G) integration case with different shapes (e.g., coupling matrix)
///
/// Coupling vectors:
///
/// ```text
/// →     ⌠       →
/// Kᵐⁿ = │ NBᵐ s Gⁿ dΩ
///       ⌡
///       Ωₑ
/// ```
pub fn mat_coupling_nsg() -> Result<(), StrError> {
    Err("mat_coupling_nsg: TODO")
}

/// Implements the gradient(G) time tensor(T) time shape(N) integration case with different shapes (e.g., coupling matrix)
///
/// Coupling vectors:
///
/// ```text
/// →     ⌠ →
/// Kᵐⁿ = │ GBᵐ ⋅ T Nⁿ dΩ
///       ⌡       ▔
///       Ωₑ
/// ```
pub fn mat_coupling_gtn() -> Result<(), StrError> {
    Err("mat_coupling_gtn: TODO")
}

/// Implements the shape(N) time vector(V) time shape(N) integration case with different shapes (e.g., coupling matrix)
///
/// Coupling vectors:
///
/// ```text
/// →     ⌠    →
/// Kᵐⁿ = │ Nᵐ v NBⁿ dΩ
///       ⌡
///       Ωₑ
/// ```
pub fn mat_coupling_nvn() -> Result<(), StrError> {
    Err("mat_coupling_nvn: TODO")
}

/// Implements the gradient(G) time scalar(S) time shape(N) integration case with different shapes (e.g., coupling matrix)
///
/// Coupling vectors:
///
/// ```text
/// →     ⌠ →
/// Kᵐⁿ = │ Gᵐ s NBⁿ dΩ
///       ⌡
///       Ωₑ
/// ```
pub fn mat_coupling_gsn() -> Result<(), StrError> {
    Err("mat_coupling_gsn: TODO")
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#[cfg(test)]
mod tests {
    use super::{mat_coupling_gsn, mat_coupling_gtn, mat_coupling_nsg, mat_coupling_nvn};

    #[test]
    fn functions_return_todo() {
        assert_eq!(mat_coupling_nsg().err(), Some("mat_coupling_nsg: TODO"));
        assert_eq!(mat_coupling_gtn().err(), Some("mat_coupling_gtn: TODO"));
        assert_eq!(mat_coupling_nvn().err(), Some("mat_coupling_nvn: TODO"));
        assert_eq!(mat_coupling_gsn().err(), Some("mat_coupling_gsn: TODO"));
    }
}
<|endoftext|>


<commit_before>pub struct Allergies;

#[derive(Debug, PartialEq)]
pub enum Allergen {
    Eggs,
    Peanuts,
    Shellfish,
    Strawberries,
    Tomatoes,
    Chocolate,
    Pollen,
    Cats,
}

impl Allergies {
    pub fn new(score: u32) -> Self {
        unimplemented!(
            "Given the '{}' score, construct a new Allergies struct.",
            score
        );
    }

    pub fn is_allergic_to(&self, allergen: &Allergen) -> bool {
        unimplemented!(
            "Determine if the patient is allergic to the '{:?}' allergen.",
            allergen
        );
    }

    pub fn allergies(&self) -> Vec<Allergen> {
        unimplemented!("Return the list of allergens contained within the score with which the Allergies struct was made.");
    }
}
<commit_msg>WIP based on my Go solution<commit_after>use std::collections::HashMap;

pub struct Allergies {
    score: u32,
}

#[derive(Debug, PartialEq)]
pub enum Allergen {
    Eggs,
    Peanuts,
    Shellfish,
    Strawberries,
    Tomatoes,
    Chocolate,
    Pollen,
    Cats,
}

impl Allergies {
    pub fn new(score: u32) -> Self {
        return Allergies { score };
    }

    pub fn is_allergic_to(&self, allergen: &Allergen) -> bool {
        for candidate in self.allergies() {
            if candidate == allergen {
                return true;
            }
        }
        return false;
    }

    pub fn allergies(&self) -> Vec<&Allergen> {
        let score_to_allergen: HashMap<u32, &Allergen> = HashMap::from([
            (1, &Allergen::Eggs),
            (2, &Allergen::Peanuts),
            (4, &Allergen::Shellfish),
            (8, &Allergen::Strawberries),
            (16, &Allergen::Tomatoes),
            (32, &Allergen::Chocolate),
            (64, &Allergen::Pollen),
            (128, &Allergen::Cats),
        ]);

        let mut score: u32 = self.score;
        let mut allergies: Vec<&Allergen> = vec![];
        if score >= 256 {
            score %= 256
        }
        for key in self.descending_keys(score_to_allergen) {
            let allergen = score_to_allergen
                .get(&key)
                .expect("expected allergy to exist");

            if score / key == 1 {
                allergies.push(allergen);
                score %= key;
            }
        }
        allergies
    }

    fn descending_keys(&self, map: HashMap<u32, &Allergen>) -> Vec<u32> {
        let mut keys: Vec<u32> = map.into_keys().collect();
        keys.sort();
        keys
    }
}
<|endoftext|>


<commit_before>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::num::One;
use std::vec::bytes::{MutableByteVector, copy_memory};

/// Write a u64 into a vector, which must be 8 bytes long. The value is written in big-endian
/// format.
pub fn write_u64_be(dst: &mut[u8], input: u64) {
    use std::cast::transmute;
    use std::unstable::intrinsics::to_be64;
    assert!(dst.len() == 8);
    unsafe {
        let x: *mut i64 = transmute(dst.unsafe_mut_ref(0));
        *x = to_be64(input as i64);
    }
}

/// Write a u32 into a vector, which must be 4 bytes long. The value is written in big-endian
/// format.
pub fn write_u32_be(dst: &mut[u8], input: u32) {
    use std::cast::transmute;
    use std::unstable::intrinsics::to_be32;
    assert!(dst.len() == 4);
    unsafe {
        let x: *mut i32 = transmute(dst.unsafe_mut_ref(0));
        *x = to_be32(input as i32);
    }
}

/// Read a vector of bytes into a vector of u64s. The values are read in big-endian format.
pub fn read_u64v_be(dst: &mut[u64], input: &[u8]) {
    use std::cast::transmute;
    use std::unstable::intrinsics::to_be64;
    assert!(dst.len() * 8 == input.len());
    unsafe {
        let mut x: *mut i64 = transmute(dst.unsafe_mut_ref(0));
        let mut y: *i64 = transmute(input.unsafe_ref(0));
        do dst.len().times() {
            *x = to_be64(*y);
            x = x.offset(1);
            y = y.offset(1);
        }
    }
}

/// Read a vector of bytes into a vector of u32s. The values are read in big-endian format.
pub fn read_u32v_be(dst: &mut[u32], input: &[u8]) {
    use std::cast::transmute;
    use std::unstable::intrinsics::to_be32;
    assert!(dst.len() * 4 == input.len());
    unsafe {
        let mut x: *mut i32 = transmute(dst.unsafe_mut_ref(0));
        let mut y: *i32 = transmute(input.unsafe_ref(0));
        do dst.len().times() {
            *x = to_be32(*y);
            x = x.offset(1);
            y = y.offset(1);
        }
    }
}

/// Returns true if adding the two parameters will result in integer overflow
pub fn will_add_overflow<T: Int + Unsigned>(x: T, y: T) -> bool {
    // This doesn't handle negative values! Don't copy this code elsewhere without considering if
    // negative values are important to you!
    let max: T = Bounded::max_value();
    return x > max - y;
}

/// Shifts the second parameter and then adds it to the first. fails!() if there would be unsigned
/// integer overflow.
pub fn shift_add_check_overflow<T: Int + Unsigned + Clone>(x: T, mut y: T, shift: T) -> T {
    if y.leading_zeros() < shift {
        fail!("Could not add values - integer overflow.");
    }
    y = y << shift;

    if will_add_overflow(x.clone(), y.clone()) {
        fail!("Could not add values - integer overflow.");
    }

    return x + y;
}

/// Shifts the second parameter and then adds it to the first, which is a tuple where the first
/// element is the high order value. fails!() if there would be unsigned integer overflow.
pub fn shift_add_check_overflow_tuple
        <T: Int + Unsigned + Clone>
        (x: (T, T), mut y: T, shift: T) -> (T, T) {
    if y.leading_zeros() < shift {
        fail!("Could not add values - integer overflow.");
    }
    y = y << shift;

    match x {
        (hi, low) => {
            let one: T = One::one();
            if will_add_overflow(low.clone(), y.clone()) {
                if will_add_overflow(hi.clone(), one.clone()) {
                    fail!("Could not add values - integer overflow.");
                } else {
                    return (hi + one, low + y);
                }
            } else {
                return (hi, low + y);
            }
        }
    }
}

/// A FixedBuffer, likes its name implies, is a fixed size buffer. When the buffer becomes full, it
/// must be processed. The input() method takes care of processing and then clearing the buffer
/// automatically. However, other methods do not and require the caller to process the buffer. Any
/// method that modifies the buffer directory or provides the caller with bytes that can be modifies
/// results in those bytes being marked as used by the buffer.
pub trait FixedBuffer {
    /// Input a vector of bytes. If the buffer becomes full, proccess it with the provided
    /// function and then clear the buffer.
    fn input(&mut self, input: &[u8], func: &fn(&[u8]));

    /// Reset the buffer.
    fn reset(&mut self);

    /// Zero the buffer up until the specified index. The buffer position currently must not be
    /// greater than that index.
    fn zero_until(&mut self, idx: uint);

    /// Get a slice of the buffer of the specified size. There must be at least that many bytes
    /// remaining in the buffer.
    fn next<'s>(&'s mut self, len: uint) -> &'s mut [u8];

    /// Get the current buffer. The buffer must already be full. This clears the buffer as well.
    fn full_buffer<'s>(&'s mut self) -> &'s [u8];

    /// Get the current position of the buffer.
    fn position(&self) -> uint;

    /// Get the number of bytes remaining in the buffer until it is full.
    fn remaining(&self) -> uint;

    /// Get the size of the buffer
    fn size(&self) -> uint;
}

macro_rules! impl_fixed_buffer( ($name:ident, $size:expr) => (
    impl FixedBuffer for $name {
        fn input(&mut self, input: &[u8], func: &fn(&[u8])) {
            let mut i = 0;

            // FIXME: #6304 - This local variable shouldn't be necessary.
            let size = $size;

            // If there is already data in the buffer, copy as much as we can into it and process
            // the data if the buffer becomes full.
            if self.buffer_idx != 0 {
                let buffer_remaining = size - self.buffer_idx;
                if input.len() >= buffer_remaining {
                        copy_memory(
                            self.buffer.mut_slice(self.buffer_idx, size),
                            input.slice_to(buffer_remaining),
                            buffer_remaining);
                    self.buffer_idx = 0;
                    func(self.buffer);
                    i += buffer_remaining;
                } else {
                    copy_memory(
                        self.buffer.mut_slice(self.buffer_idx, self.buffer_idx + input.len()),
                        input,
                        input.len());
                    self.buffer_idx += input.len();
                    return;
                }
            }

            // While we have at least a full buffer size chunks's worth of data, process that data
            // without copying it into the buffer
            while input.len() - i >= size {
                func(input.slice(i, i + size));
                i += size;
            }

            // Copy any input data into the buffer. At this point in the method, the ammount of
            // data left in the input vector will be less than the buffer size and the buffer will
            // be empty.
            let input_remaining = input.len() - i;
            copy_memory(
                self.buffer.mut_slice(0, input_remaining),
                input.slice_from(i),
                input.len() - i);
            self.buffer_idx += input_remaining;
        }

        fn reset(&mut self) {
            self.buffer_idx = 0;
        }

        fn zero_until(&mut self, idx: uint) {
            assert!(idx >= self.buffer_idx);
            self.buffer.mut_slice(self.buffer_idx, idx).set_memory(0);
            self.buffer_idx = idx;
        }

        fn next<'s>(&'s mut self, len: uint) -> &'s mut [u8] {
            self.buffer_idx += len;
            return self.buffer.mut_slice(self.buffer_idx - len, self.buffer_idx);
        }

        fn full_buffer<'s>(&'s mut self) -> &'s [u8] {
            assert!(self.buffer_idx == $size);
            self.buffer_idx = 0;
            return self.buffer.slice_to($size);
        }

        fn position(&self) -> uint { self.buffer_idx }

        fn remaining(&self) -> uint { $size - self.buffer_idx }

        fn size(&self) -> uint { $size }
    }
))

/// A fixed size buffer of 64 bytes useful for cryptographic operations.
pub struct FixedBuffer64 {
    priv buffer: [u8, ..64],
    priv buffer_idx: uint,
}

impl FixedBuffer64 {
    /// Create a new buffer
    pub fn new() -> FixedBuffer64 {
        return FixedBuffer64 {
            buffer: [0u8, ..64],
            buffer_idx: 0
        };
    }
}

impl_fixed_buffer!(FixedBuffer64, 64)

/// A fixed size buffer of 128 bytes useful for cryptographic operations.
pub struct FixedBuffer128 {
    priv buffer: [u8, ..128],
    priv buffer_idx: uint,
}

impl FixedBuffer128 {
    /// Create a new buffer
    pub fn new() -> FixedBuffer128 {
        return FixedBuffer128 {
            buffer: [0u8, ..128],
            buffer_idx: 0
        };
    }
}

impl_fixed_buffer!(FixedBuffer128, 128)

/// The StandardPadding trait adds a method useful for various hash algorithms to a FixedBuffer
/// struct.
pub trait StandardPadding {
    /// Add standard padding to the buffer. The buffer must not be full when this method is called
    /// and is guaranteed to have exactly rem remaining bytes when it returns. If there are not at
    /// least rem bytes available, the buffer will be zero padded, processed, cleared, and then
    /// filled with zeros again until only rem bytes are remaining.
    fn standard_padding(&mut self, rem: uint, func: &fn(&[u8]));
}

impl <T: FixedBuffer> StandardPadding for T {
    fn standard_padding(&mut self, rem: uint, func: &fn(&[u8])) {
        let size = self.size();

        self.next(1)[0] = 128;

        if self.remaining() < rem {
            self.zero_until(size);
            func(self.full_buffer());
        }

        self.zero_until(size - rem);
    }
}

#[cfg(test)]
mod test {
    use std::rand::IsaacRng;
    use std::rand::RngUtil;
    use std::vec;

    use digest::Digest;

    /// Feed 1,000,000 'a's into the digest with varying input sizes and check that the result is
    /// correct.
    pub fn test_digest_1million_random<D: Digest>(digest: &mut D, blocksize: uint, expected: &str) {
        let total_size = 1000000;
        let buffer = vec::from_elem(blocksize * 2, 'a' as u8);
        let mut rng = IsaacRng::new_unseeded();
        let mut count = 0;

        digest.reset();

        while count < total_size {
            let next: uint = rng.gen_uint_range(0, 2 * blocksize + 1);
            let remaining = total_size - count;
            let size = if next > remaining { remaining } else { next };
            digest.input(buffer.slice_to(size));
            count += size;
        }

        let result_str = digest.result_str();

        assert!(expected == result_str);
    }
}
<commit_msg>Crypto: Add little-endian versions of existing functions: read_u32v_le and write_u32_le.<commit_after>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::num::One;
use std::vec::bytes::{MutableByteVector, copy_memory};

/// Write a u64 into a vector, which must be 8 bytes long. The value is written in big-endian
/// format.
pub fn write_u64_be(dst: &mut[u8], input: u64) {
    use std::cast::transmute;
    use std::unstable::intrinsics::to_be64;
    assert!(dst.len() == 8);
    unsafe {
        let x: *mut i64 = transmute(dst.unsafe_mut_ref(0));
        *x = to_be64(input as i64);
    }
}

/// Write a u32 into a vector, which must be 4 bytes long. The value is written in big-endian
/// format.
pub fn write_u32_be(dst: &mut[u8], input: u32) {
    use std::cast::transmute;
    use std::unstable::intrinsics::to_be32;
    assert!(dst.len() == 4);
    unsafe {
        let x: *mut i32 = transmute(dst.unsafe_mut_ref(0));
        *x = to_be32(input as i32);
    }
}

/// Write a u32 into a vector, which must be 4 bytes long. The value is written in little-endian
/// format.
pub fn write_u32_le(dst: &mut[u8], input: u32) {
    use std::cast::transmute;
    use std::unstable::intrinsics::to_le32;
    assert!(dst.len() == 4);
    unsafe {
        let x: *mut i32 = transmute(dst.unsafe_mut_ref(0));
        *x = to_le32(input as i32);
    }
}

/// Read a vector of bytes into a vector of u64s. The values are read in big-endian format.
pub fn read_u64v_be(dst: &mut[u64], input: &[u8]) {
    use std::cast::transmute;
    use std::unstable::intrinsics::to_be64;
    assert!(dst.len() * 8 == input.len());
    unsafe {
        let mut x: *mut i64 = transmute(dst.unsafe_mut_ref(0));
        let mut y: *i64 = transmute(input.unsafe_ref(0));
        do dst.len().times() {
            *x = to_be64(*y);
            x = x.offset(1);
            y = y.offset(1);
        }
    }
}

/// Read a vector of bytes into a vector of u32s. The values are read in big-endian format.
pub fn read_u32v_be(dst: &mut[u32], input: &[u8]) {
    use std::cast::transmute;
    use std::unstable::intrinsics::to_be32;
    assert!(dst.len() * 4 == input.len());
    unsafe {
        let mut x: *mut i32 = transmute(dst.unsafe_mut_ref(0));
        let mut y: *i32 = transmute(input.unsafe_ref(0));
        do dst.len().times() {
            *x = to_be32(*y);
            x = x.offset(1);
            y = y.offset(1);
        }
    }
}

/// Read a vector of bytes into a vector of u32s. The values are read in little-endian format.
pub fn read_u32v_le(dst: &mut[u32], input: &[u8]) {
    use std::cast::transmute;
    use std::unstable::intrinsics::to_le32;
    assert!(dst.len() * 4 == input.len());
    unsafe {
        let mut x: *mut i32 = transmute(dst.unsafe_mut_ref(0));
        let mut y: *i32 = transmute(input.unsafe_ref(0));
        do dst.len().times() {
            *x = to_le32(*y);
            x = x.offset(1);
            y = y.offset(1);
        }
    }
}

/// Returns true if adding the two parameters will result in integer overflow
pub fn will_add_overflow<T: Int + Unsigned>(x: T, y: T) -> bool {
    // This doesn't handle negative values! Don't copy this code elsewhere without considering if
    // negative values are important to you!
    let max: T = Bounded::max_value();
    return x > max - y;
}

/// Shifts the second parameter and then adds it to the first. fails!() if there would be unsigned
/// integer overflow.
pub fn shift_add_check_overflow<T: Int + Unsigned + Clone>(x: T, mut y: T, shift: T) -> T {
    if y.leading_zeros() < shift {
        fail!("Could not add values - integer overflow.");
    }
    y = y << shift;

    if will_add_overflow(x.clone(), y.clone()) {
        fail!("Could not add values - integer overflow.");
    }

    return x + y;
}

/// Shifts the second parameter and then adds it to the first, which is a tuple where the first
/// element is the high order value. fails!() if there would be unsigned integer overflow.
pub fn shift_add_check_overflow_tuple
        <T: Int + Unsigned + Clone>
        (x: (T, T), mut y: T, shift: T) -> (T, T) {
    if y.leading_zeros() < shift {
        fail!("Could not add values - integer overflow.");
    }
    y = y << shift;

    match x {
        (hi, low) => {
            let one: T = One::one();
            if will_add_overflow(low.clone(), y.clone()) {
                if will_add_overflow(hi.clone(), one.clone()) {
                    fail!("Could not add values - integer overflow.");
                } else {
                    return (hi + one, low + y);
                }
            } else {
                return (hi, low + y);
            }
        }
    }
}

/// A FixedBuffer, likes its name implies, is a fixed size buffer. When the buffer becomes full, it
/// must be processed. The input() method takes care of processing and then clearing the buffer
/// automatically. However, other methods do not and require the caller to process the buffer. Any
/// method that modifies the buffer directory or provides the caller with bytes that can be modifies
/// results in those bytes being marked as used by the buffer.
pub trait FixedBuffer {
    /// Input a vector of bytes. If the buffer becomes full, proccess it with the provided
    /// function and then clear the buffer.
    fn input(&mut self, input: &[u8], func: &fn(&[u8]));

    /// Reset the buffer.
    fn reset(&mut self);

    /// Zero the buffer up until the specified index. The buffer position currently must not be
    /// greater than that index.
    fn zero_until(&mut self, idx: uint);

    /// Get a slice of the buffer of the specified size. There must be at least that many bytes
    /// remaining in the buffer.
    fn next<'s>(&'s mut self, len: uint) -> &'s mut [u8];

    /// Get the current buffer. The buffer must already be full. This clears the buffer as well.
    fn full_buffer<'s>(&'s mut self) -> &'s [u8];

    /// Get the current position of the buffer.
    fn position(&self) -> uint;

    /// Get the number of bytes remaining in the buffer until it is full.
    fn remaining(&self) -> uint;

    /// Get the size of the buffer
    fn size(&self) -> uint;
}

macro_rules! impl_fixed_buffer( ($name:ident, $size:expr) => (
    impl FixedBuffer for $name {
        fn input(&mut self, input: &[u8], func: &fn(&[u8])) {
            let mut i = 0;

            // FIXME: #6304 - This local variable shouldn't be necessary.
            let size = $size;

            // If there is already data in the buffer, copy as much as we can into it and process
            // the data if the buffer becomes full.
            if self.buffer_idx != 0 {
                let buffer_remaining = size - self.buffer_idx;
                if input.len() >= buffer_remaining {
                        copy_memory(
                            self.buffer.mut_slice(self.buffer_idx, size),
                            input.slice_to(buffer_remaining),
                            buffer_remaining);
                    self.buffer_idx = 0;
                    func(self.buffer);
                    i += buffer_remaining;
                } else {
                    copy_memory(
                        self.buffer.mut_slice(self.buffer_idx, self.buffer_idx + input.len()),
                        input,
                        input.len());
                    self.buffer_idx += input.len();
                    return;
                }
            }

            // While we have at least a full buffer size chunks's worth of data, process that data
            // without copying it into the buffer
            while input.len() - i >= size {
                func(input.slice(i, i + size));
                i += size;
            }

            // Copy any input data into the buffer. At this point in the method, the ammount of
            // data left in the input vector will be less than the buffer size and the buffer will
            // be empty.
            let input_remaining = input.len() - i;
            copy_memory(
                self.buffer.mut_slice(0, input_remaining),
                input.slice_from(i),
                input.len() - i);
            self.buffer_idx += input_remaining;
        }

        fn reset(&mut self) {
            self.buffer_idx = 0;
        }

        fn zero_until(&mut self, idx: uint) {
            assert!(idx >= self.buffer_idx);
            self.buffer.mut_slice(self.buffer_idx, idx).set_memory(0);
            self.buffer_idx = idx;
        }

        fn next<'s>(&'s mut self, len: uint) -> &'s mut [u8] {
            self.buffer_idx += len;
            return self.buffer.mut_slice(self.buffer_idx - len, self.buffer_idx);
        }

        fn full_buffer<'s>(&'s mut self) -> &'s [u8] {
            assert!(self.buffer_idx == $size);
            self.buffer_idx = 0;
            return self.buffer.slice_to($size);
        }

        fn position(&self) -> uint { self.buffer_idx }

        fn remaining(&self) -> uint { $size - self.buffer_idx }

        fn size(&self) -> uint { $size }
    }
))

/// A fixed size buffer of 64 bytes useful for cryptographic operations.
pub struct FixedBuffer64 {
    priv buffer: [u8, ..64],
    priv buffer_idx: uint,
}

impl FixedBuffer64 {
    /// Create a new buffer
    pub fn new() -> FixedBuffer64 {
        return FixedBuffer64 {
            buffer: [0u8, ..64],
            buffer_idx: 0
        };
    }
}

impl_fixed_buffer!(FixedBuffer64, 64)

/// A fixed size buffer of 128 bytes useful for cryptographic operations.
pub struct FixedBuffer128 {
    priv buffer: [u8, ..128],
    priv buffer_idx: uint,
}

impl FixedBuffer128 {
    /// Create a new buffer
    pub fn new() -> FixedBuffer128 {
        return FixedBuffer128 {
            buffer: [0u8, ..128],
            buffer_idx: 0
        };
    }
}

impl_fixed_buffer!(FixedBuffer128, 128)

/// The StandardPadding trait adds a method useful for various hash algorithms to a FixedBuffer
/// struct.
pub trait StandardPadding {
    /// Add standard padding to the buffer. The buffer must not be full when this method is called
    /// and is guaranteed to have exactly rem remaining bytes when it returns. If there are not at
    /// least rem bytes available, the buffer will be zero padded, processed, cleared, and then
    /// filled with zeros again until only rem bytes are remaining.
    fn standard_padding(&mut self, rem: uint, func: &fn(&[u8]));
}

impl <T: FixedBuffer> StandardPadding for T {
    fn standard_padding(&mut self, rem: uint, func: &fn(&[u8])) {
        let size = self.size();

        self.next(1)[0] = 128;

        if self.remaining() < rem {
            self.zero_until(size);
            func(self.full_buffer());
        }

        self.zero_until(size - rem);
    }
}

#[cfg(test)]
mod test {
    use std::rand::IsaacRng;
    use std::rand::RngUtil;
    use std::vec;

    use digest::Digest;

    /// Feed 1,000,000 'a's into the digest with varying input sizes and check that the result is
    /// correct.
    pub fn test_digest_1million_random<D: Digest>(digest: &mut D, blocksize: uint, expected: &str) {
        let total_size = 1000000;
        let buffer = vec::from_elem(blocksize * 2, 'a' as u8);
        let mut rng = IsaacRng::new_unseeded();
        let mut count = 0;

        digest.reset();

        while count < total_size {
            let next: uint = rng.gen_uint_range(0, 2 * blocksize + 1);
            let remaining = total_size - count;
            let size = if next > remaining { remaining } else { next };
            digest.input(buffer.slice_to(size));
            count += size;
        }

        let result_str = digest.result_str();

        assert!(expected == result_str);
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 The Servo Project Developers. See the
// COPYRIGHT file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use syntax::ptr::P;
use syntax::codemap::Span;
use syntax::ast::{TokenTree, TtToken};
use syntax::ast;
use syntax::ext::base::{ExtCtxt, MacResult, MacExpr};
use syntax::parse::token::{get_ident, InternedString, Ident, Literal, Lit};

use std::iter::Chain;
use std::collections::HashMap;
use std::ascii::AsciiExt;

mod data;

#[path="../../../shared/repr.rs"]
mod repr;

// Build a PhfOrderedSet of static atoms.
// Takes no arguments.
pub fn expand_static_atom_set(cx: &mut ExtCtxt, sp: Span, tt: &[TokenTree]) -> Box<MacResult+'static> {
    bail_if!(tt.len() != 0, cx, sp, "Usage: static_atom_map!()");
    let tts: Vec<TokenTree> = data::ATOMS.iter().flat_map(|k| {
        (quote_tokens!(&mut *cx, $k,)).into_iter()
    }).collect();
    MacExpr::new(quote_expr!(&mut *cx, phf_ordered_set!($tts)))
}

fn atom_tok_to_str(t: &TokenTree) -> Option<InternedString> {
    Some(get_ident(match *t {
        TtToken(_, Ident(s, _)) => s,
        TtToken(_, Literal(Lit::Str_(s), _)) => s.ident(),
        _ => return None,
    }))
}

// Build a map from atoms to IDs for use in implementing the atom!() macro.
lazy_static! {
    static ref STATIC_ATOM_MAP: HashMap<&'static str, uint> = {
        let mut m = HashMap::new();
        for (i, x) in data::ATOMS.iter().enumerate() {
            m.insert(*x, i);
        }
        m
    };
}

// FIXME: libsyntax should provide this (rust-lang/rust#17637)
struct AtomResult {
    expr: P<ast::Expr>,
    pat: P<ast::Pat>,
}

impl MacResult for AtomResult {
    fn make_expr(self: Box<AtomResult>) -> Option<P<ast::Expr>> {
        Some(self.expr)
    }

    fn make_pat(self: Box<AtomResult>) -> Option<P<ast::Pat>> {
        Some(self.pat)
    }
}

fn make_atom_result(cx: &mut ExtCtxt, name: &str) -> Option<AtomResult> {
    let i = match STATIC_ATOM_MAP.get(name) {
        Some(i) => i,
        None => return None,
    };

    let data = repr::pack_static(*i as u32);

    Some(AtomResult {
        expr: quote_expr!(&mut *cx, ::string_cache::atom::Atom { data: $data }),
        pat: quote_pat!(&mut *cx, ::string_cache::atom::Atom { data: $data }),
    })
}

// Translate `atom!(title)` or `atom!("font-weight")` into an `Atom` constant or pattern.
pub fn expand_atom(cx: &mut ExtCtxt, sp: Span, tt: &[TokenTree]) -> Box<MacResult+'static> {
    let usage = "Usage: atom!(html) or atom!(\"font-weight\")";
    let name = match tt {
        [ref t] => expect!(cx, sp, atom_tok_to_str(t), usage),
        _ => bail!(cx, sp, usage),
    };
    box expect!(cx, sp, make_atom_result(cx, name.get()),
        format!("Unknown static atom {}", name.get()).as_slice())
}

// Translate `ns!(HTML)` into `Namespace { atom: atom!("http://www.w3.org/1999/xhtml") }`.
// The argument is ASCII-case-insensitive.
pub fn expand_ns(cx: &mut ExtCtxt, sp: Span, tt: &[TokenTree]) -> Box<MacResult+'static> {
    static ALL_NS: &'static [(&'static str, &'static str)] = &[
        ("", ""),
        ("html", "http://www.w3.org/1999/xhtml"),
        ("xml", "http://www.w3.org/XML/1998/namespace"),
        ("xmlns", "http://www.w3.org/2000/xmlns/"),
        ("xlink", "http://www.w3.org/1999/xlink"),
        ("svg", "http://www.w3.org/2000/svg"),
        ("mathml", "http://www.w3.org/1998/Math/MathML"),
    ];

    fn usage() -> String {
        let ns_names: Vec<&'static str> = ALL_NS[1..].iter()
            .map(|&(x, _)| x).collect();
        format!("Usage: ns!(HTML), case-insensitive. \
            Known namespaces: {}",
            ns_names.connect(" "))
    }

    let name = expect!(cx, sp, match tt {
        [ref t] => atom_tok_to_str(t),
        _ => None,
    }, usage().as_slice());

    let &(_, url) = expect!(cx, sp,
        ALL_NS.iter().find(|&&(short, _)| short.eq_ignore_ascii_case(name.get())),
        usage().as_slice());

    // All of the URLs should be in the static atom table.
    let AtomResult { expr, pat } = expect!(cx, sp, make_atom_result(cx, url),
        format!("internal plugin error: can't find namespace url {}", url).as_slice());

    box AtomResult {
        expr: quote_expr!(&mut *cx, ::string_cache::namespace::Namespace($expr)),
        pat: quote_pat!(&mut *cx, ::string_cache::namespace::Namespace($pat)),
    }
}

#[macro_export]
macro_rules! qualname (($ns:tt, $local:tt) => (
    ::string_cache::namespace::QualName {
        ns: ns!($ns),
        local: atom!($local),
    }
));
<commit_msg>InternedString changes<commit_after>// Copyright 2014 The Servo Project Developers. See the
// COPYRIGHT file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use syntax::ptr::P;
use syntax::codemap::Span;
use syntax::ast::{TokenTree, TtToken};
use syntax::ast;
use syntax::ext::base::{ExtCtxt, MacResult, MacExpr};
use syntax::parse::token::{get_ident, InternedString, Ident, Literal, Lit};

use std::iter::Chain;
use std::collections::HashMap;
use std::ascii::AsciiExt;

mod data;

#[path="../../../shared/repr.rs"]
mod repr;

// Build a PhfOrderedSet of static atoms.
// Takes no arguments.
pub fn expand_static_atom_set(cx: &mut ExtCtxt, sp: Span, tt: &[TokenTree]) -> Box<MacResult+'static> {
    bail_if!(tt.len() != 0, cx, sp, "Usage: static_atom_map!()");
    let tts: Vec<TokenTree> = data::ATOMS.iter().flat_map(|k| {
        (quote_tokens!(&mut *cx, $k,)).into_iter()
    }).collect();
    MacExpr::new(quote_expr!(&mut *cx, phf_ordered_set!($tts)))
}

fn atom_tok_to_str(t: &TokenTree) -> Option<InternedString> {
    Some(get_ident(match *t {
        TtToken(_, Ident(s, _)) => s,
        TtToken(_, Literal(Lit::Str_(s), _)) => s.ident(),
        _ => return None,
    }))
}

// Build a map from atoms to IDs for use in implementing the atom!() macro.
lazy_static! {
    static ref STATIC_ATOM_MAP: HashMap<&'static str, uint> = {
        let mut m = HashMap::new();
        for (i, x) in data::ATOMS.iter().enumerate() {
            m.insert(*x, i);
        }
        m
    };
}

// FIXME: libsyntax should provide this (rust-lang/rust#17637)
struct AtomResult {
    expr: P<ast::Expr>,
    pat: P<ast::Pat>,
}

impl MacResult for AtomResult {
    fn make_expr(self: Box<AtomResult>) -> Option<P<ast::Expr>> {
        Some(self.expr)
    }

    fn make_pat(self: Box<AtomResult>) -> Option<P<ast::Pat>> {
        Some(self.pat)
    }
}

fn make_atom_result(cx: &mut ExtCtxt, name: &str) -> Option<AtomResult> {
    let i = match STATIC_ATOM_MAP.get(name) {
        Some(i) => i,
        None => return None,
    };

    let data = repr::pack_static(*i as u32);

    Some(AtomResult {
        expr: quote_expr!(&mut *cx, ::string_cache::atom::Atom { data: $data }),
        pat: quote_pat!(&mut *cx, ::string_cache::atom::Atom { data: $data }),
    })
}

// Translate `atom!(title)` or `atom!("font-weight")` into an `Atom` constant or pattern.
pub fn expand_atom(cx: &mut ExtCtxt, sp: Span, tt: &[TokenTree]) -> Box<MacResult+'static> {
    let usage = "Usage: atom!(html) or atom!(\"font-weight\")";
    let name = match tt {
        [ref t] => expect!(cx, sp, atom_tok_to_str(t), usage),
        _ => bail!(cx, sp, usage),
    };
    box expect!(cx, sp, make_atom_result(cx, &*name),
        format!("Unknown static atom {}", &*name).as_slice())
}

// Translate `ns!(HTML)` into `Namespace { atom: atom!("http://www.w3.org/1999/xhtml") }`.
// The argument is ASCII-case-insensitive.
pub fn expand_ns(cx: &mut ExtCtxt, sp: Span, tt: &[TokenTree]) -> Box<MacResult+'static> {
    static ALL_NS: &'static [(&'static str, &'static str)] = &[
        ("", ""),
        ("html", "http://www.w3.org/1999/xhtml"),
        ("xml", "http://www.w3.org/XML/1998/namespace"),
        ("xmlns", "http://www.w3.org/2000/xmlns/"),
        ("xlink", "http://www.w3.org/1999/xlink"),
        ("svg", "http://www.w3.org/2000/svg"),
        ("mathml", "http://www.w3.org/1998/Math/MathML"),
    ];

    fn usage() -> String {
        let ns_names: Vec<&'static str> = ALL_NS[1..].iter()
            .map(|&(x, _)| x).collect();
        format!("Usage: ns!(HTML), case-insensitive. \
            Known namespaces: {}",
            ns_names.connect(" "))
    }

    let name = expect!(cx, sp, match tt {
        [ref t] => atom_tok_to_str(t),
        _ => None,
    }, usage().as_slice());

    let &(_, url) = expect!(cx, sp,
        ALL_NS.iter().find(|&&(short, _)| short.eq_ignore_ascii_case(&*name)),
        usage().as_slice());

    // All of the URLs should be in the static atom table.
    let AtomResult { expr, pat } = expect!(cx, sp, make_atom_result(cx, url),
        format!("internal plugin error: can't find namespace url {}", url).as_slice());

    box AtomResult {
        expr: quote_expr!(&mut *cx, ::string_cache::namespace::Namespace($expr)),
        pat: quote_pat!(&mut *cx, ::string_cache::namespace::Namespace($pat)),
    }
}

#[macro_export]
macro_rules! qualname (($ns:tt, $local:tt) => (
    ::string_cache::namespace::QualName {
        ns: ns!($ns),
        local: atom!($local),
    }
));
<|endoftext|>