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

use super::token;
use super::token::XPathToken;

pub struct XPathTokenizer {
    xpath: XPathString,
    start: uint,
    prefer_recognition_of_operator_names: bool,
}

pub type TokenResult = Result<XPathToken, TokenizerErr>;

#[deriving(Show,PartialEq,Clone)]
pub enum TokenizerErr {
    MissingLocalName,
    MismatchedQuoteCharacters,
    UnableToCreateToken,
}

struct XPathString {
    xpath: Vec<char>,
}

impl XPathString {
    fn new(xpath: &str) -> XPathString {
        XPathString {
            xpath: xpath.chars().collect(),
        }
    }

    fn len(& self) -> uint {
        self.xpath.len()
    }

    fn str_at_is(& self, offset: uint, needle: &[char]) -> bool {
        let s_len = needle.len();

        if self.xpath.len() < offset + s_len { return false; }

        let xpath_chars = self.xpath.slice(offset, offset + s_len);

        needle == xpath_chars
    }

    fn valid_ncname_start_char(& self, offset: uint) -> bool {
        let c = self.xpath[offset];
        if c >= 'A' && c <= 'Z' { return true }
        if c == '_' { return true }
        if c >= 'a' && c <= 'z' { return true }
        // TODO: All non-ASCII codepoints
        return false;
    }

    fn valid_ncname_follow_char(& self, offset: uint) -> bool {
        let c = self.xpath[offset];
        if self.valid_ncname_start_char(offset) { return true }
        if c == '-' { return true }
        if c == '.' { return true }
        if c >= '0' && c <= '9' { return true }
        // TODO: All non-ASCII codepoints
        return false;
    }

    fn while_valid_string(& self, offset: uint) -> uint {
        let mut offset = offset;

        if offset < self.xpath.len() && self.valid_ncname_start_char(offset) {
            offset += 1;

            while offset < self.xpath.len() && self.valid_ncname_follow_char(offset) {
                offset += 1;
            }
        }

        return offset;
    }

    fn while_valid_number(& self, offset: uint) -> uint {
        let mut offset = offset;

        while offset < self.xpath.len() && is_number_char(self.xpath[offset]) {
            offset += 1;
        }

        return offset;
    }

    fn while_not_character(& self, offset: uint, end_char: char) -> uint {
        let mut offset = offset;

        while offset < self.xpath.len() && self.xpath[offset] != end_char {
            offset += 1;
        }

        return offset;
    }

    fn substr(& self, start: uint, end: uint) -> String {
        String::from_chars(self.xpath.slice(start, end))
    }

    fn safe_substr(& self, start: uint, end: uint) -> Option<String> {
        if self.xpath.len() >= end {
            Some(self.substr(start, end))
        } else {
            None
        }
    }

    fn char_at(&self, offset: uint) -> char {
        self.xpath[offset]
    }

    fn char_at_is(&self, offset: uint, c: char) -> bool {
        let has_one_more = self.xpath.len() >= offset + 1;

        has_one_more && self.xpath[offset] == c
    }

    fn char_at_is_not(&self, offset: uint, c: char) -> bool {
        let has_one_more = self.xpath.len() >= offset + 1;

        ! has_one_more || self.xpath[offset] != c
    }

    fn char_at_is_not_digit(& self, offset: uint) -> bool {
        let has_more_chars = self.xpath.len() >= offset + 1;

        ! has_more_chars || ! is_digit(self.xpath[offset])
    }

    fn is_xml_space(&self, offset: uint) -> bool {
        let c = self.xpath[offset];

        return
            c == ' '  ||
            c == '\t' ||
            c == '\n' ||
            c == '\r';
    }

    fn end_of_whitespace(& self, offset: uint) -> uint {
        let mut offset = offset;

        while offset < self.xpath.len() && self.is_xml_space(offset) {
            offset += 1;
        }

        offset
    }
}

static QUOTE_CHARS: [char, .. 2] =  ['\'', '\"'];

impl XPathTokenizer {
    pub fn new(xpath: & str) -> XPathTokenizer {
        XPathTokenizer {
            xpath: XPathString::new(xpath),
            start: 0,
            prefer_recognition_of_operator_names: false,
        }
    }

    pub fn has_more_tokens(& self) -> bool {
        self.xpath.len() > self.start
    }

    fn two_char_tokens(& self) -> HashMap<String, XPathToken> {
        let mut m = HashMap::new();
        m.insert("<=".to_string(), token::LessThanOrEqual);
        m.insert(">=".to_string(), token::GreaterThanOrEqual);
        m.insert("!=".to_string(), token::NotEqual);
        m.insert("::".to_string(), token::DoubleColon);
        m.insert("//".to_string(), token::DoubleSlash);
        m.insert("..".to_string(), token::ParentNode);
        m
    }

    fn single_char_tokens(&self) -> HashMap<char, XPathToken> {
        let mut m = HashMap::new();
        m.insert('/', token::Slash);
        m.insert('(', token::LeftParen);
        m.insert(')', token::RightParen);
        m.insert('[', token::LeftBracket);
        m.insert(']', token::RightBracket);
        m.insert('@', token::AtSign);
        m.insert('$', token::DollarSign);
        m.insert('+', token::PlusSign);
        m.insert('-', token::MinusSign);
        m.insert('|', token::Pipe);
        m.insert('=', token::Equal);
        m.insert('<', token::LessThan);
        m.insert('>', token::GreaterThan);
        m
    }

    fn named_operators(& self) -> Vec<(& 'static str, XPathToken)> {
        vec!(("and", token::And),
             ("or",  token::Or),
             ("mod", token::Remainder),
             ("div", token::Divide),
             ("*",   token::Multiply))
    }

    fn tokenize_literal(& mut self, quote_char: char) -> TokenResult {
        let mut offset = self.start;

        offset += 1; // Skip over the starting quote
        let start_of_string = offset;

        offset = self.xpath.while_not_character(offset, quote_char);
        let end_of_string = offset;

        if self.xpath.char_at_is_not(offset, quote_char) {
            return Err(MismatchedQuoteCharacters);
        }
        offset += 1; // Skip over ending quote

        self.start = offset;
        return Ok(token::Literal(self.xpath.substr(start_of_string, end_of_string)));
    }

    fn raw_next_token(& mut self) -> TokenResult {
        match self.xpath.safe_substr(self.start, self.start + 2) {
            Some(first_two) => {
                match self.two_char_tokens().get(&first_two) {
                    Some(token) => {
                        self.start += 2;
                        return Ok(token.clone());
                    }
                    _ => {}
                }
            },
            _ => {}
        }

        let c = self.xpath.char_at(self.start);

        match self.single_char_tokens().get(&c) {
            Some(token) => {
                self.start += 1;
                return Ok(token.clone());
            }
            _ => {}
        }

        for quote_char in QUOTE_CHARS.iter() {
            if *quote_char == c {
                return self.tokenize_literal(*quote_char);
            }
        }

        if '.' == c {
            if self.xpath.char_at_is_not_digit(self.start + 1) {
                // Ugly. Should we use START / FOLLOW constructs?
                self.start += 1;
                return Ok(token::CurrentNode);
            }
        }

        if is_number_char(c) {
            let mut offset = self.start;
            let current_start = self.start;

            offset = self.xpath.while_valid_number(offset);

            self.start = offset;
            let substr = self.xpath.substr(current_start, offset);
            match from_str(substr.as_slice()) {
                Some(value) => Ok(token::Number(value)),
                None => panic!("Not really a number!")
            }
        } else {
            let mut offset = self.start;
            let current_start = self.start;

            if self.prefer_recognition_of_operator_names {
                for &(ref name, ref token) in self.named_operators().iter() {
                    let name_chars: Vec<char> = name.chars().collect();
                    let name_chars_slice = name_chars.as_slice();

                    if self.xpath.str_at_is(offset, name_chars_slice) {
                        self.start += name_chars.len();
                        return Ok(token.clone());
                    }
                }
            }

            if self.xpath.char_at_is(offset, '*') {
                self.start = offset + 1;
                return Ok(token::String("*".to_string()));
            }

            offset = self.xpath.while_valid_string(offset);

            if self.xpath.char_at_is(offset, ':') && self.xpath.char_at_is_not(offset + 1, ':') {
                let prefix = self.xpath.substr(current_start, offset);

                offset += 1;

                let current_start = offset;
                offset = self.xpath.while_valid_string(offset);

                if current_start == offset {
                    return Err(MissingLocalName);
                }

                let name = self.xpath.substr(current_start, offset);

                self.start = offset;
                return Ok(token::PrefixedName(prefix, name));

            } else {
                self.start = offset;
                return Ok(token::String(self.xpath.substr(current_start, offset)));
            }
        }
    }

    fn consume_whitespace(& mut self) {
        self.start = self.xpath.end_of_whitespace(self.start);
    }

    fn next_token(& mut self) -> TokenResult {
        self.consume_whitespace();

        let old_start = self.start;
        let token = self.raw_next_token();
        if token.is_err() { return token; }

        let token = token.unwrap();

        if old_start == self.start {
            return Err(UnableToCreateToken);
        }

        self.consume_whitespace();

        if ! (token.precedes_node_test() ||
              token.precedes_expression() ||
              token.is_operator()) {
            // See http://www.w3.org/TR/xpath/#exprlex
            self.prefer_recognition_of_operator_names = true;
        } else {
            self.prefer_recognition_of_operator_names = false;
        }

        return Ok(token);
    }
}

impl Iterator<TokenResult> for XPathTokenizer {
    fn next(&mut self) -> Option<TokenResult> {
        if self.has_more_tokens() {
            Some(self.next_token())
        } else {
            None
        }
    }
}

fn is_number_char(c: char) -> bool {
    return is_digit(c) || '.' == c;
}

pub struct XPathTokenDisambiguator<T, I> {
    source: ::std::iter::Peekable<T, I>,
}

impl<T, I: Iterator<T>> XPathTokenDisambiguator<T, I> {
    pub fn new(source: I) -> XPathTokenDisambiguator<T, I> {
        XPathTokenDisambiguator{
            source: source.peekable(),
        }
    }
}

static node_test_names : [&'static str, .. 4] =
    [ "comment", "text", "processing-instruction", "node" ];

impl<I: Iterator<TokenResult>> Iterator<TokenResult> for XPathTokenDisambiguator<TokenResult, I> {
    fn next(&mut self) -> Option<TokenResult> {
        let token = self.source.next();
        let next  = self.source.peek();

        match (token, next) {
            (Some(Ok(token::String(val))), Some(&Ok(token::LeftParen))) => {
                if node_test_names.contains(&val.as_slice()) {
                    Some(Ok(token::NodeTest(val)))
                } else {
                    Some(Ok(token::Function(val)))
                }
            },
            (Some(Ok(token::String(val))), Some(&Ok(token::DoubleColon))) => {
                Some(Ok(token::Axis(val)))
            },
            (token, _) => token,
        }
    }
}

pub struct XPathTokenDeabbreviator<I> {
    source: I,
    buffer: Vec<XPathToken>,
}

impl<I> XPathTokenDeabbreviator<I> {
    pub fn new(source: I) -> XPathTokenDeabbreviator<I> {
        XPathTokenDeabbreviator {
            source: source,
            buffer: vec!(),
        }
    }

    fn push(&mut self, token: XPathToken) {
        self.buffer.push(token);
    }

    fn expand_token(&mut self, token: XPathToken) {
        match token {
            token::AtSign => {
                self.push(token::String("attribute".to_string()));
                self.push(token::DoubleColon);
            }
            token::DoubleSlash => {
                self.push(token::Slash);
                self.push(token::String("descendant-or-self".to_string()));
                self.push(token::DoubleColon);
                self.push(token::String("node".to_string()));
                self.push(token::LeftParen);
                self.push(token::RightParen);
                self.push(token::Slash);
            }
            token::CurrentNode => {
                self.push(token::String("self".to_string()));
                self.push(token::DoubleColon);
                self.push(token::String("node".to_string()));
                self.push(token::LeftParen);
                self.push(token::RightParen);
            }
            token::ParentNode => {
                self.push(token::String("parent".to_string()));
                self.push(token::DoubleColon);
                self.push(token::String("node".to_string()));
                self.push(token::LeftParen);
                self.push(token::RightParen);
            }
            _ => {
                self.push(token);
            }
        }
    }
}

impl<I: Iterator<TokenResult>> Iterator<TokenResult> for XPathTokenDeabbreviator<I> {
    fn next(&mut self) -> Option<TokenResult> {
        if self.buffer.is_empty() {
            let token = self.source.next();

            match token {
                None => return token,
                Some(Err(_)) => return token,
                Some(Ok(token)) => self.expand_token(token),
            }
        }

        match self.buffer.remove(0) {
            Some(t) => Some(Ok(t)),
            None => panic!("No tokens left to return"), // Can't happen, we always add one
        }
    }
}
<commit_msg>Constants should be uppercase<commit_after>use std::collections::HashMap;
use std::char::is_digit;

use super::token;
use super::token::XPathToken;

pub struct XPathTokenizer {
    xpath: XPathString,
    start: uint,
    prefer_recognition_of_operator_names: bool,
}

pub type TokenResult = Result<XPathToken, TokenizerErr>;

#[deriving(Show,PartialEq,Clone)]
pub enum TokenizerErr {
    MissingLocalName,
    MismatchedQuoteCharacters,
    UnableToCreateToken,
}

struct XPathString {
    xpath: Vec<char>,
}

impl XPathString {
    fn new(xpath: &str) -> XPathString {
        XPathString {
            xpath: xpath.chars().collect(),
        }
    }

    fn len(& self) -> uint {
        self.xpath.len()
    }

    fn str_at_is(& self, offset: uint, needle: &[char]) -> bool {
        let s_len = needle.len();

        if self.xpath.len() < offset + s_len { return false; }

        let xpath_chars = self.xpath.slice(offset, offset + s_len);

        needle == xpath_chars
    }

    fn valid_ncname_start_char(& self, offset: uint) -> bool {
        let c = self.xpath[offset];
        if c >= 'A' && c <= 'Z' { return true }
        if c == '_' { return true }
        if c >= 'a' && c <= 'z' { return true }
        // TODO: All non-ASCII codepoints
        return false;
    }

    fn valid_ncname_follow_char(& self, offset: uint) -> bool {
        let c = self.xpath[offset];
        if self.valid_ncname_start_char(offset) { return true }
        if c == '-' { return true }
        if c == '.' { return true }
        if c >= '0' && c <= '9' { return true }
        // TODO: All non-ASCII codepoints
        return false;
    }

    fn while_valid_string(& self, offset: uint) -> uint {
        let mut offset = offset;

        if offset < self.xpath.len() && self.valid_ncname_start_char(offset) {
            offset += 1;

            while offset < self.xpath.len() && self.valid_ncname_follow_char(offset) {
                offset += 1;
            }
        }

        return offset;
    }

    fn while_valid_number(& self, offset: uint) -> uint {
        let mut offset = offset;

        while offset < self.xpath.len() && is_number_char(self.xpath[offset]) {
            offset += 1;
        }

        return offset;
    }

    fn while_not_character(& self, offset: uint, end_char: char) -> uint {
        let mut offset = offset;

        while offset < self.xpath.len() && self.xpath[offset] != end_char {
            offset += 1;
        }

        return offset;
    }

    fn substr(& self, start: uint, end: uint) -> String {
        String::from_chars(self.xpath.slice(start, end))
    }

    fn safe_substr(& self, start: uint, end: uint) -> Option<String> {
        if self.xpath.len() >= end {
            Some(self.substr(start, end))
        } else {
            None
        }
    }

    fn char_at(&self, offset: uint) -> char {
        self.xpath[offset]
    }

    fn char_at_is(&self, offset: uint, c: char) -> bool {
        let has_one_more = self.xpath.len() >= offset + 1;

        has_one_more && self.xpath[offset] == c
    }

    fn char_at_is_not(&self, offset: uint, c: char) -> bool {
        let has_one_more = self.xpath.len() >= offset + 1;

        ! has_one_more || self.xpath[offset] != c
    }

    fn char_at_is_not_digit(& self, offset: uint) -> bool {
        let has_more_chars = self.xpath.len() >= offset + 1;

        ! has_more_chars || ! is_digit(self.xpath[offset])
    }

    fn is_xml_space(&self, offset: uint) -> bool {
        let c = self.xpath[offset];

        return
            c == ' '  ||
            c == '\t' ||
            c == '\n' ||
            c == '\r';
    }

    fn end_of_whitespace(& self, offset: uint) -> uint {
        let mut offset = offset;

        while offset < self.xpath.len() && self.is_xml_space(offset) {
            offset += 1;
        }

        offset
    }
}

static QUOTE_CHARS: [char, .. 2] =  ['\'', '\"'];

impl XPathTokenizer {
    pub fn new(xpath: & str) -> XPathTokenizer {
        XPathTokenizer {
            xpath: XPathString::new(xpath),
            start: 0,
            prefer_recognition_of_operator_names: false,
        }
    }

    pub fn has_more_tokens(& self) -> bool {
        self.xpath.len() > self.start
    }

    fn two_char_tokens(& self) -> HashMap<String, XPathToken> {
        let mut m = HashMap::new();
        m.insert("<=".to_string(), token::LessThanOrEqual);
        m.insert(">=".to_string(), token::GreaterThanOrEqual);
        m.insert("!=".to_string(), token::NotEqual);
        m.insert("::".to_string(), token::DoubleColon);
        m.insert("//".to_string(), token::DoubleSlash);
        m.insert("..".to_string(), token::ParentNode);
        m
    }

    fn single_char_tokens(&self) -> HashMap<char, XPathToken> {
        let mut m = HashMap::new();
        m.insert('/', token::Slash);
        m.insert('(', token::LeftParen);
        m.insert(')', token::RightParen);
        m.insert('[', token::LeftBracket);
        m.insert(']', token::RightBracket);
        m.insert('@', token::AtSign);
        m.insert('$', token::DollarSign);
        m.insert('+', token::PlusSign);
        m.insert('-', token::MinusSign);
        m.insert('|', token::Pipe);
        m.insert('=', token::Equal);
        m.insert('<', token::LessThan);
        m.insert('>', token::GreaterThan);
        m
    }

    fn named_operators(& self) -> Vec<(& 'static str, XPathToken)> {
        vec!(("and", token::And),
             ("or",  token::Or),
             ("mod", token::Remainder),
             ("div", token::Divide),
             ("*",   token::Multiply))
    }

    fn tokenize_literal(& mut self, quote_char: char) -> TokenResult {
        let mut offset = self.start;

        offset += 1; // Skip over the starting quote
        let start_of_string = offset;

        offset = self.xpath.while_not_character(offset, quote_char);
        let end_of_string = offset;

        if self.xpath.char_at_is_not(offset, quote_char) {
            return Err(MismatchedQuoteCharacters);
        }
        offset += 1; // Skip over ending quote

        self.start = offset;
        return Ok(token::Literal(self.xpath.substr(start_of_string, end_of_string)));
    }

    fn raw_next_token(& mut self) -> TokenResult {
        match self.xpath.safe_substr(self.start, self.start + 2) {
            Some(first_two) => {
                match self.two_char_tokens().get(&first_two) {
                    Some(token) => {
                        self.start += 2;
                        return Ok(token.clone());
                    }
                    _ => {}
                }
            },
            _ => {}
        }

        let c = self.xpath.char_at(self.start);

        match self.single_char_tokens().get(&c) {
            Some(token) => {
                self.start += 1;
                return Ok(token.clone());
            }
            _ => {}
        }

        for quote_char in QUOTE_CHARS.iter() {
            if *quote_char == c {
                return self.tokenize_literal(*quote_char);
            }
        }

        if '.' == c {
            if self.xpath.char_at_is_not_digit(self.start + 1) {
                // Ugly. Should we use START / FOLLOW constructs?
                self.start += 1;
                return Ok(token::CurrentNode);
            }
        }

        if is_number_char(c) {
            let mut offset = self.start;
            let current_start = self.start;

            offset = self.xpath.while_valid_number(offset);

            self.start = offset;
            let substr = self.xpath.substr(current_start, offset);
            match from_str(substr.as_slice()) {
                Some(value) => Ok(token::Number(value)),
                None => panic!("Not really a number!")
            }
        } else {
            let mut offset = self.start;
            let current_start = self.start;

            if self.prefer_recognition_of_operator_names {
                for &(ref name, ref token) in self.named_operators().iter() {
                    let name_chars: Vec<char> = name.chars().collect();
                    let name_chars_slice = name_chars.as_slice();

                    if self.xpath.str_at_is(offset, name_chars_slice) {
                        self.start += name_chars.len();
                        return Ok(token.clone());
                    }
                }
            }

            if self.xpath.char_at_is(offset, '*') {
                self.start = offset + 1;
                return Ok(token::String("*".to_string()));
            }

            offset = self.xpath.while_valid_string(offset);

            if self.xpath.char_at_is(offset, ':') && self.xpath.char_at_is_not(offset + 1, ':') {
                let prefix = self.xpath.substr(current_start, offset);

                offset += 1;

                let current_start = offset;
                offset = self.xpath.while_valid_string(offset);

                if current_start == offset {
                    return Err(MissingLocalName);
                }

                let name = self.xpath.substr(current_start, offset);

                self.start = offset;
                return Ok(token::PrefixedName(prefix, name));

            } else {
                self.start = offset;
                return Ok(token::String(self.xpath.substr(current_start, offset)));
            }
        }
    }

    fn consume_whitespace(& mut self) {
        self.start = self.xpath.end_of_whitespace(self.start);
    }

    fn next_token(& mut self) -> TokenResult {
        self.consume_whitespace();

        let old_start = self.start;
        let token = self.raw_next_token();
        if token.is_err() { return token; }

        let token = token.unwrap();

        if old_start == self.start {
            return Err(UnableToCreateToken);
        }

        self.consume_whitespace();

        if ! (token.precedes_node_test() ||
              token.precedes_expression() ||
              token.is_operator()) {
            // See http://www.w3.org/TR/xpath/#exprlex
            self.prefer_recognition_of_operator_names = true;
        } else {
            self.prefer_recognition_of_operator_names = false;
        }

        return Ok(token);
    }
}

impl Iterator<TokenResult> for XPathTokenizer {
    fn next(&mut self) -> Option<TokenResult> {
        if self.has_more_tokens() {
            Some(self.next_token())
        } else {
            None
        }
    }
}

fn is_number_char(c: char) -> bool {
    return is_digit(c) || '.' == c;
}

pub struct XPathTokenDisambiguator<T, I> {
    source: ::std::iter::Peekable<T, I>,
}

impl<T, I: Iterator<T>> XPathTokenDisambiguator<T, I> {
    pub fn new(source: I) -> XPathTokenDisambiguator<T, I> {
        XPathTokenDisambiguator{
            source: source.peekable(),
        }
    }
}

static NODE_TEST_NAMES : [&'static str, .. 4] =
    [ "comment", "text", "processing-instruction", "node" ];

impl<I: Iterator<TokenResult>> Iterator<TokenResult> for XPathTokenDisambiguator<TokenResult, I> {
    fn next(&mut self) -> Option<TokenResult> {
        let token = self.source.next();
        let next  = self.source.peek();

        match (token, next) {
            (Some(Ok(token::String(val))), Some(&Ok(token::LeftParen))) => {
                if NODE_TEST_NAMES.contains(&val.as_slice()) {
                    Some(Ok(token::NodeTest(val)))
                } else {
                    Some(Ok(token::Function(val)))
                }
            },
            (Some(Ok(token::String(val))), Some(&Ok(token::DoubleColon))) => {
                Some(Ok(token::Axis(val)))
            },
            (token, _) => token,
        }
    }
}

pub struct XPathTokenDeabbreviator<I> {
    source: I,
    buffer: Vec<XPathToken>,
}

impl<I> XPathTokenDeabbreviator<I> {
    pub fn new(source: I) -> XPathTokenDeabbreviator<I> {
        XPathTokenDeabbreviator {
            source: source,
            buffer: vec!(),
        }
    }

    fn push(&mut self, token: XPathToken) {
        self.buffer.push(token);
    }

    fn expand_token(&mut self, token: XPathToken) {
        match token {
            token::AtSign => {
                self.push(token::String("attribute".to_string()));
                self.push(token::DoubleColon);
            }
            token::DoubleSlash => {
                self.push(token::Slash);
                self.push(token::String("descendant-or-self".to_string()));
                self.push(token::DoubleColon);
                self.push(token::String("node".to_string()));
                self.push(token::LeftParen);
                self.push(token::RightParen);
                self.push(token::Slash);
            }
            token::CurrentNode => {
                self.push(token::String("self".to_string()));
                self.push(token::DoubleColon);
                self.push(token::String("node".to_string()));
                self.push(token::LeftParen);
                self.push(token::RightParen);
            }
            token::ParentNode => {
                self.push(token::String("parent".to_string()));
                self.push(token::DoubleColon);
                self.push(token::String("node".to_string()));
                self.push(token::LeftParen);
                self.push(token::RightParen);
            }
            _ => {
                self.push(token);
            }
        }
    }
}

impl<I: Iterator<TokenResult>> Iterator<TokenResult> for XPathTokenDeabbreviator<I> {
    fn next(&mut self) -> Option<TokenResult> {
        if self.buffer.is_empty() {
            let token = self.source.next();

            match token {
                None => return token,
                Some(Err(_)) => return token,
                Some(Ok(token)) => self.expand_token(token),
            }
        }

        match self.buffer.remove(0) {
            Some(t) => Some(Ok(t)),
            None => panic!("No tokens left to return"), // Can't happen, we always add one
        }
    }
}
<|endoftext|>


<commit_before>mod prelude {
    pub use super::log_request::add_custom_metadata;
    pub use conduit::{box_error, header, Body, Handler, RequestExt, Response, StatusCode};
    pub use conduit_middleware::{AfterResult, AroundMiddleware, BeforeResult, Middleware};
}

use self::app::AppMiddleware;
use self::debug::*;
use self::ember_html::EmberHtml;
use self::head::Head;
use self::known_error_to_json::KnownErrorToJson;
use self::log_connection_pool_status::LogConnectionPoolStatus;
use self::response_timing::ResponseTiming;
use self::static_or_continue::StaticOrContinue;
use self::update_metrics::UpdateMetrics;

pub mod app;
mod balance_capacity;
mod block_traffic;
mod debug;
mod ember_html;
mod head;
mod known_error_to_json;
mod log_connection_pool_status;
pub mod log_request;
mod normalize_path;
mod require_user_agent;
pub mod response_timing;
mod static_or_continue;
mod update_metrics;

use conduit_conditional_get::ConditionalGet;
use conduit_cookie::{Middleware as Cookie, SessionMiddleware};
use conduit_middleware::MiddlewareBuilder;
use conduit_router::RouteBuilder;

use std::env;
use std::sync::Arc;

use crate::sentry::SentryMiddleware;
use crate::{App, Env};

pub fn build_middleware(app: Arc<App>, endpoints: RouteBuilder) -> MiddlewareBuilder {
    let mut m = MiddlewareBuilder::new(endpoints);
    let env = app.config.env();
    let blocked_traffic = app.config.blocked_traffic.clone();

    if env != Env::Test {
        m.add(SentryMiddleware::with_transactions());
        m.add(log_request::LogRequests::default());
    }

    m.add(ResponseTiming::default());

    if env == Env::Development {
        // Optionally print debug information for each request
        // To enable, set the environment variable: `RUST_LOG=cargo_registry::middleware=debug`
        m.add(Debug);
    }

    if env::var_os("LOG_CONNECTION_POOL_STATUS").is_some() {
        m.add(LogConnectionPoolStatus::new(&app));
    }

    m.add(normalize_path::NormalizePath);
    m.add(ConditionalGet);

    m.add(Cookie::new());
    m.add(SessionMiddleware::new(
        "cargo_session",
        cookie::Key::derive_from(app.session_key().as_bytes()),
        env == Env::Production,
    ));

    m.add(AppMiddleware::new(app));
    m.add(KnownErrorToJson);

    // This is added *after* AppMiddleware to make sure the app is available.
    m.add(UpdateMetrics);

    // Note: The following `m.around()` middleware is run from bottom to top

    // This is currently the final middleware to run. If a middleware layer requires a database
    // connection, it should be run after this middleware so that the potential pool usage can be
    // tracked here.
    //
    // In production we currently have 2 equally sized pools (primary and a read-only replica).
    // Because such a large portion of production traffic is for download requests (which update
    // download counts), we consider only the primary pool here.
    if let Ok(capacity) = env::var("DB_PRIMARY_POOL_SIZE") {
        if let Ok(capacity) = capacity.parse() {
            if capacity >= 10 {
                println!("Enabling BalanceCapacity middleware with {capacity} pool capacity");
                m.around(balance_capacity::BalanceCapacity::new(capacity))
            } else {
                println!(
                    "BalanceCapacity middleware not enabled. DB_PRIMARY_POOL_SIZE is too low."
                );
            }
        }
    }

    // Serve the static files in the *dist* directory, which are the frontend assets.
    // Not needed for the backend tests.
    if env != Env::Test {
        m.around(EmberHtml::new("dist"));
        m.around(StaticOrContinue::new("dist"));
    }

    if env == Env::Development {
        // Locally serve crates and readmes
        m.around(StaticOrContinue::new("local_uploads"));
    }

    m.around(Head::default());

    for (header, blocked_values) in blocked_traffic {
        m.around(block_traffic::BlockTraffic::new(header, blocked_values));
    }

    m.around(require_user_agent::RequireUserAgent::default());

    m
}
<commit_msg>middleware: Use `tracing` macros instead of `println!()`<commit_after>mod prelude {
    pub use super::log_request::add_custom_metadata;
    pub use conduit::{box_error, header, Body, Handler, RequestExt, Response, StatusCode};
    pub use conduit_middleware::{AfterResult, AroundMiddleware, BeforeResult, Middleware};
}

use self::app::AppMiddleware;
use self::debug::*;
use self::ember_html::EmberHtml;
use self::head::Head;
use self::known_error_to_json::KnownErrorToJson;
use self::log_connection_pool_status::LogConnectionPoolStatus;
use self::response_timing::ResponseTiming;
use self::static_or_continue::StaticOrContinue;
use self::update_metrics::UpdateMetrics;

pub mod app;
mod balance_capacity;
mod block_traffic;
mod debug;
mod ember_html;
mod head;
mod known_error_to_json;
mod log_connection_pool_status;
pub mod log_request;
mod normalize_path;
mod require_user_agent;
pub mod response_timing;
mod static_or_continue;
mod update_metrics;

use conduit_conditional_get::ConditionalGet;
use conduit_cookie::{Middleware as Cookie, SessionMiddleware};
use conduit_middleware::MiddlewareBuilder;
use conduit_router::RouteBuilder;

use std::env;
use std::sync::Arc;

use crate::sentry::SentryMiddleware;
use crate::{App, Env};

pub fn build_middleware(app: Arc<App>, endpoints: RouteBuilder) -> MiddlewareBuilder {
    let mut m = MiddlewareBuilder::new(endpoints);
    let env = app.config.env();
    let blocked_traffic = app.config.blocked_traffic.clone();

    if env != Env::Test {
        m.add(SentryMiddleware::with_transactions());
        m.add(log_request::LogRequests::default());
    }

    m.add(ResponseTiming::default());

    if env == Env::Development {
        // Optionally print debug information for each request
        // To enable, set the environment variable: `RUST_LOG=cargo_registry::middleware=debug`
        m.add(Debug);
    }

    if env::var_os("LOG_CONNECTION_POOL_STATUS").is_some() {
        m.add(LogConnectionPoolStatus::new(&app));
    }

    m.add(normalize_path::NormalizePath);
    m.add(ConditionalGet);

    m.add(Cookie::new());
    m.add(SessionMiddleware::new(
        "cargo_session",
        cookie::Key::derive_from(app.session_key().as_bytes()),
        env == Env::Production,
    ));

    m.add(AppMiddleware::new(app));
    m.add(KnownErrorToJson);

    // This is added *after* AppMiddleware to make sure the app is available.
    m.add(UpdateMetrics);

    // Note: The following `m.around()` middleware is run from bottom to top

    // This is currently the final middleware to run. If a middleware layer requires a database
    // connection, it should be run after this middleware so that the potential pool usage can be
    // tracked here.
    //
    // In production we currently have 2 equally sized pools (primary and a read-only replica).
    // Because such a large portion of production traffic is for download requests (which update
    // download counts), we consider only the primary pool here.
    if let Ok(capacity) = env::var("DB_PRIMARY_POOL_SIZE") {
        if let Ok(capacity) = capacity.parse() {
            if capacity >= 10 {
                info!(?capacity, "Enabling BalanceCapacity middleware");
                m.around(balance_capacity::BalanceCapacity::new(capacity))
            } else {
                info!("BalanceCapacity middleware not enabled. DB_PRIMARY_POOL_SIZE is too low.");
            }
        }
    }

    // Serve the static files in the *dist* directory, which are the frontend assets.
    // Not needed for the backend tests.
    if env != Env::Test {
        m.around(EmberHtml::new("dist"));
        m.around(StaticOrContinue::new("dist"));
    }

    if env == Env::Development {
        // Locally serve crates and readmes
        m.around(StaticOrContinue::new("local_uploads"));
    }

    m.around(Head::default());

    for (header, blocked_values) in blocked_traffic {
        m.around(block_traffic::BlockTraffic::new(header, blocked_values));
    }

    m.around(require_user_agent::RequireUserAgent::default());

    m
}
<|endoftext|>


<commit_before>use std::rc::Rc;

use automation::Automation;
use partial::Partial;

use super::node::{ANode, YNode, ASrcNode, YSrcNode, YSinkNode};
use super::send::Send;

trait Tree {
    /// Connect two nodes in the tree.
    fn add_send(&mut self, send: Send);

    /// add Automation external stimuli to the tree.
    fn feed_a(&mut self, a: Automation, src: Rc<ASrcNode>);
    /// add Partial external stimuli to the tree.
    fn feed_y(&mut self, y: Partial, src: Rc<YSrcNode>);
    /// Poll the next Partial to arrive at the provided Sink.
    /// Will return None if there are no new partials to be read.
    fn sink_y(&mut self, sink: Rc<YSinkNode>) -> Option<Partial>;
}
<commit_msg>next() function takes no parameters. If the caller gets an unexpected node, they may ignore it.<commit_after>use std::rc::Rc;

use automation::Automation;
use partial::Partial;

use super::node::{ANode, YNode, ASrcNode, YSrcNode, YSinkNode};
use super::send::Send;

trait Tree {
    /// Connect two nodes in the tree.
    fn add_send(&mut self, send: Send);

    /// add Automation external stimuli to the tree.
    fn feed_a(&mut self, a: Automation, src: Rc<ASrcNode>);
    /// add Partial external stimuli to the tree.
    fn feed_y(&mut self, y: Partial, src: Rc<YSrcNode>);
    /// Poll the next Partial to arrive at any sink.
    /// Will return None if there are no new partials to be output.
    fn next(&mut self) -> Option<Rc<YSinkNode>, Partial>;
}
<|endoftext|>


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

use models::DependencyKind;

#[derive(PartialEq, Debug, Serialize, Deserialize)]
pub struct EncodableBadge {
    pub badge_type: String,
    pub attributes: HashMap<String, Option<String>>,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct EncodableCategory {
    pub id: String,
    pub category: String,
    pub slug: String,
    pub description: String,
    #[serde(with = "::util::rfc3339")]
    pub created_at: NaiveDateTime,
    pub crates_cnt: i32,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct EncodableCategoryWithSubcategories {
    pub id: String,
    pub category: String,
    pub slug: String,
    pub description: String,
    #[serde(with = "::util::rfc3339")]
    pub created_at: NaiveDateTime,
    pub crates_cnt: i32,
    pub subcategories: Vec<EncodableCategory>,
    pub parent_categories: Vec<EncodableCategory>,
}

/// The serialization format for the `CrateOwnerInvitation` model.
#[derive(Deserialize, Serialize, Debug)]
pub struct EncodableCrateOwnerInvitation {
    pub invited_by_username: String,
    pub crate_name: String,
    pub crate_id: i32,
    #[serde(with = "::util::rfc3339")]
    pub created_at: NaiveDateTime,
}

#[derive(Deserialize, Serialize, Debug, Copy, Clone)]
pub struct InvitationResponse {
    pub crate_id: i32,
    pub accepted: bool,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct EncodableDependency {
    pub id: i32,
    pub version_id: i32,
    pub crate_id: String,
    pub req: String,
    pub optional: bool,
    pub default_features: bool,
    pub features: Vec<String>,
    pub target: Option<String>,
    pub kind: DependencyKind,
    pub downloads: i32,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct EncodableVersionDownload {
    pub id: i32,
    pub version: i32,
    pub downloads: i32,
    pub date: String,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct EncodableKeyword {
    pub id: String,
    pub keyword: String,
    #[serde(with = "::util::rfc3339")]
    pub created_at: NaiveDateTime,
    pub crates_cnt: i32,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct EncodableCrate {
    pub id: String,
    pub name: String,
    #[serde(with = "::util::rfc3339")]
    pub updated_at: NaiveDateTime,
    pub versions: Option<Vec<i32>>,
    pub keywords: Option<Vec<String>>,
    pub categories: Option<Vec<String>>,
    pub badges: Option<Vec<EncodableBadge>>,
    #[serde(with = "::util::rfc3339")]
    pub created_at: NaiveDateTime,
    pub downloads: i32,
    pub recent_downloads: Option<i64>,
    pub max_version: String,
    pub description: Option<String>,
    pub homepage: Option<String>,
    pub documentation: Option<String>,
    pub repository: Option<String>,
    pub links: EncodableCrateLinks,
    pub exact_match: bool,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct EncodableCrateLinks {
    pub version_downloads: String,
    pub versions: Option<String>,
    pub owners: Option<String>,
    pub owner_team: Option<String>,
    pub owner_user: Option<String>,
    pub reverse_dependencies: String,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct EncodableOwner {
    pub id: i32,
    pub login: String,
    pub kind: String,
    pub url: Option<String>,
    pub name: Option<String>,
    pub avatar: Option<String>,
}

#[derive(Serialize, Debug)]
pub struct EncodableTeam {
    pub id: i32,
    pub login: String,
    pub name: Option<String>,
    pub avatar: Option<String>,
    pub url: Option<String>,
}

/// The serialization format for the `ApiToken` model with its token value.
/// This should only be used when initially creating a new token to minimize
/// the chance of token leaks.
#[derive(Deserialize, Serialize, Debug)]
pub struct EncodableApiTokenWithToken {
    pub id: i32,
    pub name: String,
    pub token: String,
    #[serde(with = "::util::rfc3339")]
    pub created_at: NaiveDateTime,
    #[serde(with = "::util::rfc3339::option")]
    pub last_used_at: Option<NaiveDateTime>,
}

/// The serialization format for the `User` model.
/// Same as public user, except for addition of
/// email field
#[derive(Deserialize, Serialize, Debug)]
pub struct EncodablePrivateUser {
    pub id: i32,
    pub login: String,
    pub email: Option<String>,
    pub email_verified: bool,
    pub email_verification_sent: bool,
    pub name: Option<String>,
    pub avatar: Option<String>,
    pub url: Option<String>,
}

/// The serialization format for the `User` model.
/// Same as private user, except no email field
#[derive(Deserialize, Serialize, Debug)]
pub struct EncodablePublicUser {
    pub id: i32,
    pub login: String,
    pub name: Option<String>,
    pub avatar: Option<String>,
    pub url: Option<String>,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct EncodableVersion {
    pub id: i32,
    #[serde(rename = "crate")]
    pub krate: String,
    pub num: String,
    pub dl_path: String,
    pub readme_path: String,
    #[serde(with = "::util::rfc3339")]
    pub updated_at: NaiveDateTime,
    #[serde(with = "::util::rfc3339")]
    pub created_at: NaiveDateTime,
    pub downloads: i32,
    pub features: HashMap<String, Vec<String>>,
    pub yanked: bool,
    pub license: Option<String>,
    pub links: EncodableVersionLinks,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct EncodableVersionLinks {
    pub dependencies: String,
    pub version_downloads: String,
    pub authors: String,
}

// TODO: Prefix many of these with `Encodable` then clean up the reexports
pub mod krate_publish;
pub use self::krate_publish::CrateDependency as EncodableCrateDependency;
pub use self::krate_publish::NewCrate as EncodableCrateUpload;

#[cfg(test)]
mod tests {
    use super::*;
    use chrono::NaiveDate;
    use serde_json;
    use std::collections::HashMap;

    #[test]
    fn category_dates_serializes_to_rfc3339() {
        let cat = EncodableCategory {
            id: "".to_string(),
            category: "".to_string(),
            slug: "".to_string(),
            description: "".to_string(),
            crates_cnt: 1,
            created_at: NaiveDate::from_ymd(2017, 1, 6).and_hms(14, 23, 11),
        };
        let json = serde_json::to_string(&cat).unwrap();
        assert!(
            json.as_str()
                .find(r#""created_at":"2017-01-06T14:23:11+00:00""#)
                .is_some()
        );
    }

    #[test]
    fn category_with_sub_dates_serializes_to_rfc3339() {
        let cat = EncodableCategoryWithSubcategories {
            id: "".to_string(),
            category: "".to_string(),
            slug: "".to_string(),
            description: "".to_string(),
            crates_cnt: 1,
            created_at: NaiveDate::from_ymd(2017, 1, 6).and_hms(14, 23, 11),
            subcategories: vec![],
        };
        let json = serde_json::to_string(&cat).unwrap();
        assert!(
            json.as_str()
                .find(r#""created_at":"2017-01-06T14:23:11+00:00""#)
                .is_some()
        );
    }

    #[test]
    fn keyword_serializes_to_rfc3339() {
        let key = EncodableKeyword {
            id: "".to_string(),
            keyword: "".to_string(),
            created_at: NaiveDate::from_ymd(2017, 1, 6).and_hms(14, 23, 11),
            crates_cnt: 0,
        };
        let json = serde_json::to_string(&key).unwrap();
        assert!(
            json.as_str()
                .find(r#""created_at":"2017-01-06T14:23:11+00:00""#)
                .is_some()
        );
    }

    #[test]
    fn version_serializes_to_rfc3339() {
        let ver = EncodableVersion {
            id: 1,
            krate: "".to_string(),
            num: "".to_string(),
            dl_path: "".to_string(),
            readme_path: "".to_string(),
            updated_at: NaiveDate::from_ymd(2017, 1, 6).and_hms(14, 23, 11),
            created_at: NaiveDate::from_ymd(2017, 1, 6).and_hms(14, 23, 12),
            downloads: 0,
            features: HashMap::new(),
            yanked: false,
            license: None,
            links: EncodableVersionLinks {
                dependencies: "".to_string(),
                version_downloads: "".to_string(),
                authors: "".to_string(),
            },
        };
        let json = serde_json::to_string(&ver).unwrap();
        assert!(
            json.as_str()
                .find(r#""updated_at":"2017-01-06T14:23:11+00:00""#)
                .is_some()
        );
        assert!(
            json.as_str()
                .find(r#""created_at":"2017-01-06T14:23:12+00:00""#)
                .is_some()
        );
    }

    #[test]
    fn crate_serializes_to_rfc3399() {
        let crt = EncodableCrate {
            id: "".to_string(),
            name: "".to_string(),
            updated_at: NaiveDate::from_ymd(2017, 1, 6).and_hms(14, 23, 11),
            versions: None,
            keywords: None,
            categories: None,
            badges: None,
            created_at: NaiveDate::from_ymd(2017, 1, 6).and_hms(14, 23, 12),
            downloads: 0,
            recent_downloads: None,
            max_version: "".to_string(),
            description: None,
            homepage: None,
            documentation: None,
            repository: None,
            links: EncodableCrateLinks {
                version_downloads: "".to_string(),
                versions: None,
                owners: None,
                owner_team: None,
                owner_user: None,
                reverse_dependencies: "".to_string(),
            },
            exact_match: false,
        };
        let json = serde_json::to_string(&crt).unwrap();
        assert!(
            json.as_str()
                .find(r#""updated_at":"2017-01-06T14:23:11+00:00""#)
                .is_some()
        );
        assert!(
            json.as_str()
                .find(r#""created_at":"2017-01-06T14:23:12+00:00""#)
                .is_some()
        );
    }

    #[test]
    fn crate_owner_invitation_serializes_to_rfc3339() {
        let inv = EncodableCrateOwnerInvitation {
            invited_by_username: "".to_string(),
            crate_name: "".to_string(),
            crate_id: 123,
            created_at: NaiveDate::from_ymd(2017, 1, 6).and_hms(14, 23, 11),
        };
        let json = serde_json::to_string(&inv).unwrap();
        assert!(
            json.as_str()
                .find(r#""created_at":"2017-01-06T14:23:11+00:00""#)
                .is_some()
        );
    }
}
<commit_msg>master merge fixup<commit_after>use chrono::NaiveDateTime;
use std::collections::HashMap;

use models::DependencyKind;

#[derive(PartialEq, Debug, Serialize, Deserialize)]
pub struct EncodableBadge {
    pub badge_type: String,
    pub attributes: HashMap<String, Option<String>>,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct EncodableCategory {
    pub id: String,
    pub category: String,
    pub slug: String,
    pub description: String,
    #[serde(with = "::util::rfc3339")]
    pub created_at: NaiveDateTime,
    pub crates_cnt: i32,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct EncodableCategoryWithSubcategories {
    pub id: String,
    pub category: String,
    pub slug: String,
    pub description: String,
    #[serde(with = "::util::rfc3339")]
    pub created_at: NaiveDateTime,
    pub crates_cnt: i32,
    pub subcategories: Vec<EncodableCategory>,
    pub parent_categories: Vec<EncodableCategory>,
}

/// The serialization format for the `CrateOwnerInvitation` model.
#[derive(Deserialize, Serialize, Debug)]
pub struct EncodableCrateOwnerInvitation {
    pub invited_by_username: String,
    pub crate_name: String,
    pub crate_id: i32,
    #[serde(with = "::util::rfc3339")]
    pub created_at: NaiveDateTime,
}

#[derive(Deserialize, Serialize, Debug, Copy, Clone)]
pub struct InvitationResponse {
    pub crate_id: i32,
    pub accepted: bool,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct EncodableDependency {
    pub id: i32,
    pub version_id: i32,
    pub crate_id: String,
    pub req: String,
    pub optional: bool,
    pub default_features: bool,
    pub features: Vec<String>,
    pub target: Option<String>,
    pub kind: DependencyKind,
    pub downloads: i32,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct EncodableVersionDownload {
    pub id: i32,
    pub version: i32,
    pub downloads: i32,
    pub date: String,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct EncodableKeyword {
    pub id: String,
    pub keyword: String,
    #[serde(with = "::util::rfc3339")]
    pub created_at: NaiveDateTime,
    pub crates_cnt: i32,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct EncodableCrate {
    pub id: String,
    pub name: String,
    #[serde(with = "::util::rfc3339")]
    pub updated_at: NaiveDateTime,
    pub versions: Option<Vec<i32>>,
    pub keywords: Option<Vec<String>>,
    pub categories: Option<Vec<String>>,
    pub badges: Option<Vec<EncodableBadge>>,
    #[serde(with = "::util::rfc3339")]
    pub created_at: NaiveDateTime,
    pub downloads: i32,
    pub recent_downloads: Option<i64>,
    pub max_version: String,
    pub description: Option<String>,
    pub homepage: Option<String>,
    pub documentation: Option<String>,
    pub repository: Option<String>,
    pub links: EncodableCrateLinks,
    pub exact_match: bool,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct EncodableCrateLinks {
    pub version_downloads: String,
    pub versions: Option<String>,
    pub owners: Option<String>,
    pub owner_team: Option<String>,
    pub owner_user: Option<String>,
    pub reverse_dependencies: String,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct EncodableOwner {
    pub id: i32,
    pub login: String,
    pub kind: String,
    pub url: Option<String>,
    pub name: Option<String>,
    pub avatar: Option<String>,
}

#[derive(Serialize, Debug)]
pub struct EncodableTeam {
    pub id: i32,
    pub login: String,
    pub name: Option<String>,
    pub avatar: Option<String>,
    pub url: Option<String>,
}

/// The serialization format for the `ApiToken` model with its token value.
/// This should only be used when initially creating a new token to minimize
/// the chance of token leaks.
#[derive(Deserialize, Serialize, Debug)]
pub struct EncodableApiTokenWithToken {
    pub id: i32,
    pub name: String,
    pub token: String,
    #[serde(with = "::util::rfc3339")]
    pub created_at: NaiveDateTime,
    #[serde(with = "::util::rfc3339::option")]
    pub last_used_at: Option<NaiveDateTime>,
}

/// The serialization format for the `User` model.
/// Same as public user, except for addition of
/// email field
#[derive(Deserialize, Serialize, Debug)]
pub struct EncodablePrivateUser {
    pub id: i32,
    pub login: String,
    pub email: Option<String>,
    pub email_verified: bool,
    pub email_verification_sent: bool,
    pub name: Option<String>,
    pub avatar: Option<String>,
    pub url: Option<String>,
}

/// The serialization format for the `User` model.
/// Same as private user, except no email field
#[derive(Deserialize, Serialize, Debug)]
pub struct EncodablePublicUser {
    pub id: i32,
    pub login: String,
    pub name: Option<String>,
    pub avatar: Option<String>,
    pub url: Option<String>,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct EncodableVersion {
    pub id: i32,
    #[serde(rename = "crate")]
    pub krate: String,
    pub num: String,
    pub dl_path: String,
    pub readme_path: String,
    #[serde(with = "::util::rfc3339")]
    pub updated_at: NaiveDateTime,
    #[serde(with = "::util::rfc3339")]
    pub created_at: NaiveDateTime,
    pub downloads: i32,
    pub features: HashMap<String, Vec<String>>,
    pub yanked: bool,
    pub license: Option<String>,
    pub links: EncodableVersionLinks,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct EncodableVersionLinks {
    pub dependencies: String,
    pub version_downloads: String,
    pub authors: String,
}

// TODO: Prefix many of these with `Encodable` then clean up the reexports
pub mod krate_publish;
pub use self::krate_publish::CrateDependency as EncodableCrateDependency;
pub use self::krate_publish::NewCrate as EncodableCrateUpload;

#[cfg(test)]
mod tests {
    use super::*;
    use chrono::NaiveDate;
    use serde_json;
    use std::collections::HashMap;

    #[test]
    fn category_dates_serializes_to_rfc3339() {
        let cat = EncodableCategory {
            id: "".to_string(),
            category: "".to_string(),
            slug: "".to_string(),
            description: "".to_string(),
            crates_cnt: 1,
            created_at: NaiveDate::from_ymd(2017, 1, 6).and_hms(14, 23, 11),
        };
        let json = serde_json::to_string(&cat).unwrap();
        assert!(
            json.as_str()
                .find(r#""created_at":"2017-01-06T14:23:11+00:00""#)
                .is_some()
        );
    }

    #[test]
    fn category_with_sub_dates_serializes_to_rfc3339() {
        let cat = EncodableCategoryWithSubcategories {
            id: "".to_string(),
            category: "".to_string(),
            slug: "".to_string(),
            description: "".to_string(),
            crates_cnt: 1,
            created_at: NaiveDate::from_ymd(2017, 1, 6).and_hms(14, 23, 11),
            subcategories: vec![],
            parent_categories: vec![],
        };
        let json = serde_json::to_string(&cat).unwrap();
        assert!(
            json.as_str()
                .find(r#""created_at":"2017-01-06T14:23:11+00:00""#)
                .is_some()
        );
    }

    #[test]
    fn keyword_serializes_to_rfc3339() {
        let key = EncodableKeyword {
            id: "".to_string(),
            keyword: "".to_string(),
            created_at: NaiveDate::from_ymd(2017, 1, 6).and_hms(14, 23, 11),
            crates_cnt: 0,
        };
        let json = serde_json::to_string(&key).unwrap();
        assert!(
            json.as_str()
                .find(r#""created_at":"2017-01-06T14:23:11+00:00""#)
                .is_some()
        );
    }

    #[test]
    fn version_serializes_to_rfc3339() {
        let ver = EncodableVersion {
            id: 1,
            krate: "".to_string(),
            num: "".to_string(),
            dl_path: "".to_string(),
            readme_path: "".to_string(),
            updated_at: NaiveDate::from_ymd(2017, 1, 6).and_hms(14, 23, 11),
            created_at: NaiveDate::from_ymd(2017, 1, 6).and_hms(14, 23, 12),
            downloads: 0,
            features: HashMap::new(),
            yanked: false,
            license: None,
            links: EncodableVersionLinks {
                dependencies: "".to_string(),
                version_downloads: "".to_string(),
                authors: "".to_string(),
            },
        };
        let json = serde_json::to_string(&ver).unwrap();
        assert!(
            json.as_str()
                .find(r#""updated_at":"2017-01-06T14:23:11+00:00""#)
                .is_some()
        );
        assert!(
            json.as_str()
                .find(r#""created_at":"2017-01-06T14:23:12+00:00""#)
                .is_some()
        );
    }

    #[test]
    fn crate_serializes_to_rfc3399() {
        let crt = EncodableCrate {
            id: "".to_string(),
            name: "".to_string(),
            updated_at: NaiveDate::from_ymd(2017, 1, 6).and_hms(14, 23, 11),
            versions: None,
            keywords: None,
            categories: None,
            badges: None,
            created_at: NaiveDate::from_ymd(2017, 1, 6).and_hms(14, 23, 12),
            downloads: 0,
            recent_downloads: None,
            max_version: "".to_string(),
            description: None,
            homepage: None,
            documentation: None,
            repository: None,
            links: EncodableCrateLinks {
                version_downloads: "".to_string(),
                versions: None,
                owners: None,
                owner_team: None,
                owner_user: None,
                reverse_dependencies: "".to_string(),
            },
            exact_match: false,
        };
        let json = serde_json::to_string(&crt).unwrap();
        assert!(
            json.as_str()
                .find(r#""updated_at":"2017-01-06T14:23:11+00:00""#)
                .is_some()
        );
        assert!(
            json.as_str()
                .find(r#""created_at":"2017-01-06T14:23:12+00:00""#)
                .is_some()
        );
    }

    #[test]
    fn crate_owner_invitation_serializes_to_rfc3339() {
        let inv = EncodableCrateOwnerInvitation {
            invited_by_username: "".to_string(),
            crate_name: "".to_string(),
            crate_id: 123,
            created_at: NaiveDate::from_ymd(2017, 1, 6).and_hms(14, 23, 11),
        };
        let json = serde_json::to_string(&inv).unwrap();
        assert!(
            json.as_str()
                .find(r#""created_at":"2017-01-06T14:23:11+00:00""#)
                .is_some()
        );
    }
}
<|endoftext|>


<commit_before>use std::{mem, ptr, int};
use alloc::heap;
use token::Token;

/// A preallocated chunk of memory for storing objects of the same type.
pub struct Slab<T> {
    // Chunk of memory
    mem: *mut Entry<T>,
    // Number of elements currently in the slab
    len: int,
    // The total number of elements that the slab can hold
    cap: int,
    // THe token offset
    off: uint,
    // Offset of the next available slot in the slab. Set to the slab's
    // capacity when the slab is full.
    nxt: int,
    // The total number of slots that were initialized
    init: int,
}

const MAX: uint = int::MAX as uint;

// When Entry.nxt is set to this, the entry is in use
const IN_USE: int = -1;

impl<T> Slab<T> {
    pub fn new(cap: uint) -> Slab<T> {
        Slab::new_starting_at(Token(0), cap)
    }

    pub fn new_starting_at(offset: Token, cap: uint) -> Slab<T> {
        assert!(cap <= MAX, "capacity too large");
        // TODO:
        // - Rename to with_capacity
        // - Use a power of 2 capacity
        // - Ensure that mem size is less than uint::MAX

        let size = cap.checked_mul(&mem::size_of::<Entry<T>>())
            .expect("capacity overflow");

        let ptr = unsafe { heap::allocate(size, mem::min_align_of::<Entry<T>>()) };

        Slab {
            mem: ptr as *mut Entry<T>,
            cap: cap as int,
            len: 0,
            off: offset.as_uint(),
            nxt: 0,
            init: 0,
        }
    }

    #[inline]
    pub fn count(&self) -> uint {
        self.len as uint
    }

    #[inline]
    pub fn is_empty(&self) -> bool {
        self.len == 0
    }

    #[inline]
    pub fn remaining(&self) -> uint {
        (self.cap - self.len) as uint
    }

    #[inline]
    pub fn has_remaining(&self) -> bool {
        self.remaining() > 0
    }

    #[inline]
    pub fn contains(&self, idx: Token) -> bool {
        let idx = self.token_to_idx(idx);

        if idx <= MAX {
            let idx = idx as int;

            if idx < self.init {
                return self.entry(idx).in_use();
            }
        }

        false
    }

    pub fn get(&self, idx: Token) -> Option<&T> {
        let idx = self.token_to_idx(idx);

        if idx <= MAX {
            let idx = idx as int;

            if idx < self.init {
                let entry = self.entry(idx);

                if entry.in_use() {
                    return Some(&entry.val);
                }
            }
        }

        None
    }

    pub fn insert(&mut self, val: T) -> Result<Token, T> {
        let idx = self.nxt;

        if idx == self.init {
            // Using an uninitialized entry
            if idx == self.cap {
                // No more capacity
                debug!("slab out of capacity; cap={}", self.cap);
                return Err(val);
            }

            self.mut_entry(idx).put(val, true);

            self.init += 1;
            self.len = self.init;
            self.nxt = self.init;

            debug!("inserting into new slot; idx={}", idx);
        }
        else {
            self.len += 1;
            self.nxt = self.mut_entry(idx).put(val, false);

            debug!("inserting into reused slot; idx={}", idx);
        }

        Ok(self.idx_to_token(idx))
    }

    /// Releases the given slot
    pub fn remove(&mut self, idx: Token) -> Option<T> {
        debug!("removing value; idx={}", idx);

        // Cast to uint
        let idx = self.token_to_idx(idx);

        if idx > MAX {
            return None;
        }

        let idx = idx as int;

        // Ensure index is within capacity of slab
        if idx >= self.init {
            return None;
        }

        let nxt = self.nxt;

        match self.mut_entry(idx).remove(nxt) {
            Some(v) => {
                self.nxt = idx;
                self.len -= 1;
                Some(v)
            }
            None => None
        }
    }

    #[inline]
    fn entry(&self, idx: int) -> &Entry<T> {
        unsafe { &*self.mem.offset(idx) }
    }

    #[inline]
    fn mut_entry(&mut self, idx: int) -> &mut Entry<T> {
        unsafe { &mut *self.mem.offset(idx) }
    }

    #[inline]
    fn validate_idx(&self, idx: uint) -> int {
        if idx <= MAX {
            let idx = idx as int;

            if idx < self.init {
                return idx;
            }
        }

        panic!("invalid index {} -- greater than capacity {}", idx, self.cap);
    }

    fn token_to_idx(&self, token: Token) -> uint {
        token.as_uint() - self.off
    }

    fn idx_to_token(&self, idx: int) -> Token {
        Token(idx as uint + self.off)
    }
}

impl<T> Index<Token, T> for Slab<T> {
    fn index<'a>(&'a self, idx: &Token) -> &'a T {
        let idx = self.token_to_idx(*idx);
        let idx = self.validate_idx(idx);

        let e = self.entry(idx);

        if !e.in_use() {
            panic!("invalid index; idx={}", idx);
        }

        &e.val
    }
}

impl<T> IndexMut<Token, T> for Slab<T> {
    fn index_mut<'a>(&'a mut self, idx: &Token) -> &'a mut T {
        let idx = self.token_to_idx(*idx);
        let idx = self.validate_idx(idx);

        let e = self.mut_entry(idx);

        if !e.in_use() {
            panic!("invalid index; idx={}", idx);
        }

        &mut e.val
    }
}

#[unsafe_destructor]
impl<T> Drop for Slab<T> {
    fn drop(&mut self) {
        // TODO: check whether or not this is needed with intrinsics::needs_drop
        let mut i = 0;

        while i < self.init {
            self.mut_entry(i).release();
            i += 1;
        }
    }
}

// Holds the values in the slab.
struct Entry<T> {
    nxt: int,
    val: T
}

impl<T> Entry<T> {
    #[inline]
    fn put(&mut self, val: T, init: bool) -> int {
        assert!(init || self.nxt != IN_USE);

        let ret = self.nxt;

        unsafe { ptr::write(&mut self.val as *mut T, val); }
        self.nxt = IN_USE;

        // Could be uninitialized memory, but the caller (Slab) should guard
        // not use the return value in those cases.
        ret
    }

    fn remove(&mut self, nxt: int) -> Option<T> {
        if self.in_use() {
            self.nxt = nxt;
            Some(unsafe { ptr::read(&self.val as *const T) })
        } else {
            None
        }
    }

    fn release(&mut self) {
        if self.in_use() {
            let _ = Some(unsafe { ptr::read(&self.val as *const T) });
        }
    }

    #[inline]
    fn in_use(&self) -> bool {
        self.nxt == IN_USE
    }
}

#[cfg(test)]
mod tests {
    use super::Slab;
    use {Token};

    #[test]
    fn test_insertion() {
        let mut slab = Slab::new(1);
        let token = slab.insert(10u).ok().expect("Failed to insert");
        assert_eq!(slab[token], 10u);
    }

    #[test]
    fn test_repeated_insertion() {
        let mut slab = Slab::new(10);

        for i in range(0u, 10u) {
            let token = slab.insert(i + 10u).ok().expect("Failed to insert");
            assert_eq!(slab[token], i + 10u);
        }

        slab.insert(20).err().expect("Inserted when full");
    }

    #[test]
    fn test_repeated_insertion_and_removal() {
        let mut slab = Slab::new(10);
        let mut tokens = vec![];

        for i in range(0u, 10u) {
            let token = slab.insert(i + 10u).ok().expect("Failed to insert");
            tokens.push(token);
            assert_eq!(slab[token], i + 10u);
        }

        for &i in tokens.iter() {
            slab.remove(i);
        }

        slab.insert(20).ok().expect("Failed to insert in newly empty slab");
    }

    #[test]
    fn test_insertion_when_full() {
        let mut slab = Slab::new(1);
        slab.insert(10u).ok().expect("Failed to insert");
        slab.insert(10u).err().expect("Inserted into a full slab");
    }

    #[test]
    fn test_removal_is_successful() {
        let mut slab = Slab::new(1);
        let t1 = slab.insert(10u).ok().expect("Failed to insert");
        slab.remove(t1);
        let t2 = slab.insert(20u).ok().expect("Failed to insert");
        assert_eq!(slab[t2], 20u);
    }

    #[test]
    fn test_mut_retrieval() {
        let mut slab = Slab::new(1);
        let t1 = slab.insert("foo".to_string()).ok().expect("Failed to insert");

        slab[t1].push_str("bar");

        assert_eq!(slab[t1].as_slice(), "foobar");
    }

    #[test]
    #[should_fail]
    fn test_reusing_slots_1() {
        let mut slab = Slab::new(16);

        let t0 = slab.insert(123u).unwrap();
        let t1 = slab.insert(456u).unwrap();

        assert!(slab.count() == 2);
        assert!(slab.remaining() == 14);

        slab.remove(t0);

        assert!(slab.count() == 1, "actual={}", slab.count());
        assert!(slab.remaining() == 15);

        slab.remove(t1);

        assert!(slab.count() == 0);
        assert!(slab.remaining() == 16);

        let _ = slab[t1];
    }

    #[test]
    fn test_reusing_slots_2() {
        let mut slab = Slab::new(16);

        let t0 = slab.insert(123u).unwrap();

        assert!(slab[t0] == 123u);
        assert!(slab.remove(t0) == Some(123u));

        let t0 = slab.insert(456u).unwrap();

        assert!(slab[t0] == 456u);

        let t1 = slab.insert(789u).unwrap();

        assert!(slab[t0] == 456u);
        assert!(slab[t1] == 789u);

        assert!(slab.remove(t0).unwrap() == 456u);
        assert!(slab.remove(t1).unwrap() == 789u);

        assert!(slab.count() == 0);
    }

    #[test]
    #[should_fail]
    fn test_accessing_out_of_bounds() {
        let slab = Slab::<uint>::new(16);
        slab[Token(0)];
    }
}
<commit_msg>[test] Slab.contains()<commit_after>use std::{mem, ptr, int};
use alloc::heap;
use token::Token;

/// A preallocated chunk of memory for storing objects of the same type.
pub struct Slab<T> {
    // Chunk of memory
    mem: *mut Entry<T>,
    // Number of elements currently in the slab
    len: int,
    // The total number of elements that the slab can hold
    cap: int,
    // THe token offset
    off: uint,
    // Offset of the next available slot in the slab. Set to the slab's
    // capacity when the slab is full.
    nxt: int,
    // The total number of slots that were initialized
    init: int,
}

const MAX: uint = int::MAX as uint;

// When Entry.nxt is set to this, the entry is in use
const IN_USE: int = -1;

impl<T> Slab<T> {
    pub fn new(cap: uint) -> Slab<T> {
        Slab::new_starting_at(Token(0), cap)
    }

    pub fn new_starting_at(offset: Token, cap: uint) -> Slab<T> {
        assert!(cap <= MAX, "capacity too large");
        // TODO:
        // - Rename to with_capacity
        // - Use a power of 2 capacity
        // - Ensure that mem size is less than uint::MAX

        let size = cap.checked_mul(&mem::size_of::<Entry<T>>())
            .expect("capacity overflow");

        let ptr = unsafe { heap::allocate(size, mem::min_align_of::<Entry<T>>()) };

        Slab {
            mem: ptr as *mut Entry<T>,
            cap: cap as int,
            len: 0,
            off: offset.as_uint(),
            nxt: 0,
            init: 0,
        }
    }

    #[inline]
    pub fn count(&self) -> uint {
        self.len as uint
    }

    #[inline]
    pub fn is_empty(&self) -> bool {
        self.len == 0
    }

    #[inline]
    pub fn remaining(&self) -> uint {
        (self.cap - self.len) as uint
    }

    #[inline]
    pub fn has_remaining(&self) -> bool {
        self.remaining() > 0
    }

    #[inline]
    pub fn contains(&self, idx: Token) -> bool {
        let idx = self.token_to_idx(idx);

        if idx <= MAX {
            let idx = idx as int;

            if idx < self.init {
                return self.entry(idx).in_use();
            }
        }

        false
    }

    pub fn get(&self, idx: Token) -> Option<&T> {
        let idx = self.token_to_idx(idx);

        if idx <= MAX {
            let idx = idx as int;

            if idx < self.init {
                let entry = self.entry(idx);

                if entry.in_use() {
                    return Some(&entry.val);
                }
            }
        }

        None
    }

    pub fn insert(&mut self, val: T) -> Result<Token, T> {
        let idx = self.nxt;

        if idx == self.init {
            // Using an uninitialized entry
            if idx == self.cap {
                // No more capacity
                debug!("slab out of capacity; cap={}", self.cap);
                return Err(val);
            }

            self.mut_entry(idx).put(val, true);

            self.init += 1;
            self.len = self.init;
            self.nxt = self.init;

            debug!("inserting into new slot; idx={}", idx);
        }
        else {
            self.len += 1;
            self.nxt = self.mut_entry(idx).put(val, false);

            debug!("inserting into reused slot; idx={}", idx);
        }

        Ok(self.idx_to_token(idx))
    }

    /// Releases the given slot
    pub fn remove(&mut self, idx: Token) -> Option<T> {
        debug!("removing value; idx={}", idx);

        // Cast to uint
        let idx = self.token_to_idx(idx);

        if idx > MAX {
            return None;
        }

        let idx = idx as int;

        // Ensure index is within capacity of slab
        if idx >= self.init {
            return None;
        }

        let nxt = self.nxt;

        match self.mut_entry(idx).remove(nxt) {
            Some(v) => {
                self.nxt = idx;
                self.len -= 1;
                Some(v)
            }
            None => None
        }
    }

    #[inline]
    fn entry(&self, idx: int) -> &Entry<T> {
        unsafe { &*self.mem.offset(idx) }
    }

    #[inline]
    fn mut_entry(&mut self, idx: int) -> &mut Entry<T> {
        unsafe { &mut *self.mem.offset(idx) }
    }

    #[inline]
    fn validate_idx(&self, idx: uint) -> int {
        if idx <= MAX {
            let idx = idx as int;

            if idx < self.init {
                return idx;
            }
        }

        panic!("invalid index {} -- greater than capacity {}", idx, self.cap);
    }

    fn token_to_idx(&self, token: Token) -> uint {
        token.as_uint() - self.off
    }

    fn idx_to_token(&self, idx: int) -> Token {
        Token(idx as uint + self.off)
    }
}

impl<T> Index<Token, T> for Slab<T> {
    fn index<'a>(&'a self, idx: &Token) -> &'a T {
        let idx = self.token_to_idx(*idx);
        let idx = self.validate_idx(idx);

        let e = self.entry(idx);

        if !e.in_use() {
            panic!("invalid index; idx={}", idx);
        }

        &e.val
    }
}

impl<T> IndexMut<Token, T> for Slab<T> {
    fn index_mut<'a>(&'a mut self, idx: &Token) -> &'a mut T {
        let idx = self.token_to_idx(*idx);
        let idx = self.validate_idx(idx);

        let e = self.mut_entry(idx);

        if !e.in_use() {
            panic!("invalid index; idx={}", idx);
        }

        &mut e.val
    }
}

#[unsafe_destructor]
impl<T> Drop for Slab<T> {
    fn drop(&mut self) {
        // TODO: check whether or not this is needed with intrinsics::needs_drop
        let mut i = 0;

        while i < self.init {
            self.mut_entry(i).release();
            i += 1;
        }
    }
}

// Holds the values in the slab.
struct Entry<T> {
    nxt: int,
    val: T
}

impl<T> Entry<T> {
    #[inline]
    fn put(&mut self, val: T, init: bool) -> int {
        assert!(init || self.nxt != IN_USE);

        let ret = self.nxt;

        unsafe { ptr::write(&mut self.val as *mut T, val); }
        self.nxt = IN_USE;

        // Could be uninitialized memory, but the caller (Slab) should guard
        // not use the return value in those cases.
        ret
    }

    fn remove(&mut self, nxt: int) -> Option<T> {
        if self.in_use() {
            self.nxt = nxt;
            Some(unsafe { ptr::read(&self.val as *const T) })
        } else {
            None
        }
    }

    fn release(&mut self) {
        if self.in_use() {
            let _ = Some(unsafe { ptr::read(&self.val as *const T) });
        }
    }

    #[inline]
    fn in_use(&self) -> bool {
        self.nxt == IN_USE
    }
}

#[cfg(test)]
mod tests {
    use super::Slab;
    use {Token};

    #[test]
    fn test_insertion() {
        let mut slab = Slab::new(1);
        let token = slab.insert(10u).ok().expect("Failed to insert");
        assert_eq!(slab[token], 10u);
    }

    #[test]
    fn test_repeated_insertion() {
        let mut slab = Slab::new(10);

        for i in range(0u, 10u) {
            let token = slab.insert(i + 10u).ok().expect("Failed to insert");
            assert_eq!(slab[token], i + 10u);
        }

        slab.insert(20).err().expect("Inserted when full");
    }

    #[test]
    fn test_repeated_insertion_and_removal() {
        let mut slab = Slab::new(10);
        let mut tokens = vec![];

        for i in range(0u, 10u) {
            let token = slab.insert(i + 10u).ok().expect("Failed to insert");
            tokens.push(token);
            assert_eq!(slab[token], i + 10u);
        }

        for &i in tokens.iter() {
            slab.remove(i);
        }

        slab.insert(20).ok().expect("Failed to insert in newly empty slab");
    }

    #[test]
    fn test_insertion_when_full() {
        let mut slab = Slab::new(1);
        slab.insert(10u).ok().expect("Failed to insert");
        slab.insert(10u).err().expect("Inserted into a full slab");
    }

    #[test]
    fn test_removal_is_successful() {
        let mut slab = Slab::new(1);
        let t1 = slab.insert(10u).ok().expect("Failed to insert");
        slab.remove(t1);
        let t2 = slab.insert(20u).ok().expect("Failed to insert");
        assert_eq!(slab[t2], 20u);
    }

    #[test]
    fn test_mut_retrieval() {
        let mut slab = Slab::new(1);
        let t1 = slab.insert("foo".to_string()).ok().expect("Failed to insert");

        slab[t1].push_str("bar");

        assert_eq!(slab[t1].as_slice(), "foobar");
    }

    #[test]
    #[should_fail]
    fn test_reusing_slots_1() {
        let mut slab = Slab::new(16);

        let t0 = slab.insert(123u).unwrap();
        let t1 = slab.insert(456u).unwrap();

        assert!(slab.count() == 2);
        assert!(slab.remaining() == 14);

        slab.remove(t0);

        assert!(slab.count() == 1, "actual={}", slab.count());
        assert!(slab.remaining() == 15);

        slab.remove(t1);

        assert!(slab.count() == 0);
        assert!(slab.remaining() == 16);

        let _ = slab[t1];
    }

    #[test]
    fn test_reusing_slots_2() {
        let mut slab = Slab::new(16);

        let t0 = slab.insert(123u).unwrap();

        assert!(slab[t0] == 123u);
        assert!(slab.remove(t0) == Some(123u));

        let t0 = slab.insert(456u).unwrap();

        assert!(slab[t0] == 456u);

        let t1 = slab.insert(789u).unwrap();

        assert!(slab[t0] == 456u);
        assert!(slab[t1] == 789u);

        assert!(slab.remove(t0).unwrap() == 456u);
        assert!(slab.remove(t1).unwrap() == 789u);

        assert!(slab.count() == 0);
    }

    #[test]
    #[should_fail]
    fn test_accessing_out_of_bounds() {
        let slab = Slab::<uint>::new(16);
        slab[Token(0)];
    }

    #[test]
    fn test_contains() {
        let mut slab = Slab::new_starting_at(Token(5),16);
        assert!(!slab.contains(Token(0)));

        let tok = slab.insert(111u).unwrap();
        assert!(slab.contains(tok));
    }
}
<|endoftext|>


<commit_before>use crate::config::Config;
use crate::layout::{Layout, Tall};
use crate::layout::LayoutMsg;
use crate::stack::Stack;
use crate::xlib_window_system::XlibWindowSystem;
use std::cmp;
use x11::xlib::Window;
use serde::{Serialize, Deserialize};

#[allow(dead_code)]
pub struct WorkspaceInfo {
    pub tags: String,
    pub layout: String,
    pub current: bool,
    pub visible: bool,
    pub urgent: bool,
}

pub struct WorkspaceConfig {
    pub tag: String,
    pub screen: usize,
    pub layout: Box<dyn Layout>,
}

pub enum MoveOp {
    Up,
    Down,
    Swap,
}

#[derive(Serialize, Deserialize)]
pub struct Workspace {
    pub(crate) managed: Stack,
    pub(crate) unmanaged: Stack,
    pub(crate) tag: String,
    pub screen: usize,
    pub visible: bool,
}

impl Default for Workspace {
    fn default() -> Self {
        Self {
            managed: Stack::new(Some(Tall::new(1, 0.5, 0.05))),
            unmanaged: Stack::new(None),
            tag: String::new(),
            screen: 0,
            visible: false,
        }
    }
}

impl Workspace {
    pub fn all(&self) -> Vec<Window> {
        self.unmanaged.all_windows().iter().chain(self.managed.all_windows().iter()).copied().collect()
    }

    fn all_urgent(&self) -> Vec<Window> {
        self.unmanaged.urgent.iter().chain(self.managed.urgent.iter()).copied().collect()
    }

    pub fn send_layout_message(&mut self, msg: LayoutMsg) {
        if let Some(layout) = self.managed.layout.as_mut() {
            layout.send_msg(msg);
        }
    }

    pub fn get_tag(&self) -> &str {
        &self.tag
    }

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

    pub fn is_unmanaged(&self, window: Window) -> bool {
        self.unmanaged.contains(window)
    }

    pub fn is_managed(&self, window: Window) -> bool {
        self.managed.contains(window)
    }

    pub fn is_urgent(&self) -> bool {
        self.managed.is_urgent() || self.unmanaged.is_urgent()
    }

    pub fn is_visible(&self) -> bool {
        self.visible
    }

    pub fn focused_window(&self) -> Option<Window> {
        if self.unmanaged.focused_window().is_none() {
            self.managed.focused_window()
        } else {
            self.unmanaged.focused_window()
        }
    }

    pub fn add_window(&mut self, xws: &XlibWindowSystem, config: &Config, window: Window) {
        if !xws.is_floating_window(window) {
            debug!("Add Managed: {}", window);
            self.managed.add_window(window);

            if self.unmanaged.len() > 0 {
                debug!("Restacking");
                xws.restack_windows(self.all());
            }
        } else {
            self.unmanaged.add_window(window);
            debug!("Add Unmanaged: {}", window);
        }

        if self.visible {
            self.redraw(xws, config);
            xws.show_window(window);
        }
    }

    pub fn nest_layout(&mut self, layout: Box<dyn Layout>) {
        if self.managed.len() > 1 {
            self.managed.add_container(layout);
        } else  if let Some(s) = self.managed.all_container_mut().first_mut() {
            if s.len() < 1 {
                s.layout = Some(layout);
            } else {
                self.managed.add_container(layout);
            }
        } else {
            self.managed.add_container(layout);
        }
    }

    pub fn set_urgency(&mut self, urgent: bool, xws: &XlibWindowSystem,  config: &Config, window: Window) {
        if !urgent {
            debug!("unset urgent {}", window);
            self.remove_urgent_window(window);
            self.redraw(xws, config);
        } else if urgent {
            debug!("set urgent {}", window);
            if self.is_managed(window) {
                self.managed.urgent.push(window);
            } else {
                self.unmanaged.urgent.push(window);
            }
            self.redraw(xws, config);
        }
    }

    fn remove_urgent_window(&mut self, window: Window) {
        let res = self.unmanaged.urgent
            .iter()
            .enumerate()
            .find(|&(_, &x)| x == window)
            .map(|(i, _)| i);

        if let Some(index) = res {
            if index < self.unmanaged.urgent.len() {
                self.unmanaged.urgent.remove(index - 1);
            }
        } else {
            self.managed.remove_urgent(window);
        }
    }

    fn remove_managed(&mut self, xws: &XlibWindowSystem, config: &Config, window: Window) {
        trace!("remove managed window: {}", window);
        xws.unmap_window(window);
        self.managed.remove(window);

        if self.visible {
            self.redraw(xws, config);
        }
    }

    fn remove_unmanaged(&mut self, xws: &XlibWindowSystem, config: &Config, window: Window) {
        trace!("remove unmanaged window: {}", window);
        xws.unmap_window(window);
        self.unmanaged.remove(window);
        self.unmanaged.focus = if self.unmanaged.nodes.is_empty() {
            None
        } else {
            Some(self.unmanaged.nodes.len() - 1)
        };

        if self.visible {
            self.redraw(xws, config);
        }
    }

    pub fn remove_window(&mut self, xws: &XlibWindowSystem, config: &Config, window: Window) {
        if self.managed.contains(window) {
            trace!("Remove Managed: {}", window);
            self.remove_managed(xws, config, window);
        } else if self.unmanaged.contains(window) {
            trace!("Remove Unmanaged: {}", window);
            self.remove_unmanaged(xws, config, window);
        }
    }

    pub fn focus_window(&mut self, xws: &XlibWindowSystem, config: &Config, window: Window) {
        if window == 0 || self.unmanaged.focused_window() == Some(window) || self.managed.focused_window() == Some(window) {
            return;
        }

        self.remove_urgent_window(window);
        self.remove_window_highlight(xws, config);

        if self.unmanaged.contains(window) {
            self.unmanaged.focus_window(window);
        } else {
            self.managed.focus_window(window);
        }

        xws.focus_window(window, config.border_focus_color);
        self.redraw(xws, config);
    }

    pub fn remove_window_highlight(&mut self, xws: &XlibWindowSystem, config: &Config) {
        if let Some(window) = self.focused_window() {
            xws.set_window_border_color(window, config.border_color);
        }
    }

    pub fn move_parent_focus(&mut self, xws: &XlibWindowSystem, config: &Config, op: MoveOp) {
        if self.managed.move_parent_focus(op).is_some() {
            self.redraw(xws, config);
        }
    }

    // TODO: impl managed and unmanaged focus mode incl switching
    pub fn move_focus(&mut self, xws: &XlibWindowSystem, config: &Config, op: MoveOp) {
        if self.managed.move_focus(op).is_some() {
            self.redraw(xws, config);
        }
    }

    pub fn move_window(&mut self, xws: &XlibWindowSystem, config: &Config, op: MoveOp) {
        let focused_window = self.focused_window();
        trace!("move window: {:?}", focused_window);

        if focused_window.is_none() {
            return;
        }

        self.managed.move_window(op);
        self.redraw(xws, config);
    }

    pub fn move_parent_window(&mut self, xws: &XlibWindowSystem, config: &Config, op: MoveOp) {
        let focused_window = self.focused_window();
        trace!("move parent window: {:?}", focused_window);

        if focused_window.is_none() {
            return;
        }

        self.managed.move_parent_window(op);
        self.redraw(xws, config);
    }

    pub fn contains(&self, window: Window) -> bool {
        self.all().iter().any(|&w| w == window)
    }

    pub fn unfocus(&mut self, xws: &XlibWindowSystem, config: &Config) {
        if let Some(window) = self.focused_window() {
            trace!("unfocus window: {}", window);
            xws.set_window_border_color(window, config.border_color);
        }
    }

    pub fn focus(&self, xws: &XlibWindowSystem, config: &Config) {
        if let Some(window) = self.focused_window() {
            trace!("focus window: {}", window);
            xws.focus_window(window, config.border_focus_color);
            xws.skip_enter_events();
        }
    }

    pub fn center_pointer(&self, xws: &XlibWindowSystem) {
        let screen = xws.get_screen_infos()[self.screen];
        xws.move_pointer((screen.x + (screen.width / 2)) as i32 - 1, (screen.y + (screen.height / 2)) as i32);
    }

    pub fn hide(&mut self, xws: &XlibWindowSystem) {
        self.visible = false;

        for &w in self.managed.all_windows().iter().filter(|&w| Some(*w) != self.focused_window()) {
            xws.hide_window(w);
        }

        for &w in self.unmanaged.all_windows().iter().filter(|&w| Some(*w) != self.focused_window()) {
            xws.hide_window(w);
        }

        if let Some(w) = self.focused_window() {
            xws.hide_window(w);
        }
    }

    pub fn show(&mut self, xws: &XlibWindowSystem, config: &Config) {
        self.visible = true;

        self.redraw(xws, config);
        for &w in self.managed.all_windows().iter() {
            xws.show_window(w);
        }

        for &w in self.unmanaged.all_windows().iter() {
            xws.show_window(w);
        }
    }

    pub fn redraw(&self, xws: &XlibWindowSystem, config: &Config) {
        trace!("Redraw...");

        let screen = xws.get_screen_infos()[self.screen];

        for (rect, window) in self.managed.apply_layout(screen, xws) {
            xws.setup_window(rect.x,
                rect.y,
                rect.width,
                rect.height,
                config.border_width,
                config.border_color,
                window);
        }

        for &window in self.unmanaged.all_windows().iter() {
            let mut rect = xws.get_geometry(window);
            rect.width = cmp::min(screen.width, rect.width + (2 * config.border_width));
            rect.height = cmp::min(screen.height, rect.height + (2 * config.border_width));

            xws.setup_window(screen.x + (screen.width - rect.width) / 2,
                            screen.y + (screen.height - rect.height) / 2,
                            rect.width,
                            rect.height,
                            config.border_width,
                            config.border_color,
                            window);
        }

        for &window in self.all_urgent().iter() {
            xws.set_window_border_color(window, config.border_urgent_color);
        }

        if let Some(window) = self.focused_window() {
            xws.focus_window(window, config.border_focus_color);
        }

        //self.focus(xws, config);
    }
}
<commit_msg>Fix focus not updating when switching windows<commit_after>use crate::config::Config;
use crate::layout::{Layout, Tall};
use crate::layout::LayoutMsg;
use crate::stack::Stack;
use crate::xlib_window_system::XlibWindowSystem;
use std::cmp;
use x11::xlib::Window;
use serde::{Serialize, Deserialize};

#[allow(dead_code)]
pub struct WorkspaceInfo {
    pub tags: String,
    pub layout: String,
    pub current: bool,
    pub visible: bool,
    pub urgent: bool,
}

pub struct WorkspaceConfig {
    pub tag: String,
    pub screen: usize,
    pub layout: Box<dyn Layout>,
}

pub enum MoveOp {
    Up,
    Down,
    Swap,
}

#[derive(Serialize, Deserialize)]
pub struct Workspace {
    pub(crate) managed: Stack,
    pub(crate) unmanaged: Stack,
    pub(crate) tag: String,
    pub screen: usize,
    pub visible: bool,
}

impl Default for Workspace {
    fn default() -> Self {
        Self {
            managed: Stack::new(Some(Tall::new(1, 0.5, 0.05))),
            unmanaged: Stack::new(None),
            tag: String::new(),
            screen: 0,
            visible: false,
        }
    }
}

impl Workspace {
    pub fn all(&self) -> Vec<Window> {
        self.unmanaged.all_windows().iter().chain(self.managed.all_windows().iter()).copied().collect()
    }

    fn all_urgent(&self) -> Vec<Window> {
        self.unmanaged.urgent.iter().chain(self.managed.urgent.iter()).copied().collect()
    }

    pub fn send_layout_message(&mut self, msg: LayoutMsg) {
        if let Some(layout) = self.managed.layout.as_mut() {
            layout.send_msg(msg);
        }
    }

    pub fn get_tag(&self) -> &str {
        &self.tag
    }

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

    pub fn is_unmanaged(&self, window: Window) -> bool {
        self.unmanaged.contains(window)
    }

    pub fn is_managed(&self, window: Window) -> bool {
        self.managed.contains(window)
    }

    pub fn is_urgent(&self) -> bool {
        self.managed.is_urgent() || self.unmanaged.is_urgent()
    }

    pub fn is_visible(&self) -> bool {
        self.visible
    }

    pub fn focused_window(&self) -> Option<Window> {
        if self.unmanaged.focused_window().is_none() {
            self.managed.focused_window()
        } else {
            self.unmanaged.focused_window()
        }
    }

    pub fn add_window(&mut self, xws: &XlibWindowSystem, config: &Config, window: Window) {
        if !xws.is_floating_window(window) {
            debug!("Add Managed: {}", window);
            self.managed.add_window(window);

            if self.unmanaged.len() > 0 {
                debug!("Restacking");
                xws.restack_windows(self.all());
            }
        } else {
            self.unmanaged.add_window(window);
            debug!("Add Unmanaged: {}", window);
        }

        if self.visible {
            self.redraw(xws, config);
            xws.show_window(window);
        }
    }

    pub fn nest_layout(&mut self, layout: Box<dyn Layout>) {
        if self.managed.len() > 1 {
            self.managed.add_container(layout);
        } else  if let Some(s) = self.managed.all_container_mut().first_mut() {
            if s.len() < 1 {
                s.layout = Some(layout);
            } else {
                self.managed.add_container(layout);
            }
        } else {
            self.managed.add_container(layout);
        }
    }

    pub fn set_urgency(&mut self, urgent: bool, xws: &XlibWindowSystem,  config: &Config, window: Window) {
        if !urgent {
            debug!("unset urgent {}", window);
            self.remove_urgent_window(window);
            self.redraw(xws, config);
        } else if urgent {
            debug!("set urgent {}", window);
            if self.is_managed(window) {
                self.managed.urgent.push(window);
            } else {
                self.unmanaged.urgent.push(window);
            }
            self.redraw(xws, config);
        }
    }

    fn remove_urgent_window(&mut self, window: Window) {
        let res = self.unmanaged.urgent
            .iter()
            .enumerate()
            .find(|&(_, &x)| x == window)
            .map(|(i, _)| i);

        if let Some(index) = res {
            if index < self.unmanaged.urgent.len() {
                self.unmanaged.urgent.remove(index - 1);
            }
        } else {
            self.managed.remove_urgent(window);
        }
    }

    fn remove_managed(&mut self, xws: &XlibWindowSystem, config: &Config, window: Window) {
        trace!("remove managed window: {}", window);
        xws.unmap_window(window);
        self.managed.remove(window);

        if self.visible {
            self.redraw(xws, config);
        }
    }

    fn remove_unmanaged(&mut self, xws: &XlibWindowSystem, config: &Config, window: Window) {
        trace!("remove unmanaged window: {}", window);
        xws.unmap_window(window);
        self.unmanaged.remove(window);
        self.unmanaged.focus = if self.unmanaged.nodes.is_empty() {
            None
        } else {
            Some(self.unmanaged.nodes.len() - 1)
        };

        if self.visible {
            self.redraw(xws, config);
        }
    }

    pub fn remove_window(&mut self, xws: &XlibWindowSystem, config: &Config, window: Window) {
        if self.managed.contains(window) {
            trace!("Remove Managed: {}", window);
            self.remove_managed(xws, config, window);
        } else if self.unmanaged.contains(window) {
            trace!("Remove Unmanaged: {}", window);
            self.remove_unmanaged(xws, config, window);
        }
    }

    pub fn focus_window(&mut self, xws: &XlibWindowSystem, config: &Config, window: Window) {
        if window == 0 || self.unmanaged.focused_window() == Some(window) || self.managed.focused_window() == Some(window) {
            return;
        }

        self.remove_urgent_window(window);
        self.remove_window_highlight(xws, config);

        if self.unmanaged.contains(window) {
            self.unmanaged.focus_window(window);
        } else {
            self.managed.focus_window(window);
        }

        xws.focus_window(window, config.border_focus_color);
        self.redraw(xws, config);
    }

    pub fn remove_window_highlight(&mut self, xws: &XlibWindowSystem, config: &Config) {
        if let Some(window) = self.focused_window() {
            xws.set_window_border_color(window, config.border_color);
        }
    }

    pub fn move_parent_focus(&mut self, xws: &XlibWindowSystem, config: &Config, op: MoveOp) {
        if self.managed.move_parent_focus(op).is_some() {
            self.redraw(xws, config);
        }
    }

    // TODO: impl managed and unmanaged focus mode incl switching
    pub fn move_focus(&mut self, xws: &XlibWindowSystem, config: &Config, op: MoveOp) {
        if self.managed.move_focus(op).is_some() {
            self.redraw(xws, config);
        }
    }

    pub fn move_window(&mut self, xws: &XlibWindowSystem, config: &Config, op: MoveOp) {
        if let Some(window) = self.focused_window() {
            trace!("move window: {:?}", window);

            self.managed.move_window(op);
            self.redraw(xws, config);
        }
    }

    pub fn move_parent_window(&mut self, xws: &XlibWindowSystem, config: &Config, op: MoveOp) {
        if let Some(window) = self.focused_window() {
            trace!("move parent window: {:?}", window);

            self.managed.move_parent_window(op);
            self.redraw(xws, config);
        }
    }

    pub fn contains(&self, window: Window) -> bool {
        self.all().iter().any(|&w| w == window)
    }

    pub fn unfocus(&mut self, xws: &XlibWindowSystem, config: &Config) {
        if let Some(window) = self.focused_window() {
            trace!("unfocus window: {}", window);
            xws.set_window_border_color(window, config.border_color);
        }
    }

    pub fn focus(&self, xws: &XlibWindowSystem, config: &Config) {
        if let Some(window) = self.focused_window() {
            trace!("focus window: {}", window);
            xws.focus_window(window, config.border_focus_color);
            xws.skip_enter_events();
        }
    }

    pub fn center_pointer(&self, xws: &XlibWindowSystem) {
        let screen = xws.get_screen_infos()[self.screen];
        xws.move_pointer((screen.x + (screen.width / 2)) as i32 - 1, (screen.y + (screen.height / 2)) as i32);
    }

    pub fn hide(&mut self, xws: &XlibWindowSystem) {
        self.visible = false;

        for &w in self.managed.all_windows().iter().filter(|&w| Some(*w) != self.focused_window()) {
            xws.hide_window(w);
        }

        for &w in self.unmanaged.all_windows().iter().filter(|&w| Some(*w) != self.focused_window()) {
            xws.hide_window(w);
        }

        if let Some(w) = self.focused_window() {
            xws.hide_window(w);
        }
    }

    pub fn show(&mut self, xws: &XlibWindowSystem, config: &Config) {
        self.visible = true;

        self.redraw(xws, config);
        for &w in self.managed.all_windows().iter() {
            xws.show_window(w);
        }

        for &w in self.unmanaged.all_windows().iter() {
            xws.show_window(w);
        }
    }

    pub fn redraw(&self, xws: &XlibWindowSystem, config: &Config) {
        trace!("Redraw...");

        let screen = xws.get_screen_infos()[self.screen];

        for (rect, window) in self.managed.apply_layout(screen, xws) {
            xws.setup_window(rect.x,
                rect.y,
                rect.width,
                rect.height,
                config.border_width,
                config.border_color,
                window);
        }

        for &window in self.unmanaged.all_windows().iter() {
            let mut rect = xws.get_geometry(window);
            rect.width = cmp::min(screen.width, rect.width + (2 * config.border_width));
            rect.height = cmp::min(screen.height, rect.height + (2 * config.border_width));

            xws.setup_window(screen.x + (screen.width - rect.width) / 2,
                            screen.y + (screen.height - rect.height) / 2,
                            rect.width,
                            rect.height,
                            config.border_width,
                            config.border_color,
                            window);
        }

        for &window in self.all_urgent().iter() {
            xws.set_window_border_color(window, config.border_urgent_color);
        }

        self.focus(xws, config);
    }
}
<|endoftext|>