<commit_before>//! Some unit tests for all the internal functionality of lrs

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

    macro_rules! symbol {
        ($v:expr, $s:expr) => ( Symbol { val: $v, state: $s } );
    }

    #[test]
     fn lrs_symbol_create() {
        let s = symbol!('A', true);
        assert!(s.val == 'A');
        assert!(s.state == true);
    }

    #[test]
    fn lrs_term_create() {
        let s = symbol!('A', true);
        let t = Term::new(s);

        assert!(t.contains(&symbol!('A', true)));
    }
}
<commit_msg>Adding a remove unit test and now using emoji 🔥<commit_after>//! Some unit tests for all the internal functionality of lrs

#[cfg(test)]
#[allow(dead_code)]
#[allow(unused_macros)]
#[allow(unused_imports)]
mod tests {
    use terms::*;
    use equation::*;

    // macro_rules! symbol {
    //     ($v:expr, $s:expr) => ( Symbol { val: $v, state: $s } );
    // }

    #[test]
     fn lrs_symbol_create() {
        let s = symbol!["A"];
        assert!(s.val == 'A');
        assert!(s.state == true);
    }

    #[test]
    fn lrs_term_create() {
        let term = term!["A", "!🐎", "🐟", "C"];

        assert!(term.contains(&symbol!["A"]));
        assert!(term.contains(&symbol!["!🐎"]));
        assert!(term.contains(&symbol!["🐟"]));
        assert!(term.contains(&symbol!["C"]));
    }

    #[test]
    #[allow(unused_variables)]
    fn lrs_term_remove() {
        let mut term = term!["A", "!🐎", "🐟", "C"];

        term.remove(symbol!["A"]);
        assert!(! term.contains(&symbol!["A"]));

        term.remove(symbol!["!🐎"]);
        assert!(! term.contains(&symbol!["!🐎"]));

        term.remove(symbol!["🐟"]);
        assert!(! term.contains(&symbol!["🐟"]));

        term.remove(symbol!["C"]);
        assert!(! term.contains(&symbol!["C"]));
    }
}
<|endoftext|>


<commit_before>use error::RuntimeError;

use sys::x11;
use sys::xcb;

pub struct LinuxApplication {
   pub x11_display: X11DisplayHandler,
   pub connection: ConnectionHandler,
   pub screen: ScreenHandler,
}

impl LinuxApplication {
   pub fn new() -> Result<Self, RuntimeError> {
      let x11_display = try!(X11DisplayHandler::new());
      let connection = try!(ConnectionHandler::new(&x11_display));
      let screen = ScreenHandler::new(&x11_display, &connection);

      Ok(LinuxApplication {
         x11_display: x11_display,
         connection: connection,
         screen: screen,
      })
   }

   pub fn screen_size(&self) -> (u32, u32) {
      self.screen.size()
   }
}

pub struct X11DisplayHandler {
   pub display: x11::Display,
}

impl X11DisplayHandler {
   #[inline]
   pub fn new() -> Result<Self, RuntimeError> {
      let display = try!(x11::Display::default());

      display.xcb_own_event_queue();

      Ok(X11DisplayHandler {
         display: display
      })
   }

   #[inline]
   pub fn connection(&self) -> Result<xcb::Connection, RuntimeError> {
      self.display.xcb_connection()
   }

   #[inline]
   pub fn screen_id(&self) -> x11::ScreenID {
      self.display.default_screen()
   }
}

pub struct ConnectionHandler {
   pub connection: xcb::Connection,
}

impl ConnectionHandler {
   #[inline]
   pub fn new(display: &X11DisplayHandler) -> Result<Self, RuntimeError> {
      Ok(ConnectionHandler {
         connection: try!(display.connection())
      })
   }

   #[inline]
   pub fn screen_of_display(&self, display: &X11DisplayHandler) -> xcb::Screen {
      let screen_id = display.screen_id();

      self.connection.screen_of_display(&screen_id)
   }
}

pub struct ScreenHandler {
   pub screen: xcb::Screen,
}

impl ScreenHandler {
   #[inline]
   pub fn new(display: &X11DisplayHandler, connection: &ConnectionHandler) -> Self {
      ScreenHandler {
         screen: connection.screen_of_display(display)
      }
   }

   pub fn size(&self) -> (u32, u32) {
      (
         self.screen.width_in_pixels() as u32,
         self.screen.height_in_pixels() as u32
      )
   }
}
<commit_msg>Adding a couple of inline markers<commit_after>use error::RuntimeError;

use sys::x11;
use sys::xcb;

pub struct LinuxApplication {
   pub x11_display: X11DisplayHandler,
   pub connection: ConnectionHandler,
   pub screen: ScreenHandler,
}

impl LinuxApplication {
   pub fn new() -> Result<Self, RuntimeError> {
      let x11_display = try!(X11DisplayHandler::new());
      let connection = try!(ConnectionHandler::new(&x11_display));
      let screen = ScreenHandler::new(&x11_display, &connection);

      Ok(LinuxApplication {
         x11_display: x11_display,
         connection: connection,
         screen: screen,
      })
   }

   #[inline]
   pub fn screen_size(&self) -> (u32, u32) {
      self.screen.size()
   }
}

pub struct X11DisplayHandler {
   pub display: x11::Display,
}

impl X11DisplayHandler {
   #[inline]
   pub fn new() -> Result<Self, RuntimeError> {
      let display = try!(x11::Display::default());

      display.xcb_own_event_queue();

      Ok(X11DisplayHandler {
         display: display
      })
   }

   #[inline]
   pub fn connection(&self) -> Result<xcb::Connection, RuntimeError> {
      self.display.xcb_connection()
   }

   #[inline]
   pub fn screen_id(&self) -> x11::ScreenID {
      self.display.default_screen()
   }
}

pub struct ConnectionHandler {
   pub connection: xcb::Connection,
}

impl ConnectionHandler {
   #[inline]
   pub fn new(display: &X11DisplayHandler) -> Result<Self, RuntimeError> {
      Ok(ConnectionHandler {
         connection: try!(display.connection())
      })
   }

   #[inline]
   pub fn screen_of_display(&self, display: &X11DisplayHandler) -> xcb::Screen {
      let screen_id = display.screen_id();

      self.connection.screen_of_display(&screen_id)
   }
}

pub struct ScreenHandler {
   pub screen: xcb::Screen,
}

impl ScreenHandler {
   #[inline]
   pub fn new(display: &X11DisplayHandler, connection: &ConnectionHandler) -> Self {
      ScreenHandler {
         screen: connection.screen_of_display(display)
      }
   }

   #[inline]
   pub fn size(&self) -> (u32, u32) {
      (
         self.screen.width_in_pixels() as u32,
         self.screen.height_in_pixels() as u32
      )
   }
}
<|endoftext|>


<commit_before>// Dependencies
use xml::reader::EventReader;
use xml::reader::events::*;
use xml::attribute::OwnedAttribute;
use std::io::Read;

use std::collections::HashMap;
use ErrorReporter;
use oil_shared;
use parsing::BufferConsumer;

use super::HasNodeChildren;
use super::Library;
use super::ErrorType;
use super::ErrorStatus;
use super::tags;
use super::lookup_name;
use super::ParseError;

use super::TEMPLATE_TAG;
use super::VIEW_TAG;
use super::GROUP_TAG;
use super::BUTTON_TAG;
use super::LINE_INPUT_TAG;
use super::PROGRESS_BAR_TAG;
use super::REPEAT_TAG;
use super::MAIN_VIEW_NAME;

use oil_shared::markup::{
    Node,
    View,
    Template,
    NodeType
};

/// Parser
pub struct Parser<E, B: Read> {
    err: E,
    parser: EventReader,
}

impl<E, B> Parser<E, B>
    where E: ErrorReporter,
          B: Read
{

    pub fn new(reporter: E, reader: B) -> Parser<E, B> {
        Parser {
            err: reporter,
            parser: EventReader::new(reader)
        }
    }

    pub fn parse(&mut self) -> Library<E>
    {
        let mut views = HashMap::new();
        let mut templates = HashMap::new();

        'doc: loop {

            match self.parser.next() {
                XmlEvent::StartElement { name, attributes, .. } => {

                    let test_parse = self.parse_root_tag(
                        &mut views,
                        &mut templates,
                        &name.local_name,
                        &attributes
                    );

                    match test_parse {
                        Err((ErrorType::Fatal, _)) => break 'doc,
                        _ => ()
                    }
                }
                XmlEvent::Error(e) => {
                    self.err.log(format!("Error: {}", e));
                    break 'doc;
                }
                XmlEvent::EndDocument => break 'doc,
                XmlEvent::StartDocument { .. } => (),
                _ => unreachable!(),
            }
        }

        Library::new(self.err.clone(), views, templates)
    }

    fn parse_view(&mut self) -> Result<View, ParseError>
    {
        let mut view = oil_shared::markup::new_view(None);

        try!(self.parse_loop(VIEW_TAG, &mut view));
        Ok(view)
    }

    fn parse_template_decl(&mut self) -> Result<Template, ParseError>
    {
        let mut template = oil_shared::markup::new_template(None);

        try!(self.parse_loop(TEMPLATE_TAG, &mut template));
        Ok(template)
    }

    fn parse_root_tag(&mut self,
                      views: &mut HashMap<String, View>,
                      templates: &mut HashMap<String, Template>,
                      name: &str,
                      attributes: &Vec<OwnedAttribute>) -> Result<(), ParseError>
    {
        match name {
            TEMPLATE_TAG => {
                let attr_name = lookup_name("name", attributes);

                match attr_name {
                    None => {
                        // FIXME(Waiting the pull request on netvl/xml-rs to be merged)
                        // let (row, col) = self.parser.get_cursor();
                        let (row, col) = (0, 0);
                        self.err.log(
                            format!(
                                "Warning {}:{} : `template` has no name add an \
                                 attribute 'name=\"\"'",
                            row, col)
                        );

                        self.consume_children(name)
                    }
                    Some(template_name) => {
                        let template = try!(self.parse_template_decl());
                        templates.insert(template_name, template);
                        Ok(())
                    }
                }
            }
            VIEW_TAG => {
                let view = try!(self.parse_view());
                let attr_name = lookup_name("name", attributes)
                    .unwrap_or(MAIN_VIEW_NAME.to_string());
                views.insert(attr_name, view);
                Ok(())
            }
            _ => {
                // FIXME(Waiting the pull request on netvl/xml-rs to be merged)
                // let (row, col) = self.parser.get_cursor();
                let (row, col) = (0, 0);
                self.err.log(
                    format!(
                        "Warning {}:{} : `{}` can't be at root level, \
                        you can only have `template` or `view`"
                    , row+1, col+1, name));

                self.consume_children(name)
            }
        }
    }

    fn parse_tag(&mut self,
                 name: &str,
                 attributes: &Vec<OwnedAttribute>)
                 -> Result<Option<Node>, ParseError>
    {
        let ignore_child = name == TEMPLATE_TAG;

        let node_type = match name {
            TEMPLATE_TAG     => tags::parse_template(attributes),
            GROUP_TAG        => Ok(NodeType::Group),
            BUTTON_TAG       => tags::parse_button(attributes),
            LINE_INPUT_TAG   => tags::parse_linput(attributes),
            PROGRESS_BAR_TAG => tags::parse_pbar(attributes),
            REPEAT_TAG       => tags::parse_repeat(attributes),
            _ => {
                // FIXME(Waiting the pull request on netvl/xml-rs to be merged)
                // let (row, col) = self.parser.get_cursor();
                let (row, col) = (0, 0);
                self.err.log(
                    format!("Warning {}:{} : Unknown tag `{}`", row+1, col+1, name)
                );
                Err((ErrorType::Warning, ErrorStatus::Reported))
            }
        };

        match node_type {
            Err(parse_error) => {
                match self.report_error_if_needed(parse_error) {
                    (ErrorType::Warning, _) => {
                        match self.consume_children(name) {
                            Err(parse_err) =>
                                Err(self.report_error_if_needed(parse_err)),
                            Ok(()) =>
                                Ok(None)
                        }
                    },
                    reported_parse_error => Err(reported_parse_error)
                }
            }
            Ok(nt) => {
                let classes = lookup_name("class", attributes);
                let mut node = Node::new(classes, nt);

                if ignore_child {

                    // Consume children
                    try!(self.consume_children(name));
                    Ok(Some(node))

                } else {

                    // Parse children
                    try!(self.parse_loop(name, &mut node));
                    Ok(Some(node))
                }
            }
        }
    }

    fn parse_data_binding(&mut self, text: &str, parent: &mut Node) {
        let mut buf_consumer = BufferConsumer::new(text.as_bytes());
        loop {
            let text = buf_consumer.consume_while(|c| c != '{').unwrap();
            if !text.is_empty() {
                parent.add(Some(Node::new(
                            None,
                            NodeType::Text(text))));
            }
            match buf_consumer.consume_any_char() {
                Some('{') => {
                    match buf_consumer.consume_any_char() {
                        Some('{') => {
                            buf_consumer.consume_any_char();    // XXX: If I don't do this the data binding will contain one '{'
                            let mut data_binding = buf_consumer.consume_while(|c| c != '}').unwrap();
                            match buf_consumer.consume_any_char() {
                                Some('}') => {
                                    match buf_consumer.consume_any_char() {
                                        Some('}') => {
                                            buf_consumer.consume_any_char();    // XXX: If I don't do this the text after data binding will contain one '}'
                                            // Yahoo! We have a correct data binding
                                            parent.add(Some(Node::new(
                                                        None,
                                                        NodeType::Binding(data_binding))));
                                        }
                                        _ => {
                                            let (row, col) = (0, 0);
                                            self.err.log(format!("Warning {}:{} : Missing '}}' for data binding", row, col));
                                            data_binding.insert(0, '{');
                                            data_binding.insert(0, '{');
                                            data_binding.push('}');
                                            parent.add(Some(Node::new(
                                                        None,
                                                        NodeType::Text(data_binding))));
                                            break;
                                        },
                                    }
                                }
                                _ => {
                                    let (row, col) = (0, 0);
                                    self.err.log(format!("Warning {}:{} : Missing '}}' for data binding", row, col));
                                    data_binding.insert(0, '{');
                                    data_binding.insert(0, '{');
                                    parent.add(Some(Node::new(
                                                None,
                                                NodeType::Text(data_binding))));
                                    break;
                                },
                            }
                        }
                        _ => {
                            let (row, col) = (0, 0);
                            self.err.log(format!("Warning {}:{} : Missing \"{{ .. }}}}\" for data binding", row, col));
                            let text = "{".to_string();
                            parent.add(Some(Node::new(
                                        None,
                                        NodeType::Text(text))));
                            break;
                        },
                    }
                }
                _ => break,
            }
        }
    }

    fn report_error_if_needed(&mut self,
                              parse_error: ParseError) -> ParseError
    {
        // FIXME(Waiting the pull request on netvl/xml-rs to be merged)
        // let (row, col) = self.parser.get_cursor();
        let (row, col) = (0, 0);
        match parse_error {
            (ErrorType::Fatal, ErrorStatus::NotReported(msg)) => {
                self.err.log(
                    format!("Error {}:{} : {}", row+1, col+1, msg)
                );
                (ErrorType::Fatal, ErrorStatus::Reported)
            }
            (ErrorType::Warning, ErrorStatus::NotReported(msg)) => {
                self.err.log(
                    format!("Warning {}:{} : {}", row+1, col+1, msg)
                );
                (ErrorType::Warning, ErrorStatus::Reported)
            }
            _ => parse_error
        }
    }

    // This function may only return Ok(()) or
    // Err((ErrorType::Fatal, ErrorStatus::Reported)).
    fn consume_children(&mut self, tag: &str) -> Result<(), ParseError>
    {
        let mut depth = 1i32;
        loop {
            match self.parser.next() {
                XmlEvent::StartElement { name, .. } => {

                    depth += 1;

                    // FIXME(Waiting the pull request on netvl/xml-rs to be merged)
                    // let (row, col) = self.parser.get_cursor();
                    let (row, col) = (0, 0);
                    self.err.log(
                        format!("Warning {}:{}, `{}` has been ignored",
                                row+1, col+1, name)
                    );
                }
                XmlEvent::EndElement { name } => {

                    depth -= 1;
                    if name.local_name == tag && depth == 0 {
                        return Ok(());
                    }
                }
                XmlEvent::Error( e ) => {

                    self.err.log(format!("Error: {}", e));
                    return Err((ErrorType::Fatal, ErrorStatus::Reported));
                }
                _ => ()
            }
        }
    }

    fn parse_loop(&mut self,
                tag: &str,
                parent: &mut Node)
                -> Result<(), ParseError>
    {
        loop {
            match self.parser.next() {
                XmlEvent::StartElement { name, attributes, .. } => {

                    let test_parse_child = self.parse_tag(
                        &name.local_name,
                        &attributes
                    );

                    match test_parse_child {
                        // We're fine continue parsing.
                        Ok(node) => {
                            parent.add(node);
                        },
                        // Error has been reported: stop parsing.
                        Err(reported_error) => return Err(reported_error),
                    }
                }
                XmlEvent::EndElement { name } => {

                    // TODO: remove at some point.
                    assert_eq!(name.local_name, tag);
                    return Ok(());
                }
                XmlEvent::Characters( text ) => {
                    self.parse_data_binding(&text, parent);
                }
                XmlEvent::Error( e ) => {

                    self.err.log(format!("Error: {}", e));
                    return Err((ErrorType::Fatal, ErrorStatus::Reported));
                }
                XmlEvent::EndDocument => unreachable!(),
                _ => ()
            }
        }
    }

}

#[cfg(test)]
mod test {

    use std::io::BufReader;
    use EmptyErrorReporter;

    #[test]
    fn reject_invalid_root_tags() {
        let reader = BufReader::new("<test></test>".as_bytes());
        let mut parser = super::Parser::new(EmptyErrorReporter, reader);

        let res = parser.parse();
        assert_eq!(res.views.len(), 0);
        assert_eq!(res.templates.len(), 0);
    }

    #[test]
    fn ignore_unknown_tags() {
        let reader = BufReader::new(
            "<view>\
                <toto />\

Test
\
             </view>
            ".as_bytes());
        let mut parser = super::Parser::new(EmptyErrorReporter, reader);

        let res = parser.parse();

        assert_eq!(res.views.len(), 1);
        assert_eq!(res.views.values().next().unwrap().children.len(), 0);
        assert_eq!(res.templates.len(), 0);
    }

    #[test]
    fn reject_unnamed_template() {
        let reader = BufReader::new(
            "<template>\
                <toto />\
             </template>
            ".as_bytes());
        let mut parser = super::Parser::new(EmptyErrorReporter, reader);

        let res = parser.parse();

        assert_eq!(res.views.len(), 0);
        assert_eq!(res.templates.len(), 0);
    }

    #[test]
    fn ignore_ill_formed_repeat_1() {
        let reader = BufReader::new(
            "<view>\
                <repeat template-name=\"test\"/>\
             </view>
            ".as_bytes());
        let mut parser = super::Parser::new(EmptyErrorReporter, reader);

        let res = parser.parse();

        assert_eq!(res.views.len(), 1);
        assert_eq!(res.views.values().next().unwrap().children.len(), 0);
        assert_eq!(res.templates.len(), 0);
    }

    #[test]
    fn ignore_ill_formed_repeat_2() {
        let reader = BufReader::new(
            "<view>\
                <repeat iter=\"{test}\"/>\
             </view>
            ".as_bytes());
        let mut parser = super::Parser::new(EmptyErrorReporter, reader);

        let res = parser.parse();

        assert_eq!(res.views.len(), 1);
        assert_eq!(res.views.values().next().unwrap().children.len(), 0);
        assert_eq!(res.templates.len(), 0);
    }

    #[test]
    fn accept_well_formed_repeat() {
        let reader = BufReader::new(
            "<view>\
                <repeat iter=\"{arf}\" template-name=\"test\"/>\
             </view>
            ".as_bytes());
        let mut parser = super::Parser::new(EmptyErrorReporter, reader);

        let res = parser.parse();

        assert_eq!(res.views.len(), 1);
        assert_eq!(res.views.values().next().unwrap().children.len(), 1);
        assert_eq!(res.templates.len(), 0);
    }
}
<commit_msg>Bug fix after consume_any_char fix.<commit_after>// Dependencies
use xml::reader::EventReader;
use xml::reader::events::*;
use xml::attribute::OwnedAttribute;
use std::io::Read;

use std::collections::HashMap;
use ErrorReporter;
use oil_shared;
use parsing::BufferConsumer;

use super::HasNodeChildren;
use super::Library;
use super::ErrorType;
use super::ErrorStatus;
use super::tags;
use super::lookup_name;
use super::ParseError;

use super::TEMPLATE_TAG;
use super::VIEW_TAG;
use super::GROUP_TAG;
use super::BUTTON_TAG;
use super::LINE_INPUT_TAG;
use super::PROGRESS_BAR_TAG;
use super::REPEAT_TAG;
use super::MAIN_VIEW_NAME;

use oil_shared::markup::{
    Node,
    View,
    Template,
    NodeType
};

/// Parser
pub struct Parser<E, B: Read> {
    err: E,
    parser: EventReader,
}

impl<E, B> Parser<E, B>
    where E: ErrorReporter,
          B: Read
{

    pub fn new(reporter: E, reader: B) -> Parser<E, B> {
        Parser {
            err: reporter,
            parser: EventReader::new(reader)
        }
    }

    pub fn parse(&mut self) -> Library<E>
    {
        let mut views = HashMap::new();
        let mut templates = HashMap::new();

        'doc: loop {

            match self.parser.next() {
                XmlEvent::StartElement { name, attributes, .. } => {

                    let test_parse = self.parse_root_tag(
                        &mut views,
                        &mut templates,
                        &name.local_name,
                        &attributes
                    );

                    match test_parse {
                        Err((ErrorType::Fatal, _)) => break 'doc,
                        _ => ()
                    }
                }
                XmlEvent::Error(e) => {
                    self.err.log(format!("Error: {}", e));
                    break 'doc;
                }
                XmlEvent::EndDocument => break 'doc,
                XmlEvent::StartDocument { .. } => (),
                _ => unreachable!(),
            }
        }

        Library::new(self.err.clone(), views, templates)
    }

    fn parse_view(&mut self) -> Result<View, ParseError>
    {
        let mut view = oil_shared::markup::new_view(None);

        try!(self.parse_loop(VIEW_TAG, &mut view));
        Ok(view)
    }

    fn parse_template_decl(&mut self) -> Result<Template, ParseError>
    {
        let mut template = oil_shared::markup::new_template(None);

        try!(self.parse_loop(TEMPLATE_TAG, &mut template));
        Ok(template)
    }

    fn parse_root_tag(&mut self,
                      views: &mut HashMap<String, View>,
                      templates: &mut HashMap<String, Template>,
                      name: &str,
                      attributes: &Vec<OwnedAttribute>) -> Result<(), ParseError>
    {
        match name {
            TEMPLATE_TAG => {
                let attr_name = lookup_name("name", attributes);

                match attr_name {
                    None => {
                        // FIXME(Waiting the pull request on netvl/xml-rs to be merged)
                        // let (row, col) = self.parser.get_cursor();
                        let (row, col) = (0, 0);
                        self.err.log(
                            format!(
                                "Warning {}:{} : `template` has no name add an \
                                 attribute 'name=\"\"'",
                            row, col)
                        );

                        self.consume_children(name)
                    }
                    Some(template_name) => {
                        let template = try!(self.parse_template_decl());
                        templates.insert(template_name, template);
                        Ok(())
                    }
                }
            }
            VIEW_TAG => {
                let view = try!(self.parse_view());
                let attr_name = lookup_name("name", attributes)
                    .unwrap_or(MAIN_VIEW_NAME.to_string());
                views.insert(attr_name, view);
                Ok(())
            }
            _ => {
                // FIXME(Waiting the pull request on netvl/xml-rs to be merged)
                // let (row, col) = self.parser.get_cursor();
                let (row, col) = (0, 0);
                self.err.log(
                    format!(
                        "Warning {}:{} : `{}` can't be at root level, \
                        you can only have `template` or `view`"
                    , row+1, col+1, name));

                self.consume_children(name)
            }
        }
    }

    fn parse_tag(&mut self,
                 name: &str,
                 attributes: &Vec<OwnedAttribute>)
                 -> Result<Option<Node>, ParseError>
    {
        let ignore_child = name == TEMPLATE_TAG;

        let node_type = match name {
            TEMPLATE_TAG     => tags::parse_template(attributes),
            GROUP_TAG        => Ok(NodeType::Group),
            BUTTON_TAG       => tags::parse_button(attributes),
            LINE_INPUT_TAG   => tags::parse_linput(attributes),
            PROGRESS_BAR_TAG => tags::parse_pbar(attributes),
            REPEAT_TAG       => tags::parse_repeat(attributes),
            _ => {
                // FIXME(Waiting the pull request on netvl/xml-rs to be merged)
                // let (row, col) = self.parser.get_cursor();
                let (row, col) = (0, 0);
                self.err.log(
                    format!("Warning {}:{} : Unknown tag `{}`", row+1, col+1, name)
                );
                Err((ErrorType::Warning, ErrorStatus::Reported))
            }
        };

        match node_type {
            Err(parse_error) => {
                match self.report_error_if_needed(parse_error) {
                    (ErrorType::Warning, _) => {
                        match self.consume_children(name) {
                            Err(parse_err) =>
                                Err(self.report_error_if_needed(parse_err)),
                            Ok(()) =>
                                Ok(None)
                        }
                    },
                    reported_parse_error => Err(reported_parse_error)
                }
            }
            Ok(nt) => {
                let classes = lookup_name("class", attributes);
                let mut node = Node::new(classes, nt);

                if ignore_child {

                    // Consume children
                    try!(self.consume_children(name));
                    Ok(Some(node))

                } else {

                    // Parse children
                    try!(self.parse_loop(name, &mut node));
                    Ok(Some(node))
                }
            }
        }
    }

    fn parse_data_binding(&mut self, text: &str, parent: &mut Node) {
        let mut buf_consumer = BufferConsumer::new(text.as_bytes());
        loop {
            let text = buf_consumer.consume_while(|c| c != '{').unwrap();
            if !text.is_empty() {
                parent.add(Some(Node::new(
                            None,
                            NodeType::Text(text))));
            }
            match buf_consumer.consume_any_char() {
                Some('{') => {
                    match buf_consumer.consume_any_char() {
                        Some('{') => {
                            let mut data_binding = buf_consumer.consume_while(|c| c != '}').unwrap();
                            match buf_consumer.consume_any_char() {
                                Some('}') => {
                                    match buf_consumer.consume_any_char() {
                                        Some('}') => {
                                            // Yahoo! We have a correct data binding
                                            parent.add(Some(Node::new(
                                                        None,
                                                        NodeType::Binding(data_binding))));
                                        }
                                        _ => {
                                            let (row, col) = (0, 0);
                                            self.err.log(format!("Warning {}:{} : Missing '}}' for data binding", row, col));
                                            data_binding.insert(0, '{');
                                            data_binding.insert(0, '{');
                                            data_binding.push('}');
                                            parent.add(Some(Node::new(
                                                        None,
                                                        NodeType::Text(data_binding))));
                                            break;
                                        },
                                    }
                                }
                                _ => {
                                    let (row, col) = (0, 0);
                                    self.err.log(format!("Warning {}:{} : Missing '}}' for data binding", row, col));
                                    data_binding.insert(0, '{');
                                    data_binding.insert(0, '{');
                                    parent.add(Some(Node::new(
                                                None,
                                                NodeType::Text(data_binding))));
                                    break;
                                },
                            }
                        }
                        _ => {
                            let (row, col) = (0, 0);
                            self.err.log(format!("Warning {}:{} : Missing \"{{ .. }}}}\" for data binding", row, col));
                            let text = "{".to_string();
                            parent.add(Some(Node::new(
                                        None,
                                        NodeType::Text(text))));
                            break;
                        },
                    }
                }
                _ => break,
            }
        }
    }

    fn report_error_if_needed(&mut self,
                              parse_error: ParseError) -> ParseError
    {
        // FIXME(Waiting the pull request on netvl/xml-rs to be merged)
        // let (row, col) = self.parser.get_cursor();
        let (row, col) = (0, 0);
        match parse_error {
            (ErrorType::Fatal, ErrorStatus::NotReported(msg)) => {
                self.err.log(
                    format!("Error {}:{} : {}", row+1, col+1, msg)
                );
                (ErrorType::Fatal, ErrorStatus::Reported)
            }
            (ErrorType::Warning, ErrorStatus::NotReported(msg)) => {
                self.err.log(
                    format!("Warning {}:{} : {}", row+1, col+1, msg)
                );
                (ErrorType::Warning, ErrorStatus::Reported)
            }
            _ => parse_error
        }
    }

    // This function may only return Ok(()) or
    // Err((ErrorType::Fatal, ErrorStatus::Reported)).
    fn consume_children(&mut self, tag: &str) -> Result<(), ParseError>
    {
        let mut depth = 1i32;
        loop {
            match self.parser.next() {
                XmlEvent::StartElement { name, .. } => {

                    depth += 1;

                    // FIXME(Waiting the pull request on netvl/xml-rs to be merged)
                    // let (row, col) = self.parser.get_cursor();
                    let (row, col) = (0, 0);
                    self.err.log(
                        format!("Warning {}:{}, `{}` has been ignored",
                                row+1, col+1, name)
                    );
                }
                XmlEvent::EndElement { name } => {

                    depth -= 1;
                    if name.local_name == tag && depth == 0 {
                        return Ok(());
                    }
                }
                XmlEvent::Error( e ) => {

                    self.err.log(format!("Error: {}", e));
                    return Err((ErrorType::Fatal, ErrorStatus::Reported));
                }
                _ => ()
            }
        }
    }

    fn parse_loop(&mut self,
                tag: &str,
                parent: &mut Node)
                -> Result<(), ParseError>
    {
        loop {
            match self.parser.next() {
                XmlEvent::StartElement { name, attributes, .. } => {

                    let test_parse_child = self.parse_tag(
                        &name.local_name,
                        &attributes
                    );

                    match test_parse_child {
                        // We're fine continue parsing.
                        Ok(node) => {
                            parent.add(node);
                        },
                        // Error has been reported: stop parsing.
                        Err(reported_error) => return Err(reported_error),
                    }
                }
                XmlEvent::EndElement { name } => {

                    // TODO: remove at some point.
                    assert_eq!(name.local_name, tag);
                    return Ok(());
                }
                XmlEvent::Characters( text ) => {
                    self.parse_data_binding(&text, parent);
                }
                XmlEvent::Error( e ) => {

                    self.err.log(format!("Error: {}", e));
                    return Err((ErrorType::Fatal, ErrorStatus::Reported));
                }
                XmlEvent::EndDocument => unreachable!(),
                _ => ()
            }
        }
    }

}

#[cfg(test)]
mod test {

    use std::io::BufReader;
    use EmptyErrorReporter;

    #[test]
    fn reject_invalid_root_tags() {
        let reader = BufReader::new("<test></test>".as_bytes());
        let mut parser = super::Parser::new(EmptyErrorReporter, reader);

        let res = parser.parse();
        assert_eq!(res.views.len(), 0);
        assert_eq!(res.templates.len(), 0);
    }

    #[test]
    fn ignore_unknown_tags() {
        let reader = BufReader::new(
            "<view>\
                <toto />\

Test
\
             </view>
            ".as_bytes());
        let mut parser = super::Parser::new(EmptyErrorReporter, reader);

        let res = parser.parse();

        assert_eq!(res.views.len(), 1);
        assert_eq!(res.views.values().next().unwrap().children.len(), 0);
        assert_eq!(res.templates.len(), 0);
    }

    #[test]
    fn reject_unnamed_template() {
        let reader = BufReader::new(
            "<template>\
                <toto />\
             </template>
            ".as_bytes());
        let mut parser = super::Parser::new(EmptyErrorReporter, reader);

        let res = parser.parse();

        assert_eq!(res.views.len(), 0);
        assert_eq!(res.templates.len(), 0);
    }

    #[test]
    fn ignore_ill_formed_repeat_1() {
        let reader = BufReader::new(
            "<view>\
                <repeat template-name=\"test\"/>\
             </view>
            ".as_bytes());
        let mut parser = super::Parser::new(EmptyErrorReporter, reader);

        let res = parser.parse();

        assert_eq!(res.views.len(), 1);
        assert_eq!(res.views.values().next().unwrap().children.len(), 0);
        assert_eq!(res.templates.len(), 0);
    }

    #[test]
    fn ignore_ill_formed_repeat_2() {
        let reader = BufReader::new(
            "<view>\
                <repeat iter=\"{test}\"/>\
             </view>
            ".as_bytes());
        let mut parser = super::Parser::new(EmptyErrorReporter, reader);

        let res = parser.parse();

        assert_eq!(res.views.len(), 1);
        assert_eq!(res.views.values().next().unwrap().children.len(), 0);
        assert_eq!(res.templates.len(), 0);
    }

    #[test]
    fn accept_well_formed_repeat() {
        let reader = BufReader::new(
            "<view>\
                <repeat iter=\"{arf}\" template-name=\"test\"/>\
             </view>
            ".as_bytes());
        let mut parser = super::Parser::new(EmptyErrorReporter, reader);

        let res = parser.parse();

        assert_eq!(res.views.len(), 1);
        assert_eq!(res.views.values().next().unwrap().children.len(), 1);
        assert_eq!(res.templates.len(), 0);
    }
}
<|endoftext|>


<commit_before>// This example uses get_sock() to find out which file descriptors c-ares
// wants us to listen on, and uses epoll() to satisfy those requirements.
extern crate c_ares;
extern crate nix;

use nix::sys::epoll::{
    epoll_create,
    epoll_ctl,
    epoll_wait,
    EpollEvent,
    EpollEventKind,
    EpollOp,
    EPOLLIN,
    EPOLLOUT,
};
use std::collections::HashSet;
use std::error::Error;
use std::os::unix::io;

fn print_a_results(result: Result<c_ares::AResults, c_ares::AresError>) {
    match result {
        Err(e) => {
            println!("A lookup failed with error '{}'", e.description());
        }
        Ok(a_results) => {
            println!("Successful A lookup...");
            println!("Hostname: {}", a_results.hostname());
            for a_result in &a_results {
                println!("{:}", a_result.ipv4_addr());
            }
        }
    }
}

fn print_aaaa_results(result: Result<c_ares::AAAAResults, c_ares::AresError>) {
    match result {
        Err(e) => {
            println!("AAAA lookup failed with error '{}'", e.description());
        }
        Ok(aaaa_results) => {
            println!("Successful AAAA lookup...");
            println!("Hostname: {}", aaaa_results.hostname());
            for aaaa_result in &aaaa_results {
                println!("{:}", aaaa_result.ipv6_addr());
            }
        }
    }
}

fn print_srv_results(result: Result<c_ares::SRVResults, c_ares::AresError>) {
    match result {
        Err(e) => {
            println!("SRV lookup failed with error '{}'", e.description());
        }
        Ok(srv_results) => {
            println!("Successful SRV lookup...");
            for srv_result in &srv_results {
                println!("host: {} (port: {}), priority: {} weight: {}",
                         srv_result.host(),
                         srv_result.port(),
                         srv_result.weight(),
                         srv_result.priority());
            }
        }
    }
}

fn main() {
    // Create the c_ares::Channel.
    let mut options = c_ares::Options::new();
    options
        .set_flags(c_ares::flags::STAYOPEN)
        .set_timeout(500)
        .set_tries(3);
    let mut ares_channel = c_ares::Channel::new(options)
        .ok()
        .expect("Failed to create channel");

    // Set up some queries.
    ares_channel.query_a("apple.com", move |result| {
        println!("");
        print_a_results(result);
    });

    ares_channel.query_aaaa("google.com", move |result| {
        println!("");
        print_aaaa_results(result);
    });

    ares_channel.query_srv("_xmpp-server._tcp.gmail.com", move |result| {
        println!("");
        print_srv_results(result);
    });

    // Create an epoll file descriptor so that we can listen for events.
    let epoll = epoll_create().ok().expect("Failed to create epoll");
    let mut tracked_fds = HashSet::<io::RawFd>::new();
    loop {
        // Ask c-ares what file descriptors we should be listening on, and map
        // those requests onto the epoll file descriptor.
        let mut active = false;
        for (fd, readable, writable) in &ares_channel.get_sock() {
            let mut interest = EpollEventKind::empty();
            if readable { interest = interest | EPOLLIN; }
            if writable { interest = interest | EPOLLOUT; }
            let event = EpollEvent {
                events: interest,
                data: fd as u64,
            };
            let op = if tracked_fds.insert(fd) {
                EpollOp::EpollCtlAdd
            } else {
                EpollOp::EpollCtlMod
            };
            epoll_ctl(epoll, op, fd, &event).ok().expect("epoll_ctl failed");
            active = true;
        }
        if !active { break }

        // Wait for something to happen.
        let empty_event = EpollEvent {
            events: EpollEventKind::empty(),
            data: 0,
        };
        let mut events = [empty_event; 2];
        let results = epoll_wait(epoll, &mut events, 500)
            .ok()
            .expect("epoll_wait failed");

        // Process whatever happened.
        match results {
            0 => {
                // No events - must be a timeout.  Tell c-ares about it.
                ares_channel.process_fd(
                    c_ares::INVALID_FD,
                    c_ares::INVALID_FD);
            },
            n => {
                // Sockets became readable or writable.  Tell c-ares about it.
                for i in 0..n {
                    let event = events[i];
                    let active_fd = event.data as io::RawFd;
                    let readable_fd = if (event.events & EPOLLIN).is_empty() {
                        c_ares::INVALID_FD
                    } else {
                        active_fd
                    };
                    let writable_fd = if (event.events & EPOLLOUT).is_empty() {
                        c_ares::INVALID_FD
                    } else {
                        active_fd
                    };
                    ares_channel.process_fd(readable_fd, writable_fd);
                }
            }
        }
    }
}
<commit_msg>Priority and weight flipped in example<commit_after>// This example uses get_sock() to find out which file descriptors c-ares
// wants us to listen on, and uses epoll() to satisfy those requirements.
extern crate c_ares;
extern crate nix;

use nix::sys::epoll::{
    epoll_create,
    epoll_ctl,
    epoll_wait,
    EpollEvent,
    EpollEventKind,
    EpollOp,
    EPOLLIN,
    EPOLLOUT,
};
use std::collections::HashSet;
use std::error::Error;
use std::os::unix::io;

fn print_a_results(result: Result<c_ares::AResults, c_ares::AresError>) {
    match result {
        Err(e) => {
            println!("A lookup failed with error '{}'", e.description());
        }
        Ok(a_results) => {
            println!("Successful A lookup...");
            println!("Hostname: {}", a_results.hostname());
            for a_result in &a_results {
                println!("{:}", a_result.ipv4_addr());
            }
        }
    }
}

fn print_aaaa_results(result: Result<c_ares::AAAAResults, c_ares::AresError>) {
    match result {
        Err(e) => {
            println!("AAAA lookup failed with error '{}'", e.description());
        }
        Ok(aaaa_results) => {
            println!("Successful AAAA lookup...");
            println!("Hostname: {}", aaaa_results.hostname());
            for aaaa_result in &aaaa_results {
                println!("{:}", aaaa_result.ipv6_addr());
            }
        }
    }
}

fn print_srv_results(result: Result<c_ares::SRVResults, c_ares::AresError>) {
    match result {
        Err(e) => {
            println!("SRV lookup failed with error '{}'", e.description());
        }
        Ok(srv_results) => {
            println!("Successful SRV lookup...");
            for srv_result in &srv_results {
                println!("host: {} (port: {}), priority: {} weight: {}",
                         srv_result.host(),
                         srv_result.port(),
                         srv_result.priority(),
                         srv_result.weight());
            }
        }
    }
}

fn main() {
    // Create the c_ares::Channel.
    let mut options = c_ares::Options::new();
    options
        .set_flags(c_ares::flags::STAYOPEN)
        .set_timeout(500)
        .set_tries(3);
    let mut ares_channel = c_ares::Channel::new(options)
        .ok()
        .expect("Failed to create channel");

    // Set up some queries.
    ares_channel.query_a("apple.com", move |result| {
        println!("");
        print_a_results(result);
    });

    ares_channel.query_aaaa("google.com", move |result| {
        println!("");
        print_aaaa_results(result);
    });

    ares_channel.query_srv("_xmpp-server._tcp.gmail.com", move |result| {
        println!("");
        print_srv_results(result);
    });

    // Create an epoll file descriptor so that we can listen for events.
    let epoll = epoll_create().ok().expect("Failed to create epoll");
    let mut tracked_fds = HashSet::<io::RawFd>::new();
    loop {
        // Ask c-ares what file descriptors we should be listening on, and map
        // those requests onto the epoll file descriptor.
        let mut active = false;
        for (fd, readable, writable) in &ares_channel.get_sock() {
            let mut interest = EpollEventKind::empty();
            if readable { interest = interest | EPOLLIN; }
            if writable { interest = interest | EPOLLOUT; }
            let event = EpollEvent {
                events: interest,
                data: fd as u64,
            };
            let op = if tracked_fds.insert(fd) {
                EpollOp::EpollCtlAdd
            } else {
                EpollOp::EpollCtlMod
            };
            epoll_ctl(epoll, op, fd, &event).ok().expect("epoll_ctl failed");
            active = true;
        }
        if !active { break }

        // Wait for something to happen.
        let empty_event = EpollEvent {
            events: EpollEventKind::empty(),
            data: 0,
        };
        let mut events = [empty_event; 2];
        let results = epoll_wait(epoll, &mut events, 500)
            .ok()
            .expect("epoll_wait failed");

        // Process whatever happened.
        match results {
            0 => {
                // No events - must be a timeout.  Tell c-ares about it.
                ares_channel.process_fd(
                    c_ares::INVALID_FD,
                    c_ares::INVALID_FD);
            },
            n => {
                // Sockets became readable or writable.  Tell c-ares about it.
                for i in 0..n {
                    let event = events[i];
                    let active_fd = event.data as io::RawFd;
                    let readable_fd = if (event.events & EPOLLIN).is_empty() {
                        c_ares::INVALID_FD
                    } else {
                        active_fd
                    };
                    let writable_fd = if (event.events & EPOLLOUT).is_empty() {
                        c_ares::INVALID_FD
                    } else {
                        active_fd
                    };
                    ares_channel.process_fd(readable_fd, writable_fd);
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::ops::Deref;
use std::rc::Rc;
use std::cell::RefCell;
use super::Position;
use super::GapBuffer;

/// Read-only wrapper for a `Position`, to allow field level access to a
/// buffer's cursor while simultaneously enforcing bounds-checking when
/// updating its value.
pub struct Cursor {
    pub data: Rc<RefCell<GapBuffer>>,
    pub position: Position,
}

impl Deref for Cursor {
    type Target = Position;

    fn deref(&self) -> &Position {
        &self.position
    }
}

impl Cursor {
    /// Moves the cursor to the specified location. The location is
    /// bounds-checked against the data and the cursor will not be
    /// updated if it is out-of-bounds.
    ///
    /// # Examples
    ///
    /// ```
    /// let mut buffer = scribe::buffer::new();
    /// let in_bounds = scribe::buffer::Position{ line: 0, offset: 2 };
    /// let out_of_bounds = scribe::buffer::Position{ line: 2, offset: 2 };
    /// buffer.insert("scribe");
    ///
    /// buffer.cursor.move_to(in_bounds);
    /// assert_eq!(buffer.cursor.line, 0);
    /// assert_eq!(buffer.cursor.offset, 2);
    ///
    /// buffer.cursor.move_to(out_of_bounds);
    /// assert_eq!(buffer.cursor.line, 0);
    /// assert_eq!(buffer.cursor.offset, 2);
    /// ```
    pub fn move_to(&mut self, position: Position) {
        if self.data.borrow().in_bounds(&position) {
            self.position = position;
        }
    }
}
<commit_msg>Add up/down/left/right cursor movement methods.<commit_after>use std::ops::Deref;
use std::rc::Rc;
use std::cell::RefCell;
use super::Position;
use super::GapBuffer;

/// Read-only wrapper for a `Position`, to allow field level access to a
/// buffer's cursor while simultaneously enforcing bounds-checking when
/// updating its value.
pub struct Cursor {
    pub data: Rc<RefCell<GapBuffer>>,
    pub position: Position,
}

impl Deref for Cursor {
    type Target = Position;

    fn deref(&self) -> &Position {
        &self.position
    }
}

impl Cursor {
    /// Moves the cursor to the specified location. The location is
    /// bounds-checked against the data and the cursor will not be
    /// updated if it is out-of-bounds.
    ///
    /// # Examples
    ///
    /// ```
    /// let mut buffer = scribe::buffer::new();
    /// let in_bounds = scribe::buffer::Position{ line: 0, offset: 2 };
    /// let out_of_bounds = scribe::buffer::Position{ line: 2, offset: 2 };
    /// buffer.insert("scribe");
    ///
    /// buffer.cursor.move_to(in_bounds);
    /// assert_eq!(buffer.cursor.line, 0);
    /// assert_eq!(buffer.cursor.offset, 2);
    ///
    /// buffer.cursor.move_to(out_of_bounds);
    /// assert_eq!(buffer.cursor.line, 0);
    /// assert_eq!(buffer.cursor.offset, 2);
    /// ```
    pub fn move_to(&mut self, position: Position) {
        if self.data.borrow().in_bounds(&position) {
            self.position = position;
        }
    }

    /// Decrements the cursor line. The location is bounds-checked against
    /// the data and the cursor will not be updated if it is out-of-bounds.
    pub fn move_up(&mut self) {
        let new_position = Position{ line: self.line-1, offset: self.offset };
        self.move_to(new_position);
    }

    /// Increments the cursor line. The location is bounds-checked against
    /// the data and the cursor will not be updated if it is out-of-bounds.
    pub fn move_down(&mut self) {
        let new_position = Position{ line: self.line+1, offset: self.offset };
        self.move_to(new_position);
    }

    /// Decrements the cursor offset. The location is bounds-checked against
    /// the data and the cursor will not be updated if it is out-of-bounds.
    pub fn move_left(&mut self) {
        let new_position = Position{ line: self.line, offset: self.offset-1 };
        self.move_to(new_position);
    }

    /// Increments the cursor offset. The location is bounds-checked against
    /// the data and the cursor will not be updated if it is out-of-bounds.
    pub fn move_right(&mut self) {
        let new_position = Position{ line: self.line, offset: self.offset+1 };
        self.move_to(new_position);
    }
}
<|endoftext|>


<commit_before>//! Shader module.
//!
//! Shader functions and declarations can be grouped in so-called *modules*. Modules structure is
//! inherently tied to the filesystem’s tree.
//!
//! You’re not supposed to use modules at the Rust level, even though you can. You’re supposed to
//! actually write modules that will be used by shader programs.

use std::fs::File;
use std::io::Read;
use std::path::PathBuf;

use render::shader::lang::parser;
use render::shader::lang::syntax::{Declaration, ExternalDeclaration, FunctionDefinition, FullySpecifiedType,
                                   FunctionParameterDeclaration, InitDeclaratorList,
                                   Module as SyntaxModule, SingleDeclaration, StorageQualifier,
                                   StructFieldSpecifier, TypeSpecifier, TypeQualifierSpec};
use sys::resource::{CacheKey, Load, LoadError, LoadResult, Store, StoreKey};

/// Shader module.
///
/// A shader module is a piece of GLSL code with optional import lists (dependencies).
///
/// You’re not supposed to directly manipulate any object of this type. You just write modules on
/// disk and let everyting happen automatically for you.
#[derive(Clone, Debug, PartialEq)]
pub struct Module(pub SyntaxModule); // FIXME: remove the pub

impl Module {
  /// Retrieve all the modules this module depends on, without duplicates.
  pub fn deps(&self, store: &mut Store, key: &ModuleKey) -> Result<Vec<ModuleKey>, DepsError> {
    let mut deps = Vec::new();
    self.deps_no_cycle(store, &key, &mut Vec::new(), &mut deps).map(|_| deps)
  }

  fn deps_no_cycle(&self, store: &mut Store, key: &ModuleKey, parents: &mut Vec<ModuleKey>, deps: &mut Vec<ModuleKey>) -> Result<(), DepsError> {
    let imports = self.0.imports.iter().map(|il| &il.module);

    parents.push(key.clone());

    for module_path in imports {
      let module_key = ModuleKey(module_path.path.join("."));

      // check whether it’s already in the deps
      if deps.contains(&module_key) {
        continue;
      }

      // check whether the module was already visited
      if parents.contains(&module_key) {
        return Err(DepsError::Cycle(module_key.clone(), module_key.clone()));
      }

      // get the dependency module
      let module = store.get(&module_key).ok_or_else(|| DepsError::LoadError(module_key.clone()))?;
      module.borrow().deps_no_cycle(store, &module_key, parents, deps)?;

      deps.push(module_key.clone());
      parents.pop();
    }

    Ok(())
  }

  /// Fold a module and its dependencies into a single module. The list of dependencies is also
  /// returned.
  pub fn gather(&self, store: &mut Store, k: &ModuleKey) -> Result<(Self, Vec<ModuleKey>), DepsError> {
    let deps = self.deps(store, k)?;
    let glsl =
      deps.iter()
          .flat_map(|kd| {
              let m = store.get(kd).unwrap();
              let g = m.borrow().0.glsl.clone();
              g
            })
          .chain(self.0.glsl.clone())
          .collect();

    let module = Module(SyntaxModule {
      imports: Vec::new(),
      glsl
    });

    Ok((module, deps))
  }

  /// Get all the uniforms defined in a module.
  pub fn uniforms(&self) -> Vec<SingleDeclaration> {
    let mut uniforms = Vec::new();

    for glsl in &self.0.glsl {
      if let ExternalDeclaration::Declaration(Declaration::InitDeclaratorList(ref i)) = *glsl {
        if let Some(ref q) = i.head.ty.qualifier {
          if q.qualifiers.contains(&TypeQualifierSpec::Storage(StorageQualifier::Uniform)) {
            uniforms.push(i.head.clone());

            // check whether we have more
            for next in &i.tail {
              uniforms.push(SingleDeclaration {
                ty: i.head.ty.clone(),
                name: Some(next.name.clone()),
                array_specifier: next.array_specifier.clone(),
                initializer: None
              })
            }
          }
        }
      }
    }

    uniforms
  }

  /// Get all the functions.
  pub fn functions(&self) -> Vec<FunctionDefinition> {
    self.0.glsl.iter().filter_map(|ed| match *ed {
      ExternalDeclaration::FunctionDefinition(ref def) => Some(def.clone()),
      _ => None
    }).collect()
  }
}

/// Vertex shader I/O interface.
///
/// It contains the inputs and the outputs to the next stage.
#[derive(Clone, Debug, PartialEq)]
pub struct VertexShaderInterface {
  inputs: Vec<ExternalDeclaration>,
  outputs: Vec<ExternalDeclaration>
}

#[derive(Clone, Debug, PartialEq)]
pub enum VertexShaderInterfaceError {
  UnnamedInput,
  OutputHasMainQualifier,
  OutputTypeMustBeAStruct(TypeSpecifier),
  WrongOutputFirstField(StructFieldSpecifier),
  OutputFieldCannotBeStruct(usize, TypeSpecifier),
  OutputFieldCannotHaveSeveralIdentifiers(usize, StructFieldSpecifier)
}

/// Build the vertex shader interface from a function definition.
pub fn vertex_shader_interface(fun_def: &FunctionDefinition) -> Result<VertexShaderInterface, VertexShaderInterfaceError> {
  let proto = &fun_def.prototype;
  let inputs = vertex_shader_inputs(proto.parameters.iter())?;
  let outputs = vertex_shader_outputs(&proto.ty)?;

  Ok(VertexShaderInterface { inputs, outputs })
}

fn vertex_shader_inputs<'a, I>(args: I) -> Result<Vec<ExternalDeclaration>, VertexShaderInterfaceError> where I: IntoIterator<Item = &'a FunctionParameterDeclaration> {
  let mut inputs = Vec::new();

  for arg in args {
    match *arg {
      FunctionParameterDeclaration::Unnamed(..) => return Err(VertexShaderInterfaceError::UnnamedInput),
      FunctionParameterDeclaration::Named(ref ty_qual, ref decl) => {
        let qualifier = ty_qual.clone();
        let ty = decl.ty.clone();
        let name = Some(decl.name.clone());
        let array_spec = decl.array_spec.clone();
        let idl = InitDeclaratorList {
          head: SingleDeclaration {
            ty: FullySpecifiedType {
              qualifier,
              ty
            },
            name,
            array_specifier: array_spec,
            initializer: None
          },
          tail: Vec::new()
        };
        let ed = ExternalDeclaration::Declaration(Declaration::InitDeclaratorList(idl));

        inputs.push(ed);
      }
    }
  }

  Ok(inputs)
}

fn vertex_shader_outputs(fsty: &FullySpecifiedType) -> Result<Vec<ExternalDeclaration>, VertexShaderInterfaceError> {
  // we refuse that the output has a main qualifier
  if fsty.qualifier.is_some() {
    return Err(VertexShaderInterfaceError::OutputHasMainQualifier);
  }

  let ty = &fsty.ty;

  // we enforce that the output must be a struct that follows a certain pattern
  match *ty {
    TypeSpecifier::Struct(ref s) => { // it must be a struct
      // the first field must be named "gl_Position", has type vec4 and no qualifier
      let first_field = &s.fields[0];

      if first_field.qualifier.is_some() ||
         first_field.ty != TypeSpecifier::Vec4 ||
         first_field.identifiers != vec![("gl_Position".to_owned(), None)] {
        return Err(VertexShaderInterfaceError::WrongOutputFirstField(first_field.clone()));
      }

      // then, for all other fields, we check that they are not composite type (i.e. structs); if
      // they are not, add them to the interface; otherwise, fail
      let mut outputs = Vec::new();

      for (i, field) in (&s.fields[1..]).into_iter().enumerate() {
        if let TypeSpecifier::Struct(_) = field.ty {
          return Err(VertexShaderInterfaceError::OutputFieldCannotBeStruct(i, field.ty.clone()));
        }

        if field.identifiers.len() > 1 {
          return Err(VertexShaderInterfaceError::OutputFieldCannotHaveSeveralIdentifiers(i, field.clone()));
        }

        outputs.push(vertex_shader_output_field_to_ext_decl(&field));
      }

      Ok(outputs)
    },
    _ => Err(VertexShaderInterfaceError::OutputTypeMustBeAStruct(ty.clone()))
  }
}

fn vertex_shader_output_field_to_ext_decl(field: &StructFieldSpecifier) -> ExternalDeclaration {
  let fsty = FullySpecifiedType {
    qualifier: field.qualifier.clone(),
    ty: field.ty.clone()
  };
  let decl = SingleDeclaration {
    ty: fsty,
    name: Some(field.identifiers[0].0.clone()),
    array_specifier: field.identifiers[0].1.clone(),
    initializer: None
  };

  ExternalDeclaration::Declaration(
    Declaration::InitDeclaratorList(
      InitDeclaratorList {
        head: decl,
        tail: Vec::new()
      }
    )
  )
}

/// Class of errors that can happen in dependencies.
#[derive(Clone, Debug, PartialEq)]
pub enum DepsError {
  /// If a module’s dependencies has any cycle, the dependencies are unusable and the cycle is
  /// returned.
  Cycle(ModuleKey, ModuleKey),
  /// There was a loading error of a module.
  LoadError(ModuleKey)
}

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct ModuleKey(String);

impl ModuleKey {
  pub fn new(key: &str) -> Self {
    ModuleKey(key.to_owned())
  }
}

impl CacheKey for ModuleKey {
  type Target = Module;
}

impl StoreKey for ModuleKey {
  fn key_to_path(&self) -> PathBuf {
    PathBuf::from(self.0.replace(".", "/") + ".spsl")
  }
}

impl Load for Module {
  fn load<K>(key: &K, _: &mut Store) -> Result<LoadResult<Self>, LoadError> where K: StoreKey<Target = Self> {
    let path = key.key_to_path();

    let mut fh = File::open(&path).map_err(|_| LoadError::FileNotFound(path.into()))?;
    let mut src = String::new();
    let _ = fh.read_to_string(&mut src);

    match parser::parse_str(&src[..], parser::module) {
      parser::ParseResult::Ok(module) => {
        Ok(Module(module).into())
      }
      parser::ParseResult::Err(e) => Err(LoadError::ConversionFailed(format!("{:?}", e))),
      _ => Err(LoadError::ConversionFailed("incomplete input".to_owned()))
    }
  }
}

<commit_msg>Fixed vertex_shader_interface.<commit_after>//! Shader module.
//!
//! Shader functions and declarations can be grouped in so-called *modules*. Modules structure is
//! inherently tied to the filesystem’s tree.
//!
//! You’re not supposed to use modules at the Rust level, even though you can. You’re supposed to
//! actually write modules that will be used by shader programs.

use std::fs::File;
use std::io::Read;
use std::path::PathBuf;

use render::shader::lang::parser;
use render::shader::lang::syntax::{Declaration, ExternalDeclaration, FunctionDefinition, FullySpecifiedType,
                                   FunctionParameterDeclaration, InitDeclaratorList,
                                   Module as SyntaxModule, SingleDeclaration, StorageQualifier,
                                   StructSpecifier, StructFieldSpecifier,
                                   TypeSpecifier, TypeQualifierSpec};
use sys::resource::{CacheKey, Load, LoadError, LoadResult, Store, StoreKey};

/// Shader module.
///
/// A shader module is a piece of GLSL code with optional import lists (dependencies).
///
/// You’re not supposed to directly manipulate any object of this type. You just write modules on
/// disk and let everyting happen automatically for you.
#[derive(Clone, Debug, PartialEq)]
pub struct Module(pub SyntaxModule); // FIXME: remove the pub

impl Module {
  /// Retrieve all the modules this module depends on, without duplicates.
  pub fn deps(&self, store: &mut Store, key: &ModuleKey) -> Result<Vec<ModuleKey>, DepsError> {
    let mut deps = Vec::new();
    self.deps_no_cycle(store, &key, &mut Vec::new(), &mut deps).map(|_| deps)
  }

  fn deps_no_cycle(&self, store: &mut Store, key: &ModuleKey, parents: &mut Vec<ModuleKey>, deps: &mut Vec<ModuleKey>) -> Result<(), DepsError> {
    let imports = self.0.imports.iter().map(|il| &il.module);

    parents.push(key.clone());

    for module_path in imports {
      let module_key = ModuleKey(module_path.path.join("."));

      // check whether it’s already in the deps
      if deps.contains(&module_key) {
        continue;
      }

      // check whether the module was already visited
      if parents.contains(&module_key) {
        return Err(DepsError::Cycle(module_key.clone(), module_key.clone()));
      }

      // get the dependency module
      let module = store.get(&module_key).ok_or_else(|| DepsError::LoadError(module_key.clone()))?;
      module.borrow().deps_no_cycle(store, &module_key, parents, deps)?;

      deps.push(module_key.clone());
      parents.pop();
    }

    Ok(())
  }

  /// Fold a module and its dependencies into a single module. The list of dependencies is also
  /// returned.
  pub fn gather(&self, store: &mut Store, k: &ModuleKey) -> Result<(Self, Vec<ModuleKey>), DepsError> {
    let deps = self.deps(store, k)?;
    let glsl =
      deps.iter()
          .flat_map(|kd| {
              let m = store.get(kd).unwrap();
              let g = m.borrow().0.glsl.clone();
              g
            })
          .chain(self.0.glsl.clone())
          .collect();

    let module = Module(SyntaxModule {
      imports: Vec::new(),
      glsl
    });

    Ok((module, deps))
  }

  /// Get all the uniforms defined in a module.
  pub fn uniforms(&self) -> Vec<SingleDeclaration> {
    let mut uniforms = Vec::new();

    for glsl in &self.0.glsl {
      if let ExternalDeclaration::Declaration(Declaration::InitDeclaratorList(ref i)) = *glsl {
        if let Some(ref q) = i.head.ty.qualifier {
          if q.qualifiers.contains(&TypeQualifierSpec::Storage(StorageQualifier::Uniform)) {
            uniforms.push(i.head.clone());

            // check whether we have more
            for next in &i.tail {
              uniforms.push(SingleDeclaration {
                ty: i.head.ty.clone(),
                name: Some(next.name.clone()),
                array_specifier: next.array_specifier.clone(),
                initializer: None
              })
            }
          }
        }
      }
    }

    uniforms
  }

  /// Get all the functions.
  pub fn functions(&self) -> Vec<FunctionDefinition> {
    self.0.glsl.iter().filter_map(|ed| match *ed {
      ExternalDeclaration::FunctionDefinition(ref def) => Some(def.clone()),
      _ => None
    }).collect()
  }

  /// Get all the declared structures.
  pub fn structs(&self) -> Vec<StructSpecifier> {
    self.0.glsl.iter().filter_map(|ed| {
      match *ed {
        ExternalDeclaration::Declaration(
          Declaration::InitDeclaratorList(
            InitDeclaratorList {
              head: SingleDeclaration {
                ty: FullySpecifiedType {
                  ty: TypeSpecifier::Struct(ref s),
                  ..
                },
                ..
              },
              ..
            }
          )
        ) => Some(s.clone()),
        _ => None
      }
    }).collect()
  }
}

/// Vertex shader I/O interface.
///
/// It contains the inputs and the outputs to the next stage.
#[derive(Clone, Debug, PartialEq)]
pub struct VertexShaderInterface {
  inputs: Vec<ExternalDeclaration>,
  outputs: Vec<ExternalDeclaration>
}

#[derive(Clone, Debug, PartialEq)]
pub enum VertexShaderInterfaceError {
  UnnamedInput,
  OutputHasMainQualifier,
  OutputTypeMustBeAStruct(TypeSpecifier),
  WrongOutputFirstField(StructFieldSpecifier),
  OutputFieldCannotBeStruct(usize, TypeSpecifier),
  OutputFieldCannotHaveSeveralIdentifiers(usize, StructFieldSpecifier)
}

/// Build the vertex shader interface from a function definition.
pub fn vertex_shader_interface(fun_def: &FunctionDefinition, structs: &[StructSpecifier]) -> Result<VertexShaderInterface, VertexShaderInterfaceError> {
  let proto = &fun_def.prototype;
  let inputs = vertex_shader_inputs(proto.parameters.iter())?;
  let outputs = vertex_shader_outputs(&proto.ty, structs)?;

  Ok(VertexShaderInterface { inputs, outputs })
}

fn vertex_shader_inputs<'a, I>(args: I) -> Result<Vec<ExternalDeclaration>, VertexShaderInterfaceError> where I: IntoIterator<Item = &'a FunctionParameterDeclaration> {
  let mut inputs = Vec::new();

  for arg in args {
    match *arg {
      FunctionParameterDeclaration::Unnamed(..) => return Err(VertexShaderInterfaceError::UnnamedInput),
      FunctionParameterDeclaration::Named(ref ty_qual, ref decl) => {
        let qualifier = ty_qual.clone();
        let ty = decl.ty.clone();
        let name = Some(decl.name.clone());
        let array_spec = decl.array_spec.clone();
        let idl = InitDeclaratorList {
          head: SingleDeclaration {
            ty: FullySpecifiedType {
              qualifier,
              ty
            },
            name,
            array_specifier: array_spec,
            initializer: None
          },
          tail: Vec::new()
        };
        let ed = ExternalDeclaration::Declaration(Declaration::InitDeclaratorList(idl));

        inputs.push(ed);
      }
    }
  }

  Ok(inputs)
}

fn vertex_shader_outputs(fsty: &FullySpecifiedType, structs: &[StructSpecifier]) -> Result<Vec<ExternalDeclaration>, VertexShaderInterfaceError> {
  // we refuse that the output has a main qualifier
  if fsty.qualifier.is_some() {
    return Err(VertexShaderInterfaceError::OutputHasMainQualifier);
  }

  let ty = &fsty.ty;

  // we enforce that the output must be a struct that follows a certain pattern
  match *ty {
    TypeSpecifier::TypeName(ref ty_name) => {
      let real_ty = structs.iter().find(|ref s| s.name.as_ref() == Some(ty_name));

      match real_ty {
        Some(ref s) => {
          // the first field must be named "gl_Position", has type vec4 and no qualifier
          let first_field = &s.fields[0];

          if first_field.qualifier.is_some() ||
             first_field.ty != TypeSpecifier::Vec4 ||
             first_field.identifiers != vec![("gl_Position".to_owned(), None)] {
            return Err(VertexShaderInterfaceError::WrongOutputFirstField(first_field.clone()));
          }

          // then, for all other fields, we check that they are not composite type (i.e. structs); if
          // they are not, add them to the interface; otherwise, fail
          let mut outputs = Vec::new();

          for (i, field) in (&s.fields[1..]).into_iter().enumerate() {
            if let TypeSpecifier::Struct(_) = field.ty {
              return Err(VertexShaderInterfaceError::OutputFieldCannotBeStruct(i, field.ty.clone()));
            }

            if field.identifiers.len() > 1 {
              return Err(VertexShaderInterfaceError::OutputFieldCannotHaveSeveralIdentifiers(i, field.clone()));
            }

            outputs.push(vertex_shader_output_field_to_ext_decl(&field));
          }

          Ok(outputs)
        }
        _ => Err(VertexShaderInterfaceError::OutputTypeMustBeAStruct(ty.clone()))
      }
    }
    _ => Err(VertexShaderInterfaceError::OutputTypeMustBeAStruct(ty.clone()))
  }
}

fn vertex_shader_output_field_to_ext_decl(field: &StructFieldSpecifier) -> ExternalDeclaration {
  let fsty = FullySpecifiedType {
    qualifier: field.qualifier.clone(),
    ty: field.ty.clone()
  };
  let decl = SingleDeclaration {
    ty: fsty,
    name: Some(field.identifiers[0].0.clone()),
    array_specifier: field.identifiers[0].1.clone(),
    initializer: None
  };

  ExternalDeclaration::Declaration(
    Declaration::InitDeclaratorList(
      InitDeclaratorList {
        head: decl,
        tail: Vec::new()
      }
    )
  )
}

/// Class of errors that can happen in dependencies.
#[derive(Clone, Debug, PartialEq)]
pub enum DepsError {
  /// If a module’s dependencies has any cycle, the dependencies are unusable and the cycle is
  /// returned.
  Cycle(ModuleKey, ModuleKey),
  /// There was a loading error of a module.
  LoadError(ModuleKey)
}

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct ModuleKey(String);

impl ModuleKey {
  pub fn new(key: &str) -> Self {
    ModuleKey(key.to_owned())
  }
}

impl CacheKey for ModuleKey {
  type Target = Module;
}

impl StoreKey for ModuleKey {
  fn key_to_path(&self) -> PathBuf {
    PathBuf::from(self.0.replace(".", "/") + ".spsl")
  }
}

impl Load for Module {
  fn load<K>(key: &K, _: &mut Store) -> Result<LoadResult<Self>, LoadError> where K: StoreKey<Target = Self> {
    let path = key.key_to_path();

    let mut fh = File::open(&path).map_err(|_| LoadError::FileNotFound(path.into()))?;
    let mut src = String::new();
    let _ = fh.read_to_string(&mut src);

    match parser::parse_str(&src[..], parser::module) {
      parser::ParseResult::Ok(module) => {
        Ok(Module(module).into())
      }
      parser::ParseResult::Err(e) => Err(LoadError::ConversionFailed(format!("{:?}", e))),
      _ => Err(LoadError::ConversionFailed("incomplete input".to_owned()))
    }
  }
}

<|endoftext|>


<commit_before>use unicode_width::{UnicodeWidthStr,UnicodeWidthChar};
use super::Renderer;

/// State corresponding to a partially constructed line.
struct PartialLine {
    text: String,
    /// The width in character cells of the text, or
    /// current position.
    pos: usize,
}

impl PartialLine {
    pub fn new() -> PartialLine {
        PartialLine {
            text: String::new(),
            pos: 0,
        }
    }
}

/// A renderer which just outputs plain text.
pub struct TextRenderer {
    width: usize,
    lines: Vec<String>,
    /// True at the end of a block, meaning we should add
    /// a blank line if any other text is added.
    at_block_end: bool,
    partial_line: Option<PartialLine>,
}

impl TextRenderer {
    /// Construct a new empty TextRenderer.
    pub fn new(width: usize) -> TextRenderer {
        html_trace!("new({})", width);
        TextRenderer {
            width: width,
            lines: Vec::new(),
            at_block_end: false,
            partial_line: None,
        }
    }

    /// Take the partial line out of self, or create one
    /// if there wasn't one.
    fn take_partial_line(&mut self) -> PartialLine {
        if let Some(p) = self.partial_line.take() {
            p
        } else {
            PartialLine::new()
        }
    }

    pub fn add_subblock(&mut self, s: &str) {
        html_trace!("add_subblock({}, {})", self.width, s);
        self.lines.extend(s.lines().map(|l| l.into()));
    }

    fn push_line(&mut self, s: String) {
        self.lines.push(s);
    }
    fn flush_line(&mut self) {
        if let Some(s) = self.partial_line.take() {
            if s.text.len() > 0 {
                self.push_line(s.text);
            }
        }
    }

    pub fn into_string(mut self) -> String {
        self.flush_line();
        let mut result = String::new();
        for s in self.lines.into_iter() {
            result.push_str(&s);
            result.push('\n');
        }
        html_trace!("into_string({}, {:?})", self.width, result);
        result
    }

    fn into_lines(mut self) -> Vec<String> {
        self.flush_line();
        self.lines
    }
}

impl Renderer for TextRenderer {
    type Sub = TextRenderer;

    fn add_empty_line(&mut self) {
        html_trace!("add_empty_line()");
        self.flush_line();
        self.lines.push("".into());
        html_trace_quiet!("add_empty_line: at_block_end <- false");
        self.at_block_end = false;
        html_trace_quiet!("add_empty_line: new lines: {:?}", self.lines);
    }

    fn new_sub_renderer(&self, width: usize) -> Self::Sub {
        TextRenderer::new(width)
    }

    fn start_block(&mut self) {
        html_trace!("start_block({})", self.width);
        self.flush_line();
        if self.lines.len() > 0 {
            self.add_empty_line();
        }
        html_trace_quiet!("start_block; at_block_end <- false");
        self.at_block_end = false;
    }

    fn add_preformatted_block(&mut self, text: &str) {
        html_trace!("add_block({}, {})", self.width, text);
        self.start_block();
        self.add_subblock(text);
        html_trace_quiet!("add_block: at_block_end <- true");
        self.at_block_end = true;
    }

    fn end_block(&mut self) {
        self.at_block_end = true;
    }

    fn add_inline_text(&mut self, text: &str) {
        html_trace!("add_inline_text({}, {})", self.width, text);
        let mut partial = self.take_partial_line();
        for word in text.split_whitespace() {
            if self.width <= (partial.pos + 1) {
                self.push_line(partial.text);
                partial = self.take_partial_line();
            }
            let space_left = self.width - partial.pos - 1;
            let word_width = UnicodeWidthStr::width(word);
            if word_width <= space_left {
                /* It fits; no problem.  Add a space if not at the
                 * start of line.*/
                if partial.pos > 0 {
                    partial.text.push(' ');
                    partial.pos += 1;
                }
                partial.text.push_str(word);
                partial.pos += word_width;
                continue;
            }

            /* It doesn't fit.  If we're not at the start of the line,
             * then go to a new line. */
            if partial.pos > 0 {
                self.push_line(partial.text);
                partial = self.take_partial_line();
            }

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

                    partial.text.push(c);
                    partial.pos += c_width;
                }
            } else {
                partial.text.push_str(word);
                partial.pos += word_width;
            }
        }
        self.partial_line = Some(partial);
    }

    fn width(&self) -> usize {
        self.width
    }

    fn add_block_line(&mut self, line: &str)
    {
        self.add_subblock(line);
    }

    fn append_subrender<'a, I>(&mut self, other: Self::Sub,
                               prefixes: I)
                           where I:Iterator<Item=&'a str>
    {
        self.flush_line();
        self.lines.extend(other.into_lines()
                               .into_iter()
                               .zip(prefixes)
                               .map(|(line, prefix)| prefix.to_string() + &line));
    }

    fn append_columns<I>(&mut self, cols: I, separator: &str)
                           where I:IntoIterator<Item=Self::Sub> {
        self.flush_line();

        let line_sets = cols.into_iter()
                            .map(|sub_r| {
                                let width = sub_r.width;
                                (width, sub_r.into_lines()
                                             .into_iter()
                                             .map(|line| format!("{: <width$}", width=width))
                                             .collect())
                                 })
                            .collect::<Vec<(usize, Vec<String>)>>();

        let cell_height = line_sets.iter()
                                   .map(|&(_, ref v)| v.len())
                                   .max().unwrap_or(0);
        let spaces:String = (0..self.width).map(|_| ' ').collect();
        for i in 0..cell_height {
            let mut line = String::new();
            for (cellno, &(width, ref ls)) in line_sets.iter().enumerate() {
                let piece = ls.get(i).map(|s| s.as_str()).unwrap_or(&spaces[0..width]);
                line.push_str(piece);
                if cellno != line_sets.len()-1 {
                    line.push('|')
                }
            }
            self.add_block_line(&line);
        }
    }

    fn empty(&self) -> bool {
        self.lines.len() == 0 && self.partial_line.is_none()
    }

    fn text_len(&self) -> usize {
        let mut result = 0;
        for line in &self.lines {
            result += UnicodeWidthStr::width(line.as_str());
        }
        if let Some(ref line) = self.partial_line {
            result += line.pos;
        }
        result
    }
}<commit_msg>Fix table output.<commit_after>use unicode_width::{UnicodeWidthStr,UnicodeWidthChar};
use super::Renderer;

/// State corresponding to a partially constructed line.
struct PartialLine {
    text: String,
    /// The width in character cells of the text, or
    /// current position.
    pos: usize,
}

impl PartialLine {
    pub fn new() -> PartialLine {
        PartialLine {
            text: String::new(),
            pos: 0,
        }
    }
}

/// A renderer which just outputs plain text.
pub struct TextRenderer {
    width: usize,
    lines: Vec<String>,
    /// True at the end of a block, meaning we should add
    /// a blank line if any other text is added.
    at_block_end: bool,
    partial_line: Option<PartialLine>,
}

impl TextRenderer {
    /// Construct a new empty TextRenderer.
    pub fn new(width: usize) -> TextRenderer {
        html_trace!("new({})", width);
        TextRenderer {
            width: width,
            lines: Vec::new(),
            at_block_end: false,
            partial_line: None,
        }
    }

    /// Take the partial line out of self, or create one
    /// if there wasn't one.
    fn take_partial_line(&mut self) -> PartialLine {
        if let Some(p) = self.partial_line.take() {
            p
        } else {
            PartialLine::new()
        }
    }

    pub fn add_subblock(&mut self, s: &str) {
        html_trace!("add_subblock({}, {})", self.width, s);
        self.lines.extend(s.lines().map(|l| l.into()));
    }

    fn push_line(&mut self, s: String) {
        self.lines.push(s);
    }
    fn flush_line(&mut self) {
        if let Some(s) = self.partial_line.take() {
            if s.text.len() > 0 {
                self.push_line(s.text);
            }
        }
    }

    pub fn into_string(mut self) -> String {
        self.flush_line();
        let mut result = String::new();
        for s in self.lines.into_iter() {
            result.push_str(&s);
            result.push('\n');
        }
        html_trace!("into_string({}, {:?})", self.width, result);
        result
    }

    fn into_lines(mut self) -> Vec<String> {
        self.flush_line();
        self.lines
    }
}

impl Renderer for TextRenderer {
    type Sub = TextRenderer;

    fn add_empty_line(&mut self) {
        html_trace!("add_empty_line()");
        self.flush_line();
        self.lines.push("".into());
        html_trace_quiet!("add_empty_line: at_block_end <- false");
        self.at_block_end = false;
        html_trace_quiet!("add_empty_line: new lines: {:?}", self.lines);
    }

    fn new_sub_renderer(&self, width: usize) -> Self::Sub {
        TextRenderer::new(width)
    }

    fn start_block(&mut self) {
        html_trace!("start_block({})", self.width);
        self.flush_line();
        if self.lines.len() > 0 {
            self.add_empty_line();
        }
        html_trace_quiet!("start_block; at_block_end <- false");
        self.at_block_end = false;
    }

    fn add_preformatted_block(&mut self, text: &str) {
        html_trace!("add_block({}, {})", self.width, text);
        self.start_block();
        self.add_subblock(text);
        html_trace_quiet!("add_block: at_block_end <- true");
        self.at_block_end = true;
    }

    fn end_block(&mut self) {
        self.at_block_end = true;
    }

    fn add_inline_text(&mut self, text: &str) {
        html_trace!("add_inline_text({}, {})", self.width, text);
        let mut partial = self.take_partial_line();
        for word in text.split_whitespace() {
            if self.width <= (partial.pos + 1) {
                self.push_line(partial.text);
                partial = self.take_partial_line();
            }
            let space_left = self.width - partial.pos - 1;
            let word_width = UnicodeWidthStr::width(word);
            if word_width <= space_left {
                /* It fits; no problem.  Add a space if not at the
                 * start of line.*/
                if partial.pos > 0 {
                    partial.text.push(' ');
                    partial.pos += 1;
                }
                partial.text.push_str(word);
                partial.pos += word_width;
                continue;
            }

            /* It doesn't fit.  If we're not at the start of the line,
             * then go to a new line. */
            if partial.pos > 0 {
                self.push_line(partial.text);
                partial = self.take_partial_line();
            }

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

                    partial.text.push(c);
                    partial.pos += c_width;
                }
            } else {
                partial.text.push_str(word);
                partial.pos += word_width;
            }
        }
        self.partial_line = Some(partial);
    }

    fn width(&self) -> usize {
        self.width
    }

    fn add_block_line(&mut self, line: &str)
    {
        self.add_subblock(line);
    }

    fn append_subrender<'a, I>(&mut self, other: Self::Sub,
                               prefixes: I)
                           where I:Iterator<Item=&'a str>
    {
        self.flush_line();
        self.lines.extend(other.into_lines()
                               .into_iter()
                               .zip(prefixes)
                               .map(|(line, prefix)| prefix.to_string() + &line));
    }

    fn append_columns<I>(&mut self, cols: I, separator: &str)
                           where I:IntoIterator<Item=Self::Sub> {
        self.flush_line();

        let line_sets = cols.into_iter()
                            .map(|sub_r| {
                                let width = sub_r.width;
                                (width, sub_r.into_lines()
                                             .into_iter()
                                             .map(|line| format!("{: <width$}", line, width=width))
                                             .collect())
                                 })
                            .collect::<Vec<(usize, Vec<String>)>>();

        let cell_height = line_sets.iter()
                                   .map(|&(_, ref v)| v.len())
                                   .max().unwrap_or(0);
        let spaces:String = (0..self.width).map(|_| ' ').collect();
        for i in 0..cell_height {
            let mut line = String::new();
            for (cellno, &(width, ref ls)) in line_sets.iter().enumerate() {
                let piece = ls.get(i).map(|s| s.as_str()).unwrap_or(&spaces[0..width]);
                line.push_str(piece);
                if cellno != line_sets.len()-1 {
                    line.push('|')
                }
            }
            self.add_block_line(&line);
        }
    }

    fn empty(&self) -> bool {
        self.lines.len() == 0 && self.partial_line.is_none()
    }

    fn text_len(&self) -> usize {
        let mut result = 0;
        for line in &self.lines {
            result += UnicodeWidthStr::width(line.as_str());
        }
        if let Some(ref line) = self.partial_line {
            result += line.pos;
        }
        result
    }
}<|endoftext|>