<commit_before>//! FBX binary parser.

use std::io;
use std::io::Read;

pub use self::error::{Result, Error, Warning};
pub use self::event::{Event, FbxHeader, FbxFooter, StartNode};
pub use self::event::{Attributes, Attribute, SpecialAttributeType};
pub use self::event::{PrimitiveAttribute, ArrayAttribute, SpecialAttribute};
pub use self::event::ArrayAttributeReader;
use self::event::{EventBuilder, NodeHeader, StartNodeBuilder};
use self::event::read_fbx_header;
pub use self::reader::{ParserSource, BasicSource, SeekableSource, LimitedSeekReader};

mod error;
mod event;
mod reader;
pub mod utils;

/// Warnings store.
#[derive(Default, Debug, Clone)]
pub struct Warnings(Vec<Warning>);

impl Warnings {
    /// Creates a new `Warnings`.
    pub fn new() -> Self {
        Default::default()
    }

    /// Add a warning.
    pub fn warn(&mut self, warning: Warning) {
        warn!("FBX binary parser warning: {}", warning);
        self.0.push(warning);
    }

    /// Returns the inner vector.
    pub fn inner(self) -> Vec<Warning> {
        self.0
    }
}

impl ::std::ops::Deref for Warnings {
    type Target = [Warning];

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

/// Parser of a FBX binary node.
pub trait Parser<R: ParserSource> {
    /// Returns the root parser.
    fn root_parser(&self) -> &RootParser<R>;
    /// Parses FBX from the given stream and returns the next event.
    fn next_event(&mut self) -> Result<Event<R>>;
    /// Skips to the end of the current node.
    ///
    /// Returns `Ok(true)` if the current node is skipped and closed,
    /// `Ok(false)` if no nodes are open (i.e. the parser is reading under implicit root node),
    /// `Err(err)` if error happened.
    fn skip_current_node(&mut self) -> Result<bool>;
    /// Creates subtree parser for the current node.
    fn subtree_parser(&mut self) -> SubtreeParser<R>;
}

/// Parser state without error.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum State {
    /// Reading file header.
    Header,
    /// A node started.
    ///
    /// This status means:
    ///
    /// - there might be some attributes remain unread, or
    /// - the most recent opened node might close without no null node header.
    NodeStarted,
    /// A node ended.
    ///
    /// This status means:
    ///
    /// - if the next event is `NodeEnd`, there must be a null node header, and
    /// - if the parser got an extra null header, it indicates end of implicit root node.
    NodeEnded,
}

/// Information about opened (but not yet closed) node.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
struct OpenNode {
    /// Start offset of the node attribute.
    ///
    /// Note that this doesn't mean start offset of node header.
    begin: u64,
    /// End offset of the node.
    end: u64,
    /// End offset of attributes of the node.
    attributes_end: u64,
}

/// Pull parser for whole FBX with binary format.
#[derive(Debug)]
pub struct RootParser<R> {
    /// Source reader.
    source: R,
    /// Parser state.
    ///
    /// `Ok(State)` if the parser is working without critical error,
    /// `Err(Error)` if the parsing failed and cannot be continued.
    state: Result<State>,
    /// Warnings.
    warnings: Warnings,
    /// FBX version.
    fbx_version: Option<u32>,
    /// Open nodes stack.
    open_nodes: Vec<OpenNode>,
    /// Node name of the recent opened node.
    recent_node_name: Option<String>,
}

impl<R: Read> RootParser<BasicSource<R>> {
    /// Creates a new binary parser.
    pub fn new(source: R) -> Self {
        RootParser {
            source: BasicSource::new(source),
            state: Ok(State::Header),
            warnings: Warnings::new(),
            fbx_version: None,
            open_nodes: Vec::new(),
            recent_node_name: None,
        }
    }
}

impl<R: Read + io::Seek> RootParser<SeekableSource<R>> {
    /// Creates a new binary parser.
    pub fn from_seekable(source: R) -> Self {
        RootParser {
            source: SeekableSource::new(source),
            state: Ok(State::Header),
            warnings: Warnings::new(),
            fbx_version: None,
            open_nodes: Vec::new(),
            recent_node_name: None,
        }
    }
}

impl<R: ParserSource> RootParser<R> {
    /// Returns FBX version of the reading input.
    ///
    /// Returns `None` if unknown yet.
    pub fn fbx_version(&self) -> Option<u32> {
        self.fbx_version
    }

    /// Returns the parser error if available.
    pub fn error(&self) -> Option<&Error> {
        self.state.as_ref().err()
    }

    /// Returns reference to the warnings.
    pub fn warnings(&self) -> &[Warning] {
        &self.warnings
    }

    /// Returns the number of the opened (and not closed) node.
    pub fn num_open_nodes(&self) -> usize {
        self.open_nodes.len()
    }

    /// Returns the node name of the recent opened node.
    pub fn recent_node_name(&self) -> Option<&str> {
        self.recent_node_name.as_ref().map(String::as_str)
    }

    /// Returns the node name of the recent opened node with ownership.
    pub fn take_recent_node_name(&mut self) -> Option<String> {
        self.recent_node_name.take()
    }

    /// Set the parser state as finished parsing.
    fn set_finish(&mut self) {
        self.state = Err(Error::Finished);
    }

    /// Set the parser state as error.
    fn set_error(&mut self, err: &Error) {
        error!("FBX binary parser error: {}", err);
        debug!("Parser: {:#?}", self);
        self.state = Err(err.clone());
    }

    /// Add warning.
    fn warn(&mut self, warning: Warning) {
        self.warnings.warn(warning);
        debug!("Parser: {:#?}", self);
    }

    /// Reads FBX header.
    fn read_fbx_header(&mut self) -> Result<EventBuilder> {
        let header = read_fbx_header(self)?;
        self.fbx_version = Some(header.version);
        self.state = Ok(State::NodeEnded);
        Ok(header.into())
    }

    /// Gets event after node start.
    fn read_after_node_start(&mut self) -> Result<EventBuilder> {
        // Attributes of recent opened node might remain partially unread.
        // They should be skipped before getting a next node event.
        self.skip_attributes()?;

        // Most recent opened node might ends here without a null node header.
        if let Some(end) = self.open_nodes.last().map(|v| v.end) {
            if self.source.position() == end {
                // Most recent opened node ends here (without a null node header).
                self.state = Ok(State::NodeEnded);
                self.open_nodes.pop();
                return Ok(EventBuilder::EndNode);
            }
        }

        let builder = self.read_node_event()?;
        Ok(builder)
    }

    /// Gets event after node end.
    fn read_after_node_end(&mut self) -> Result<EventBuilder> {
        self.read_node_event()
    }

    /// Reads a next node-related event from the source.
    ///
    /// This always returns `Ok(EventBuilder::StartNode)`, `Ok(EventBuilder::EndNode)`,
    /// `Ok(EventBuilder::EndFbx)` or `Err(_)`.
    fn read_node_event(&mut self) -> Result<EventBuilder> {
        let header = NodeHeader::read_from_parser(self)?;
        if header.is_node_end() {
            if let Some(last_node) = self.open_nodes.pop() {
                // There is open nodes, so this is not end of the FBX.
                let current_pos = self.source.position();
                if current_pos != last_node.end {
                    // Invalid node header.
                    return Err(Error::WrongNodeEndOffset {
                        begin: last_node.begin,
                        expected_end: last_node.end,
                        real_end: current_pos,
                    });
                }
            } else {
                assert_eq!(self.state.as_ref().ok(),
                           Some(&State::NodeEnded),
                           "End of implicit root node is read with unexpected parser state {:?}",
                           self.state);
                // No open nodes, so this `EndNode` event indicates the end of
                // the implicit root node.
                // FBX file has no more nodes.
                let footer = self.read_fbx_footer();
                return Ok(footer.into());
            }

            self.state = Ok(State::NodeEnded);
            Ok(EventBuilder::EndNode)
        } else {
            // Reuse node name buffer.
            self.recent_node_name = {
                // Take node name buffer inside the string if the buffer remains.
                // Create a new buffer if the buffer was already taken.
                let mut vecbuf = self.recent_node_name
                    .take()
                    .map(|s| {
                        // Get inner `Vec` of the string.
                        let mut v = s.into_bytes();
                        // Resize buffer.
                        // This reallocates only if the buffer is too small.
                        v.resize(header.bytelen_name as usize, 0);
                        v
                    })
                    .unwrap_or_else(|| vec![0; header.bytelen_name as usize]);
                // Read the node name into the buffer.
                self.source.read_exact(&mut vecbuf)?;
                // Covert the name into `String`.
                // If conversion failed, the buffer will be left empty.
                // This is ok because no more node events would be loaded and
                // the buffer would no longer be used.
                Some(String::from_utf8(vecbuf).map_err(Error::node_name_invalid_utf8)?)
            };

            let current_pos = self.source.position();
            self.open_nodes.push(OpenNode {
                begin: current_pos,
                end: header.end_offset,
                attributes_end: current_pos + header.bytelen_attributes,
            });

            // Zero or more attributes come after node start.
            self.state = Ok(State::NodeStarted);
            Ok(StartNodeBuilder { header: header }.into())
        }
    }

    /// Reads an FBX footer.
    fn read_fbx_footer(&mut self) -> Result<FbxFooter> {
        self.set_finish();
        FbxFooter::read_from_parser(self)
    }

    /// Skip attributes of the most recent opened node.
    fn skip_attributes(&mut self) -> io::Result<()> {
        let attributes_end = self.open_nodes
            .last()
            .expect("`RootParser::skip_attributes()` is called but no nodes are open")
            .attributes_end;
        self.source.skip_to(attributes_end)
    }
}

impl<R: ParserSource> Parser<R> for RootParser<R> {
    fn root_parser(&self) -> &RootParser<R> {
        self
    }

    fn next_event(&mut self) -> Result<Event<R>> {
        let builder = match self.state.clone()? {
            State::Header => self.read_fbx_header(),
            State::NodeStarted => self.read_after_node_start(),
            State::NodeEnded => self.read_after_node_end(),
        };
        if let Err(ref err) = builder {
            self.set_error(err);
        }
        Ok(builder?.build(self))
    }

    fn skip_current_node(&mut self) -> Result<bool> {
        if let Some(end) = self.open_nodes.pop().map(|v| v.end) {
            self.source.skip_to(end)?;
            self.state = Ok(State::NodeEnded);
            Ok(true)
        } else {
            Ok(false)
        }
    }

    fn subtree_parser(&mut self) -> SubtreeParser<R> {
        SubtreeParser::new(self)
    }
}

/// Pull parser for a subtree of the FBX binary.
pub struct SubtreeParser<'a, R: 'a> {
    /// Root parser.
    root_parser: &'a mut RootParser<R>,
    /// Initial depth.
    ///
    /// Depth of the implicit root node is `0`.
    initial_depth: usize,
}

impl<'a, R: 'a + ParserSource> SubtreeParser<'a, R> {
    /// Creates a new `SubtreeParser`.
    pub fn new(root_parser: &'a mut RootParser<R>) -> Self {
        let initial_depth = root_parser.num_open_nodes();
        SubtreeParser {
            root_parser: root_parser,
            initial_depth: initial_depth,
        }
    }

    /// Checks if the subtree parser can emit more events.
    ///
    /// Returns `Ok(())` if more events can be read,
    /// `Err(Error::Finished)` if the subtree is all read,
    /// `Err(_)` if error happened.
    fn check_finished(&self) -> Result<()> {
        if self.is_finished()? {
            Err(Error::Finished)
        } else {
            Ok(())
        }
    }

    /// Checks if the subtree parser finished reading events.
    fn is_finished(&self) -> Result<bool> {
        if let Some(err) = self.root_parser.error() {
            return Err(err.clone());
        }
        Ok(self.root_parser.num_open_nodes() < self.initial_depth)
    }
}

impl<'a, R: 'a + ParserSource> Parser<R> for SubtreeParser<'a, R> {
    fn root_parser(&self) -> &RootParser<R> {
        self.root_parser
    }

    fn next_event(&mut self) -> Result<Event<R>> {
        self.check_finished()?;
        self.root_parser.next_event()
    }

    fn skip_current_node(&mut self) -> Result<bool> {
        self.check_finished()?;
        self.root_parser.skip_current_node()
    }

    fn subtree_parser(&mut self) -> SubtreeParser<R> {
        SubtreeParser::new(self.root_parser)
    }
}

impl<'a, R: ParserSource, P: Parser<R>> Parser<R> for &'a mut P {
    fn root_parser(&self) -> &RootParser<R> {
        (**self).root_parser()
    }

    fn next_event(&mut self) -> Result<Event<R>> {
        (**self).next_event()
    }

    fn skip_current_node(&mut self) -> Result<bool> {
        (**self).skip_current_node()
    }

    fn subtree_parser(&mut self) -> SubtreeParser<R> {
        (**self).subtree_parser()
    }
}
<commit_msg>Add `SubtreeParser::skip_to_end()`<commit_after>//! FBX binary parser.

use std::io;
use std::io::Read;

pub use self::error::{Result, Error, Warning};
pub use self::event::{Event, FbxHeader, FbxFooter, StartNode};
pub use self::event::{Attributes, Attribute, SpecialAttributeType};
pub use self::event::{PrimitiveAttribute, ArrayAttribute, SpecialAttribute};
pub use self::event::ArrayAttributeReader;
use self::event::{EventBuilder, NodeHeader, StartNodeBuilder};
use self::event::read_fbx_header;
pub use self::reader::{ParserSource, BasicSource, SeekableSource, LimitedSeekReader};

mod error;
mod event;
mod reader;
pub mod utils;

/// Warnings store.
#[derive(Default, Debug, Clone)]
pub struct Warnings(Vec<Warning>);

impl Warnings {
    /// Creates a new `Warnings`.
    pub fn new() -> Self {
        Default::default()
    }

    /// Add a warning.
    pub fn warn(&mut self, warning: Warning) {
        warn!("FBX binary parser warning: {}", warning);
        self.0.push(warning);
    }

    /// Returns the inner vector.
    pub fn inner(self) -> Vec<Warning> {
        self.0
    }
}

impl ::std::ops::Deref for Warnings {
    type Target = [Warning];

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

/// Parser of a FBX binary node.
pub trait Parser<R: ParserSource> {
    /// Returns the root parser.
    fn root_parser(&self) -> &RootParser<R>;
    /// Parses FBX from the given stream and returns the next event.
    fn next_event(&mut self) -> Result<Event<R>>;
    /// Skips to the end of the current node.
    ///
    /// Returns `Ok(true)` if the current node is skipped and closed,
    /// `Ok(false)` if no nodes are open (i.e. the parser is reading under implicit root node),
    /// `Err(err)` if error happened.
    fn skip_current_node(&mut self) -> Result<bool>;
    /// Creates subtree parser for the current node.
    fn subtree_parser(&mut self) -> SubtreeParser<R>;
}

/// Parser state without error.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum State {
    /// Reading file header.
    Header,
    /// A node started.
    ///
    /// This status means:
    ///
    /// - there might be some attributes remain unread, or
    /// - the most recent opened node might close without no null node header.
    NodeStarted,
    /// A node ended.
    ///
    /// This status means:
    ///
    /// - if the next event is `NodeEnd`, there must be a null node header, and
    /// - if the parser got an extra null header, it indicates end of implicit root node.
    NodeEnded,
}

/// Information about opened (but not yet closed) node.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
struct OpenNode {
    /// Start offset of the node attribute.
    ///
    /// Note that this doesn't mean start offset of node header.
    begin: u64,
    /// End offset of the node.
    end: u64,
    /// End offset of attributes of the node.
    attributes_end: u64,
}

/// Pull parser for whole FBX with binary format.
#[derive(Debug)]
pub struct RootParser<R> {
    /// Source reader.
    source: R,
    /// Parser state.
    ///
    /// `Ok(State)` if the parser is working without critical error,
    /// `Err(Error)` if the parsing failed and cannot be continued.
    state: Result<State>,
    /// Warnings.
    warnings: Warnings,
    /// FBX version.
    fbx_version: Option<u32>,
    /// Open nodes stack.
    open_nodes: Vec<OpenNode>,
    /// Node name of the recent opened node.
    recent_node_name: Option<String>,
}

impl<R: Read> RootParser<BasicSource<R>> {
    /// Creates a new binary parser.
    pub fn new(source: R) -> Self {
        RootParser {
            source: BasicSource::new(source),
            state: Ok(State::Header),
            warnings: Warnings::new(),
            fbx_version: None,
            open_nodes: Vec::new(),
            recent_node_name: None,
        }
    }
}

impl<R: Read + io::Seek> RootParser<SeekableSource<R>> {
    /// Creates a new binary parser.
    pub fn from_seekable(source: R) -> Self {
        RootParser {
            source: SeekableSource::new(source),
            state: Ok(State::Header),
            warnings: Warnings::new(),
            fbx_version: None,
            open_nodes: Vec::new(),
            recent_node_name: None,
        }
    }
}

impl<R: ParserSource> RootParser<R> {
    /// Returns FBX version of the reading input.
    ///
    /// Returns `None` if unknown yet.
    pub fn fbx_version(&self) -> Option<u32> {
        self.fbx_version
    }

    /// Returns the parser error if available.
    pub fn error(&self) -> Option<&Error> {
        self.state.as_ref().err()
    }

    /// Returns reference to the warnings.
    pub fn warnings(&self) -> &[Warning] {
        &self.warnings
    }

    /// Returns the number of the opened (and not closed) node.
    pub fn num_open_nodes(&self) -> usize {
        self.open_nodes.len()
    }

    /// Returns the node name of the recent opened node.
    pub fn recent_node_name(&self) -> Option<&str> {
        self.recent_node_name.as_ref().map(String::as_str)
    }

    /// Returns the node name of the recent opened node with ownership.
    pub fn take_recent_node_name(&mut self) -> Option<String> {
        self.recent_node_name.take()
    }

    /// Set the parser state as finished parsing.
    fn set_finish(&mut self) {
        self.state = Err(Error::Finished);
    }

    /// Set the parser state as error.
    fn set_error(&mut self, err: &Error) {
        error!("FBX binary parser error: {}", err);
        debug!("Parser: {:#?}", self);
        self.state = Err(err.clone());
    }

    /// Add warning.
    fn warn(&mut self, warning: Warning) {
        self.warnings.warn(warning);
        debug!("Parser: {:#?}", self);
    }

    /// Reads FBX header.
    fn read_fbx_header(&mut self) -> Result<EventBuilder> {
        let header = read_fbx_header(self)?;
        self.fbx_version = Some(header.version);
        self.state = Ok(State::NodeEnded);
        Ok(header.into())
    }

    /// Gets event after node start.
    fn read_after_node_start(&mut self) -> Result<EventBuilder> {
        // Attributes of recent opened node might remain partially unread.
        // They should be skipped before getting a next node event.
        self.skip_attributes()?;

        // Most recent opened node might ends here without a null node header.
        if let Some(end) = self.open_nodes.last().map(|v| v.end) {
            if self.source.position() == end {
                // Most recent opened node ends here (without a null node header).
                self.state = Ok(State::NodeEnded);
                self.open_nodes.pop();
                return Ok(EventBuilder::EndNode);
            }
        }

        let builder = self.read_node_event()?;
        Ok(builder)
    }

    /// Gets event after node end.
    fn read_after_node_end(&mut self) -> Result<EventBuilder> {
        self.read_node_event()
    }

    /// Reads a next node-related event from the source.
    ///
    /// This always returns `Ok(EventBuilder::StartNode)`, `Ok(EventBuilder::EndNode)`,
    /// `Ok(EventBuilder::EndFbx)` or `Err(_)`.
    fn read_node_event(&mut self) -> Result<EventBuilder> {
        let header = NodeHeader::read_from_parser(self)?;
        if header.is_node_end() {
            if let Some(last_node) = self.open_nodes.pop() {
                // There is open nodes, so this is not end of the FBX.
                let current_pos = self.source.position();
                if current_pos != last_node.end {
                    // Invalid node header.
                    return Err(Error::WrongNodeEndOffset {
                        begin: last_node.begin,
                        expected_end: last_node.end,
                        real_end: current_pos,
                    });
                }
            } else {
                assert_eq!(self.state.as_ref().ok(),
                           Some(&State::NodeEnded),
                           "End of implicit root node is read with unexpected parser state {:?}",
                           self.state);
                // No open nodes, so this `EndNode` event indicates the end of
                // the implicit root node.
                // FBX file has no more nodes.
                let footer = self.read_fbx_footer();
                return Ok(footer.into());
            }

            self.state = Ok(State::NodeEnded);
            Ok(EventBuilder::EndNode)
        } else {
            // Reuse node name buffer.
            self.recent_node_name = {
                // Take node name buffer inside the string if the buffer remains.
                // Create a new buffer if the buffer was already taken.
                let mut vecbuf = self.recent_node_name
                    .take()
                    .map(|s| {
                        // Get inner `Vec` of the string.
                        let mut v = s.into_bytes();
                        // Resize buffer.
                        // This reallocates only if the buffer is too small.
                        v.resize(header.bytelen_name as usize, 0);
                        v
                    })
                    .unwrap_or_else(|| vec![0; header.bytelen_name as usize]);
                // Read the node name into the buffer.
                self.source.read_exact(&mut vecbuf)?;
                // Covert the name into `String`.
                // If conversion failed, the buffer will be left empty.
                // This is ok because no more node events would be loaded and
                // the buffer would no longer be used.
                Some(String::from_utf8(vecbuf).map_err(Error::node_name_invalid_utf8)?)
            };

            let current_pos = self.source.position();
            self.open_nodes.push(OpenNode {
                begin: current_pos,
                end: header.end_offset,
                attributes_end: current_pos + header.bytelen_attributes,
            });

            // Zero or more attributes come after node start.
            self.state = Ok(State::NodeStarted);
            Ok(StartNodeBuilder { header: header }.into())
        }
    }

    /// Reads an FBX footer.
    fn read_fbx_footer(&mut self) -> Result<FbxFooter> {
        self.set_finish();
        FbxFooter::read_from_parser(self)
    }

    /// Skip attributes of the most recent opened node.
    fn skip_attributes(&mut self) -> io::Result<()> {
        let attributes_end = self.open_nodes
            .last()
            .expect("`RootParser::skip_attributes()` is called but no nodes are open")
            .attributes_end;
        self.source.skip_to(attributes_end)
    }
}

impl<R: ParserSource> Parser<R> for RootParser<R> {
    fn root_parser(&self) -> &RootParser<R> {
        self
    }

    fn next_event(&mut self) -> Result<Event<R>> {
        let builder = match self.state.clone()? {
            State::Header => self.read_fbx_header(),
            State::NodeStarted => self.read_after_node_start(),
            State::NodeEnded => self.read_after_node_end(),
        };
        if let Err(ref err) = builder {
            self.set_error(err);
        }
        Ok(builder?.build(self))
    }

    fn skip_current_node(&mut self) -> Result<bool> {
        if let Some(end) = self.open_nodes.pop().map(|v| v.end) {
            self.source.skip_to(end)?;
            self.state = Ok(State::NodeEnded);
            Ok(true)
        } else {
            Ok(false)
        }
    }

    fn subtree_parser(&mut self) -> SubtreeParser<R> {
        SubtreeParser::new(self)
    }
}

/// Pull parser for a subtree of the FBX binary.
pub struct SubtreeParser<'a, R: 'a> {
    /// Root parser.
    root_parser: &'a mut RootParser<R>,
    /// Initial depth.
    ///
    /// Depth of the implicit root node is `0`.
    initial_depth: usize,
}

impl<'a, R: 'a + ParserSource> SubtreeParser<'a, R> {
    /// Creates a new `SubtreeParser`.
    pub fn new(root_parser: &'a mut RootParser<R>) -> Self {
        let initial_depth = root_parser.num_open_nodes();
        SubtreeParser {
            root_parser: root_parser,
            initial_depth: initial_depth,
        }
    }

    /// Checks if the subtree parser can emit more events.
    ///
    /// Returns `Ok(())` if more events can be read,
    /// `Err(Error::Finished)` if the subtree is all read,
    /// `Err(_)` if error happened.
    fn check_finished(&self) -> Result<()> {
        if self.is_finished()? {
            Err(Error::Finished)
        } else {
            Ok(())
        }
    }

    /// Checks if the subtree parser finished reading events.
    fn is_finished(&self) -> Result<bool> {
        if let Some(err) = self.root_parser.error() {
            return Err(err.clone());
        }
        Ok(self.root_parser.num_open_nodes() < self.initial_depth)
    }

    /// Skip to the end of the subtree parser's readable range.
    ///
    /// Note that this is not intended to called for `SubtreeParser` reading implicit root node.
    /// If the subtree parser can read whole data, the parser skips all events including `FbxEnd`
    /// and returns `Err(Error::Finished)`.
    pub fn skip_to_end(self) -> Result<()> {
        if self.is_finished()? {
            return Ok(());
        }
        self.root_parser.open_nodes.truncate(self.initial_depth);
        if let Some(end) = self.root_parser.open_nodes.pop().map(|v| v.end) {
            self.root_parser.source.skip_to(end)?;
            self.root_parser.state = Ok(State::NodeEnded);
            Ok(())
        } else {
            self.root_parser.state = Err(Error::Finished);
            Err(Error::Finished)
        }
    }
}

impl<'a, R: 'a + ParserSource> Parser<R> for SubtreeParser<'a, R> {
    fn root_parser(&self) -> &RootParser<R> {
        self.root_parser
    }

    fn next_event(&mut self) -> Result<Event<R>> {
        self.check_finished()?;
        self.root_parser.next_event()
    }

    fn skip_current_node(&mut self) -> Result<bool> {
        self.check_finished()?;
        self.root_parser.skip_current_node()
    }

    fn subtree_parser(&mut self) -> SubtreeParser<R> {
        SubtreeParser::new(self.root_parser)
    }
}

impl<'a, R: ParserSource, P: Parser<R>> Parser<R> for &'a mut P {
    fn root_parser(&self) -> &RootParser<R> {
        (**self).root_parser()
    }

    fn next_event(&mut self) -> Result<Event<R>> {
        (**self).next_event()
    }

    fn skip_current_node(&mut self) -> Result<bool> {
        (**self).skip_current_node()
    }

    fn subtree_parser(&mut self) -> SubtreeParser<R> {
        (**self).subtree_parser()
    }
}
<|endoftext|>


<commit_before>use sdl2;

use geometry;

struct Player {
	size: geometry::Size,
}

struct PlayerState {
	player: ~Player,
	position: geometry::Point,
	sprite: ~sdl2::surface::Surface,
	sprite_path: ~str,
}

impl Player {
	pub fn new(size: geometry::Size) -> Player {
		Player{size: size}
	}

	pub fn clone(&self) -> ~Player {
		~Player{size: self.size}
	}
}

impl PlayerState {
	pub fn new(player: ~Player, position: geometry::Point, sprite_path: ~str) -> PlayerState {
        let sprite = match sdl2::surface::Surface::from_bmp(~Path::new(~"./player.bmp")) {
        	Ok(loaded_sprite) => loaded_sprite,
        	Err(_) => fail!(format!("Failed to load player sprite at path: {}", sprite_path))
        };

		PlayerState{player: player, position: position, sprite: sprite, sprite_path: sprite_path}
	}

	pub fn clone(&self) -> ~PlayerState {
        let sprite = sdl2::surface::Surface::from_bmp(~Path::new(~"./player.bmp")).unwrap();
		~PlayerState{player: self.player.clone(), position: self.position, sprite: sprite, sprite_path: self.sprite_path.clone()}
	}
}<commit_msg>Explicitly implement Clone for PlayerState.<commit_after>use sdl2;

use geometry;

struct Player {
	size: geometry::Size,
}

struct PlayerState {
	player: ~Player,
	position: geometry::Point,
	sprite: ~sdl2::surface::Surface,
	sprite_path: ~str,
}

impl Player {
	pub fn new(size: geometry::Size) -> Player {
		Player{size: size}
	}

	pub fn clone(&self) -> ~Player {
		~Player{size: self.size}
	}
}

impl PlayerState {
	pub fn new(player: ~Player, position: geometry::Point, sprite_path: ~str) -> PlayerState {
        let sprite = match sdl2::surface::Surface::from_bmp(~Path::new(~"./player.bmp")) {
        	Ok(loaded_sprite) => loaded_sprite,
        	Err(_) => fail!(format!("Failed to load player sprite at path: {}", sprite_path))
        };

		PlayerState{player: player, position: position, sprite: sprite, sprite_path: sprite_path}
	}
}

impl Clone for PlayerState {
	fn clone(&self) -> PlayerState {
        let sprite = sdl2::surface::Surface::from_bmp(~Path::new(~"./player.bmp")).unwrap();
		PlayerState{player: self.player.clone(), position: self.position, sprite: sprite, sprite_path: self.sprite_path.clone()}
	}
}<|endoftext|>


<commit_before>use utils::gas::Gas;
use utils::address::Address;
use utils::bigint::U256;

use super::errors::RequireError;
use super::{Context, ContextVM, AccountState, BlockhashState, Patch, BlockHeader, Memory};

pub enum Transaction {
    MessageCall {
        address: Address,
        caller: Address,
        gas_price: Gas,
        gas_limit: Gas,
        value: U256,
        data: Vec<u8>,
    },
    ContractCreation {
        caller: Address,
        gas_price: Gas,
        gas_limit: Gas,
        value: U256,
        init: Vec<u8>,
    },
}

impl Transaction {
    #[allow(unused_variables)]
    pub fn intrinsic_gas(&self) -> Gas {
        unimplemented!()
    }

    #[allow(unused_variables)]
    pub fn into_context(self, origin: Option<Address>,
                        account_state: &AccountState) -> Result<Context, RequireError> {
        unimplemented!()
    }
}

enum TransactionVMState<M> {
    Running {
        vm: ContextVM<M>,
        intrinsic_gas: Gas,
    },
    Constructing {
        transaction: Transaction,
        block: BlockHeader,
        patch: &'static Patch,

        account_state: AccountState,
        blockhash_state: BlockhashState,
    },
}

pub struct TransactionVM<M>(TransactionVMState<M>);

impl<M: Memory + Default> TransactionVM<M> {
    pub fn new(transaction: Transaction, block: BlockHeader, patch: &'static Patch) -> Self {
        TransactionVM(TransactionVMState::Constructing {
            transaction: transaction,
            block: block,
            patch: patch,

            account_state: AccountState::default(),
            blockhash_state: BlockhashState::default(),
        })
    }
}
<commit_msg>Problem: #152 wrapping transactions for VM<commit_after>use std::collections::hash_map;
use utils::gas::Gas;
use utils::address::Address;
use utils::bigint::{U256, M256};

use super::errors::{RequireError, CommitError};
use super::{Context, ContextVM, VM, AccountState, BlockhashState, Patch, BlockHeader, Memory,
            VMStatus, AccountCommitment, Log, Account};

#[derive(Debug, Clone)]
pub enum Transaction {
    MessageCall {
        address: Address,
        caller: Address,
        gas_price: Gas,
        gas_limit: Gas,
        value: U256,
        data: Vec<u8>,
    },
    ContractCreation {
        caller: Address,
        gas_price: Gas,
        gas_limit: Gas,
        value: U256,
        init: Vec<u8>,
    },
}

impl Transaction {
    #[allow(unused_variables)]
    pub fn intrinsic_gas(&self) -> Gas {
        unimplemented!()
    }

    #[allow(unused_variables)]
    pub fn into_context(self, origin: Option<Address>,
                        account_state: &AccountState) -> Result<Context, RequireError> {
        unimplemented!()
    }

    #[allow(unused_variables)]
    pub fn gas_limit(&self) -> Gas {
        unimplemented!()
    }
}

enum TransactionVMState<M> {
    Running {
        vm: ContextVM<M>,
        intrinsic_gas: Gas,
    },
    Constructing {
        transaction: Transaction,
        block: BlockHeader,
        patch: &'static Patch,

        account_state: AccountState,
        blockhash_state: BlockhashState,
    },
}

pub struct TransactionVM<M>(TransactionVMState<M>);

impl<M: Memory + Default> TransactionVM<M> {
    pub fn new(transaction: Transaction, block: BlockHeader, patch: &'static Patch) -> Self {
        TransactionVM(TransactionVMState::Constructing {
            transaction: transaction,
            block: block,
            patch: patch,

            account_state: AccountState::default(),
            blockhash_state: BlockhashState::default(),
        })
    }
}

impl<M: Memory + Default> VM for TransactionVM<M> {
    fn commit_account(&mut self, commitment: AccountCommitment) -> Result<(), CommitError> {
        match self.0 {
            TransactionVMState::Running { ref mut vm, .. } => vm.commit_account(commitment),
            TransactionVMState::Constructing { ref mut account_state, .. } => account_state.commit(commitment),
        }
    }

    fn commit_blockhash(&mut self, number: M256, hash: M256) -> Result<(), CommitError> {
        match self.0 {
            TransactionVMState::Running { ref mut vm, .. } => vm.commit_blockhash(number, hash),
            TransactionVMState::Constructing { ref mut blockhash_state, .. } => blockhash_state.commit(number, hash),
        }
    }

    fn status(&self) -> VMStatus {
        match self.0 {
            TransactionVMState::Running { ref vm, .. } => vm.status(),
            TransactionVMState::Constructing { .. } => VMStatus::Running,
        }
    }

    fn step(&mut self) -> Result<(), RequireError> {
        let mut cgas: Option<Gas> = None;
        let mut ccontext: Option<Context> = None;
        let mut cblock: Option<BlockHeader> = None;
        let mut cpatch: Option<&'static Patch> = None;
        let mut caccount_state: Option<AccountState> = None;
        let mut cblockhash_state: Option<BlockhashState> = None;

        match self.0 {
            TransactionVMState::Running { ref mut vm, .. } => return vm.step(),
            TransactionVMState::Constructing {
                ref transaction, ref block, ref patch,
                ref account_state, ref blockhash_state } => {

                cgas = Some(transaction.intrinsic_gas());
                ccontext = Some(transaction.clone().into_context(None, account_state)?);
                cblock = Some(block.clone());
                cpatch = Some(patch);
                caccount_state = Some(account_state.clone());
                cblockhash_state = Some(blockhash_state.clone());
            }
        }

        self.0 = TransactionVMState::Running {
            vm: ContextVM::with_states(ccontext.unwrap(), cblock.unwrap(), cpatch.unwrap(),
                                       caccount_state.unwrap(), cblockhash_state.unwrap()),
            intrinsic_gas: cgas.unwrap(),
        };

        Ok(())
    }

    fn accounts(&self) -> hash_map::Values<Address, Account> {
        match self.0 {
            TransactionVMState::Running { ref vm, .. } => vm.accounts(),
            TransactionVMState::Constructing { ref account_state, .. } => account_state.accounts(),
        }
    }

    fn out(&self) -> &[u8] {
        match self.0 {
            TransactionVMState::Running { ref vm, .. } => vm.out(),
            TransactionVMState::Constructing { .. } => &[],
        }
    }

    fn available_gas(&self) -> Gas {
        match self.0 {
            TransactionVMState::Running { ref vm, .. } => vm.available_gas(),
            TransactionVMState::Constructing { ref transaction, .. } => transaction.gas_limit(),
        }
    }

    fn used_gas(&self) -> Gas {
        match self.0 {
            TransactionVMState::Running { ref vm, .. } => vm.used_gas(),
            TransactionVMState::Constructing { .. } => Gas::zero(),
        }
    }

    fn refunded_gas(&self) -> Gas {
        match self.0 {
            TransactionVMState::Running { ref vm, .. } => vm.refunded_gas(),
            TransactionVMState::Constructing { .. } => Gas::zero(),
        }
    }

    fn logs(&self) -> &[Log] {
        match self.0 {
            TransactionVMState::Running { ref vm, .. } => vm.logs(),
            TransactionVMState::Constructing { .. } => &[],
        }
    }
}
<|endoftext|>


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

use cssparser::Parser as CssParser;
use document_loader::LoadType;
use dom::attr::Attr;
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::DOMTokenListBinding::DOMTokenListMethods;
use dom::bindings::codegen::Bindings::HTMLLinkElementBinding;
use dom::bindings::codegen::Bindings::HTMLLinkElementBinding::HTMLLinkElementMethods;
use dom::bindings::inheritance::Castable;
use dom::bindings::js::{JS, MutNullableHeap, Root, RootedReference};
use dom::bindings::refcounted::Trusted;
use dom::bindings::str::DOMString;
use dom::document::Document;
use dom::domtokenlist::DOMTokenList;
use dom::element::{AttributeMutation, Element, ElementCreator};
use dom::eventtarget::EventTarget;
use dom::htmlelement::HTMLElement;
use dom::node::{Node, document_from_node, window_from_node};
use dom::virtualmethods::VirtualMethods;
use encoding::EncodingRef;
use encoding::all::UTF_8;
use hyper::header::ContentType;
use hyper::mime::{Mime, TopLevel, SubLevel};
use hyper_serde::Serde;
use ipc_channel::ipc;
use ipc_channel::router::ROUTER;
use msg::constellation_msg::ReferrerPolicy;
use net_traits::{AsyncResponseListener, AsyncResponseTarget, Metadata, NetworkError};
use network_listener::{NetworkListener, PreInvoke};
use script_layout_interface::message::Msg;
use script_traits::{MozBrowserEvent, ScriptMsg as ConstellationMsg};
use std::ascii::AsciiExt;
use std::borrow::ToOwned;
use std::cell::Cell;
use std::default::Default;
use std::mem;
use std::sync::{Arc, Mutex};
use string_cache::Atom;
use style::attr::AttrValue;
use style::media_queries::{MediaQueryList, parse_media_query_list};
use style::parser::ParserContextExtraData;
use style::str::HTML_SPACE_CHARACTERS;
use style::stylesheets::{Stylesheet, Origin};
use url::Url;

no_jsmanaged_fields!(Stylesheet);

#[dom_struct]
pub struct HTMLLinkElement {
    htmlelement: HTMLElement,
    rel_list: MutNullableHeap<JS<DOMTokenList>>,
    stylesheet: DOMRefCell<Option<Arc<Stylesheet>>>,

    /// https://html.spec.whatwg.org/multipage/#a-style-sheet-that-is-blocking-scripts
    parser_inserted: Cell<bool>,
}

impl HTMLLinkElement {
    fn new_inherited(local_name: Atom, prefix: Option<DOMString>, document: &Document,
                     creator: ElementCreator) -> HTMLLinkElement {
        HTMLLinkElement {
            htmlelement: HTMLElement::new_inherited(local_name, prefix, document),
            rel_list: Default::default(),
            parser_inserted: Cell::new(creator == ElementCreator::ParserCreated),
            stylesheet: DOMRefCell::new(None),
        }
    }

    #[allow(unrooted_must_root)]
    pub fn new(local_name: Atom,
               prefix: Option<DOMString>,
               document: &Document,
               creator: ElementCreator) -> Root<HTMLLinkElement> {
        Node::reflect_node(box HTMLLinkElement::new_inherited(local_name, prefix, document, creator),
                           document,
                           HTMLLinkElementBinding::Wrap)
    }

    pub fn get_stylesheet(&self) -> Option<Arc<Stylesheet>> {
        self.stylesheet.borrow().clone()
    }
}

fn get_attr(element: &Element, local_name: &Atom) -> Option<String> {
    let elem = element.get_attribute(&ns!(), local_name);
    elem.map(|e| {
        let value = e.value();
        (**value).to_owned()
    })
}

fn string_is_stylesheet(value: &Option<String>) -> bool {
    match *value {
        Some(ref value) => {
            let mut found_stylesheet = false;
            for s in value.split(HTML_SPACE_CHARACTERS).into_iter() {
                if s.eq_ignore_ascii_case("alternate") {
                    return false;
                }

                if s.eq_ignore_ascii_case("stylesheet") {
                    found_stylesheet = true;
                }
            }
            found_stylesheet
        },
        None => false,
    }
}

/// Favicon spec usage in accordance with CEF implementation:
/// only url of icon is required/used
/// https://html.spec.whatwg.org/multipage/#rel-icon
fn is_favicon(value: &Option<String>) -> bool {
    match *value {
        Some(ref value) => {
            value.split(HTML_SPACE_CHARACTERS)
                .any(|s| s.eq_ignore_ascii_case("icon") || s.eq_ignore_ascii_case("apple-touch-icon"))
        },
        None => false,
    }
}

impl VirtualMethods for HTMLLinkElement {
    fn super_type(&self) -> Option<&VirtualMethods> {
        Some(self.upcast::<HTMLElement>() as &VirtualMethods)
    }

    fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation) {
        self.super_type().unwrap().attribute_mutated(attr, mutation);
        if !self.upcast::<Node>().is_in_doc() || mutation == AttributeMutation::Removed {
            return;
        }

        let rel = get_attr(self.upcast(), &atom!("rel"));
        match attr.local_name() {
            &atom!("href") => {
                if string_is_stylesheet(&rel) {
                    self.handle_stylesheet_url(&attr.value());
                } else if is_favicon(&rel) {
                    let sizes = get_attr(self.upcast(), &atom!("sizes"));
                    self.handle_favicon_url(rel.as_ref().unwrap(), &attr.value(), &sizes);
                }
            },
            &atom!("sizes") => {
                if is_favicon(&rel) {
                    if let Some(ref href) = get_attr(self.upcast(), &atom!("href")) {
                        self.handle_favicon_url(rel.as_ref().unwrap(), href, &Some(attr.value().to_string()));
                    }
                }
            },
            &atom!("media") => {
                if string_is_stylesheet(&rel) {
                    if let Some(href) = self.upcast::<Element>().get_attribute(&ns!(), &atom!("href")) {
                        self.handle_stylesheet_url(&href.value());
                    }
                }
            },
            _ => {},
        }
    }

    fn parse_plain_attribute(&self, name: &Atom, value: DOMString) -> AttrValue {
        match name {
            &atom!("rel") => AttrValue::from_serialized_tokenlist(value.into()),
            _ => self.super_type().unwrap().parse_plain_attribute(name, value),
        }
    }

    fn bind_to_tree(&self, tree_in_doc: bool) {
        if let Some(ref s) = self.super_type() {
            s.bind_to_tree(tree_in_doc);
        }

        if tree_in_doc {
            let element = self.upcast();

            let rel = get_attr(element, &atom!("rel"));
            let href = get_attr(element, &atom!("href"));
            let sizes = get_attr(self.upcast(), &atom!("sizes"));

            match href {
                Some(ref href) if string_is_stylesheet(&rel) => {
                    self.handle_stylesheet_url(href);
                }
                Some(ref href) if is_favicon(&rel) => {
                    self.handle_favicon_url(rel.as_ref().unwrap(), href, &sizes);
                }
                _ => {}
            }
        }
    }
}

impl HTMLLinkElement {
    fn handle_stylesheet_url(&self, href: &str) {
        let document = document_from_node(self);
        if document.browsing_context().is_none() {
            return;
        }

        match document.base_url().join(href) {
            Ok(url) => {
                let element = self.upcast::<Element>();

                let mq_attribute = element.get_attribute(&ns!(), &atom!("media"));
                let value = mq_attribute.r().map(|a| a.value());
                let mq_str = match value {
                    Some(ref value) => &***value,
                    None => "",
                };
                let mut css_parser = CssParser::new(&mq_str);
                let media = parse_media_query_list(&mut css_parser);

                // TODO: #8085 - Don't load external stylesheets if the node's mq doesn't match.
                let elem = Trusted::new(self);

                let context = Arc::new(Mutex::new(StylesheetContext {
                    elem: elem,
                    media: Some(media),
                    data: vec!(),
                    metadata: None,
                    url: url.clone(),
                }));

                let (action_sender, action_receiver) = ipc::channel().unwrap();
                let listener = NetworkListener {
                    context: context,
                    script_chan: document.window().networking_task_source(),
                    wrapper: Some(document.window().get_runnable_wrapper()),
                };
                let response_target = AsyncResponseTarget {
                    sender: action_sender,
                };
                ROUTER.add_route(action_receiver.to_opaque(), box move |message| {
                    listener.notify_action(message.to().unwrap());
                });

                if self.parser_inserted.get() {
                    document.increment_script_blocking_stylesheet_count();
                }

                let referrer_policy = match self.RelList().Contains("noreferrer".into()) {
                    true => Some(ReferrerPolicy::NoReferrer),
                    false => None,
                };

                document.load_async(LoadType::Stylesheet(url), response_target, referrer_policy);
            }
            Err(e) => debug!("Parsing url {} failed: {}", href, e)
        }
    }

    fn handle_favicon_url(&self, rel: &str, href: &str, sizes: &Option<String>) {
        let document = document_from_node(self);
        match document.base_url().join(href) {
            Ok(url) => {
                let event = ConstellationMsg::NewFavicon(url.clone());
                document.window().constellation_chan().send(event).unwrap();

                let mozbrowser_event = match *sizes {
                    Some(ref sizes) => MozBrowserEvent::IconChange(rel.to_owned(), url.to_string(), sizes.to_owned()),
                    None => MozBrowserEvent::IconChange(rel.to_owned(), url.to_string(), "".to_owned())
                };
                document.trigger_mozbrowser_event(mozbrowser_event);
            }
            Err(e) => debug!("Parsing url {} failed: {}", href, e)
        }
    }
}

/// The context required for asynchronously loading an external stylesheet.
struct StylesheetContext {
    /// The element that initiated the request.
    elem: Trusted<HTMLLinkElement>,
    media: Option<MediaQueryList>,
    /// The response body received to date.
    data: Vec<u8>,
    /// The response metadata received to date.
    metadata: Option<Metadata>,
    /// The initial URL requested.
    url: Url,
}

impl PreInvoke for StylesheetContext {}

impl AsyncResponseListener for StylesheetContext {
    fn headers_available(&mut self, metadata: Result<Metadata, NetworkError>) {
        self.metadata = metadata.ok();
        if let Some(ref meta) = self.metadata {
            if let Some(Serde(ContentType(Mime(TopLevel::Text, SubLevel::Css, _)))) = meta.content_type {
            } else {
                self.elem.root().upcast::<EventTarget>().fire_simple_event("error");
            }
        }
    }

    fn data_available(&mut self, payload: Vec<u8>) {
        let mut payload = payload;
        self.data.append(&mut payload);
    }

    fn response_complete(&mut self, status: Result<(), NetworkError>) {
        let elem = self.elem.root();
        let document = document_from_node(&*elem);
        let mut successful = false;

        if status.is_ok() {
            let metadata = match self.metadata.take() {
                Some(meta) => meta,
                None => return,
            };
            let is_css = metadata.content_type.map_or(false, |Serde(ContentType(Mime(top, sub, _)))|
                top == TopLevel::Text && sub == SubLevel::Css);

            let data = if is_css { mem::replace(&mut self.data, vec!()) } else { vec!() };

            // TODO: Get the actual value. http://dev.w3.org/csswg/css-syntax/#environment-encoding
            let environment_encoding = UTF_8 as EncodingRef;
            let protocol_encoding_label = metadata.charset.as_ref().map(|s| &**s);
            let final_url = metadata.final_url;

            let win = window_from_node(&*elem);

            let mut sheet = Stylesheet::from_bytes(&data, final_url, protocol_encoding_label,
                                                   Some(environment_encoding), Origin::Author,
                                                   win.css_error_reporter(),
                                                   ParserContextExtraData::default());
            let media = self.media.take().unwrap();
            sheet.set_media(Some(media));
            let sheet = Arc::new(sheet);

            let elem = elem.r();
            let document = document.r();

            let win = window_from_node(elem);
            win.layout_chan().send(Msg::AddStylesheet(sheet.clone())).unwrap();

            *elem.stylesheet.borrow_mut() = Some(sheet);
            document.invalidate_stylesheets();

            // FIXME: Revisit once consensus is reached at: https://github.com/whatwg/html/issues/1142
            successful = metadata.status.map_or(false, |(code, _)| code == 200);
        }

        if elem.parser_inserted.get() {
            document.decrement_script_blocking_stylesheet_count();
        }

        document.finish_load(LoadType::Stylesheet(self.url.clone()));

        let event = if successful { "load" } else { "error" };

        elem.upcast::<EventTarget>().fire_simple_event(event);
    }
}

impl HTMLLinkElementMethods for HTMLLinkElement {
    // https://html.spec.whatwg.org/multipage/#dom-link-href
    make_url_getter!(Href, "href");

    // https://html.spec.whatwg.org/multipage/#dom-link-href
    make_setter!(SetHref, "href");

    // https://html.spec.whatwg.org/multipage/#dom-link-rel
    make_getter!(Rel, "rel");

    // https://html.spec.whatwg.org/multipage/#dom-link-rel
    fn SetRel(&self, rel: DOMString) {
        self.upcast::<Element>().set_tokenlist_attribute(&atom!("rel"), rel);
    }

    // https://html.spec.whatwg.org/multipage/#dom-link-media
    make_getter!(Media, "media");

    // https://html.spec.whatwg.org/multipage/#dom-link-media
    make_setter!(SetMedia, "media");

    // https://html.spec.whatwg.org/multipage/#dom-link-hreflang
    make_getter!(Hreflang, "hreflang");

    // https://html.spec.whatwg.org/multipage/#dom-link-hreflang
    make_setter!(SetHreflang, "hreflang");

    // https://html.spec.whatwg.org/multipage/#dom-link-type
    make_getter!(Type, "type");

    // https://html.spec.whatwg.org/multipage/#dom-link-type
    make_setter!(SetType, "type");

    // https://html.spec.whatwg.org/multipage/#dom-link-rellist
    fn RelList(&self) -> Root<DOMTokenList> {
        self.rel_list.or_init(|| DOMTokenList::new(self.upcast(), &atom!("rel")))
    }

    // https://html.spec.whatwg.org/multipage/#dom-link-charset
    make_getter!(Charset, "charset");

    // https://html.spec.whatwg.org/multipage/#dom-link-charset
    make_setter!(SetCharset, "charset");

    // https://html.spec.whatwg.org/multipage/#dom-link-rev
    make_getter!(Rev, "rev");

    // https://html.spec.whatwg.org/multipage/#dom-link-rev
    make_setter!(SetRev, "rev");

    // https://html.spec.whatwg.org/multipage/#dom-link-target
    make_getter!(Target, "target");

    // https://html.spec.whatwg.org/multipage/#dom-link-target
    make_setter!(SetTarget, "target");
}
<commit_msg>Deindent the main part of handle_stylesheet_url.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use cssparser::Parser as CssParser;
use document_loader::LoadType;
use dom::attr::Attr;
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::DOMTokenListBinding::DOMTokenListMethods;
use dom::bindings::codegen::Bindings::HTMLLinkElementBinding;
use dom::bindings::codegen::Bindings::HTMLLinkElementBinding::HTMLLinkElementMethods;
use dom::bindings::inheritance::Castable;
use dom::bindings::js::{JS, MutNullableHeap, Root, RootedReference};
use dom::bindings::refcounted::Trusted;
use dom::bindings::str::DOMString;
use dom::document::Document;
use dom::domtokenlist::DOMTokenList;
use dom::element::{AttributeMutation, Element, ElementCreator};
use dom::eventtarget::EventTarget;
use dom::htmlelement::HTMLElement;
use dom::node::{Node, document_from_node, window_from_node};
use dom::virtualmethods::VirtualMethods;
use encoding::EncodingRef;
use encoding::all::UTF_8;
use hyper::header::ContentType;
use hyper::mime::{Mime, TopLevel, SubLevel};
use hyper_serde::Serde;
use ipc_channel::ipc;
use ipc_channel::router::ROUTER;
use msg::constellation_msg::ReferrerPolicy;
use net_traits::{AsyncResponseListener, AsyncResponseTarget, Metadata, NetworkError};
use network_listener::{NetworkListener, PreInvoke};
use script_layout_interface::message::Msg;
use script_traits::{MozBrowserEvent, ScriptMsg as ConstellationMsg};
use std::ascii::AsciiExt;
use std::borrow::ToOwned;
use std::cell::Cell;
use std::default::Default;
use std::mem;
use std::sync::{Arc, Mutex};
use string_cache::Atom;
use style::attr::AttrValue;
use style::media_queries::{MediaQueryList, parse_media_query_list};
use style::parser::ParserContextExtraData;
use style::str::HTML_SPACE_CHARACTERS;
use style::stylesheets::{Stylesheet, Origin};
use url::Url;

no_jsmanaged_fields!(Stylesheet);

#[dom_struct]
pub struct HTMLLinkElement {
    htmlelement: HTMLElement,
    rel_list: MutNullableHeap<JS<DOMTokenList>>,
    stylesheet: DOMRefCell<Option<Arc<Stylesheet>>>,

    /// https://html.spec.whatwg.org/multipage/#a-style-sheet-that-is-blocking-scripts
    parser_inserted: Cell<bool>,
}

impl HTMLLinkElement {
    fn new_inherited(local_name: Atom, prefix: Option<DOMString>, document: &Document,
                     creator: ElementCreator) -> HTMLLinkElement {
        HTMLLinkElement {
            htmlelement: HTMLElement::new_inherited(local_name, prefix, document),
            rel_list: Default::default(),
            parser_inserted: Cell::new(creator == ElementCreator::ParserCreated),
            stylesheet: DOMRefCell::new(None),
        }
    }

    #[allow(unrooted_must_root)]
    pub fn new(local_name: Atom,
               prefix: Option<DOMString>,
               document: &Document,
               creator: ElementCreator) -> Root<HTMLLinkElement> {
        Node::reflect_node(box HTMLLinkElement::new_inherited(local_name, prefix, document, creator),
                           document,
                           HTMLLinkElementBinding::Wrap)
    }

    pub fn get_stylesheet(&self) -> Option<Arc<Stylesheet>> {
        self.stylesheet.borrow().clone()
    }
}

fn get_attr(element: &Element, local_name: &Atom) -> Option<String> {
    let elem = element.get_attribute(&ns!(), local_name);
    elem.map(|e| {
        let value = e.value();
        (**value).to_owned()
    })
}

fn string_is_stylesheet(value: &Option<String>) -> bool {
    match *value {
        Some(ref value) => {
            let mut found_stylesheet = false;
            for s in value.split(HTML_SPACE_CHARACTERS).into_iter() {
                if s.eq_ignore_ascii_case("alternate") {
                    return false;
                }

                if s.eq_ignore_ascii_case("stylesheet") {
                    found_stylesheet = true;
                }
            }
            found_stylesheet
        },
        None => false,
    }
}

/// Favicon spec usage in accordance with CEF implementation:
/// only url of icon is required/used
/// https://html.spec.whatwg.org/multipage/#rel-icon
fn is_favicon(value: &Option<String>) -> bool {
    match *value {
        Some(ref value) => {
            value.split(HTML_SPACE_CHARACTERS)
                .any(|s| s.eq_ignore_ascii_case("icon") || s.eq_ignore_ascii_case("apple-touch-icon"))
        },
        None => false,
    }
}

impl VirtualMethods for HTMLLinkElement {
    fn super_type(&self) -> Option<&VirtualMethods> {
        Some(self.upcast::<HTMLElement>() as &VirtualMethods)
    }

    fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation) {
        self.super_type().unwrap().attribute_mutated(attr, mutation);
        if !self.upcast::<Node>().is_in_doc() || mutation == AttributeMutation::Removed {
            return;
        }

        let rel = get_attr(self.upcast(), &atom!("rel"));
        match attr.local_name() {
            &atom!("href") => {
                if string_is_stylesheet(&rel) {
                    self.handle_stylesheet_url(&attr.value());
                } else if is_favicon(&rel) {
                    let sizes = get_attr(self.upcast(), &atom!("sizes"));
                    self.handle_favicon_url(rel.as_ref().unwrap(), &attr.value(), &sizes);
                }
            },
            &atom!("sizes") => {
                if is_favicon(&rel) {
                    if let Some(ref href) = get_attr(self.upcast(), &atom!("href")) {
                        self.handle_favicon_url(rel.as_ref().unwrap(), href, &Some(attr.value().to_string()));
                    }
                }
            },
            &atom!("media") => {
                if string_is_stylesheet(&rel) {
                    if let Some(href) = self.upcast::<Element>().get_attribute(&ns!(), &atom!("href")) {
                        self.handle_stylesheet_url(&href.value());
                    }
                }
            },
            _ => {},
        }
    }

    fn parse_plain_attribute(&self, name: &Atom, value: DOMString) -> AttrValue {
        match name {
            &atom!("rel") => AttrValue::from_serialized_tokenlist(value.into()),
            _ => self.super_type().unwrap().parse_plain_attribute(name, value),
        }
    }

    fn bind_to_tree(&self, tree_in_doc: bool) {
        if let Some(ref s) = self.super_type() {
            s.bind_to_tree(tree_in_doc);
        }

        if tree_in_doc {
            let element = self.upcast();

            let rel = get_attr(element, &atom!("rel"));
            let href = get_attr(element, &atom!("href"));
            let sizes = get_attr(self.upcast(), &atom!("sizes"));

            match href {
                Some(ref href) if string_is_stylesheet(&rel) => {
                    self.handle_stylesheet_url(href);
                }
                Some(ref href) if is_favicon(&rel) => {
                    self.handle_favicon_url(rel.as_ref().unwrap(), href, &sizes);
                }
                _ => {}
            }
        }
    }
}

impl HTMLLinkElement {
    fn handle_stylesheet_url(&self, href: &str) {
        let document = document_from_node(self);
        if document.browsing_context().is_none() {
            return;
        }

        let url = match document.base_url().join(href) {
            Err(e) => return debug!("Parsing url {} failed: {}", href, e),
            Ok(url) => url,
        };

        let element = self.upcast::<Element>();

        let mq_attribute = element.get_attribute(&ns!(), &atom!("media"));
        let value = mq_attribute.r().map(|a| a.value());
        let mq_str = match value {
            Some(ref value) => &***value,
            None => "",
        };
        let mut css_parser = CssParser::new(&mq_str);
        let media = parse_media_query_list(&mut css_parser);

        // TODO: #8085 - Don't load external stylesheets if the node's mq doesn't match.
        let elem = Trusted::new(self);

        let context = Arc::new(Mutex::new(StylesheetContext {
            elem: elem,
            media: Some(media),
            data: vec!(),
            metadata: None,
            url: url.clone(),
        }));

        let (action_sender, action_receiver) = ipc::channel().unwrap();
        let listener = NetworkListener {
            context: context,
            script_chan: document.window().networking_task_source(),
            wrapper: Some(document.window().get_runnable_wrapper()),
        };
        let response_target = AsyncResponseTarget {
            sender: action_sender,
        };
        ROUTER.add_route(action_receiver.to_opaque(), box move |message| {
            listener.notify_action(message.to().unwrap());
        });

        if self.parser_inserted.get() {
            document.increment_script_blocking_stylesheet_count();
        }

        let referrer_policy = match self.RelList().Contains("noreferrer".into()) {
            true => Some(ReferrerPolicy::NoReferrer),
            false => None,
        };

        document.load_async(LoadType::Stylesheet(url), response_target, referrer_policy);
    }

    fn handle_favicon_url(&self, rel: &str, href: &str, sizes: &Option<String>) {
        let document = document_from_node(self);
        match document.base_url().join(href) {
            Ok(url) => {
                let event = ConstellationMsg::NewFavicon(url.clone());
                document.window().constellation_chan().send(event).unwrap();

                let mozbrowser_event = match *sizes {
                    Some(ref sizes) => MozBrowserEvent::IconChange(rel.to_owned(), url.to_string(), sizes.to_owned()),
                    None => MozBrowserEvent::IconChange(rel.to_owned(), url.to_string(), "".to_owned())
                };
                document.trigger_mozbrowser_event(mozbrowser_event);
            }
            Err(e) => debug!("Parsing url {} failed: {}", href, e)
        }
    }
}

/// The context required for asynchronously loading an external stylesheet.
struct StylesheetContext {
    /// The element that initiated the request.
    elem: Trusted<HTMLLinkElement>,
    media: Option<MediaQueryList>,
    /// The response body received to date.
    data: Vec<u8>,
    /// The response metadata received to date.
    metadata: Option<Metadata>,
    /// The initial URL requested.
    url: Url,
}

impl PreInvoke for StylesheetContext {}

impl AsyncResponseListener for StylesheetContext {
    fn headers_available(&mut self, metadata: Result<Metadata, NetworkError>) {
        self.metadata = metadata.ok();
        if let Some(ref meta) = self.metadata {
            if let Some(Serde(ContentType(Mime(TopLevel::Text, SubLevel::Css, _)))) = meta.content_type {
            } else {
                self.elem.root().upcast::<EventTarget>().fire_simple_event("error");
            }
        }
    }

    fn data_available(&mut self, payload: Vec<u8>) {
        let mut payload = payload;
        self.data.append(&mut payload);
    }

    fn response_complete(&mut self, status: Result<(), NetworkError>) {
        let elem = self.elem.root();
        let document = document_from_node(&*elem);
        let mut successful = false;

        if status.is_ok() {
            let metadata = match self.metadata.take() {
                Some(meta) => meta,
                None => return,
            };
            let is_css = metadata.content_type.map_or(false, |Serde(ContentType(Mime(top, sub, _)))|
                top == TopLevel::Text && sub == SubLevel::Css);

            let data = if is_css { mem::replace(&mut self.data, vec!()) } else { vec!() };

            // TODO: Get the actual value. http://dev.w3.org/csswg/css-syntax/#environment-encoding
            let environment_encoding = UTF_8 as EncodingRef;
            let protocol_encoding_label = metadata.charset.as_ref().map(|s| &**s);
            let final_url = metadata.final_url;

            let win = window_from_node(&*elem);

            let mut sheet = Stylesheet::from_bytes(&data, final_url, protocol_encoding_label,
                                                   Some(environment_encoding), Origin::Author,
                                                   win.css_error_reporter(),
                                                   ParserContextExtraData::default());
            let media = self.media.take().unwrap();
            sheet.set_media(Some(media));
            let sheet = Arc::new(sheet);

            let elem = elem.r();
            let document = document.r();

            let win = window_from_node(elem);
            win.layout_chan().send(Msg::AddStylesheet(sheet.clone())).unwrap();

            *elem.stylesheet.borrow_mut() = Some(sheet);
            document.invalidate_stylesheets();

            // FIXME: Revisit once consensus is reached at: https://github.com/whatwg/html/issues/1142
            successful = metadata.status.map_or(false, |(code, _)| code == 200);
        }

        if elem.parser_inserted.get() {
            document.decrement_script_blocking_stylesheet_count();
        }

        document.finish_load(LoadType::Stylesheet(self.url.clone()));

        let event = if successful { "load" } else { "error" };

        elem.upcast::<EventTarget>().fire_simple_event(event);
    }
}

impl HTMLLinkElementMethods for HTMLLinkElement {
    // https://html.spec.whatwg.org/multipage/#dom-link-href
    make_url_getter!(Href, "href");

    // https://html.spec.whatwg.org/multipage/#dom-link-href
    make_setter!(SetHref, "href");

    // https://html.spec.whatwg.org/multipage/#dom-link-rel
    make_getter!(Rel, "rel");

    // https://html.spec.whatwg.org/multipage/#dom-link-rel
    fn SetRel(&self, rel: DOMString) {
        self.upcast::<Element>().set_tokenlist_attribute(&atom!("rel"), rel);
    }

    // https://html.spec.whatwg.org/multipage/#dom-link-media
    make_getter!(Media, "media");

    // https://html.spec.whatwg.org/multipage/#dom-link-media
    make_setter!(SetMedia, "media");

    // https://html.spec.whatwg.org/multipage/#dom-link-hreflang
    make_getter!(Hreflang, "hreflang");

    // https://html.spec.whatwg.org/multipage/#dom-link-hreflang
    make_setter!(SetHreflang, "hreflang");

    // https://html.spec.whatwg.org/multipage/#dom-link-type
    make_getter!(Type, "type");

    // https://html.spec.whatwg.org/multipage/#dom-link-type
    make_setter!(SetType, "type");

    // https://html.spec.whatwg.org/multipage/#dom-link-rellist
    fn RelList(&self) -> Root<DOMTokenList> {
        self.rel_list.or_init(|| DOMTokenList::new(self.upcast(), &atom!("rel")))
    }

    // https://html.spec.whatwg.org/multipage/#dom-link-charset
    make_getter!(Charset, "charset");

    // https://html.spec.whatwg.org/multipage/#dom-link-charset
    make_setter!(SetCharset, "charset");

    // https://html.spec.whatwg.org/multipage/#dom-link-rev
    make_getter!(Rev, "rev");

    // https://html.spec.whatwg.org/multipage/#dom-link-rev
    make_setter!(SetRev, "rev");

    // https://html.spec.whatwg.org/multipage/#dom-link-target
    make_getter!(Target, "target");

    // https://html.spec.whatwg.org/multipage/#dom-link-target
    make_setter!(SetTarget, "target");
}
<|endoftext|>


<commit_before>use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};

use graph::geometry::Geometry;
use graph::mesh::{Edge, Mesh};
use graph::storage::EdgeKey;

pub type EdgeRef<'a, G> = EdgeView<&'a Mesh<G>, G>;
pub type EdgeMut<'a, G> = EdgeView<&'a mut Mesh<G>, G>;

#[derive(Clone, Copy)]
pub struct EdgeView<M, G>
where
    M: AsRef<Mesh<G>>,
    G: Geometry,
{
    mesh: M,
    pub key: EdgeKey,
    phantom: PhantomData<G>,
}

impl<M, G> EdgeView<M, G>
where
    M: AsRef<Mesh<G>>,
    G: Geometry,
{
    pub(crate) fn new(mesh: M, edge: EdgeKey) -> Self {
        EdgeView {
            mesh: mesh,
            key: edge,
            phantom: PhantomData,
        }
    }

    // Resolve the `M` parameter to a concrete reference.
    fn with_mesh_ref(&self) -> EdgeView<&Mesh<G>, G> {
        EdgeView::new(self.mesh.as_ref(), self.key)
    }
}

impl<M, G> EdgeView<M, G>
where
    M: AsRef<Mesh<G>> + AsMut<Mesh<G>>,
    G: Geometry,
{
    // Resolve the `M` parameter to a concrete reference.
    fn with_mesh_mut(&mut self) -> EdgeView<&mut Mesh<G>, G> {
        EdgeView::new(self.mesh.as_mut(), self.key)
    }
}

impl<M, G> AsRef<EdgeView<M, G>> for EdgeView<M, G>
where
    M: AsRef<Mesh<G>>,
    G: Geometry,
{
    fn as_ref(&self) -> &EdgeView<M, G> {
        self
    }
}

impl<M, G> AsMut<EdgeView<M, G>> for EdgeView<M, G>
where
    M: AsRef<Mesh<G>> + AsMut<Mesh<G>>,
    G: Geometry,
{
    fn as_mut(&mut self) -> &mut EdgeView<M, G> {
        self
    }
}

impl<M, G> Deref for EdgeView<M, G>
where
    M: AsRef<Mesh<G>>,
    G: Geometry,
{
    type Target = Edge<G::Edge>;

    fn deref(&self) -> &Self::Target {
        self.mesh.as_ref().edges.get(&self.key).unwrap()
    }
}

impl<M, G> DerefMut for EdgeView<M, G>
where
    M: AsRef<Mesh<G>> + AsMut<Mesh<G>>,
    G: Geometry,
{
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.mesh.as_mut().edges.get_mut(&self.key).unwrap()
    }
}
<commit_msg>Allow dead code.<commit_after>use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};

use graph::geometry::Geometry;
use graph::mesh::{Edge, Mesh};
use graph::storage::EdgeKey;

pub type EdgeRef<'a, G> = EdgeView<&'a Mesh<G>, G>;
pub type EdgeMut<'a, G> = EdgeView<&'a mut Mesh<G>, G>;

#[derive(Clone, Copy)]
pub struct EdgeView<M, G>
where
    M: AsRef<Mesh<G>>,
    G: Geometry,
{
    mesh: M,
    pub key: EdgeKey,
    phantom: PhantomData<G>,
}

impl<M, G> EdgeView<M, G>
where
    M: AsRef<Mesh<G>>,
    G: Geometry,
{
    pub(crate) fn new(mesh: M, edge: EdgeKey) -> Self {
        EdgeView {
            mesh: mesh,
            key: edge,
            phantom: PhantomData,
        }
    }

    // Resolve the `M` parameter to a concrete reference.
    #[allow(dead_code)]
    fn with_mesh_ref(&self) -> EdgeView<&Mesh<G>, G> {
        EdgeView::new(self.mesh.as_ref(), self.key)
    }
}

impl<M, G> EdgeView<M, G>
where
    M: AsRef<Mesh<G>> + AsMut<Mesh<G>>,
    G: Geometry,
{
    // Resolve the `M` parameter to a concrete reference.
    #[allow(dead_code)]
    fn with_mesh_mut(&mut self) -> EdgeView<&mut Mesh<G>, G> {
        EdgeView::new(self.mesh.as_mut(), self.key)
    }
}

impl<M, G> AsRef<EdgeView<M, G>> for EdgeView<M, G>
where
    M: AsRef<Mesh<G>>,
    G: Geometry,
{
    fn as_ref(&self) -> &EdgeView<M, G> {
        self
    }
}

impl<M, G> AsMut<EdgeView<M, G>> for EdgeView<M, G>
where
    M: AsRef<Mesh<G>> + AsMut<Mesh<G>>,
    G: Geometry,
{
    fn as_mut(&mut self) -> &mut EdgeView<M, G> {
        self
    }
}

impl<M, G> Deref for EdgeView<M, G>
where
    M: AsRef<Mesh<G>>,
    G: Geometry,
{
    type Target = Edge<G::Edge>;

    fn deref(&self) -> &Self::Target {
        self.mesh.as_ref().edges.get(&self.key).unwrap()
    }
}

impl<M, G> DerefMut for EdgeView<M, G>
where
    M: AsRef<Mesh<G>> + AsMut<Mesh<G>>,
    G: Geometry,
{
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.mesh.as_mut().edges.get_mut(&self.key).unwrap()
    }
}
<|endoftext|>


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

//! Utility functions for doubly-linked lists.

use std::collections::DList;
use std::mem;
use std::ptr;

struct RawDList<T> {
    length: uint,
    head: Option<Box<RawNode<T>>>,
    tail: *mut RawNode<T>,
}

#[allow(dead_code)]
struct RawNode<T> {
    next: Option<Box<RawNode<T>>>,
    prev: *mut RawNode<T>,
    value: T,
}

#[unsafe_destructor]
impl<T> Drop for RawDList<T> {
    fn drop(&mut self) {
        fail!("shouldn't happen")
    }
}

/// Workaround for a missing method on Rust's `DList` type. Splits the head off a list in O(1)
/// time.
pub fn split<T>(list: &mut DList<T>) -> DList<T> {
    let list = unsafe {
        mem::transmute::<&mut DList<T>,&mut RawDList<T>>(list)
    };

    if list.length == 0 {
        fail!("split_dlist(): empty list")
    }
    let mut head_node = mem::replace(&mut list.head, None);
    let head_node_ptr: *mut RawNode<T> = &mut **head_node.as_mut().unwrap();
    let mut head_list = RawDList {
        length: 1,
        head: head_node,
        tail: head_node_ptr,
    };
    debug_assert!(list.head.is_none());
    mem::swap(&mut head_list.head.as_mut().unwrap().next, &mut list.head);
    debug_assert!(head_list.head.as_mut().unwrap().next.is_none());
    debug_assert!(head_list.head.as_mut().unwrap().prev.is_null());
    head_list.head.as_mut().unwrap().prev = ptr::null_mut();

    list.length -= 1;
    if list.length == 0 {
        list.tail = ptr::null_mut()
    } else {
        if list.length == 1 {
            list.tail = &mut **list.head.as_mut().unwrap() as *mut RawNode<T>
        }
        list.head.as_mut().unwrap().prev = ptr::null_mut()
    }

    unsafe {
        mem::transmute::<RawDList<T>,DList<T>>(head_list)
    }
}

<commit_msg>auto merge of #3831 : pcwalton/servo/append-from, r=mbrubeck<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Utility functions for doubly-linked lists.

use std::collections::DList;
use std::mem;
use std::ptr;

struct RawDList<T> {
    length: uint,
    head: Option<Box<RawNode<T>>>,
    tail: *mut RawNode<T>,
}

#[allow(dead_code)]
struct RawNode<T> {
    next: Option<Box<RawNode<T>>>,
    prev: *mut RawNode<T>,
    value: T,
}

#[unsafe_destructor]
impl<T> Drop for RawDList<T> {
    fn drop(&mut self) {
        fail!("shouldn't happen")
    }
}

/// Workaround for a missing method on Rust's `DList` type. Splits the head off a list in O(1)
/// time.
pub fn split<T>(list: &mut DList<T>) -> DList<T> {
    let list = unsafe {
        mem::transmute::<&mut DList<T>,&mut RawDList<T>>(list)
    };

    if list.length == 0 {
        fail!("split_dlist(): empty list")
    }
    let mut head_node = mem::replace(&mut list.head, None);
    let head_node_ptr: *mut RawNode<T> = &mut **head_node.as_mut().unwrap();
    let mut head_list = RawDList {
        length: 1,
        head: head_node,
        tail: head_node_ptr,
    };
    debug_assert!(list.head.is_none());
    mem::swap(&mut head_list.head.as_mut().unwrap().next, &mut list.head);
    debug_assert!(head_list.head.as_mut().unwrap().next.is_none());
    debug_assert!(head_list.head.as_mut().unwrap().prev.is_null());
    head_list.head.as_mut().unwrap().prev = ptr::null_mut();

    list.length -= 1;
    if list.length == 0 {
        list.tail = ptr::null_mut()
    } else {
        if list.length == 1 {
            list.tail = &mut **list.head.as_mut().unwrap() as *mut RawNode<T>
        }
        list.head.as_mut().unwrap().prev = ptr::null_mut()
    }

    unsafe {
        mem::transmute::<RawDList<T>,DList<T>>(head_list)
    }
}

/// Appends the items in the other list to this one, leaving the other list empty.
#[inline]
pub fn append_from<T>(this: &mut DList<T>, other: &mut DList<T>) {
    unsafe {
        let this = mem::transmute::<&mut DList<T>,&mut RawDList<T>>(this);
        let other = mem::transmute::<&mut DList<T>,&mut RawDList<T>>(other);
        if this.length == 0 {
            this.head = mem::replace(&mut other.head, None);
            this.tail = mem::replace(&mut other.tail, ptr::null_mut());
            this.length = mem::replace(&mut other.length, 0);
            return
        }

        (*this.tail).next = match mem::replace(&mut other.head, None) {
            None => return,
            Some(mut head) => {
                head.prev = this.tail;
                Some(head)
            }
        };
        this.tail = mem::replace(&mut other.tail, ptr::null_mut());
        this.length += other.length;
        other.length = 0;
    }
}

<|endoftext|>