<commit_before>/*

TODO
-parser in eigenes struct packen. zumindest sollten die functionen raus aus dem globalen

----------------------------------------
Grammatik:

LL(1)
----------------------------------------|
S -> Passage S2                         |
S2 -> S                                 |
S2 -> ɛ                                 |
Passage -> PassageName PassageContent   |
PassageContent -> TextPassage B         |
PassageContent -> Formatting B          |
PassageContent -> Newline B             |
B -> PassageContent                     |
B -> ɛ                                  |
----------------------------------------|

Hello World im LL(1)-Parser:
token: [TokPassageName("Start"), TokText("Hello World\n")]

input                   | stack                         | output                              |
------------------------+-------------------------------+-------------------------------------+---------------------------------------------------
PassageName TextPassage | S                             | S->Passage S'                       | passage and s' as child of S
        --||--          | Passage S2                    | Passage->PassageName PassageContent | passageName and passagecontent as child of passage
        --||--          | PassageName PassageContent S2 |                                     | gehe bei den token 1 weiter
TextPassage             | PassageContent S2             | PassageContent->TextPassage B       | textpassage and b as child of PassageContent
        --||--          | TextPassage B S'              |                                     | gehe bei den token 1 weiter
empty                   | B S'                          | B->ɛ                                |
empty                   | S'                            | S' -> ɛ                             |
empty                   | empty                         | ACCEPT                              |
------------------------+-------------------------------+-------------------------------------|---------------------------------------------------

*/

pub use frontend::lexer::Token;

//==============================
// grammar

#[derive(Debug)]
enum NonTerminalType {
    S,
    S2,
    Passage,
    PassageContent,
    B
}

pub fn temp_create_parse_tree(tokens: Vec<Token>) {

    let mut parser: Parser = Parser::new(tokens);
    parser.start();
}

//==============================

struct Parser {
    tree: ParseTree,
    stack: Stack,
    tokens: Vec<Token>,
    lookahead: usize
}

impl Parser {
    pub fn new(tokens: Vec<Token>) -> Parser {
        Parser {
            tree: ParseTree::new(),
            stack: Stack::new(),
            tokens: tokens,
            lookahead: 0
        }
    }

    pub fn start(&mut self) {
        self.stack.push_start();
        //let mut lookahead = 0;

        // stack parser...
        while !self.stack.is_empty() {
            let mut is_terminal;
            let top_path;

            // check if the top-element of the stack is a terminal or non terminal
            if let Some(top) = self.stack.last() {
                is_terminal = self.tree.root.is_terminal( top.to_vec() );
                top_path = top.to_vec();
            } else {
                panic!("error (but can't happen, becouse the stack can't be empty becouse of the while loop)");
            }

            self.stack.pop();

            if is_terminal {
                self.next_token();

            } else {

                let to_add_path: Vec<usize> = top_path.to_vec();

                // parse table in code
                match self.tree.root.get_non_terminal(top_path) {
                    &NonTerminalType::S => {
                        if let Some(token) = self.tokens.get(self.lookahead) {
                            match token {
                                &Token::TokPassageName (_) => {
                                    self.tree.add_two_nodes(NodeType::new_non_terminal(NonTerminalType::Passage), NodeType::new_non_terminal(NonTerminalType::S2), &to_add_path);
                                    self.stack.push_path(2, to_add_path);
                                },
                                _ => { }
                            }
                        }
                    },
                    &NonTerminalType::S2 => {
                        // check follow...
                        if let Some(token) = self.tokens.get(self.lookahead) {
                            match token {
                                &Token::TokPassageName (_) => {
                                    self.tree.add_one_node(NodeType::new_non_terminal(NonTerminalType::S), &to_add_path);
                                    self.stack.push_path(1, to_add_path);
                                },
                                _ => { }
                            }
                        }
                    },
                    &NonTerminalType::Passage => {
                        if let Some(token) = self.tokens.get(self.lookahead) {
                            match token {
                                &Token::TokPassageName (ref name) => {
                                    let new_token: Token = Token::TokPassageName(name.clone());
                                    self.tree.add_two_nodes(NodeType::new_terminal(new_token), NodeType::new_non_terminal(NonTerminalType::PassageContent), &to_add_path);
                                    self.stack.push_path(2, to_add_path);
                                },
                                _ => { }
                            }
                        }
                    },
                    &NonTerminalType::PassageContent => {
                         if let Some(token) = self.tokens.get(self.lookahead) {
                            match token {
                                &Token::TokText (ref text) => {
                                    let new_token: Token = Token::TokText(text.clone());
                                    self.tree.add_two_nodes(NodeType::new_terminal(new_token), NodeType::new_non_terminal(NonTerminalType::B), &to_add_path);
                                    self.stack.push_path(2, to_add_path);
                                },
                                _ => { }
                            }
                        }
                    },
                    &NonTerminalType::B => {
                        // not implemented
                    }
                }
            }
        }

        debug!("Parse Tree");
        self.tree.root.print(0);
    }

    fn next_token(&mut self) {
        self.lookahead = self.lookahead + 1;
    }
}

//==============================

struct Stack {
    data: Vec<Vec<usize>>
}

impl Stack {
    pub fn new() -> Stack {
        Stack { data: Vec::new() }
    }

    fn push_start(&mut self) {
        self.data.push(vec![]);
    }

    // save the path of the nodes in the tree to the stack
    // the right part of the production
    // should be on the stack in reverse order
    fn push_path(&mut self, count_elements: u8, to_add_path: Vec<usize>) {
        for i in 0..count_elements {
            let mut path: Vec<usize> = to_add_path.to_vec();
            path.push((count_elements-i-1) as usize);
            self.data.push(path);
        }
    }

    fn is_empty(&self) -> bool {
        self.data.is_empty()
    }

    fn last(&self) -> Option<&Vec<usize>> {
        self.data.last()
    }

    fn pop(&mut self) -> Option<Vec<usize>> {
        self.data.pop()
    }
}

//==============================

struct ParseTree {
    root: NodeType
}

impl ParseTree {
    pub fn new() -> ParseTree {
        ParseTree {
            root: NodeType::new_non_terminal(NonTerminalType::S)
        }
    }

    // adds one nodes to childs at the path
    pub fn add_one_node(&mut self, child: NodeType, to_add_path: &Vec<usize>) {
        self.root.add_child_at(&to_add_path, child);
    }

    // adds two nodes to childs at the path
    pub fn add_two_nodes(&mut self, child1: NodeType, child2: NodeType, to_add_path: &Vec<usize>) {
        self.root.add_child_at(&to_add_path, child1);
        self.root.add_child_at(&to_add_path, child2);
    }
}

//==============================

struct NodeNonTerminal {
    category: NonTerminalType,
    childs: Vec<NodeType>
}

struct NodeTerminal {
    category: Token
}

//#[derive(Debug)]
enum NodeType {
    NonTerminal (NodeNonTerminal),
    Terminal (NodeTerminal)
}

impl NodeType {

    pub fn new_terminal(terminal: Token) -> NodeType {
        NodeType::Terminal(NodeTerminal  { category: terminal })
    }

    pub fn new_non_terminal(non_terminal: NonTerminalType) -> NodeType {
        NodeType::NonTerminal(NodeNonTerminal { category: non_terminal, childs: Vec::new() })
    }

    // prints a node
    pub fn print(&self, indent: usize) {
        let mut spaces = "".to_string();
        for _ in 0..indent {
            spaces.push_str(" ");
        }

        match self {
            &NodeType::NonTerminal(ref t) => {
                debug!("{}|- Node: {:?}", spaces, t.category);
                for child in &t.childs {
                    child.print(indent+2);
                }
            }
            &NodeType::Terminal(ref t) => { debug!("{}|- Terminal: {:?}", spaces, t.category); }
        }
    }

    // returns a non_terminal of the path
    pub fn get_non_terminal(&self, path: Vec<usize>) -> &NonTerminalType {
        match self {
            &NodeType::NonTerminal(ref node) => {
                if let Some(index) = path.first() {
                    let mut new_path: Vec<usize> = path.to_vec();
                    new_path.remove(0);
                    return node.childs[*index].get_non_terminal(new_path);
                } else {
                    return &node.category;
                }
            },
            _ => panic!("error")
        }
    }

    // adds a node to the childs in path
    pub fn add_child_at(&mut self, path: &[usize], child: NodeType) {
        match self {
            &mut NodeType::NonTerminal (ref mut node) => {
                if let Some(index) = path.first() {
                    let mut new_path: Vec<usize> = path.to_vec();
                    new_path.remove(0);
                    node.childs[*index].add_child_at(&new_path, child);
                } else {
                    node.childs.push(child);
                }
            },
            _ => panic!("error")
        }
    }

    // checks if the node of the path is a terminal or not
    pub fn is_terminal(&self, path: Vec<usize>) -> bool {
        match self {
            &NodeType::NonTerminal(ref node) => {
                if let Some(index) = path.first() {
                    let mut new_path: Vec<usize> = path.to_vec();
                    new_path.remove(0);
                    return node.childs[*index].is_terminal(new_path);
                }

                return false
            },
            &NodeType::Terminal(_) => return true
        }

        false
    }
}

#[test]
fn it_works() {
}
<commit_msg>remove complexity of parser<commit_after>/*

TODO
-parser in eigenes struct packen. zumindest sollten die functionen raus aus dem globalen

----------------------------------------
Grammatik:

LL(1)
----------------------------------------|
S -> Passage S2                         |
S2 -> S                                 |
S2 -> ɛ                                 |
Passage -> PassageName PassageContent   |
PassageContent -> TextPassage B         |
PassageContent -> Formatting B          |
PassageContent -> Newline B             |
B -> PassageContent                     |
B -> ɛ                                  |
----------------------------------------|

Hello World im LL(1)-Parser:
token: [TokPassageName("Start"), TokText("Hello World\n")]

input                   | stack                         | output                              |
------------------------+-------------------------------+-------------------------------------+---------------------------------------------------
PassageName TextPassage | S                             | S->Passage S'                       | passage and s' as child of S
        --||--          | Passage S2                    | Passage->PassageName PassageContent | passageName and passagecontent as child of passage
        --||--          | PassageName PassageContent S2 |                                     | gehe bei den token 1 weiter
TextPassage             | PassageContent S2             | PassageContent->TextPassage B       | textpassage and b as child of PassageContent
        --||--          | TextPassage B S'              |                                     | gehe bei den token 1 weiter
empty                   | B S'                          | B->ɛ                                |
empty                   | S'                            | S' -> ɛ                             |
empty                   | empty                         | ACCEPT                              |
------------------------+-------------------------------+-------------------------------------|---------------------------------------------------

*/

pub use frontend::lexer::Token;

//==============================
// grammar

//#[derive(Debug)]
#[derive(Debug, Copy, Clone)]
enum NonTerminalType {
    S,
    S2,
    Passage,
    PassageContent,
    B
}
/*impl Copy for NonTerminalType {}
impl Clone for NonTerminalType {
    fn clone(&self) -> NonTerminalType { *self }
}*/
//impl Clone for NonTerminalType {}

pub fn temp_create_parse_tree(tokens: Vec<Token>) {

    let mut parser: Parser = Parser::new(tokens);
    parser.start();
}

//==============================

struct Parser {
    tree: ParseTree,
    stack: Stack,
    tokens: Vec<Token>,
    lookahead: usize
}

impl Parser {
    pub fn new(tokens: Vec<Token>) -> Parser {
        Parser {
            tree: ParseTree::new(),
            stack: Stack::new(),
            tokens: tokens,
            lookahead: 0
        }
    }

    pub fn start(&mut self) {
        self.stack.push_start();
        //let mut lookahead = 0;

        // stack parser...
        while !self.stack.is_empty() {
            let mut is_terminal;
            let top_path;

            // check if the top-element of the stack is a terminal or non terminal
            if let Some(top) = self.stack.last() {
                is_terminal = self.tree.root.is_terminal( top.to_vec() );
                top_path = top.to_vec();
            } else {
                panic!("error (but can't happen, becouse the stack can't be empty becouse of the while loop)");
            }

            self.stack.pop();

            if is_terminal {
                self.next_token();

            } else {
                let to_add_path: Vec<usize> = top_path.to_vec();

                let current_token;
                if let Some(token) = self.tokens.get(self.lookahead) {
                    current_token = token
                } else {
                    // no token left
                    // only ɛ-productions could be here
                    // these productions should be poped of the stack
                    continue;
                }

                // parse table in code
                let from_to: (NonTerminalType, &Token) = (self.tree.root.get_non_terminal(top_path).clone(), current_token);

                match from_to {
                    (NonTerminalType::S, &Token::TokPassageName (_)) => {
                        self.tree.add_two_nodes(NodeType::new_non_terminal(NonTerminalType::Passage), NodeType::new_non_terminal(NonTerminalType::S2), &to_add_path);
                        self.stack.push_path(2, to_add_path);
                    },
                    (NonTerminalType::S2, &Token::TokPassageName (_)) => {
                        self.tree.add_one_node(NodeType::new_non_terminal(NonTerminalType::S), &to_add_path);
                        self.stack.push_path(1, to_add_path);
                    },
                    (NonTerminalType::Passage, &Token::TokPassageName (ref name)) => {
                        let new_token: Token = Token::TokPassageName(name.clone());
                        self.tree.add_two_nodes(NodeType::new_terminal(new_token), NodeType::new_non_terminal(NonTerminalType::PassageContent), &to_add_path);
                        self.stack.push_path(2, to_add_path);
                    },
                    (NonTerminalType::PassageContent, &Token::TokText (ref text)) => {
                        let new_token: Token = Token::TokText(text.clone());
                        self.tree.add_two_nodes(NodeType::new_terminal(new_token), NodeType::new_non_terminal(NonTerminalType::B), &to_add_path);
                        self.stack.push_path(2, to_add_path);
                    },
                    (NonTerminalType::B, _) => {
                        // not implemented
                    }
                    _ => {

                    }
                }
            }
        }

        debug!("Parse Tree");
        self.tree.root.print(0);
    }

    fn next_token(&mut self) {
        self.lookahead = self.lookahead + 1;
    }
}

//==============================

struct Stack {
    data: Vec<Vec<usize>>
}

impl Stack {
    pub fn new() -> Stack {
        Stack { data: Vec::new() }
    }

    fn push_start(&mut self) {
        self.data.push(vec![]);
    }

    // save the path of the nodes in the tree to the stack
    // the right part of the production
    // should be on the stack in reverse order
    fn push_path(&mut self, count_elements: u8, to_add_path: Vec<usize>) {
        for i in 0..count_elements {
            let mut path: Vec<usize> = to_add_path.to_vec();
            path.push((count_elements-i-1) as usize);
            self.data.push(path);
        }
    }

    fn is_empty(&self) -> bool {
        self.data.is_empty()
    }

    fn last(&self) -> Option<&Vec<usize>> {
        self.data.last()
    }

    fn pop(&mut self) -> Option<Vec<usize>> {
        self.data.pop()
    }
}

//==============================

struct ParseTree {
    root: NodeType
}

impl ParseTree {
    pub fn new() -> ParseTree {
        ParseTree {
            root: NodeType::new_non_terminal(NonTerminalType::S)
        }
    }

    // adds one nodes to childs at the path
    pub fn add_one_node(&mut self, child: NodeType, to_add_path: &Vec<usize>) {
        self.root.add_child_at(&to_add_path, child);
    }

    // adds two nodes to childs at the path
    pub fn add_two_nodes(&mut self, child1: NodeType, child2: NodeType, to_add_path: &Vec<usize>) {
        self.root.add_child_at(&to_add_path, child1);
        self.root.add_child_at(&to_add_path, child2);
    }
}

//==============================

struct NodeNonTerminal {
    category: NonTerminalType,
    childs: Vec<NodeType>
}

struct NodeTerminal {
    category: Token
}

//#[derive(Debug)]
enum NodeType {
    NonTerminal (NodeNonTerminal),
    Terminal (NodeTerminal)
}

impl NodeType {

    pub fn new_terminal(terminal: Token) -> NodeType {
        NodeType::Terminal(NodeTerminal  { category: terminal })
    }

    pub fn new_non_terminal(non_terminal: NonTerminalType) -> NodeType {
        NodeType::NonTerminal(NodeNonTerminal { category: non_terminal, childs: Vec::new() })
    }

    // prints a node
    pub fn print(&self, indent: usize) {
        let mut spaces = "".to_string();
        for _ in 0..indent {
            spaces.push_str(" ");
        }

        match self {
            &NodeType::NonTerminal(ref t) => {
                debug!("{}|- Node: {:?}", spaces, t.category);
                for child in &t.childs {
                    child.print(indent+2);
                }
            }
            &NodeType::Terminal(ref t) => { debug!("{}|- Terminal: {:?}", spaces, t.category); }
        }
    }

    // returns a non_terminal of the path
    pub fn get_non_terminal(&self, path: Vec<usize>) -> &NonTerminalType {
        match self {
            &NodeType::NonTerminal(ref node) => {
                if let Some(index) = path.first() {
                    let mut new_path: Vec<usize> = path.to_vec();
                    new_path.remove(0);
                    return node.childs[*index].get_non_terminal(new_path);
                } else {
                    return &node.category;
                }
            },
            _ => panic!("error")
        }
    }

    // adds a node to the childs in path
    pub fn add_child_at(&mut self, path: &[usize], child: NodeType) {
        match self {
            &mut NodeType::NonTerminal (ref mut node) => {
                if let Some(index) = path.first() {
                    let mut new_path: Vec<usize> = path.to_vec();
                    new_path.remove(0);
                    node.childs[*index].add_child_at(&new_path, child);
                } else {
                    node.childs.push(child);
                }
            },
            _ => panic!("error")
        }
    }

    // checks if the node of the path is a terminal or not
    pub fn is_terminal(&self, path: Vec<usize>) -> bool {
        match self {
            &NodeType::NonTerminal(ref node) => {
                if let Some(index) = path.first() {
                    let mut new_path: Vec<usize> = path.to_vec();
                    new_path.remove(0);
                    return node.childs[*index].is_terminal(new_path);
                }

                return false
            },
            &NodeType::Terminal(_) => return true
        }

        false
    }
}

#[test]
fn it_works() {
}
<|endoftext|>


<commit_before>#[cfg(target_os = "linux")]
mod linux;

#[cfg(target_os = "linux")]
use self::linux::*;

#[cfg(target_os = "macos")]
mod macos;

#[cfg(target_os = "macos")]
use self::macos::*;

use std::io;
use std::ffi::{OsStr, OsString};
use std::os::unix::io::RawFd;
use std::os::unix::ffi::{OsStrExt};
use std::path::Path;
use std::mem;

use ::libc::{c_void, size_t, c_char};

use ::util::{path_to_c, name_to_c, allocate_loop};

pub struct XAttrs {
    data: Box<[u8]>,
    offset: usize,
}

impl Clone for XAttrs {
    fn clone(&self) -> Self {
        XAttrs {
            data: Vec::from(&*self.data).into_boxed_slice(),
            offset: self.offset
        }
    }
    fn clone_from(&mut self, other: &XAttrs) {
        self.offset = other.offset;

        let mut data = mem::replace(&mut self.data, Box::new([])).into_vec();
        data.extend(&*other.data);
        self.data = data.into_boxed_slice();
    }
}

// Yes, I could avoid these allocations on linux/macos. However, if we ever want to be freebsd
// compatable, we need to be able to prepend the namespace to the extended attribute names.
// Furthermore, borrowing makes the API messy.
impl Iterator for XAttrs {
    type Item = OsString;
    fn next(&mut self) -> Option<OsString> {
        let data = &self.data[self.offset..];
        if data.is_empty() {
            None
        } else {
            let end = data.iter().position(|&b| b == 0u8).unwrap(); // always null terminated (unless empty).
            self.offset = end + 1;
            Some(OsStr::from_bytes(&data[..end]).to_owned())
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        if self.data.len() == self.offset {
            (0, Some(0))
        } else {
            (1, None)
        }
    }
}

pub fn get_fd(fd: RawFd, name: &OsStr) -> io::Result<Vec<u8>> {
    let name = try!(name_to_c(name));
    unsafe {
        allocate_loop(|buf, len| fgetxattr(fd, name.as_ptr(), buf as *mut c_void, len as size_t))
    }
}

pub fn set_fd(fd: RawFd, name: &OsStr, value: &[u8]) -> io::Result<()> {
    let name = try!(name_to_c(name));
    let ret = unsafe {
        fsetxattr(
            fd,
            name.as_ptr(),
            value.as_ptr() as *const c_void,
            value.len() as size_t)
    };
    if ret != 0 {
        Err(io::Error::last_os_error())
    } else {
        Ok(())
    }
}

pub fn remove_fd(fd: RawFd, name: &OsStr) -> io::Result<()> {
    let name = try!(name_to_c(name));
    let ret = unsafe { fremovexattr(fd, name.as_ptr()) };
    if ret != 0 {
        Err(io::Error::last_os_error())
    } else {
        Ok(())
    }
}

pub fn list_fd(fd: RawFd) -> io::Result<XAttrs> {
    let vec = unsafe {
        try!(allocate_loop(|buf, len| flistxattr(fd, buf as *mut c_char, len as size_t)))
    };
    println!("{:?}", vec);
    Ok(XAttrs {
        data: vec.into_boxed_slice(),
        offset: 0,
    })
}

pub fn get_path(path: &Path, name: &OsStr) -> io::Result<Vec<u8>> {
    let name = try!(name_to_c(name));
    let path = try!(path_to_c(path));
    unsafe {
        allocate_loop(|buf, len| lgetxattr(path.as_ptr(), name.as_ptr(), buf as *mut c_void, len as size_t))
    }
}

pub fn set_path(path: &Path, name: &OsStr, value: &[u8]) -> io::Result<()> {
    let name = try!(name_to_c(name));
    let path = try!(path_to_c(path));
    let ret = unsafe {
        lsetxattr(
            path.as_ptr(),
            name.as_ptr(),
            value.as_ptr() as *const c_void,
            value.len() as size_t)
    };
    if ret != 0 {
        Err(io::Error::last_os_error())
    } else {
        Ok(())
    }
}

pub fn remove_path(path: &Path, name: &OsStr) -> io::Result<()> {
    let name = try!(name_to_c(name));
    let path = try!(path_to_c(path));
    let ret = unsafe { lremovexattr(path.as_ptr(), name.as_ptr()) };
    if ret != 0 {
        Err(io::Error::last_os_error())
    } else {
        Ok(())
    }
}

pub fn list_path(path: &Path) -> io::Result<XAttrs> {
    let path = try!(path_to_c(path));
    let vec = unsafe {
        try!(allocate_loop(|buf, len| llistxattr(path.as_ptr(), buf as *mut c_char, len as size_t)))
    };
    Ok(XAttrs {
        data: vec.into_boxed_slice(),
        offset: 0,
    })
}

<commit_msg>Fix clone for stable.<commit_after>#[cfg(target_os = "linux")]
mod linux;

#[cfg(target_os = "linux")]
use self::linux::*;

#[cfg(target_os = "macos")]
mod macos;

#[cfg(target_os = "macos")]
use self::macos::*;

use std::io;
use std::ffi::{OsStr, OsString};
use std::os::unix::io::RawFd;
use std::os::unix::ffi::{OsStrExt};
use std::path::Path;
use std::mem;

use ::libc::{c_void, size_t, c_char};

use ::util::{path_to_c, name_to_c, allocate_loop};

pub struct XAttrs {
    data: Box<[u8]>,
    offset: usize,
}

impl Clone for XAttrs {
    fn clone(&self) -> Self {
        XAttrs {
            data: Vec::from(&*self.data).into_boxed_slice(),
            offset: self.offset
        }
    }
    fn clone_from(&mut self, other: &XAttrs) {
        self.offset = other.offset;

        let mut data = mem::replace(&mut self.data, Box::new([])).into_vec();
        data.extend(other.data.iter().cloned());
        self.data = data.into_boxed_slice();
    }
}

// Yes, I could avoid these allocations on linux/macos. However, if we ever want to be freebsd
// compatable, we need to be able to prepend the namespace to the extended attribute names.
// Furthermore, borrowing makes the API messy.
impl Iterator for XAttrs {
    type Item = OsString;
    fn next(&mut self) -> Option<OsString> {
        let data = &self.data[self.offset..];
        if data.is_empty() {
            None
        } else {
            let end = data.iter().position(|&b| b == 0u8).unwrap(); // always null terminated (unless empty).
            self.offset = end + 1;
            Some(OsStr::from_bytes(&data[..end]).to_owned())
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        if self.data.len() == self.offset {
            (0, Some(0))
        } else {
            (1, None)
        }
    }
}

pub fn get_fd(fd: RawFd, name: &OsStr) -> io::Result<Vec<u8>> {
    let name = try!(name_to_c(name));
    unsafe {
        allocate_loop(|buf, len| fgetxattr(fd, name.as_ptr(), buf as *mut c_void, len as size_t))
    }
}

pub fn set_fd(fd: RawFd, name: &OsStr, value: &[u8]) -> io::Result<()> {
    let name = try!(name_to_c(name));
    let ret = unsafe {
        fsetxattr(
            fd,
            name.as_ptr(),
            value.as_ptr() as *const c_void,
            value.len() as size_t)
    };
    if ret != 0 {
        Err(io::Error::last_os_error())
    } else {
        Ok(())
    }
}

pub fn remove_fd(fd: RawFd, name: &OsStr) -> io::Result<()> {
    let name = try!(name_to_c(name));
    let ret = unsafe { fremovexattr(fd, name.as_ptr()) };
    if ret != 0 {
        Err(io::Error::last_os_error())
    } else {
        Ok(())
    }
}

pub fn list_fd(fd: RawFd) -> io::Result<XAttrs> {
    let vec = unsafe {
        try!(allocate_loop(|buf, len| flistxattr(fd, buf as *mut c_char, len as size_t)))
    };
    println!("{:?}", vec);
    Ok(XAttrs {
        data: vec.into_boxed_slice(),
        offset: 0,
    })
}

pub fn get_path(path: &Path, name: &OsStr) -> io::Result<Vec<u8>> {
    let name = try!(name_to_c(name));
    let path = try!(path_to_c(path));
    unsafe {
        allocate_loop(|buf, len| lgetxattr(path.as_ptr(), name.as_ptr(), buf as *mut c_void, len as size_t))
    }
}

pub fn set_path(path: &Path, name: &OsStr, value: &[u8]) -> io::Result<()> {
    let name = try!(name_to_c(name));
    let path = try!(path_to_c(path));
    let ret = unsafe {
        lsetxattr(
            path.as_ptr(),
            name.as_ptr(),
            value.as_ptr() as *const c_void,
            value.len() as size_t)
    };
    if ret != 0 {
        Err(io::Error::last_os_error())
    } else {
        Ok(())
    }
}

pub fn remove_path(path: &Path, name: &OsStr) -> io::Result<()> {
    let name = try!(name_to_c(name));
    let path = try!(path_to_c(path));
    let ret = unsafe { lremovexattr(path.as_ptr(), name.as_ptr()) };
    if ret != 0 {
        Err(io::Error::last_os_error())
    } else {
        Ok(())
    }
}

pub fn list_path(path: &Path) -> io::Result<XAttrs> {
    let path = try!(path_to_c(path));
    let vec = unsafe {
        try!(allocate_loop(|buf, len| llistxattr(path.as_ptr(), buf as *mut c_char, len as size_t)))
    };
    Ok(XAttrs {
        data: vec.into_boxed_slice(),
        offset: 0,
    })
}

<|endoftext|>


<commit_before>// @has macros/macro.my_macro.html //pre 'macro_rules! my_macro {'
// @has - //pre '() => { ... };'
// @has - //pre '($a:tt) => { ... };'
// @has - //pre '($e:expr) => { ... };'
#[macro_export]
macro_rules! my_macro {
    () => [];
    ($a:tt) => ();
    ($e:expr) => {};
}
<commit_msg>Add rustdoc test.<commit_after>// @has macros/macro.my_macro.html //pre 'macro_rules! my_macro {'
// @has - //pre '() => { ... };'
// @has - //pre '($a:tt) => { ... };'
// @has - //pre '($e:expr) => { ... };'
#[macro_export]
macro_rules! my_macro {
    () => [];
    ($a:tt) => ();
    ($e:expr) => {};
}

// Check that exported macro defined in a module are shown at crate root.
// @has macros/macro.my_sub_macro.html //pre 'macro_rules! my_sub_macro {'
// @has - //pre '() => { ... };'
// @has - //pre '($a:tt) => { ... };'
// @has - //pre '($e:expr) => { ... };'
mod sub {
    #[macro_export]
    macro_rules! my_sub_macro {
        () => {};
        ($a:tt) => {};
        ($e:expr) => {};
    }
}
<|endoftext|>


<commit_before>//! Basic syntax highlighting functionality.
//!
//! This module uses librustc_ast's lexer to provide token-based highlighting for
//! the HTML documentation generated by rustdoc.
//!
//! Use the `render_with_highlighting` to highlight some rust code.

use crate::html::escape::Escape;

use std::fmt::{Display, Write};
use std::iter::Peekable;

use rustc_lexer::{LiteralKind, TokenKind};
use rustc_span::symbol::Ident;
use rustc_span::with_default_session_globals;

/// Highlights `src`, returning the HTML output.
crate fn render_with_highlighting(
    src: String,
    class: Option<&str>,
    playground_button: Option<&str>,
    tooltip: Option<(&str, &str)>,
) -> String {
    debug!("highlighting: ================\n{}\n==============", src);
    let mut out = String::with_capacity(src.len());
    if let Some((tooltip, class)) = tooltip {
        write!(
            out,
            "

ⓘ{}

",
            class, tooltip
        )
        .unwrap();
    }

    write_header(&mut out, class);
    write_code(&mut out, &src);
    write_footer(&mut out, playground_button);

    out
}

fn write_header(out: &mut String, class: Option<&str>) {
    write!(out, "

\n", class.unwrap_or_default())
        .unwrap()
}

fn write_code(out: &mut String, src: &str) {
    // This replace allows to fix how the code source with DOS backline characters is displayed.
    let src = src.replace("\r\n", "\n");
    Classifier::new(&src).highlight(&mut |highlight| {
        match highlight {
            Highlight::Token { text, class } => string(out, Escape(text), class),
            Highlight::EnterSpan { class } => enter_span(out, class),
            Highlight::ExitSpan => exit_span(out),
        };
    });
}

fn write_footer(out: &mut String, playground_button: Option<&str>) {
    write!(out, "
{}
\n", playground_button.unwrap_or_default()).unwrap()
}

/// How a span of text is classified. Mostly corresponds to token kinds.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum Class {
    None,
    Comment,
    DocComment,
    Attribute,
    KeyWord,
    // Keywords that do pointer/reference stuff.
    RefKeyWord,
    Self_,
    Op,
    Macro,
    MacroNonTerminal,
    String,
    Number,
    Bool,
    Ident,
    Lifetime,
    PreludeTy,
    PreludeVal,
    QuestionMark,
}

impl Class {
    /// Returns the css class expected by rustdoc for each `Class`.
    fn as_html(self) -> &'static str {
        match self {
            Class::None => "",
            Class::Comment => "comment",
            Class::DocComment => "doccomment",
            Class::Attribute => "attribute",
            Class::KeyWord => "kw",
            Class::RefKeyWord => "kw-2",
            Class::Self_ => "self",
            Class::Op => "op",
            Class::Macro => "macro",
            Class::MacroNonTerminal => "macro-nonterminal",
            Class::String => "string",
            Class::Number => "number",
            Class::Bool => "bool-val",
            Class::Ident => "ident",
            Class::Lifetime => "lifetime",
            Class::PreludeTy => "prelude-ty",
            Class::PreludeVal => "prelude-val",
            Class::QuestionMark => "question-mark",
        }
    }
}

enum Highlight<'a> {
    Token { text: &'a str, class: Class },
    EnterSpan { class: Class },
    ExitSpan,
}

struct TokenIter<'a> {
    src: &'a str,
}

impl Iterator for TokenIter<'a> {
    type Item = (TokenKind, &'a str);
    fn next(&mut self) -> Option<(TokenKind, &'a str)> {
        if self.src.is_empty() {
            return None;
        }
        let token = rustc_lexer::first_token(self.src);
        let (text, rest) = self.src.split_at(token.len);
        self.src = rest;
        Some((token.kind, text))
    }
}

/// Processes program tokens, classifying strings of text by highlighting
/// category (`Class`).
struct Classifier<'a> {
    tokens: Peekable<TokenIter<'a>>,
    in_attribute: bool,
    in_macro: bool,
    in_macro_nonterminal: bool,
}

impl<'a> Classifier<'a> {
    fn new(src: &str) -> Classifier<'_> {
        let tokens = TokenIter { src }.peekable();
        Classifier { tokens, in_attribute: false, in_macro: false, in_macro_nonterminal: false }
    }

    /// Exhausts the `Classifier` writing the output into `sink`.
    ///
    /// The general structure for this method is to iterate over each token,
    /// possibly giving it an HTML span with a class specifying what flavor of
    /// token is used.
    fn highlight(mut self, sink: &mut dyn FnMut(Highlight<'a>)) {
        with_default_session_globals(|| {
            while let Some((token, text)) = self.tokens.next() {
                self.advance(token, text, sink);
            }
        })
    }

    /// Single step of highlighting. This will classify `token`, but maybe also
    /// a couple of following ones as well.
    fn advance(&mut self, token: TokenKind, text: &'a str, sink: &mut dyn FnMut(Highlight<'a>)) {
        let lookahead = self.peek();
        let class = match token {
            TokenKind::Whitespace => Class::None,
            TokenKind::LineComment { doc_style } | TokenKind::BlockComment { doc_style, .. } => {
                if doc_style.is_some() {
                    Class::DocComment
                } else {
                    Class::Comment
                }
            }
            // Consider this as part of a macro invocation if there was a
            // leading identifier.
            TokenKind::Bang if self.in_macro => {
                self.in_macro = false;
                Class::Macro
            }

            // Assume that '&' or '*' is the reference or dereference operator
            // or a reference or pointer type. Unless, of course, it looks like
            // a logical and or a multiplication operator: `&&` or `* `.
            TokenKind::Star => match lookahead {
                Some(TokenKind::Whitespace) => Class::Op,
                _ => Class::RefKeyWord,
            },
            TokenKind::And => match lookahead {
                Some(TokenKind::And) => {
                    let _and = self.tokens.next();
                    sink(Highlight::Token { text: "&&", class: Class::Op });
                    return;
                }
                Some(TokenKind::Eq) => {
                    let _eq = self.tokens.next();
                    sink(Highlight::Token { text: "&=", class: Class::Op });
                    return;
                }
                Some(TokenKind::Whitespace) => Class::Op,
                _ => Class::RefKeyWord,
            },

            // Operators.
            TokenKind::Minus
            | TokenKind::Plus
            | TokenKind::Or
            | TokenKind::Slash
            | TokenKind::Caret
            | TokenKind::Percent
            | TokenKind::Bang
            | TokenKind::Eq
            | TokenKind::Lt
            | TokenKind::Gt => Class::Op,

            // Miscellaneous, no highlighting.
            TokenKind::Dot
            | TokenKind::Semi
            | TokenKind::Comma
            | TokenKind::OpenParen
            | TokenKind::CloseParen
            | TokenKind::OpenBrace
            | TokenKind::CloseBrace
            | TokenKind::OpenBracket
            | TokenKind::At
            | TokenKind::Tilde
            | TokenKind::Colon
            | TokenKind::Unknown => Class::None,

            TokenKind::Question => Class::QuestionMark,

            TokenKind::Dollar => match lookahead {
                Some(TokenKind::Ident) => {
                    self.in_macro_nonterminal = true;
                    Class::MacroNonTerminal
                }
                _ => Class::None,
            },

            // This might be the start of an attribute. We're going to want to
            // continue highlighting it as an attribute until the ending ']' is
            // seen, so skip out early. Down below we terminate the attribute
            // span when we see the ']'.
            TokenKind::Pound => {
                match lookahead {
                    // Case 1: #![inner_attribute]
                    Some(TokenKind::Bang) => {
                        let _not = self.tokens.next().unwrap();
                        if let Some(TokenKind::OpenBracket) = self.peek() {
                            self.in_attribute = true;
                            sink(Highlight::EnterSpan { class: Class::Attribute });
                        }
                        sink(Highlight::Token { text: "#", class: Class::None });
                        sink(Highlight::Token { text: "!", class: Class::None });
                        return;
                    }
                    // Case 2: #[outer_attribute]
                    Some(TokenKind::OpenBracket) => {
                        self.in_attribute = true;
                        sink(Highlight::EnterSpan { class: Class::Attribute });
                    }
                    _ => (),
                }
                Class::None
            }
            TokenKind::CloseBracket => {
                if self.in_attribute {
                    self.in_attribute = false;
                    sink(Highlight::Token { text: "]", class: Class::None });
                    sink(Highlight::ExitSpan);
                    return;
                }
                Class::None
            }
            TokenKind::Literal { kind, .. } => match kind {
                // Text literals.
                LiteralKind::Byte { .. }
                | LiteralKind::Char { .. }
                | LiteralKind::Str { .. }
                | LiteralKind::ByteStr { .. }
                | LiteralKind::RawStr { .. }
                | LiteralKind::RawByteStr { .. } => Class::String,
                // Number literals.
                LiteralKind::Float { .. } | LiteralKind::Int { .. } => Class::Number,
            },
            TokenKind::Ident | TokenKind::RawIdent if lookahead == Some(TokenKind::Bang) => {
                self.in_macro = true;
                Class::Macro
            }
            TokenKind::Ident => match text {
                "ref" | "mut" => Class::RefKeyWord,
                "self" | "Self" => Class::Self_,
                "false" | "true" => Class::Bool,
                "Option" | "Result" => Class::PreludeTy,
                "Some" | "None" | "Ok" | "Err" => Class::PreludeVal,
                // Keywords are also included in the identifier set.
                _ if Ident::from_str(text).is_reserved() => Class::KeyWord,
                _ if self.in_macro_nonterminal => {
                    self.in_macro_nonterminal = false;
                    Class::MacroNonTerminal
                }
                _ => Class::Ident,
            },
            TokenKind::RawIdent => Class::Ident,
            TokenKind::Lifetime { .. } => Class::Lifetime,
        };
        // Anything that didn't return above is the simple case where we the
        // class just spans a single token, so we can use the `string` method.
        sink(Highlight::Token { text, class });
    }

    fn peek(&mut self) -> Option<TokenKind> {
        self.tokens.peek().map(|(toke_kind, _text)| *toke_kind)
    }
}

/// Called when we start processing a span of text that should be highlighted.
/// The `Class` argument specifies how it should be highlighted.
fn enter_span(out: &mut String, klass: Class) {
    write!(out, "", klass.as_html()).unwrap()
}

/// Called at the end of a span of highlighted text.
fn exit_span(out: &mut String) {
    write!(out, "").unwrap()
}

/// Called for a span of text. If the text should be highlighted differently
/// from the surrounding text, then the `Class` argument will be a value other
/// than `None`.
///
/// The following sequences of callbacks are equivalent:
/// ```plain
///     enter_span(Foo), string("text", None), exit_span()
///     string("text", Foo)
/// ```
/// The latter can be thought of as a shorthand for the former, which is more
/// flexible.
fn string<T: Display>(out: &mut String, text: T, klass: Class) {
    match klass {
        Class::None => write!(out, "{}", text).unwrap(),
        klass => write!(out, "{}", klass.as_html(), text).unwrap(),
    }
}

#[cfg(test)]
mod tests;
<commit_msg>Rollup merge of #79069 - jyn514:class-none, r=GuillaumeGomez<commit_after>//! Basic syntax highlighting functionality.
//!
//! This module uses librustc_ast's lexer to provide token-based highlighting for
//! the HTML documentation generated by rustdoc.
//!
//! Use the `render_with_highlighting` to highlight some rust code.

use crate::html::escape::Escape;

use std::fmt::{Display, Write};
use std::iter::Peekable;

use rustc_lexer::{LiteralKind, TokenKind};
use rustc_span::symbol::Ident;
use rustc_span::with_default_session_globals;

/// Highlights `src`, returning the HTML output.
crate fn render_with_highlighting(
    src: String,
    class: Option<&str>,
    playground_button: Option<&str>,
    tooltip: Option<(&str, &str)>,
) -> String {
    debug!("highlighting: ================\n{}\n==============", src);
    let mut out = String::with_capacity(src.len());
    if let Some((tooltip, class)) = tooltip {
        write!(
            out,
            "

ⓘ{}

",
            class, tooltip
        )
        .unwrap();
    }

    write_header(&mut out, class);
    write_code(&mut out, &src);
    write_footer(&mut out, playground_button);

    out
}

fn write_header(out: &mut String, class: Option<&str>) {
    write!(out, "

\n", class.unwrap_or_default())
        .unwrap()
}

fn write_code(out: &mut String, src: &str) {
    // This replace allows to fix how the code source with DOS backline characters is displayed.
    let src = src.replace("\r\n", "\n");
    Classifier::new(&src).highlight(&mut |highlight| {
        match highlight {
            Highlight::Token { text, class } => string(out, Escape(text), class),
            Highlight::EnterSpan { class } => enter_span(out, class),
            Highlight::ExitSpan => exit_span(out),
        };
    });
}

fn write_footer(out: &mut String, playground_button: Option<&str>) {
    write!(out, "
{}
\n", playground_button.unwrap_or_default()).unwrap()
}

/// How a span of text is classified. Mostly corresponds to token kinds.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum Class {
    Comment,
    DocComment,
    Attribute,
    KeyWord,
    // Keywords that do pointer/reference stuff.
    RefKeyWord,
    Self_,
    Op,
    Macro,
    MacroNonTerminal,
    String,
    Number,
    Bool,
    Ident,
    Lifetime,
    PreludeTy,
    PreludeVal,
    QuestionMark,
}

impl Class {
    /// Returns the css class expected by rustdoc for each `Class`.
    fn as_html(self) -> &'static str {
        match self {
            Class::Comment => "comment",
            Class::DocComment => "doccomment",
            Class::Attribute => "attribute",
            Class::KeyWord => "kw",
            Class::RefKeyWord => "kw-2",
            Class::Self_ => "self",
            Class::Op => "op",
            Class::Macro => "macro",
            Class::MacroNonTerminal => "macro-nonterminal",
            Class::String => "string",
            Class::Number => "number",
            Class::Bool => "bool-val",
            Class::Ident => "ident",
            Class::Lifetime => "lifetime",
            Class::PreludeTy => "prelude-ty",
            Class::PreludeVal => "prelude-val",
            Class::QuestionMark => "question-mark",
        }
    }
}

enum Highlight<'a> {
    Token { text: &'a str, class: Option<Class> },
    EnterSpan { class: Class },
    ExitSpan,
}

struct TokenIter<'a> {
    src: &'a str,
}

impl Iterator for TokenIter<'a> {
    type Item = (TokenKind, &'a str);
    fn next(&mut self) -> Option<(TokenKind, &'a str)> {
        if self.src.is_empty() {
            return None;
        }
        let token = rustc_lexer::first_token(self.src);
        let (text, rest) = self.src.split_at(token.len);
        self.src = rest;
        Some((token.kind, text))
    }
}

/// Processes program tokens, classifying strings of text by highlighting
/// category (`Class`).
struct Classifier<'a> {
    tokens: Peekable<TokenIter<'a>>,
    in_attribute: bool,
    in_macro: bool,
    in_macro_nonterminal: bool,
}

impl<'a> Classifier<'a> {
    fn new(src: &str) -> Classifier<'_> {
        let tokens = TokenIter { src }.peekable();
        Classifier { tokens, in_attribute: false, in_macro: false, in_macro_nonterminal: false }
    }

    /// Exhausts the `Classifier` writing the output into `sink`.
    ///
    /// The general structure for this method is to iterate over each token,
    /// possibly giving it an HTML span with a class specifying what flavor of
    /// token is used.
    fn highlight(mut self, sink: &mut dyn FnMut(Highlight<'a>)) {
        with_default_session_globals(|| {
            while let Some((token, text)) = self.tokens.next() {
                self.advance(token, text, sink);
            }
        })
    }

    /// Single step of highlighting. This will classify `token`, but maybe also
    /// a couple of following ones as well.
    fn advance(&mut self, token: TokenKind, text: &'a str, sink: &mut dyn FnMut(Highlight<'a>)) {
        let lookahead = self.peek();
        let no_highlight = |sink: &mut dyn FnMut(_)| sink(Highlight::Token { text, class: None });
        let class = match token {
            TokenKind::Whitespace => return no_highlight(sink),
            TokenKind::LineComment { doc_style } | TokenKind::BlockComment { doc_style, .. } => {
                if doc_style.is_some() {
                    Class::DocComment
                } else {
                    Class::Comment
                }
            }
            // Consider this as part of a macro invocation if there was a
            // leading identifier.
            TokenKind::Bang if self.in_macro => {
                self.in_macro = false;
                Class::Macro
            }

            // Assume that '&' or '*' is the reference or dereference operator
            // or a reference or pointer type. Unless, of course, it looks like
            // a logical and or a multiplication operator: `&&` or `* `.
            TokenKind::Star => match lookahead {
                Some(TokenKind::Whitespace) => Class::Op,
                _ => Class::RefKeyWord,
            },
            TokenKind::And => match lookahead {
                Some(TokenKind::And) => {
                    let _and = self.tokens.next();
                    sink(Highlight::Token { text: "&&", class: Some(Class::Op) });
                    return;
                }
                Some(TokenKind::Eq) => {
                    let _eq = self.tokens.next();
                    sink(Highlight::Token { text: "&=", class: Some(Class::Op) });
                    return;
                }
                Some(TokenKind::Whitespace) => Class::Op,
                _ => Class::RefKeyWord,
            },

            // Operators.
            TokenKind::Minus
            | TokenKind::Plus
            | TokenKind::Or
            | TokenKind::Slash
            | TokenKind::Caret
            | TokenKind::Percent
            | TokenKind::Bang
            | TokenKind::Eq
            | TokenKind::Lt
            | TokenKind::Gt => Class::Op,

            // Miscellaneous, no highlighting.
            TokenKind::Dot
            | TokenKind::Semi
            | TokenKind::Comma
            | TokenKind::OpenParen
            | TokenKind::CloseParen
            | TokenKind::OpenBrace
            | TokenKind::CloseBrace
            | TokenKind::OpenBracket
            | TokenKind::At
            | TokenKind::Tilde
            | TokenKind::Colon
            | TokenKind::Unknown => return no_highlight(sink),

            TokenKind::Question => Class::QuestionMark,

            TokenKind::Dollar => match lookahead {
                Some(TokenKind::Ident) => {
                    self.in_macro_nonterminal = true;
                    Class::MacroNonTerminal
                }
                _ => return no_highlight(sink),
            },

            // This might be the start of an attribute. We're going to want to
            // continue highlighting it as an attribute until the ending ']' is
            // seen, so skip out early. Down below we terminate the attribute
            // span when we see the ']'.
            TokenKind::Pound => {
                match lookahead {
                    // Case 1: #![inner_attribute]
                    Some(TokenKind::Bang) => {
                        let _not = self.tokens.next().unwrap();
                        if let Some(TokenKind::OpenBracket) = self.peek() {
                            self.in_attribute = true;
                            sink(Highlight::EnterSpan { class: Class::Attribute });
                        }
                        sink(Highlight::Token { text: "#", class: None });
                        sink(Highlight::Token { text: "!", class: None });
                        return;
                    }
                    // Case 2: #[outer_attribute]
                    Some(TokenKind::OpenBracket) => {
                        self.in_attribute = true;
                        sink(Highlight::EnterSpan { class: Class::Attribute });
                    }
                    _ => (),
                }
                return no_highlight(sink);
            }
            TokenKind::CloseBracket => {
                if self.in_attribute {
                    self.in_attribute = false;
                    sink(Highlight::Token { text: "]", class: None });
                    sink(Highlight::ExitSpan);
                    return;
                }
                return no_highlight(sink);
            }
            TokenKind::Literal { kind, .. } => match kind {
                // Text literals.
                LiteralKind::Byte { .. }
                | LiteralKind::Char { .. }
                | LiteralKind::Str { .. }
                | LiteralKind::ByteStr { .. }
                | LiteralKind::RawStr { .. }
                | LiteralKind::RawByteStr { .. } => Class::String,
                // Number literals.
                LiteralKind::Float { .. } | LiteralKind::Int { .. } => Class::Number,
            },
            TokenKind::Ident | TokenKind::RawIdent if lookahead == Some(TokenKind::Bang) => {
                self.in_macro = true;
                Class::Macro
            }
            TokenKind::Ident => match text {
                "ref" | "mut" => Class::RefKeyWord,
                "self" | "Self" => Class::Self_,
                "false" | "true" => Class::Bool,
                "Option" | "Result" => Class::PreludeTy,
                "Some" | "None" | "Ok" | "Err" => Class::PreludeVal,
                // Keywords are also included in the identifier set.
                _ if Ident::from_str(text).is_reserved() => Class::KeyWord,
                _ if self.in_macro_nonterminal => {
                    self.in_macro_nonterminal = false;
                    Class::MacroNonTerminal
                }
                _ => Class::Ident,
            },
            TokenKind::RawIdent => Class::Ident,
            TokenKind::Lifetime { .. } => Class::Lifetime,
        };
        // Anything that didn't return above is the simple case where we the
        // class just spans a single token, so we can use the `string` method.
        sink(Highlight::Token { text, class: Some(class) });
    }

    fn peek(&mut self) -> Option<TokenKind> {
        self.tokens.peek().map(|(toke_kind, _text)| *toke_kind)
    }
}

/// Called when we start processing a span of text that should be highlighted.
/// The `Class` argument specifies how it should be highlighted.
fn enter_span(out: &mut String, klass: Class) {
    write!(out, "", klass.as_html()).unwrap()
}

/// Called at the end of a span of highlighted text.
fn exit_span(out: &mut String) {
    write!(out, "").unwrap()
}

/// Called for a span of text. If the text should be highlighted differently
/// from the surrounding text, then the `Class` argument will be a value other
/// than `None`.
///
/// The following sequences of callbacks are equivalent:
/// ```plain
///     enter_span(Foo), string("text", None), exit_span()
///     string("text", Foo)
/// ```
/// The latter can be thought of as a shorthand for the former, which is more
/// flexible.
fn string<T: Display>(out: &mut String, text: T, klass: Option<Class>) {
    match klass {
        None => write!(out, "{}", text).unwrap(),
        Some(klass) => write!(out, "{}", klass.as_html(), text).unwrap(),
    }
}

#[cfg(test)]
mod tests;
<|endoftext|>


<commit_before>use std::{
    sync::{
        atomic::{AtomicBool, AtomicUsize, Ordering},
        Arc,
    },
    thread,
};

use docopt::Docopt;
use rand::{thread_rng, Rng};
use serde::Deserialize;

#[cfg_attr(
    // only enable jemalloc on linux and macos by default
    all(
        any(target_os = "linux", target_os = "macos"),
        not(feature = "no_jemalloc"),
    ),
    global_allocator
)]
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;

static TOTAL: AtomicUsize = AtomicUsize::new(0);
static SEQ: AtomicUsize = AtomicUsize::new(0);

const USAGE: &'static str = "
Usage: stress [--threads=<#>] [--burn-in] [--duration=<s>] \
    [--key-len=<l>] [--val-len=<l>] \
    [--get-prop=<p>] \
    [--set-prop=<p>] \
    [--del-prop=<p>] \
    [--cas-prop=<p>] \
    [--scan-prop=<p>] \
    [--merge-prop=<p>] \
    [--entries=<n>] \
    [--sequential] \
    [--total-ops=<n>] \

Options:
    --threads=<#>      Number of threads [default: 4].
    --burn-in          Don't halt until we receive a signal.
    --duration=<s>     Seconds to run for [default: 10].
    --key-len=<l>      The length of keys [default: 10].
    --val-len=<l>      The length of values [default: 100].
    --get-prop=<p>     The relative proportion of get requests [default: 94].
    --set-prop=<p>     The relative proportion of set requests [default: 2].
    --del-prop=<p>     The relative proportion of del requests [default: 1].
    --cas-prop=<p>     The relative proportion of cas requests [default: 1].
    --scan-prop=<p>    The relative proportion of scan requests [default: 1].
    --merge-prop=<p>   The relative proportion of merge requests [default: 1].
    --entries=<n>      The total keyspace [default: 100000].
    --sequential       Run the test in sequential mode instead of random.
    --total-ops=<n>    Stop test after executing a total number of operations.
";

#[derive(Deserialize, Clone)]
struct Args {
    flag_threads: usize,
    flag_burn_in: bool,
    flag_duration: u64,
    flag_key_len: usize,
    flag_val_len: usize,
    flag_get_prop: usize,
    flag_set_prop: usize,
    flag_del_prop: usize,
    flag_cas_prop: usize,
    flag_scan_prop: usize,
    flag_merge_prop: usize,
    flag_entries: usize,
    flag_sequential: bool,
    flag_total_ops: Option<usize>,
}

// defaults will be applied later based on USAGE above
static mut ARGS: Args = Args {
    flag_threads: 0,
    flag_burn_in: false,
    flag_duration: 0,
    flag_key_len: 0,
    flag_val_len: 0,
    flag_get_prop: 0,
    flag_set_prop: 0,
    flag_del_prop: 0,
    flag_cas_prop: 0,
    flag_scan_prop: 0,
    flag_merge_prop: 0,
    flag_entries: 0,
    flag_sequential: false,
    flag_total_ops: None,
};

fn report(shutdown: Arc<AtomicBool>) {
    let mut last = 0;
    while !shutdown.load(Ordering::Relaxed) {
        thread::sleep(std::time::Duration::from_secs(1));
        let total = TOTAL.load(Ordering::Acquire);

        println!("did {} ops", total - last);

        last = total;
    }
}

fn concatenate_merge(
    _key: &[u8],              // the key being merged
    old_value: Option<&[u8]>, // the previous value, if one existed
    merged_bytes: &[u8],      // the new bytes being merged in
) -> Option<Vec<u8>> {
    // set the new value, return None to delete
    let mut ret = old_value.map(|ov| ov.to_vec()).unwrap_or_else(|| vec![]);

    ret.extend_from_slice(merged_bytes);

    Some(ret)
}

fn run(tree: Arc<sled::Db>, shutdown: Arc<AtomicBool>) {
    let args = unsafe { ARGS.clone() };

    let get_max = args.flag_get_prop;
    let set_max = get_max + args.flag_set_prop;
    let del_max = set_max + args.flag_del_prop;
    let cas_max = del_max + args.flag_cas_prop;
    let scan_max = cas_max + args.flag_scan_prop;
    let merge_max = scan_max + args.flag_merge_prop;

    let bytes = |len| -> Vec<u8> {
        let i = if args.flag_sequential {
            SEQ.fetch_add(1, Ordering::Relaxed)
        } else {
            thread_rng().gen::<usize>()
        } % args.flag_entries;

        let i_bytes: [u8; std::mem::size_of::<usize>()] =
            unsafe { std::mem::transmute(i) };

        i_bytes.into_iter().cycle().take(len).cloned().collect()
    };
    let mut rng = thread_rng();

    while !shutdown.load(Ordering::Relaxed) {
        TOTAL.fetch_add(1, Ordering::Release);
        let key = bytes(args.flag_key_len);
        let choice = rng.gen_range(0, merge_max + 1);

        match choice {
            v if v <= get_max => {
                tree.get(&key).unwrap();
            }
            v if v > get_max && v <= set_max => {
                tree.insert(&key, bytes(args.flag_val_len)).unwrap();
            }
            v if v > set_max && v <= del_max => {
                tree.remove(&key).unwrap();
            }
            v if v > del_max && v <= cas_max => {
                let old_k = bytes(args.flag_val_len);

                let old = if rng.gen::<bool>() {
                    Some(old_k.as_slice())
                } else {
                    None
                };

                let new = if rng.gen::<bool>() {
                    Some(bytes(args.flag_val_len))
                } else {
                    None
                };

                if let Err(e) = tree.cas(&key, old, new) {
                    panic!("operational error: {:?}", e);
                }
            }
            v if v > cas_max && v <= scan_max => {
                let iter = tree.range(key..).map(|res| res.unwrap());

                if v % 2 == 0 {
                    let _ = iter.take(rng.gen_range(0, 15)).collect::<Vec<_>>();
                } else {
                    let _ = iter
                        .rev()
                        .take(rng.gen_range(0, 15))
                        .collect::<Vec<_>>();
                }
            }
            _ => {
                tree.merge(&key, bytes(args.flag_val_len)).unwrap();
            }
        }
    }
}

fn main() {
    setup_logger();

    let args = unsafe {
        ARGS = Docopt::new(USAGE)
            .and_then(|d| d.argv(std::env::args().into_iter()).deserialize())
            .unwrap_or_else(|e| e.exit());
        ARGS.clone()
    };

    let shutdown = Arc::new(AtomicBool::new(false));

    let config = sled::ConfigBuilder::new()
        .io_buf_size(8_000_000)
        .page_consolidation_threshold(10)
        .cache_capacity(1_000_000_000)
        .flush_every_ms(Some(200))
        .snapshot_after_ops(100_000_000_000)
        .print_profile_on_drop(true)
        .build();

    let tree = Arc::new(sled::Db::start(config).unwrap());
    tree.set_merge_operator(concatenate_merge);

    let mut threads = vec![];

    let now = std::time::Instant::now();

    let n_threads = args.flag_threads;

    for i in 0..n_threads + 1 {
        let tree = tree.clone();
        let shutdown = shutdown.clone();

        let t = if i == 0 {
            thread::Builder::new()
                .name("reporter".into())
                .spawn(move || report(shutdown))
                .unwrap()
        } else {
            thread::spawn(move || run(tree, shutdown))
        };

        threads.push(t);
    }

    if let Some(ops) = args.flag_total_ops {
        assert!(
            !args.flag_burn_in,
            "don't set both --burn-in and --total-ops"
        );
        while TOTAL.load(Ordering::Relaxed) < ops {
            thread::sleep(std::time::Duration::from_millis(50));
        }
        shutdown.store(true, Ordering::SeqCst);
    } else if !args.flag_burn_in {
        thread::sleep(std::time::Duration::from_secs(unsafe {
            ARGS.flag_duration
        }));
        shutdown.store(true, Ordering::SeqCst);
    }

    for t in threads.into_iter() {
        t.join().unwrap();
    }

    let ops = TOTAL.load(Ordering::SeqCst);
    let time = now.elapsed().as_secs() as usize;

    println!(
        "did {} total ops in {} seconds. {} ops/s",
        ops,
        time,
        (ops * 1_000) / (time * 1_000)
    );
}

pub fn setup_logger() {
    use std::io::Write;

    color_backtrace::install();

    fn tn() -> String {
        std::thread::current()
            .name()
            .unwrap_or("unknown")
            .to_owned()
    }

    let mut builder = env_logger::Builder::new();
    builder
        .format(|buf, record| {
            writeln!(
                buf,
                "{:05} {:25} {:10} {}",
                record.level(),
                tn(),
                record.module_path().unwrap().split("::").last().unwrap(),
                record.args()
            )
        })
        .filter(None, log::LevelFilter::Info);

    if std::env::var("RUST_LOG").is_ok() {
        builder.parse(&std::env::var("RUST_LOG").unwrap());
    }

    let _r = builder.try_init();
}
<commit_msg>Fix docopt usage<commit_after>use std::{
    sync::{
        atomic::{AtomicBool, AtomicUsize, Ordering},
        Arc,
    },
    thread,
};

use docopt::Docopt;
use rand::{thread_rng, Rng};
use serde::Deserialize;

#[cfg_attr(
    // only enable jemalloc on linux and macos by default
    all(
        any(target_os = "linux", target_os = "macos"),
        not(feature = "no_jemalloc"),
    ),
    global_allocator
)]
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;

static TOTAL: AtomicUsize = AtomicUsize::new(0);
static SEQ: AtomicUsize = AtomicUsize::new(0);

const USAGE: &'static str = "
Usage: stress [--threads=<#>] [--burn-in] [--duration=<s>] \
    [--key-len=<l>] [--val-len=<l>] \
    [--get-prop=<p>] \
    [--set-prop=<p>] \
    [--del-prop=<p>] \
    [--cas-prop=<p>] \
    [--scan-prop=<p>] \
    [--merge-prop=<p>] \
    [--entries=<n>] \
    [--sequential] \
    [--total-ops=<n>]

Options:
    --threads=<#>      Number of threads [default: 4].
    --burn-in          Don't halt until we receive a signal.
    --duration=<s>     Seconds to run for [default: 10].
    --key-len=<l>      The length of keys [default: 10].
    --val-len=<l>      The length of values [default: 100].
    --get-prop=<p>     The relative proportion of get requests [default: 94].
    --set-prop=<p>     The relative proportion of set requests [default: 2].
    --del-prop=<p>     The relative proportion of del requests [default: 1].
    --cas-prop=<p>     The relative proportion of cas requests [default: 1].
    --scan-prop=<p>    The relative proportion of scan requests [default: 1].
    --merge-prop=<p>   The relative proportion of merge requests [default: 1].
    --entries=<n>      The total keyspace [default: 100000].
    --sequential       Run the test in sequential mode instead of random.
    --total-ops=<n>    Stop test after executing a total number of operations.
";

#[derive(Deserialize, Clone)]
struct Args {
    flag_threads: usize,
    flag_burn_in: bool,
    flag_duration: u64,
    flag_key_len: usize,
    flag_val_len: usize,
    flag_get_prop: usize,
    flag_set_prop: usize,
    flag_del_prop: usize,
    flag_cas_prop: usize,
    flag_scan_prop: usize,
    flag_merge_prop: usize,
    flag_entries: usize,
    flag_sequential: bool,
    flag_total_ops: Option<usize>,
}

// defaults will be applied later based on USAGE above
static mut ARGS: Args = Args {
    flag_threads: 0,
    flag_burn_in: false,
    flag_duration: 0,
    flag_key_len: 0,
    flag_val_len: 0,
    flag_get_prop: 0,
    flag_set_prop: 0,
    flag_del_prop: 0,
    flag_cas_prop: 0,
    flag_scan_prop: 0,
    flag_merge_prop: 0,
    flag_entries: 0,
    flag_sequential: false,
    flag_total_ops: None,
};

fn report(shutdown: Arc<AtomicBool>) {
    let mut last = 0;
    while !shutdown.load(Ordering::Relaxed) {
        thread::sleep(std::time::Duration::from_secs(1));
        let total = TOTAL.load(Ordering::Acquire);

        println!("did {} ops", total - last);

        last = total;
    }
}

fn concatenate_merge(
    _key: &[u8],              // the key being merged
    old_value: Option<&[u8]>, // the previous value, if one existed
    merged_bytes: &[u8],      // the new bytes being merged in
) -> Option<Vec<u8>> {
    // set the new value, return None to delete
    let mut ret = old_value.map(|ov| ov.to_vec()).unwrap_or_else(|| vec![]);

    ret.extend_from_slice(merged_bytes);

    Some(ret)
}

fn run(tree: Arc<sled::Db>, shutdown: Arc<AtomicBool>) {
    let args = unsafe { ARGS.clone() };

    let get_max = args.flag_get_prop;
    let set_max = get_max + args.flag_set_prop;
    let del_max = set_max + args.flag_del_prop;
    let cas_max = del_max + args.flag_cas_prop;
    let scan_max = cas_max + args.flag_scan_prop;
    let merge_max = scan_max + args.flag_merge_prop;

    let bytes = |len| -> Vec<u8> {
        let i = if args.flag_sequential {
            SEQ.fetch_add(1, Ordering::Relaxed)
        } else {
            thread_rng().gen::<usize>()
        } % args.flag_entries;

        let i_bytes: [u8; std::mem::size_of::<usize>()] =
            unsafe { std::mem::transmute(i) };

        i_bytes.into_iter().cycle().take(len).cloned().collect()
    };
    let mut rng = thread_rng();

    while !shutdown.load(Ordering::Relaxed) {
        TOTAL.fetch_add(1, Ordering::Release);
        let key = bytes(args.flag_key_len);
        let choice = rng.gen_range(0, merge_max + 1);

        match choice {
            v if v <= get_max => {
                tree.get(&key).unwrap();
            }
            v if v > get_max && v <= set_max => {
                tree.insert(&key, bytes(args.flag_val_len)).unwrap();
            }
            v if v > set_max && v <= del_max => {
                tree.remove(&key).unwrap();
            }
            v if v > del_max && v <= cas_max => {
                let old_k = bytes(args.flag_val_len);

                let old = if rng.gen::<bool>() {
                    Some(old_k.as_slice())
                } else {
                    None
                };

                let new = if rng.gen::<bool>() {
                    Some(bytes(args.flag_val_len))
                } else {
                    None
                };

                if let Err(e) = tree.cas(&key, old, new) {
                    panic!("operational error: {:?}", e);
                }
            }
            v if v > cas_max && v <= scan_max => {
                let iter = tree.range(key..).map(|res| res.unwrap());

                if v % 2 == 0 {
                    let _ = iter.take(rng.gen_range(0, 15)).collect::<Vec<_>>();
                } else {
                    let _ = iter
                        .rev()
                        .take(rng.gen_range(0, 15))
                        .collect::<Vec<_>>();
                }
            }
            _ => {
                tree.merge(&key, bytes(args.flag_val_len)).unwrap();
            }
        }
    }
}

fn main() {
    setup_logger();

    let args = unsafe {
        ARGS = Docopt::new(USAGE)
            .and_then(|d| d.argv(std::env::args().into_iter()).deserialize())
            .unwrap_or_else(|e| e.exit());
        ARGS.clone()
    };

    let shutdown = Arc::new(AtomicBool::new(false));

    let config = sled::ConfigBuilder::new()
        .io_buf_size(8_000_000)
        .page_consolidation_threshold(10)
        .cache_capacity(1_000_000_000)
        .flush_every_ms(Some(200))
        .snapshot_after_ops(100_000_000_000)
        .print_profile_on_drop(true)
        .build();

    let tree = Arc::new(sled::Db::start(config).unwrap());
    tree.set_merge_operator(concatenate_merge);

    let mut threads = vec![];

    let now = std::time::Instant::now();

    let n_threads = args.flag_threads;

    for i in 0..n_threads + 1 {
        let tree = tree.clone();
        let shutdown = shutdown.clone();

        let t = if i == 0 {
            thread::Builder::new()
                .name("reporter".into())
                .spawn(move || report(shutdown))
                .unwrap()
        } else {
            thread::spawn(move || run(tree, shutdown))
        };

        threads.push(t);
    }

    if let Some(ops) = args.flag_total_ops {
        assert!(
            !args.flag_burn_in,
            "don't set both --burn-in and --total-ops"
        );
        while TOTAL.load(Ordering::Relaxed) < ops {
            thread::sleep(std::time::Duration::from_millis(50));
        }
        shutdown.store(true, Ordering::SeqCst);
    } else if !args.flag_burn_in {
        thread::sleep(std::time::Duration::from_secs(unsafe {
            ARGS.flag_duration
        }));
        shutdown.store(true, Ordering::SeqCst);
    }

    for t in threads.into_iter() {
        t.join().unwrap();
    }

    let ops = TOTAL.load(Ordering::SeqCst);
    let time = now.elapsed().as_secs() as usize;

    println!(
        "did {} total ops in {} seconds. {} ops/s",
        ops,
        time,
        (ops * 1_000) / (time * 1_000)
    );
}

pub fn setup_logger() {
    use std::io::Write;

    color_backtrace::install();

    fn tn() -> String {
        std::thread::current()
            .name()
            .unwrap_or("unknown")
            .to_owned()
    }

    let mut builder = env_logger::Builder::new();
    builder
        .format(|buf, record| {
            writeln!(
                buf,
                "{:05} {:25} {:10} {}",
                record.level(),
                tn(),
                record.module_path().unwrap().split("::").last().unwrap(),
                record.args()
            )
        })
        .filter(None, log::LevelFilter::Info);

    if std::env::var("RUST_LOG").is_ok() {
        builder.parse(&std::env::var("RUST_LOG").unwrap());
    }

    let _r = builder.try_init();
}
<|endoftext|>


<commit_before>#![crate_name = "websocket"]

#![comment = "WebSocket client"]
#![license = "MIT/ASL2"]
#![crate_type = "dylib"]
#![crate_type = "rlib"]

#![feature(default_type_params)]

extern crate url;
extern crate openssl;
extern crate serialize;
extern crate "rust-crypto" as crypto;

#[cfg(test)]
extern crate test;

pub mod nonce;
pub mod message;
pub mod stream;
pub mod socket;

<commit_msg>rust-crypto -> crypto<commit_after>#![crate_name = "websocket"]

#![comment = "WebSocket client"]
#![license = "MIT/ASL2"]
#![crate_type = "dylib"]
#![crate_type = "rlib"]

#![feature(default_type_params)]

extern crate url;
extern crate openssl;
extern crate serialize;
extern crate crypto;

#[cfg(test)]
extern crate test;

pub mod nonce;
pub mod message;
pub mod stream;
pub mod socket;

<|endoftext|>


<commit_before>use gettextrs::gettext;

use gstreamer as gst;
use gstreamer::prelude::*;

use glib;
use glib::ObjectExt;

use log::info;

use std::{
    collections::HashSet,
    error::Error,
    path::Path,
    sync::{Arc, RwLock},
};

use super::MediaEvent;

pub struct TocSetterPipeline {
    pipeline: gst::Pipeline,
    muxer: Option<gst::Element>,
}

impl TocSetterPipeline {
    pub fn check_requirements() -> Result<(), String> {
        // Exporting to Mastroska containers is only
        // available from gst-plugins-good 1.13.1
        let (major, minor, _micro, _nano) = gst::version();
        if major >= 1 && minor >= 14 {
            gst::ElementFactory::make("matroskamux", None).map_or(
                Err(gettext(
                    "Missing `matroskamux`\ncheck your gst-plugins-good install",
                )),
                |_| Ok(()),
            )
        } else {
            Err(gettext(
                "Matroska export requires\ngst-plugins-good >= 1.14",
            ))
        }
    }

    pub fn try_new(
        input_path: &Path,
        output_path: &Path,
        streams: Arc<RwLock<HashSet<String>>>,
        sender: glib::Sender<MediaEvent>,
    ) -> Result<TocSetterPipeline, String> {
        info!(
            "{}",
            gettext("Exporting to {}...").replacen("{}", output_path.to_str().unwrap(), 1)
        );

        let mut this = TocSetterPipeline {
            pipeline: gst::Pipeline::new("toc_setter_pipeline"),
            muxer: None,
        };

        this.build_pipeline(input_path, output_path, streams);
        this.register_bus_inspector(sender);

        this.pipeline
            .set_state(gst::State::Paused)
            .map(|_| this)
            .map_err(|_| gettext("Could not set media in Paused mode"))
    }

    pub fn get_muxer(&self) -> Option<&gst::Element> {
        self.muxer.as_ref()
    }

    pub fn export(&mut self) -> Result<(), String> {
        self.pipeline
            .set_state(gst::State::Playing)
            .map(|_| ())
            .map_err(|_| gettext("Could not set media in Playing mode"))
    }

    pub fn get_position(&self) -> Option<u64> {
        let mut position_query = gst::Query::new_position(gst::Format::Time);
        self.pipeline.query(&mut position_query);
        let position = position_query.get_result().get_value();
        if position >= 0 {
            Some(position as u64)
        } else {
            None
        }
    }

    fn build_pipeline(
        &mut self,
        input_path: &Path,
        output_path: &Path,
        streams: Arc<RwLock<HashSet<String>>>,
    ) {
        // Input
        let filesrc = gst::ElementFactory::make("filesrc", None).unwrap();
        filesrc
            .set_property("location", &gst::Value::from(input_path.to_str().unwrap()))
            .unwrap();

        let parsebin = gst::ElementFactory::make("parsebin", None).unwrap();

        {
            self.pipeline.add_many(&[&filesrc, &parsebin]).unwrap();
            filesrc.link(&parsebin).unwrap();
            parsebin.sync_state_with_parent().unwrap();
        }

        // Muxer and output sink
        let muxer = gst::ElementFactory::make("matroskamux", None).unwrap();
        muxer
            .set_property("writing-app", &gst::Value::from("media-toc"))
            .unwrap();

        let filesink = gst::ElementFactory::make("filesink", "filesink").unwrap();
        filesink
            .set_property("location", &gst::Value::from(output_path.to_str().unwrap()))
            .unwrap();

        {
            self.pipeline.add_many(&[&muxer, &filesink]).unwrap();
            muxer.link(&filesink).unwrap();
            filesink.sync_state_with_parent().unwrap();
        }

        self.muxer = Some(muxer.clone());

        let pipeline_cb = self.pipeline.clone();
        parsebin.connect_pad_added(move |_element, pad| {
            let queue = gst::ElementFactory::make("queue", None).unwrap();
            pipeline_cb.add(&queue).unwrap();
            let queue_sink_pad = queue.get_static_pad("sink").unwrap();
            pad.link(&queue_sink_pad).unwrap();
            queue.sync_state_with_parent().unwrap();

            let queue_src_pad = queue.get_static_pad("src").unwrap();

            if pad.get_stream_id().is_none() {
                println!("Pad {} has no stream_id", pad.get_name());
            }

            if streams
                .read()
                .expect("TocSetterPipeline: `paserbin.pad_added` cand read streams to use")
                .contains(
                    pad.get_stream_id()
                        .expect("TocSetterPipeline::build_pipeline no stream_id for src pad")
                        .as_str(),
                )
            {
                let muxer_sink_pad = muxer.get_compatible_pad(&queue_src_pad, None).unwrap();
                queue_src_pad.link(&muxer_sink_pad).unwrap();
                muxer.sync_state_with_parent().unwrap();

                // Listen to incoming events and drop Upstream TOCs
                muxer_sink_pad.add_probe(
                    gst::PadProbeType::EVENT_DOWNSTREAM,
                    |_pad, probe_info| {
                        if let Some(ref data) = probe_info.data {
                            if let gst::PadProbeData::Event(ref event) = *data {
                                if let gst::EventView::Toc(ref _toc) = event.view() {
                                    return gst::PadProbeReturn::Drop;
                                }
                            }
                        }
                        gst::PadProbeReturn::Ok
                    },
                );
            } else {
                let fakesink = gst::ElementFactory::make("fakesink", None).unwrap();
                pipeline_cb.add(&fakesink).unwrap();
                let fakesink_sink_pad = fakesink.get_static_pad("sink").unwrap();
                queue_src_pad.link(&fakesink_sink_pad).unwrap();
                fakesink.sync_state_with_parent().unwrap();
            }
        });
    }

    // Uses sender to notify the UI controllers about the inspection process
    fn register_bus_inspector(&self, sender: glib::Sender<MediaEvent>) {
        let mut init_done = false;
        self.pipeline.get_bus().unwrap().add_watch(move |_, msg| {
            match msg.view() {
                gst::MessageView::Eos(..) => {
                    sender.send(MediaEvent::Eos).unwrap();
                    return glib::Continue(false);
                }
                gst::MessageView::Error(err) => {
                    sender
                        .send(MediaEvent::FailedToExport(
                            err.get_error().description().to_owned(),
                        ))
                        .unwrap();
                    return glib::Continue(false);
                }
                gst::MessageView::AsyncDone(_) => {
                    if !init_done {
                        init_done = true;
                        sender.send(MediaEvent::InitDone).unwrap();
                    }
                }
                _ => (),
            }

            glib::Continue(true)
        });
    }
}
<commit_msg>Remove dregs of a previous unrelated debugging session (#135)<commit_after>use gettextrs::gettext;

use gstreamer as gst;
use gstreamer::prelude::*;

use glib;
use glib::ObjectExt;

use log::info;

use std::{
    collections::HashSet,
    error::Error,
    path::Path,
    sync::{Arc, RwLock},
};

use super::MediaEvent;

pub struct TocSetterPipeline {
    pipeline: gst::Pipeline,
    muxer: Option<gst::Element>,
}

impl TocSetterPipeline {
    pub fn check_requirements() -> Result<(), String> {
        // Exporting to Mastroska containers is only
        // available from gst-plugins-good 1.13.1
        let (major, minor, _micro, _nano) = gst::version();
        if major >= 1 && minor >= 14 {
            gst::ElementFactory::make("matroskamux", None).map_or(
                Err(gettext(
                    "Missing `matroskamux`\ncheck your gst-plugins-good install",
                )),
                |_| Ok(()),
            )
        } else {
            Err(gettext(
                "Matroska export requires\ngst-plugins-good >= 1.14",
            ))
        }
    }

    pub fn try_new(
        input_path: &Path,
        output_path: &Path,
        streams: Arc<RwLock<HashSet<String>>>,
        sender: glib::Sender<MediaEvent>,
    ) -> Result<TocSetterPipeline, String> {
        info!(
            "{}",
            gettext("Exporting to {}...").replacen("{}", output_path.to_str().unwrap(), 1)
        );

        let mut this = TocSetterPipeline {
            pipeline: gst::Pipeline::new("toc_setter_pipeline"),
            muxer: None,
        };

        this.build_pipeline(input_path, output_path, streams);
        this.register_bus_inspector(sender);

        this.pipeline
            .set_state(gst::State::Paused)
            .map(|_| this)
            .map_err(|_| gettext("Could not set media in Paused mode"))
    }

    pub fn get_muxer(&self) -> Option<&gst::Element> {
        self.muxer.as_ref()
    }

    pub fn export(&mut self) -> Result<(), String> {
        self.pipeline
            .set_state(gst::State::Playing)
            .map(|_| ())
            .map_err(|_| gettext("Could not set media in Playing mode"))
    }

    pub fn get_position(&self) -> Option<u64> {
        let mut position_query = gst::Query::new_position(gst::Format::Time);
        self.pipeline.query(&mut position_query);
        let position = position_query.get_result().get_value();
        if position >= 0 {
            Some(position as u64)
        } else {
            None
        }
    }

    fn build_pipeline(
        &mut self,
        input_path: &Path,
        output_path: &Path,
        streams: Arc<RwLock<HashSet<String>>>,
    ) {
        // Input
        let filesrc = gst::ElementFactory::make("filesrc", None).unwrap();
        filesrc
            .set_property("location", &gst::Value::from(input_path.to_str().unwrap()))
            .unwrap();

        let parsebin = gst::ElementFactory::make("parsebin", None).unwrap();

        {
            self.pipeline.add_many(&[&filesrc, &parsebin]).unwrap();
            filesrc.link(&parsebin).unwrap();
            parsebin.sync_state_with_parent().unwrap();
        }

        // Muxer and output sink
        let muxer = gst::ElementFactory::make("matroskamux", None).unwrap();
        muxer
            .set_property("writing-app", &gst::Value::from("media-toc"))
            .unwrap();

        let filesink = gst::ElementFactory::make("filesink", "filesink").unwrap();
        filesink
            .set_property("location", &gst::Value::from(output_path.to_str().unwrap()))
            .unwrap();

        {
            self.pipeline.add_many(&[&muxer, &filesink]).unwrap();
            muxer.link(&filesink).unwrap();
            filesink.sync_state_with_parent().unwrap();
        }

        self.muxer = Some(muxer.clone());

        let pipeline_cb = self.pipeline.clone();
        parsebin.connect_pad_added(move |_element, pad| {
            let queue = gst::ElementFactory::make("queue", None).unwrap();
            pipeline_cb.add(&queue).unwrap();
            let queue_sink_pad = queue.get_static_pad("sink").unwrap();
            pad.link(&queue_sink_pad).unwrap();
            queue.sync_state_with_parent().unwrap();

            let queue_src_pad = queue.get_static_pad("src").unwrap();

            if streams
                .read()
                .expect("TocSetterPipeline: `paserbin.pad_added` cand read streams to use")
                .contains(
                    pad.get_stream_id()
                        .expect("TocSetterPipeline::build_pipeline no stream_id for src pad")
                        .as_str(),
                )
            {
                let muxer_sink_pad = muxer.get_compatible_pad(&queue_src_pad, None).unwrap();
                queue_src_pad.link(&muxer_sink_pad).unwrap();
                muxer.sync_state_with_parent().unwrap();

                // Listen to incoming events and drop Upstream TOCs
                muxer_sink_pad.add_probe(
                    gst::PadProbeType::EVENT_DOWNSTREAM,
                    |_pad, probe_info| {
                        if let Some(ref data) = probe_info.data {
                            if let gst::PadProbeData::Event(ref event) = *data {
                                if let gst::EventView::Toc(ref _toc) = event.view() {
                                    return gst::PadProbeReturn::Drop;
                                }
                            }
                        }
                        gst::PadProbeReturn::Ok
                    },
                );
            } else {
                let fakesink = gst::ElementFactory::make("fakesink", None).unwrap();
                pipeline_cb.add(&fakesink).unwrap();
                let fakesink_sink_pad = fakesink.get_static_pad("sink").unwrap();
                queue_src_pad.link(&fakesink_sink_pad).unwrap();
                fakesink.sync_state_with_parent().unwrap();
            }
        });
    }

    // Uses sender to notify the UI controllers about the inspection process
    fn register_bus_inspector(&self, sender: glib::Sender<MediaEvent>) {
        let mut init_done = false;
        self.pipeline.get_bus().unwrap().add_watch(move |_, msg| {
            match msg.view() {
                gst::MessageView::Eos(..) => {
                    sender.send(MediaEvent::Eos).unwrap();
                    return glib::Continue(false);
                }
                gst::MessageView::Error(err) => {
                    sender
                        .send(MediaEvent::FailedToExport(
                            err.get_error().description().to_owned(),
                        ))
                        .unwrap();
                    return glib::Continue(false);
                }
                gst::MessageView::AsyncDone(_) => {
                    if !init_done {
                        init_done = true;
                        sender.send(MediaEvent::InitDone).unwrap();
                    }
                }
                _ => (),
            }

            glib::Continue(true)
        });
    }
}
<|endoftext|>


<commit_before>use glium::backend::glutin_backend::GlutinFacade;
use glium::glutin::{Event, VirtualKeyCode};

/// Every event receiver has to return a response for each event received.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum EventResponse {
    /// The event was not handled at all
    NotHandled,
    /// The event was handled but should be forwarded to other receivers, too
    Continue,
    /// The event was handled and should *not* be forwarded to other receivers
    Break,
    /// In response to the event, the program should terminate
    Quit,
}

pub struct EventManager {
    context: GlutinFacade,
}

impl EventManager {
    pub fn new(context: GlutinFacade) -> Self {
        EventManager { context: context }
    }

    pub fn poll_events(&self, mut handlers: Vec<&mut EventHandler>) -> EventResponse {

        for ev in self.context.poll_events() {
            for i in 0..handlers.len() {
                // let x = *handler;
                // let tmp: &mut _ = &mut **handler;
                let response = handlers[i].handle_event(&ev);
                match response {
                    EventResponse::NotHandled |
                    EventResponse::Continue => (),
                    EventResponse::Break => break,
                    EventResponse::Quit => return EventResponse::Quit, //how do we quit the program
                }
            }
        }
        // Just for the sake of return value
        EventResponse::NotHandled
    }
}

pub trait EventHandler {
    fn handle_event(&mut self, e: &Event) -> EventResponse;
}

pub struct CloseHandler;

impl EventHandler for CloseHandler {
    fn handle_event(&mut self, e: &Event) -> EventResponse {
        match e {
            &Event::Closed => EventResponse::Quit,
            &Event::KeyboardInput(_, _, Some(VirtualKeyCode::Escape)) => EventResponse::Quit,
            _ => EventResponse::NotHandled,
        }
    }
}
<commit_msg>add recommended improvement to match statement<commit_after>use glium::backend::glutin_backend::GlutinFacade;
use glium::glutin::{Event, VirtualKeyCode};

/// Every event receiver has to return a response for each event received.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum EventResponse {
    /// The event was not handled at all
    NotHandled,
    /// The event was handled but should be forwarded to other receivers, too
    Continue,
    /// The event was handled and should *not* be forwarded to other receivers
    Break,
    /// In response to the event, the program should terminate
    Quit,
}

pub struct EventManager {
    context: GlutinFacade,
}

impl EventManager {
    pub fn new(context: GlutinFacade) -> Self {
        EventManager { context: context }
    }

    pub fn poll_events(&self, mut handlers: Vec<&mut EventHandler>) -> EventResponse {

        for ev in self.context.poll_events() {
            for i in 0..handlers.len() {
                // let x = *handler;
                // let tmp: &mut _ = &mut **handler;
                let response = handlers[i].handle_event(&ev);
                match response {
                    EventResponse::NotHandled |
                    EventResponse::Continue => (),
                    EventResponse::Break => break,
                    EventResponse::Quit => return EventResponse::Quit, //how do we quit the program
                }
            }
        }
        // Just for the sake of return value
        EventResponse::NotHandled
    }
}

pub trait EventHandler {
    fn handle_event(&mut self, e: &Event) -> EventResponse;
}

pub struct CloseHandler;

impl EventHandler for CloseHandler {
    fn handle_event(&mut self, e: &Event) -> EventResponse {
        match *e {
            Event::Closed => EventResponse::Quit,
            Event::KeyboardInput(_, _, Some(VirtualKeyCode::Escape)) => EventResponse::Quit,
            _ => EventResponse::NotHandled,
        }
    }
}
<|endoftext|>


<commit_before>#[allow(unused_variables)]

pub struct School {
}

impl School {
    pub fn new() -> School {
        unimplemented!()
    }

    pub fn add(&mut self, grade: u32, student: &str) {
        unimplemented!()
    }

    pub fn grades(&self) -> Vec<u32> {
        unimplemented!()
    }

    // If grade returned an `Option<&Vec<String>>`,
    // the internal implementation would be forced to keep a `Vec<String>` to lend out.
    // By returning an owned vector instead,
    // the internal implementation is free to use whatever it chooses.
    pub fn grade(&self, grade: u32) -> Option<Vec<String>> {
        unimplemented!()
    }
}
<commit_msg>grade-school: remove #[allow(unused_variables)]<commit_after>pub struct School {
}

impl School {
    pub fn new() -> School {
        unimplemented!()
    }

    pub fn add(&mut self, grade: u32, student: &str) {
        unimplemented!("Add {} to the roster for {}", student, grade)
    }

    pub fn grades(&self) -> Vec<u32> {
        unimplemented!()
    }

    // If grade returned an `Option<&Vec<String>>`,
    // the internal implementation would be forced to keep a `Vec<String>` to lend out.
    // By returning an owned vector instead,
    // the internal implementation is free to use whatever it chooses.
    pub fn grade(&self, grade: u32) -> Option<Vec<String>> {
        unimplemented!("Return the list of students in {}", grade)
    }
}
<|endoftext|>


<commit_before>//! POST /_matrix/client/r0/keys/signatures/upload
//!
//! Defined in [MSC 1756](https://github.com/matrix-org/matrix-doc/blob/master/proposals/1756-cross-signing.md#uploading-signing-keys)

use std::collections::BTreeMap;

use ruma_api::ruma_api;
use ruma_identifiers::UserId;

ruma_api! {
    metadata: {
        description: "Publishes cross-signing signatures for the user.",
        method: POST,
        name: "upload_signatures",
        path: "/_matrix/client/r0/keys/signatures/upload",
        rate_limited: false,
        authentication: AccessToken,
    }

    request: {
        /// Signed keys.
        #[ruma_api(body)]
        pub signed_keys: BTreeMap<UserId, BTreeMap<String, serde_json::Value>>,
    }

    #[derive(Default)]
    response: {}

    error: crate::Error
}

impl Request {
    /// Creates a new `Request` with the given signed keys.
    pub fn new(signed_keys: BTreeMap<UserId, BTreeMap<String, serde_json::Value>>) -> Self {
        Self { signed_keys }
    }
}

impl Response {
    /// Creates an empty `Response`.
    pub fn new() -> Self {
        Self
    }
}
<commit_msg>Import serde_json::Value as JsonValue<commit_after>//! POST /_matrix/client/r0/keys/signatures/upload
//!
//! Defined in [MSC 1756](https://github.com/matrix-org/matrix-doc/blob/master/proposals/1756-cross-signing.md#uploading-signing-keys)

use std::collections::BTreeMap;

use ruma_api::ruma_api;
use ruma_identifiers::UserId;
use serde_json::Value as JsonValue;

ruma_api! {
    metadata: {
        description: "Publishes cross-signing signatures for the user.",
        method: POST,
        name: "upload_signatures",
        path: "/_matrix/client/r0/keys/signatures/upload",
        rate_limited: false,
        authentication: AccessToken,
    }

    request: {
        /// Signed keys.
        #[ruma_api(body)]
        pub signed_keys: BTreeMap<UserId, BTreeMap<String, JsonValue>>,
    }

    #[derive(Default)]
    response: {}

    error: crate::Error
}

impl Request {
    /// Creates a new `Request` with the given signed keys.
    pub fn new(signed_keys: BTreeMap<UserId, BTreeMap<String, JsonValue>>) -> Self {
        Self { signed_keys }
    }
}

impl Response {
    /// Creates an empty `Response`.
    pub fn new() -> Self {
        Self
    }
}
<|endoftext|>


<commit_before>struct Selector<T> {
    elements: Vec<T>,
    current: usize
}

use std::ops::{Deref, DerefMut};

impl<T> Deref for Selector<T> {
    type Target = T;
    fn deref(&self) -> &T {
        &self.elements[self.current]
    }
}

impl<T> DerefMut for Selector<T> {
    fn deref_mut(&mut self) -> &mut T {
        &mut self.elements[self.current]
    }
}

fn main() {
    let mut s = Selector { elements: vec!['x', 'y', 'z'],
                           current: 2 };

    assert_eq!(*s, 'z');
}

<commit_msg>smart coercion of ref and value types<commit_after>struct Selector<T> {
    elements: Vec<T>,
    current: usize
}

use std::ops::{Deref, DerefMut};

impl<T> Deref for Selector<T> {
    type Target = T;
    fn deref(&self) -> &T {
        &self.elements[self.current]
    }
}

impl<T> DerefMut for Selector<T> {
    fn deref_mut(&mut self) -> &mut T {
        &mut self.elements[self.current]
    }
}

// A string literal is a &str, but the type that implements AsRef<Path> is str,
// without an &. And as we explained in “Deref and DerefMut” on page 289,
// Rust doesn’t try deref coercions to satisfy type variable bounds,
// so they won’t help here either.

// Fortunately, the standard library includes the blanket implementation:

// impl<'a, T, U> AsRef<U> for &'a T
//   where T: AsRef<U>, T: ?Sized, U: ?Sized
// {
//     fn as_ref(&self) -> &U {
//         (*self).as_ref()
//     }
// }

// In other words, for any types T and U, if T: AsRef<U>, then &T: AsRef<U> as well:
// simply follow the reference and proceed as before.
// In particular, since str: AsRef<Path>, then &str: AsRef<Path> as well.
// In a sense, this is a way to get a limited form of deref coercion
// in checking AsRef bounds on type variables.

fn main() {
    let mut s = Selector { elements: vec!['x', 'y', 'z'],
                           current: 2 };

    assert_eq!(*s, 'z');
}

<|endoftext|>