<commit_before>use itertools::{multipeek, MultiPeek};
use std::str;

#[derive(Debug, PartialEq)]
pub enum Token {
    LeftParen,
    RightParen,
    LeftBrace,
    RightBrace,
    Comma,
    Dot,
    Minus,
    Plus,
    Semicolon,
    Slash,
    Star,
    Bang,
    BangEqual,
    Equal,
    EqualEqual,
    Greater,
    GreaterEqual,
    Less,
    LessEqual,
    Identifier(String),
    StringLiteral(String),
    NumberLiteral(f64),
    // Keywords
    And,
    Class,
    Else,
    False,
    Fun,
    For,
    If,
    Nil,
    Or,
    Print,
    Return,
    Super,
    This,
    True,
    Var,
    While,

    // The book doesn't have tokens for comments and
    // whitespaces. Introducing them the scanner can
    // deal with them uniformly and in a more
    // functional way.
    Comment,
    Whitespace,
}

#[derive(Debug,Clone,Copy)]
/// Represents a position in the source file.
/// Both line and column are represented by a 1-based
/// index, since this struct exists only to provide
/// context to the user.
pub struct Position {
    line: usize,
    column: usize,
}

impl Position {
    fn initial() -> Position {
        Position {
            line: 1,
            column: 1,
        }
    }

    fn increment_column(&mut self) -> () {
        self.column += 1;
    }

    fn increment_line(&mut self) -> () {
        self.line += 1;
        self.column = 1;
    }
}

pub type Lexeme = String;

#[derive(Debug)]
pub struct TokenWithContext {
    pub token: Token,
    // Takes a copy. Tokens can outlive the file they came from
    pub lexeme: Lexeme,
    /// Position of the first character of the token
    pub position: Position,
}

#[derive(Debug,Clone)]
pub enum ScannerError {
    MissingStringTerminator(Position),
    UnexpectedCharacter(char, Position),
}

struct Scanner<'a> {
    current_position: Position,
    current_lexeme: String,
    source: MultiPeek<str::Chars<'a>>,
}

fn is_digit(c: char) -> bool {
    c >= '0' && c <= '9'
}

fn is_alpha(c: char) -> bool {
    (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_'
}

fn is_alphanumeric(c: char) -> bool {
    is_digit(c) || is_alpha(c)
}

fn is_whitespace(c: char) -> bool {
    match c {
        ' ' => true,
        '\r' => true,
        '\t' => true,
        '\n' => true,
        _ => false,
    }
}

impl<'a> Scanner<'a> {
    fn initialize(source: &String) -> Scanner {
        Scanner {
            current_position: Position::initial(),
            current_lexeme: "".into(),
            source: multipeek(source.chars()),
        }
    }

    fn peek_check(&mut self, check: &Fn(char) -> bool) -> bool {
        self.source.reset_peek();
        match self.source.peek() {
            Some(&c) => check(c),
            None => false,
        }
    }

    fn peek_check2(&mut self, check1: &Fn(char) -> bool, check2: &Fn(char) -> bool) -> bool {
        self.source.reset_peek();
        match self.source.peek() {
            Some(&p1) => {
                match self.source.peek() {
                    Some(&p2) => check1(p1) && check2(p2),
                    None => false,
                }
            }
            None => false,
        }
    }

    fn advance(&mut self) -> Option<char> {
        let next = self.source.next();
        match next {
            Some(c) => {
                self.current_lexeme.push(c);
                if c == '\n' {
                    self.current_position.increment_line();
                } else {
                    self.current_position.increment_column();;
                }
            }
            None => (),
        }
        next
    }

    fn advance_if_match(&mut self, expected: char) -> bool {
        if self.peek_check(&|c| c == expected) {
            let _ = self.advance();
            true
        } else {
            false
        }
    }

    fn advance_while(&mut self, condition: &Fn(char) -> bool) -> () {
        while self.peek_check(condition) {
            self.advance();
        }
    }

    fn add_context(&mut self, token: Token, initial_position: Position) -> TokenWithContext {
        let result = TokenWithContext {
            token: token,
            lexeme: self.current_lexeme.clone(),
            position: initial_position,
        };
        result
    }

    fn string(&mut self) -> Result<Token, ScannerError> {
        self.advance_while(&|c| c != '"' && c != '\n');
        if !self.advance_if_match('"') {
            return Err(ScannerError::MissingStringTerminator(self.current_position));
        }
        let literal_length = self.current_lexeme.len() - 2;
        // Trims delimiters
        let literal = self.current_lexeme.chars().skip(1).take(literal_length).collect();
        Ok(Token::StringLiteral(literal))
    }

    fn number(&mut self) -> Token {
        self.advance_while(&is_digit);
        if self.peek_check2(&|p1| p1 == '.', &is_digit) {
            self.advance(); // Consume the .
            self.advance_while(&is_digit);
        }
        let value = self.current_lexeme.parse::<f64>().unwrap();
        Token::NumberLiteral(value)
    }

    fn identifier(&mut self) -> Token {
        self.advance_while(&is_alphanumeric);
        match self.current_lexeme.as_ref() {
            "and" => Token::And,
            "class" => Token::Class,
            "else" => Token::Else,
            "false" => Token::False,
            "for" => Token::For,
            "fun" => Token::Fun,
            "if" => Token::If,
            "nil" => Token::Nil,
            "or" => Token::Or,
            "print" => Token::Print,
            "return" => Token::Return,
            "super" => Token::Super,
            "this" => Token::This,
            "true" => Token::True,
            "var" => Token::Var,
            "while" => Token::While,
            identifier => Token::Identifier(identifier.into()),
        }

    }

    fn scan_next(&mut self) -> Option<Result<TokenWithContext, ScannerError>> {
        let initial_position = self.current_position;
        self.current_lexeme.clear();
        // Check if there is something left to iterate on.
        // Early return if we're done.
        let next_char = match self.advance() {
            Some(c) => c,
            None => return None,
        };
        let token = match next_char {
            '(' => Token::LeftParen,
            ')' => Token::RightParen,
            '{' => Token::LeftBrace,
            '}' => Token::RightBrace,
            ',' => Token::Comma,
            '.' => Token::Dot,
            '-' => Token::Minus,
            '+' => Token::Plus,
            ';' => Token::Semicolon,
            '*' => Token::Star,
            '!' => {
                if self.advance_if_match('=') {
                    Token::BangEqual
                } else {
                    Token::Bang
                }
            }
            '=' => {
                if self.advance_if_match('=') {
                    Token::EqualEqual
                } else {
                    Token::Equal
                }
            }
            '<' => {
                if self.advance_if_match('=') {
                    Token::LessEqual
                } else {
                    Token::Less
                }
            }
            '>' => {
                if self.advance_if_match('=') {
                    Token::GreaterEqual
                } else {
                    Token::Greater
                }
            }
            '/' => {
                if self.advance_if_match('/') {
                    // Comments go on till the end of the line
                    self.advance_while(&|c| c != '\n');
                    Token::Comment
                } else {
                    Token::Slash
                }
            }
            '"' => {
                match self.string() {
                    Ok(token) => token,
                    Err(error) => return Some(Err(error)),
                }
            }
            c if is_whitespace(c) => Token::Whitespace,
            c if is_digit(c) => self.number(),
            c if is_alpha(c) => self.identifier(),
            c => {
                // TODO: check if position is off by one
                return Some(Err(ScannerError::UnexpectedCharacter(c, self.current_position)));
            }
        };
        Some(Ok(self.add_context(token, initial_position)))
    }
}

pub fn scan(source: &String) -> (Vec<TokenWithContext>, Vec<ScannerError>) {
    let mut scanner = Scanner::initialize(source);
    let mut tokens = Vec::new();
    let mut errors = Vec::new();
    while let Some(result) = scanner.scan_next() {
        match result {
            Ok(token_with_context) => {
                match token_with_context.token {
                    // Ignoring tokens we don't care about
                    Token::Comment => {}
                    Token::Whitespace => {}
                    _ => tokens.push(token_with_context),
                };
            }
            Err(error) => errors.push(error),
        }
    }
    (tokens, errors)
}

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

    #[test]
    fn single_token() {
        let (tokens, _) = scan(&"+".into());
        assert_eq!(tokens[0].token, Token::Plus);
    }

    #[test]
    fn expression() {
        let (tokens, _) = scan(&"1+2".into());
        assert_eq!(tokens[0].token, Token::NumberLiteral(1.0f64));
        assert_eq!(tokens[1].token, Token::Plus);
        assert_eq!(tokens[2].token, Token::NumberLiteral(2.0f64));
    }

    #[test]
    fn expression_with_whitespaces() {
        let (tokens, _) = scan(&"1 + 2".into());
        assert_eq!(tokens[0].token, Token::NumberLiteral(1.0f64));
        assert_eq!(tokens[1].token, Token::Plus);
        assert_eq!(tokens[2].token, Token::NumberLiteral(2.0f64));
    }

    #[test]
    fn assignement_with_comment() {
        let (tokens, _) = scan(&"var a = 1.0; // A comment".into());
        assert_eq!(tokens[0].token, Token::Var);
        assert_eq!(tokens[1].token, Token::Identifier("a".into()));
        assert_eq!(tokens[2].token, Token::Equal);
        assert_eq!(tokens[3].token, Token::NumberLiteral(1.0f64));
        assert_eq!(tokens[4].token, Token::Semicolon);
    }

    #[test]
    fn multiline_statements() {
        let (tokens, _) = scan(&r#"var a = 1.0;
                              var b = "Hello";"#
            .into());
        assert_eq!(tokens[0].token, Token::Var);
        assert_eq!(tokens[1].token, Token::Identifier("a".into()));
        assert_eq!(tokens[2].token, Token::Equal);
        assert_eq!(tokens[3].token, Token::NumberLiteral(1.0f64));
        assert_eq!(tokens[4].token, Token::Semicolon);
        assert_eq!(tokens[5].token, Token::Var);
        assert_eq!(tokens[6].token, Token::Identifier("b".into()));
        assert_eq!(tokens[7].token, Token::Equal);
        assert_eq!(tokens[8].token, Token::StringLiteral("Hello".into()));
        assert_eq!(tokens[9].token, Token::Semicolon);
        assert_eq!(tokens[1].position.line, 1);
        assert_eq!(tokens[1].position.column, 5);
        assert_eq!(tokens[9].position.line, 2);
        assert_eq!(tokens[9].position.column, 46); // There are 30 spaces before the text!
    }

    #[test]
    fn expression_with_bad_character() {
        let (tokens, errors) = scan(&"1 + $2".into());
        assert_eq!(tokens[0].token, Token::NumberLiteral(1.0f64));
        assert_eq!(tokens[1].token, Token::Plus);
        assert_eq!(tokens[2].token, Token::NumberLiteral(2.0f64));
        assert_eq!(errors.len(), 1);
    }

    #[test]
    fn statements_with_unterminated_string() {
        let (tokens, errors) = scan(&r#"var a = "Unterminated;
                              var b = "Hello";"#
            .into());
        assert_eq!(tokens[0].token, Token::Var);
        assert_eq!(tokens[1].token, Token::Identifier("a".into()));
        assert_eq!(tokens[2].token, Token::Equal);
        // Literal not reported, it wasn't terminated
        // Semicolon got embedded into the string
        assert_eq!(tokens[3].token, Token::Var);
        assert_eq!(tokens[4].token, Token::Identifier("b".into()));
        assert_eq!(tokens[5].token, Token::Equal);
        assert_eq!(tokens[6].token, Token::StringLiteral("Hello".into()));
        assert_eq!(tokens[7].token, Token::Semicolon);
        assert_eq!(errors.len(), 1);
    }

}
<commit_msg>Removed early returns from scan_next<commit_after>use itertools::{multipeek, MultiPeek};
use std::str;

#[derive(Debug, PartialEq)]
pub enum Token {
    LeftParen,
    RightParen,
    LeftBrace,
    RightBrace,
    Comma,
    Dot,
    Minus,
    Plus,
    Semicolon,
    Slash,
    Star,
    Bang,
    BangEqual,
    Equal,
    EqualEqual,
    Greater,
    GreaterEqual,
    Less,
    LessEqual,
    Identifier(String),
    StringLiteral(String),
    NumberLiteral(f64),
    // Keywords
    And,
    Class,
    Else,
    False,
    Fun,
    For,
    If,
    Nil,
    Or,
    Print,
    Return,
    Super,
    This,
    True,
    Var,
    While,

    // The book doesn't have tokens for comments and
    // whitespaces. Introducing them the scanner can
    // deal with them uniformly and in a more
    // functional way.
    Comment,
    Whitespace,
}

#[derive(Debug,Clone,Copy)]
/// Represents a position in the source file.
/// Both line and column are represented by a 1-based
/// index, since this struct exists only to provide
/// context to the user.
pub struct Position {
    line: usize,
    column: usize,
}

impl Position {
    fn initial() -> Position {
        Position {
            line: 1,
            column: 1,
        }
    }

    fn increment_column(&mut self) -> () {
        self.column += 1;
    }

    fn increment_line(&mut self) -> () {
        self.line += 1;
        self.column = 1;
    }
}

pub type Lexeme = String;

#[derive(Debug)]
pub struct TokenWithContext {
    pub token: Token,
    // Takes a copy. Tokens can outlive the file they came from
    pub lexeme: Lexeme,
    /// Position of the first character of the token
    pub position: Position,
}

#[derive(Debug,Clone)]
pub enum ScannerError {
    MissingStringTerminator(Position),
    UnexpectedCharacter(char, Position),
}

struct Scanner<'a> {
    current_position: Position,
    current_lexeme: String,
    source: MultiPeek<str::Chars<'a>>,
}

fn is_digit(c: char) -> bool {
    c >= '0' && c <= '9'
}

fn is_alpha(c: char) -> bool {
    (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_'
}

fn is_alphanumeric(c: char) -> bool {
    is_digit(c) || is_alpha(c)
}

fn is_whitespace(c: char) -> bool {
    match c {
        ' ' => true,
        '\r' => true,
        '\t' => true,
        '\n' => true,
        _ => false,
    }
}

impl<'a> Scanner<'a> {
    fn initialize(source: &String) -> Scanner {
        Scanner {
            current_position: Position::initial(),
            current_lexeme: "".into(),
            source: multipeek(source.chars()),
        }
    }

    fn peek_check(&mut self, check: &Fn(char) -> bool) -> bool {
        self.source.reset_peek();
        match self.source.peek() {
            Some(&c) => check(c),
            None => false,
        }
    }

    fn peek_check2(&mut self, check1: &Fn(char) -> bool, check2: &Fn(char) -> bool) -> bool {
        self.source.reset_peek();
        match self.source.peek() {
            Some(&p1) => {
                match self.source.peek() {
                    Some(&p2) => check1(p1) && check2(p2),
                    None => false,
                }
            }
            None => false,
        }
    }

    fn advance(&mut self) -> Option<char> {
        let next = self.source.next();
        match next {
            Some(c) => {
                self.current_lexeme.push(c);
                if c == '\n' {
                    self.current_position.increment_line();
                } else {
                    self.current_position.increment_column();;
                }
            }
            None => (),
        }
        next
    }

    fn advance_if_match(&mut self, expected: char) -> bool {
        if self.peek_check(&|c| c == expected) {
            let _ = self.advance();
            true
        } else {
            false
        }
    }

    fn advance_while(&mut self, condition: &Fn(char) -> bool) -> () {
        while self.peek_check(condition) {
            self.advance();
        }
    }

    fn add_context(&mut self, token: Token, initial_position: Position) -> TokenWithContext {
        let result = TokenWithContext {
            token: token,
            lexeme: self.current_lexeme.clone(),
            position: initial_position,
        };
        result
    }

    fn string(&mut self) -> Result<Token, ScannerError> {
        self.advance_while(&|c| c != '"' && c != '\n');
        if !self.advance_if_match('"') {
            return Err(ScannerError::MissingStringTerminator(self.current_position));
        }
        let literal_length = self.current_lexeme.len() - 2;
        // Trims delimiters
        let literal = self.current_lexeme.chars().skip(1).take(literal_length).collect();
        Ok(Token::StringLiteral(literal))
    }

    fn number(&mut self) -> Token {
        self.advance_while(&is_digit);
        if self.peek_check2(&|p1| p1 == '.', &is_digit) {
            self.advance(); // Consume the .
            self.advance_while(&is_digit);
        }
        let value = self.current_lexeme.parse::<f64>().unwrap();
        Token::NumberLiteral(value)
    }

    fn identifier(&mut self) -> Token {
        self.advance_while(&is_alphanumeric);
        match self.current_lexeme.as_ref() {
            "and" => Token::And,
            "class" => Token::Class,
            "else" => Token::Else,
            "false" => Token::False,
            "for" => Token::For,
            "fun" => Token::Fun,
            "if" => Token::If,
            "nil" => Token::Nil,
            "or" => Token::Or,
            "print" => Token::Print,
            "return" => Token::Return,
            "super" => Token::Super,
            "this" => Token::This,
            "true" => Token::True,
            "var" => Token::Var,
            "while" => Token::While,
            identifier => Token::Identifier(identifier.into()),
        }

    }

    fn scan_next(&mut self) -> Option<Result<TokenWithContext, ScannerError>> {
        let initial_position = self.current_position;
        self.current_lexeme.clear();
        // Check if there is something left to iterate on.
        // Early return if we're done.
        let next_char = match self.advance() {
            Some(c) => c,
            None => return None,
        };
        let result = match next_char {
            '(' => Ok(Token::LeftParen),
            ')' => Ok(Token::RightParen),
            '{' => Ok(Token::LeftBrace),
            '}' => Ok(Token::RightBrace),
            ',' => Ok(Token::Comma),
            '.' => Ok(Token::Dot),
            '-' => Ok(Token::Minus),
            '+' => Ok(Token::Plus),
            ';' => Ok(Token::Semicolon),
            '*' => Ok(Token::Star),
            '!' => {
                if self.advance_if_match('=') {
                    Ok(Token::BangEqual)
                } else {
                    Ok(Token::Bang)
                }
            }
            '=' => {
                if self.advance_if_match('=') {
                    Ok(Token::EqualEqual)
                } else {
                    Ok(Token::Equal)
                }
            }
            '<' => {
                if self.advance_if_match('=') {
                    Ok(Token::LessEqual)
                } else {
                    Ok(Token::Less)
                }
            }
            '>' => {
                if self.advance_if_match('=') {
                    Ok(Token::GreaterEqual)
                } else {
                    Ok(Token::Greater)
                }
            }
            '/' => {
                if self.advance_if_match('/') {
                    // Comments go on till the end of the line
                    self.advance_while(&|c| c != '\n');
                    Ok(Token::Comment)
                } else {
                    Ok(Token::Slash)
                }
            }
            '"' => self.string(),
            c if is_whitespace(c) => Ok(Token::Whitespace),
            c if is_digit(c) => Ok(self.number()),
            c if is_alpha(c) => Ok(self.identifier()),
            c => Err(ScannerError::UnexpectedCharacter(c, self.current_position)),
        };
        Some(result.map(|token| self.add_context(token, initial_position)))
    }
}

pub fn scan(source: &String) -> (Vec<TokenWithContext>, Vec<ScannerError>) {
    let mut scanner = Scanner::initialize(source);
    let mut tokens = Vec::new();
    let mut errors = Vec::new();
    while let Some(result) = scanner.scan_next() {
        match result {
            Ok(token_with_context) => {
                match token_with_context.token {
                    // Ignoring tokens we don't care about
                    Token::Comment => {}
                    Token::Whitespace => {}
                    _ => tokens.push(token_with_context),
                };
            }
            Err(error) => errors.push(error),
        }
    }
    (tokens, errors)
}

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

    #[test]
    fn single_token() {
        let (tokens, _) = scan(&"+".into());
        assert_eq!(tokens[0].token, Token::Plus);
    }

    #[test]
    fn expression() {
        let (tokens, _) = scan(&"1+2".into());
        assert_eq!(tokens[0].token, Token::NumberLiteral(1.0f64));
        assert_eq!(tokens[1].token, Token::Plus);
        assert_eq!(tokens[2].token, Token::NumberLiteral(2.0f64));
    }

    #[test]
    fn expression_with_whitespaces() {
        let (tokens, _) = scan(&"1 + 2".into());
        assert_eq!(tokens[0].token, Token::NumberLiteral(1.0f64));
        assert_eq!(tokens[1].token, Token::Plus);
        assert_eq!(tokens[2].token, Token::NumberLiteral(2.0f64));
    }

    #[test]
    fn assignement_with_comment() {
        let (tokens, _) = scan(&"var a = 1.0; // A comment".into());
        assert_eq!(tokens[0].token, Token::Var);
        assert_eq!(tokens[1].token, Token::Identifier("a".into()));
        assert_eq!(tokens[2].token, Token::Equal);
        assert_eq!(tokens[3].token, Token::NumberLiteral(1.0f64));
        assert_eq!(tokens[4].token, Token::Semicolon);
    }

    #[test]
    fn multiline_statements() {
        let (tokens, _) = scan(&r#"var a = 1.0;
                              var b = "Hello";"#
            .into());
        assert_eq!(tokens[0].token, Token::Var);
        assert_eq!(tokens[1].token, Token::Identifier("a".into()));
        assert_eq!(tokens[2].token, Token::Equal);
        assert_eq!(tokens[3].token, Token::NumberLiteral(1.0f64));
        assert_eq!(tokens[4].token, Token::Semicolon);
        assert_eq!(tokens[5].token, Token::Var);
        assert_eq!(tokens[6].token, Token::Identifier("b".into()));
        assert_eq!(tokens[7].token, Token::Equal);
        assert_eq!(tokens[8].token, Token::StringLiteral("Hello".into()));
        assert_eq!(tokens[9].token, Token::Semicolon);
        assert_eq!(tokens[1].position.line, 1);
        assert_eq!(tokens[1].position.column, 5);
        assert_eq!(tokens[9].position.line, 2);
        assert_eq!(tokens[9].position.column, 46); // There are 30 spaces before the text!
    }

    #[test]
    fn expression_with_bad_character() {
        let (tokens, errors) = scan(&"1 + $2".into());
        assert_eq!(tokens[0].token, Token::NumberLiteral(1.0f64));
        assert_eq!(tokens[1].token, Token::Plus);
        assert_eq!(tokens[2].token, Token::NumberLiteral(2.0f64));
        assert_eq!(errors.len(), 1);
    }

    #[test]
    fn statements_with_unterminated_string() {
        let (tokens, errors) = scan(&r#"var a = "Unterminated;
                              var b = "Hello";"#
            .into());
        assert_eq!(tokens[0].token, Token::Var);
        assert_eq!(tokens[1].token, Token::Identifier("a".into()));
        assert_eq!(tokens[2].token, Token::Equal);
        // Literal not reported, it wasn't terminated
        // Semicolon got embedded into the string
        assert_eq!(tokens[3].token, Token::Var);
        assert_eq!(tokens[4].token, Token::Identifier("b".into()));
        assert_eq!(tokens[5].token, Token::Equal);
        assert_eq!(tokens[6].token, Token::StringLiteral("Hello".into()));
        assert_eq!(tokens[7].token, Token::Semicolon);
        assert_eq!(errors.len(), 1);
    }

}
<|endoftext|>


<commit_before>//! Serializing Rust structures into TOML.
//!
//! This module contains all the Serde support for serializing Rust structures into TOML.

mod array;
mod item;
mod key;
mod table;

pub(crate) use array::*;
pub(crate) use item::*;
pub(crate) use key::*;
pub(crate) use table::*;

/// Errors that can occur when deserializing a type.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Error {
    kind: ErrorKind,
}

impl Error {
    pub(crate) fn custom<T>(msg: T) -> Self
    where
        T: std::fmt::Display,
    {
        Error {
            kind: ErrorKind::Custom(msg.to_string()),
        }
    }
}

impl serde::ser::Error for Error {
    fn custom<T>(msg: T) -> Self
    where
        T: std::fmt::Display,
    {
        Self::custom(msg)
    }
}

impl std::fmt::Display for Error {
    fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
        self.kind.fmt(formatter)
    }
}

impl From<crate::TomlError> for Error {
    fn from(e: crate::TomlError) -> Error {
        Self::custom(e)
    }
}

impl From<Error> for crate::TomlError {
    fn from(e: Error) -> crate::TomlError {
        Self::custom(e.to_string())
    }
}

impl std::error::Error for Error {}

impl From<ErrorKind> for Error {
    fn from(kind: ErrorKind) -> Self {
        Self { kind }
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
enum ErrorKind {
    UnsupportedType,
    UnsupportedNone,
    KeyNotString,
    Custom(String),
}

impl std::fmt::Display for ErrorKind {
    fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
        match self {
            ErrorKind::UnsupportedType => "unsupported Rust type".fmt(formatter),
            ErrorKind::UnsupportedNone => "unsupported None value".fmt(formatter),
            ErrorKind::KeyNotString => "map key was not a string".fmt(formatter),
            ErrorKind::Custom(s) => s.fmt(formatter),
        }
    }
}

/// Serialize the given data structure as a TOML byte vector.
///
/// Serialization can fail if `T`'s implementation of `Serialize` decides to
/// fail, if `T` contains a map with non-string keys, or if `T` attempts to
/// serialize an unsupported datatype such as an enum, tuple, or tuple struct.
pub fn to_vec<T: ?Sized>(value: &T) -> Result<Vec<u8>, Error>
where
    T: serde::ser::Serialize,
{
    to_string(value).map(|e| e.into_bytes())
}

/// Serialize the given data structure as a String of TOML.
///
/// Serialization can fail if `T`'s implementation of `Serialize` decides to
/// fail, if `T` contains a map with non-string keys, or if `T` attempts to
/// serialize an unsupported datatype such as an enum, tuple, or tuple struct.
///
/// # Examples
///
/// ```
/// use serde::Serialize;
///
/// #[derive(Serialize)]
/// struct Config {
///     database: Database,
/// }
///
/// #[derive(Serialize)]
/// struct Database {
///     ip: String,
///     port: Vec<u16>,
///     connection_max: u32,
///     enabled: bool,
/// }
///
/// let config = Config {
///     database: Database {
///         ip: "192.168.1.1".to_string(),
///         port: vec![8001, 8002, 8003],
///         connection_max: 5000,
///         enabled: false,
///     },
/// };
///
/// let toml = toml::to_string(&config).unwrap();
/// println!("{}", toml)
/// ```
pub fn to_string<T: ?Sized>(value: &T) -> Result<String, Error>
where
    T: serde::ser::Serialize,
{
    to_document(value).map(|e| e.to_string())
}

/// Serialize the given data structure as a "pretty" String of TOML.
///
/// This is identical to `to_string` except the output string has a more
/// "pretty" output. See `Serializer::pretty` for more details.
pub fn to_string_pretty<T: ?Sized>(value: &T) -> Result<String, Error>
where
    T: serde::ser::Serialize,
{
    to_document(value).map(|e| e.to_string())
}

/// Serialize the given data structure into a TOML data structure
///
/// This would allow custom formatting to be applied, mixing with format preserving edits, etc.
pub fn to_document<T: ?Sized>(value: &T) -> Result<crate::Document, Error>
where
    T: serde::ser::Serialize,
{
    let document = value.serialize(Serializer::new())?;
    Ok(document)
}

/// Serialization implementation for TOML.
///
/// This structure implements serialization support for TOML to serialize an
/// arbitrary type to TOML. Note that the TOML format does not support all
/// datatypes in Rust, such as enums, tuples, and tuple structs. These types
/// will generate an error when serialized.
///
/// Currently a serializer always writes its output to an in-memory `String`,
/// which is passed in when creating the serializer itself.
#[derive(Default)]
pub struct Serializer {}

impl Serializer {
    /// Creates a new serializer generate a TOML document.
    pub fn new() -> Self {
        Self {}
    }
}

impl serde::ser::Serializer for Serializer {
    type Ok = crate::Document;
    type Error = Error;
    type SerializeSeq = serde::ser::Impossible<Self::Ok, Self::Error>;
    type SerializeTuple = serde::ser::Impossible<Self::Ok, Self::Error>;
    type SerializeTupleStruct = serde::ser::Impossible<Self::Ok, Self::Error>;
    type SerializeTupleVariant = serde::ser::Impossible<Self::Ok, Self::Error>;
    type SerializeMap = SerializeDocument;
    type SerializeStruct = SerializeDocument;
    type SerializeStructVariant = serde::ser::Impossible<Self::Ok, Self::Error>;

    fn serialize_bool(self, _: bool) -> Result<Self::Ok, Self::Error> {
        Err(ErrorKind::UnsupportedType.into())
    }

    fn serialize_i8(self, v: i8) -> Result<Self::Ok, Self::Error> {
        self.serialize_i64(v as i64)
    }

    fn serialize_i16(self, v: i16) -> Result<Self::Ok, Self::Error> {
        self.serialize_i64(v as i64)
    }

    fn serialize_i32(self, v: i32) -> Result<Self::Ok, Self::Error> {
        self.serialize_i64(v as i64)
    }

    fn serialize_i64(self, _: i64) -> Result<Self::Ok, Self::Error> {
        Err(ErrorKind::UnsupportedType.into())
    }

    fn serialize_u8(self, v: u8) -> Result<Self::Ok, Self::Error> {
        self.serialize_i64(v as i64)
    }

    fn serialize_u16(self, v: u16) -> Result<Self::Ok, Self::Error> {
        self.serialize_i64(v as i64)
    }

    fn serialize_u32(self, v: u32) -> Result<Self::Ok, Self::Error> {
        self.serialize_i64(v as i64)
    }

    fn serialize_u64(self, v: u64) -> Result<Self::Ok, Self::Error> {
        self.serialize_i64(v as i64)
    }

    fn serialize_f32(self, v: f32) -> Result<Self::Ok, Self::Error> {
        self.serialize_f64(v as f64)
    }

    fn serialize_f64(self, _: f64) -> Result<Self::Ok, Self::Error> {
        Err(ErrorKind::UnsupportedType.into())
    }

    fn serialize_char(self, _: char) -> Result<Self::Ok, Self::Error> {
        Err(ErrorKind::UnsupportedType.into())
    }

    fn serialize_str(self, _: &str) -> Result<Self::Ok, Self::Error> {
        Err(ErrorKind::UnsupportedType.into())
    }

    fn serialize_bytes(self, _: &[u8]) -> Result<Self::Ok, Self::Error> {
        Err(ErrorKind::UnsupportedType.into())
    }

    fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
        Err(ErrorKind::UnsupportedNone.into())
    }

    fn serialize_some<T: ?Sized>(self, value: &T) -> Result<Self::Ok, Self::Error>
    where
        T: serde::ser::Serialize,
    {
        value.serialize(self)
    }

    fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
        Err(ErrorKind::UnsupportedType.into())
    }

    fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> {
        Err(ErrorKind::UnsupportedType.into())
    }

    fn serialize_unit_variant(
        self,
        _name: &'static str,
        _variant_index: u32,
        variant: &'static str,
    ) -> Result<Self::Ok, Self::Error> {
        self.serialize_str(variant)
    }

    fn serialize_newtype_struct<T: ?Sized>(
        self,
        _name: &'static str,
        value: &T,
    ) -> Result<Self::Ok, Self::Error>
    where
        T: serde::ser::Serialize,
    {
        value.serialize(self)
    }

    fn serialize_newtype_variant<T: ?Sized>(
        self,
        _name: &'static str,
        _variant_index: u32,
        _variant: &'static str,
        _value: &T,
    ) -> Result<Self::Ok, Self::Error>
    where
        T: serde::ser::Serialize,
    {
        Err(ErrorKind::UnsupportedType.into())
    }

    fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
        Err(ErrorKind::UnsupportedType.into())
    }

    fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, Self::Error> {
        self.serialize_seq(Some(len))
    }

    fn serialize_tuple_struct(
        self,
        _name: &'static str,
        len: usize,
    ) -> Result<Self::SerializeTupleStruct, Self::Error> {
        self.serialize_seq(Some(len))
    }

    fn serialize_tuple_variant(
        self,
        _name: &'static str,
        _variant_index: u32,
        _variant: &'static str,
        len: usize,
    ) -> Result<Self::SerializeTupleVariant, Self::Error> {
        self.serialize_seq(Some(len))
    }

    fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
        let serializer = match len {
            Some(len) => SerializeDocument::with_capacity(len),
            None => SerializeDocument::new(),
        };
        Ok(serializer)
    }

    fn serialize_struct(
        self,
        _name: &'static str,
        len: usize,
    ) -> Result<Self::SerializeStruct, Self::Error> {
        self.serialize_map(Some(len))
    }

    fn serialize_struct_variant(
        self,
        _name: &'static str,
        _variant_index: u32,
        _variant: &'static str,
        _len: usize,
    ) -> Result<Self::SerializeStructVariant, Self::Error> {
        Err(ErrorKind::UnsupportedType.into())
    }
}
<commit_msg>fix(serde)!: Disallow direct creation of `Serializer` (#242)<commit_after>//! Serializing Rust structures into TOML.
//!
//! This module contains all the Serde support for serializing Rust structures into TOML.

mod array;
mod item;
mod key;
mod table;

pub(crate) use array::*;
pub(crate) use item::*;
pub(crate) use key::*;
pub(crate) use table::*;

/// Errors that can occur when deserializing a type.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Error {
    kind: ErrorKind,
}

impl Error {
    pub(crate) fn custom<T>(msg: T) -> Self
    where
        T: std::fmt::Display,
    {
        Error {
            kind: ErrorKind::Custom(msg.to_string()),
        }
    }
}

impl serde::ser::Error for Error {
    fn custom<T>(msg: T) -> Self
    where
        T: std::fmt::Display,
    {
        Self::custom(msg)
    }
}

impl std::fmt::Display for Error {
    fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
        self.kind.fmt(formatter)
    }
}

impl From<crate::TomlError> for Error {
    fn from(e: crate::TomlError) -> Error {
        Self::custom(e)
    }
}

impl From<Error> for crate::TomlError {
    fn from(e: Error) -> crate::TomlError {
        Self::custom(e.to_string())
    }
}

impl std::error::Error for Error {}

impl From<ErrorKind> for Error {
    fn from(kind: ErrorKind) -> Self {
        Self { kind }
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
enum ErrorKind {
    UnsupportedType,
    UnsupportedNone,
    KeyNotString,
    Custom(String),
}

impl std::fmt::Display for ErrorKind {
    fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
        match self {
            ErrorKind::UnsupportedType => "unsupported Rust type".fmt(formatter),
            ErrorKind::UnsupportedNone => "unsupported None value".fmt(formatter),
            ErrorKind::KeyNotString => "map key was not a string".fmt(formatter),
            ErrorKind::Custom(s) => s.fmt(formatter),
        }
    }
}

/// Serialize the given data structure as a TOML byte vector.
///
/// Serialization can fail if `T`'s implementation of `Serialize` decides to
/// fail, if `T` contains a map with non-string keys, or if `T` attempts to
/// serialize an unsupported datatype such as an enum, tuple, or tuple struct.
pub fn to_vec<T: ?Sized>(value: &T) -> Result<Vec<u8>, Error>
where
    T: serde::ser::Serialize,
{
    to_string(value).map(|e| e.into_bytes())
}

/// Serialize the given data structure as a String of TOML.
///
/// Serialization can fail if `T`'s implementation of `Serialize` decides to
/// fail, if `T` contains a map with non-string keys, or if `T` attempts to
/// serialize an unsupported datatype such as an enum, tuple, or tuple struct.
///
/// # Examples
///
/// ```
/// use serde::Serialize;
///
/// #[derive(Serialize)]
/// struct Config {
///     database: Database,
/// }
///
/// #[derive(Serialize)]
/// struct Database {
///     ip: String,
///     port: Vec<u16>,
///     connection_max: u32,
///     enabled: bool,
/// }
///
/// let config = Config {
///     database: Database {
///         ip: "192.168.1.1".to_string(),
///         port: vec![8001, 8002, 8003],
///         connection_max: 5000,
///         enabled: false,
///     },
/// };
///
/// let toml = toml::to_string(&config).unwrap();
/// println!("{}", toml)
/// ```
pub fn to_string<T: ?Sized>(value: &T) -> Result<String, Error>
where
    T: serde::ser::Serialize,
{
    to_document(value).map(|e| e.to_string())
}

/// Serialize the given data structure as a "pretty" String of TOML.
///
/// This is identical to `to_string` except the output string has a more
/// "pretty" output. See `Serializer::pretty` for more details.
pub fn to_string_pretty<T: ?Sized>(value: &T) -> Result<String, Error>
where
    T: serde::ser::Serialize,
{
    to_document(value).map(|e| e.to_string())
}

/// Serialize the given data structure into a TOML data structure
///
/// This would allow custom formatting to be applied, mixing with format preserving edits, etc.
pub fn to_document<T: ?Sized>(value: &T) -> Result<crate::Document, Error>
where
    T: serde::ser::Serialize,
{
    let document = value.serialize(Serializer::new())?;
    Ok(document)
}

/// Serialization implementation for TOML.
///
/// This structure implements serialization support for TOML to serialize an
/// arbitrary type to TOML. Note that the TOML format does not support all
/// datatypes in Rust, such as enums, tuples, and tuple structs. These types
/// will generate an error when serialized.
///
/// Currently a serializer always writes its output to an in-memory `String`,
/// which is passed in when creating the serializer itself.
#[derive(Default)]
#[non_exhaustive]
pub struct Serializer {}

impl Serializer {
    /// Creates a new serializer generate a TOML document.
    pub fn new() -> Self {
        Self {}
    }
}

impl serde::ser::Serializer for Serializer {
    type Ok = crate::Document;
    type Error = Error;
    type SerializeSeq = serde::ser::Impossible<Self::Ok, Self::Error>;
    type SerializeTuple = serde::ser::Impossible<Self::Ok, Self::Error>;
    type SerializeTupleStruct = serde::ser::Impossible<Self::Ok, Self::Error>;
    type SerializeTupleVariant = serde::ser::Impossible<Self::Ok, Self::Error>;
    type SerializeMap = SerializeDocument;
    type SerializeStruct = SerializeDocument;
    type SerializeStructVariant = serde::ser::Impossible<Self::Ok, Self::Error>;

    fn serialize_bool(self, _: bool) -> Result<Self::Ok, Self::Error> {
        Err(ErrorKind::UnsupportedType.into())
    }

    fn serialize_i8(self, v: i8) -> Result<Self::Ok, Self::Error> {
        self.serialize_i64(v as i64)
    }

    fn serialize_i16(self, v: i16) -> Result<Self::Ok, Self::Error> {
        self.serialize_i64(v as i64)
    }

    fn serialize_i32(self, v: i32) -> Result<Self::Ok, Self::Error> {
        self.serialize_i64(v as i64)
    }

    fn serialize_i64(self, _: i64) -> Result<Self::Ok, Self::Error> {
        Err(ErrorKind::UnsupportedType.into())
    }

    fn serialize_u8(self, v: u8) -> Result<Self::Ok, Self::Error> {
        self.serialize_i64(v as i64)
    }

    fn serialize_u16(self, v: u16) -> Result<Self::Ok, Self::Error> {
        self.serialize_i64(v as i64)
    }

    fn serialize_u32(self, v: u32) -> Result<Self::Ok, Self::Error> {
        self.serialize_i64(v as i64)
    }

    fn serialize_u64(self, v: u64) -> Result<Self::Ok, Self::Error> {
        self.serialize_i64(v as i64)
    }

    fn serialize_f32(self, v: f32) -> Result<Self::Ok, Self::Error> {
        self.serialize_f64(v as f64)
    }

    fn serialize_f64(self, _: f64) -> Result<Self::Ok, Self::Error> {
        Err(ErrorKind::UnsupportedType.into())
    }

    fn serialize_char(self, _: char) -> Result<Self::Ok, Self::Error> {
        Err(ErrorKind::UnsupportedType.into())
    }

    fn serialize_str(self, _: &str) -> Result<Self::Ok, Self::Error> {
        Err(ErrorKind::UnsupportedType.into())
    }

    fn serialize_bytes(self, _: &[u8]) -> Result<Self::Ok, Self::Error> {
        Err(ErrorKind::UnsupportedType.into())
    }

    fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
        Err(ErrorKind::UnsupportedNone.into())
    }

    fn serialize_some<T: ?Sized>(self, value: &T) -> Result<Self::Ok, Self::Error>
    where
        T: serde::ser::Serialize,
    {
        value.serialize(self)
    }

    fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
        Err(ErrorKind::UnsupportedType.into())
    }

    fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> {
        Err(ErrorKind::UnsupportedType.into())
    }

    fn serialize_unit_variant(
        self,
        _name: &'static str,
        _variant_index: u32,
        variant: &'static str,
    ) -> Result<Self::Ok, Self::Error> {
        self.serialize_str(variant)
    }

    fn serialize_newtype_struct<T: ?Sized>(
        self,
        _name: &'static str,
        value: &T,
    ) -> Result<Self::Ok, Self::Error>
    where
        T: serde::ser::Serialize,
    {
        value.serialize(self)
    }

    fn serialize_newtype_variant<T: ?Sized>(
        self,
        _name: &'static str,
        _variant_index: u32,
        _variant: &'static str,
        _value: &T,
    ) -> Result<Self::Ok, Self::Error>
    where
        T: serde::ser::Serialize,
    {
        Err(ErrorKind::UnsupportedType.into())
    }

    fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
        Err(ErrorKind::UnsupportedType.into())
    }

    fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, Self::Error> {
        self.serialize_seq(Some(len))
    }

    fn serialize_tuple_struct(
        self,
        _name: &'static str,
        len: usize,
    ) -> Result<Self::SerializeTupleStruct, Self::Error> {
        self.serialize_seq(Some(len))
    }

    fn serialize_tuple_variant(
        self,
        _name: &'static str,
        _variant_index: u32,
        _variant: &'static str,
        len: usize,
    ) -> Result<Self::SerializeTupleVariant, Self::Error> {
        self.serialize_seq(Some(len))
    }

    fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
        let serializer = match len {
            Some(len) => SerializeDocument::with_capacity(len),
            None => SerializeDocument::new(),
        };
        Ok(serializer)
    }

    fn serialize_struct(
        self,
        _name: &'static str,
        len: usize,
    ) -> Result<Self::SerializeStruct, Self::Error> {
        self.serialize_map(Some(len))
    }

    fn serialize_struct_variant(
        self,
        _name: &'static str,
        _variant_index: u32,
        _variant: &'static str,
        _len: usize,
    ) -> Result<Self::SerializeStructVariant, Self::Error> {
        Err(ErrorKind::UnsupportedType.into())
    }
}
<|endoftext|>


<commit_before>use core::borrow::{Borrow, BorrowMut};
use core::cmp;
use core::fmt::{self, Debug};
use core::ops::{Deref, DerefMut};

#[cfg(feature = "alloc")]
use alloc::string::String;
#[cfg(feature = "alloc")]
use alloc::vec::Vec;

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

use crate::Bytes;

/// Wrapper around `Vec<u8>` to serialize and deserialize efficiently.
///
/// ```
/// use std::collections::HashMap;
/// use std::io;
///
/// use serde_bytes::ByteBuf;
///
/// fn deserialize_bytebufs() -> bincode::Result<()> {
///     let example_data = [
///         2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 116,
///         119, 111, 1, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 111, 110, 101];
///
///     let map: HashMap<u32, ByteBuf> = bincode::deserialize(&example_data[..])?;
///
///     println!("{:?}", map);
///
///     Ok(())
/// }
/// #
/// # fn main() {
/// #     deserialize_bytebufs().unwrap();
/// # }
/// ```
#[derive(Clone, Default, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub struct ByteBuf {
    bytes: Vec<u8>,
}

impl ByteBuf {
    /// Construct a new, empty `ByteBuf`.
    pub fn new() -> Self {
        ByteBuf::from(Vec::new())
    }

    /// Construct a new, empty `ByteBuf` with the specified capacity.
    pub fn with_capacity(cap: usize) -> Self {
        ByteBuf::from(Vec::with_capacity(cap))
    }

    /// Wrap existing bytes in a `ByteBuf`.
    pub fn from<T: Into<Vec<u8>>>(bytes: T) -> Self {
        ByteBuf {
            bytes: bytes.into(),
        }
    }
}

impl Debug for ByteBuf {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Debug::fmt(&self.bytes, f)
    }
}

impl From<ByteBuf> for Vec<u8> {
    fn from(wrapper: ByteBuf) -> Vec<u8> {
        wrapper.bytes
    }
}

impl From<Vec<u8>> for ByteBuf {
    fn from(bytes: Vec<u8>) -> Self {
        ByteBuf::from(bytes)
    }
}

impl AsRef<Vec<u8>> for ByteBuf {
    fn as_ref(&self) -> &Vec<u8> {
        &self.bytes
    }
}

impl AsRef<[u8]> for ByteBuf {
    fn as_ref(&self) -> &[u8] {
        &self.bytes
    }
}

impl AsMut<Vec<u8>> for ByteBuf {
    fn as_mut(&mut self) -> &mut Vec<u8> {
        &mut self.bytes
    }
}

impl AsMut<[u8]> for ByteBuf {
    fn as_mut(&mut self) -> &mut [u8] {
        &mut self.bytes
    }
}

impl Deref for ByteBuf {
    type Target = [u8];

    fn deref(&self) -> &[u8] {
        &self.bytes[..]
    }
}

impl DerefMut for ByteBuf {
    fn deref_mut(&mut self) -> &mut [u8] {
        &mut self.bytes[..]
    }
}

impl Borrow<Bytes> for ByteBuf {
    fn borrow(&self) -> &Bytes {
        Bytes::new(&self.bytes)
    }
}

impl BorrowMut<Bytes> for ByteBuf {
    fn borrow_mut(&mut self) -> &mut Bytes {
        unsafe { &mut *(&mut self.bytes as &mut [u8] as *mut [u8] as *mut Bytes) }
    }
}

impl Serialize for ByteBuf {
    #[inline]
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        serializer.serialize_bytes(&self.bytes)
    }
}

struct ByteBufVisitor;

impl<'de> Visitor<'de> for ByteBufVisitor {
    type Value = ByteBuf;

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

    #[inline]
    fn visit_seq<V>(self, mut visitor: V) -> Result<ByteBuf, V::Error>
    where
        V: SeqAccess<'de>,
    {
        let len = cmp::min(visitor.size_hint().unwrap_or(0), 4096);
        let mut values = Vec::with_capacity(len);

        while let Some(value) = visitor.next_element()? {
            values.push(value);
        }

        Ok(ByteBuf::from(values))
    }

    #[inline]
    fn visit_bytes<E>(self, v: &[u8]) -> Result<ByteBuf, E>
    where
        E: Error,
    {
        Ok(ByteBuf::from(v))
    }

    #[inline]
    fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<ByteBuf, E>
    where
        E: Error,
    {
        Ok(ByteBuf::from(v))
    }

    #[inline]
    fn visit_str<E>(self, v: &str) -> Result<ByteBuf, E>
    where
        E: Error,
    {
        Ok(ByteBuf::from(v))
    }

    #[inline]
    fn visit_string<E>(self, v: String) -> Result<ByteBuf, E>
    where
        E: Error,
    {
        Ok(ByteBuf::from(v))
    }
}

impl<'de> Deserialize<'de> for ByteBuf {
    #[inline]
    fn deserialize<D>(deserializer: D) -> Result<ByteBuf, D::Error>
    where
        D: Deserializer<'de>,
    {
        deserializer.deserialize_byte_buf(ByteBufVisitor)
    }
}
<commit_msg>Allow calling mut methods on Vec through ByteBuf<commit_after>use core::borrow::{Borrow, BorrowMut};
use core::cmp;
use core::fmt::{self, Debug};
use core::ops::{Deref, DerefMut};

#[cfg(feature = "alloc")]
use alloc::string::String;
#[cfg(feature = "alloc")]
use alloc::vec::Vec;

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

use crate::Bytes;

/// Wrapper around `Vec<u8>` to serialize and deserialize efficiently.
///
/// ```
/// use std::collections::HashMap;
/// use std::io;
///
/// use serde_bytes::ByteBuf;
///
/// fn deserialize_bytebufs() -> bincode::Result<()> {
///     let example_data = [
///         2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 116,
///         119, 111, 1, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 111, 110, 101];
///
///     let map: HashMap<u32, ByteBuf> = bincode::deserialize(&example_data[..])?;
///
///     println!("{:?}", map);
///
///     Ok(())
/// }
/// #
/// # fn main() {
/// #     deserialize_bytebufs().unwrap();
/// # }
/// ```
#[derive(Clone, Default, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub struct ByteBuf {
    bytes: Vec<u8>,
}

impl ByteBuf {
    /// Construct a new, empty `ByteBuf`.
    pub fn new() -> Self {
        ByteBuf::from(Vec::new())
    }

    /// Construct a new, empty `ByteBuf` with the specified capacity.
    pub fn with_capacity(cap: usize) -> Self {
        ByteBuf::from(Vec::with_capacity(cap))
    }

    /// Wrap existing bytes in a `ByteBuf`.
    pub fn from<T: Into<Vec<u8>>>(bytes: T) -> Self {
        ByteBuf {
            bytes: bytes.into(),
        }
    }
}

impl Debug for ByteBuf {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Debug::fmt(&self.bytes, f)
    }
}

impl From<ByteBuf> for Vec<u8> {
    fn from(wrapper: ByteBuf) -> Vec<u8> {
        wrapper.bytes
    }
}

impl From<Vec<u8>> for ByteBuf {
    fn from(bytes: Vec<u8>) -> Self {
        ByteBuf::from(bytes)
    }
}

impl AsRef<Vec<u8>> for ByteBuf {
    fn as_ref(&self) -> &Vec<u8> {
        &self.bytes
    }
}

impl AsRef<[u8]> for ByteBuf {
    fn as_ref(&self) -> &[u8] {
        &self.bytes
    }
}

impl AsMut<Vec<u8>> for ByteBuf {
    fn as_mut(&mut self) -> &mut Vec<u8> {
        &mut self.bytes
    }
}

impl AsMut<[u8]> for ByteBuf {
    fn as_mut(&mut self) -> &mut [u8] {
        &mut self.bytes
    }
}

impl Deref for ByteBuf {
    type Target = Vec<u8>;

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

impl DerefMut for ByteBuf {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.bytes
    }
}

impl Borrow<Bytes> for ByteBuf {
    fn borrow(&self) -> &Bytes {
        Bytes::new(&self.bytes)
    }
}

impl BorrowMut<Bytes> for ByteBuf {
    fn borrow_mut(&mut self) -> &mut Bytes {
        unsafe { &mut *(&mut self.bytes as &mut [u8] as *mut [u8] as *mut Bytes) }
    }
}

impl Serialize for ByteBuf {
    #[inline]
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        serializer.serialize_bytes(&self.bytes)
    }
}

struct ByteBufVisitor;

impl<'de> Visitor<'de> for ByteBufVisitor {
    type Value = ByteBuf;

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

    #[inline]
    fn visit_seq<V>(self, mut visitor: V) -> Result<ByteBuf, V::Error>
    where
        V: SeqAccess<'de>,
    {
        let len = cmp::min(visitor.size_hint().unwrap_or(0), 4096);
        let mut values = Vec::with_capacity(len);

        while let Some(value) = visitor.next_element()? {
            values.push(value);
        }

        Ok(ByteBuf::from(values))
    }

    #[inline]
    fn visit_bytes<E>(self, v: &[u8]) -> Result<ByteBuf, E>
    where
        E: Error,
    {
        Ok(ByteBuf::from(v))
    }

    #[inline]
    fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<ByteBuf, E>
    where
        E: Error,
    {
        Ok(ByteBuf::from(v))
    }

    #[inline]
    fn visit_str<E>(self, v: &str) -> Result<ByteBuf, E>
    where
        E: Error,
    {
        Ok(ByteBuf::from(v))
    }

    #[inline]
    fn visit_string<E>(self, v: String) -> Result<ByteBuf, E>
    where
        E: Error,
    {
        Ok(ByteBuf::from(v))
    }
}

impl<'de> Deserialize<'de> for ByteBuf {
    #[inline]
    fn deserialize<D>(deserializer: D) -> Result<ByteBuf, D::Error>
    where
        D: Deserializer<'de>,
    {
        deserializer.deserialize_byte_buf(ByteBufVisitor)
    }
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate env_logger;

use std::io;
use std::io::prelude::*;
use std::process;

use super::client::Client;

pub fn main(_args: &clap::ArgMatches) {
    env_logger::init().unwrap();

    let client = Client::new("couchbase://localhost/default");

    let process_command = |cmd: &str| {
        match cmd {
            "exit" | "quit" => {
                process::exit(0);
            },
            "get" => {
            },
            "info" => {
                println!("{:?}", client);
            },
            "" => {
            },
            _ => {
                println!("Unknown command \"{}\"", cmd);
            }
        }
    };

    let process_line = || {
        print!("gauc> ");
        let _ = io::stdout().flush();
        let mut input = String::new();
        match io::stdin().read_line(&mut input) {
            Ok(_) => {
                process_command(&input.trim());
            }
            _ => {}
        }
        return true;
    };

    while process_line() {}
}
<commit_msg>Simple CLI<commit_after>extern crate clap;
extern crate env_logger;

use std::io;
use std::io::prelude::*;
use std::process;

use super::client::Client;

pub fn main(_args: &clap::ArgMatches) {
    env_logger::init().unwrap();

    let mut client = Client::new("couchbase://localhost/default");

    let mut process_command = |cmd: &str| {
        let parts: Vec<&str> = cmd.split(' ').collect();
        match parts[0] {
            "exit" | "quit" => {
                process::exit(0);
            },
            "get" => {
                match parts.len() {
                    2 => {
                        client.get(parts[1], |res| {
                            println!("{}", res.value());
                        });
                    },
                    _ => println!("Wrong number of arguments, expect exactly one argument.")
                }
            },
            "info" => {
                println!("{:?}", client);
            },
            "store" => {
                match parts.len() {
                    1 | 2 => println!("Wrong number of arguments, expected key and value"),
                    _ => {
                        client.store(parts[1], &format!("{}", parts[2..].join(" "))[..], |res| {
                            println!("{:?}", res);
                        });
                    }
                }
            },
            "" => {
            },
            _ => {
                println!("Unknown command \"{}\"", cmd);
            }
        }
    };

    let mut process_line = || {
        print!("gauc> ");
        let _ = io::stdout().flush();
        let mut input = String::new();
        match io::stdin().read_line(&mut input) {
            Ok(_) => {
                process_command(&input.trim());
            }
            _ => {}
        }
        return true;
    };

    while process_line() {}
}
<|endoftext|>


<commit_before>extern crate time;
extern crate serde;
extern crate serde_json;

use std::{self, env};
use std::error::Error;
use std::time::Duration;
use std::path::{Path, PathBuf};
use std::io::{self, Write};
use std::process::exit;
use std::net::UdpSocket;

include!(concat!(env!("OUT_DIR"), "/serde_types.rs"));

pub fn stderr_write(message :String) -> io::Result<()> {
    let stderr = std::io::stderr();
    let mut handle = stderr.lock();

    try!(handle.write(message.as_bytes()));
    try!(handle.write(b"\n"));
    Ok(())
}

pub fn update_telemetry<T>(value: &T) -> Result<(), io::Error>
    where T: serde::Serialize,
{
    let serialized = serde_json::to_string(value).unwrap();
    let payload = serialized.as_bytes();
    let socket = try!(UdpSocket::bind("127.0.0.1:0"));
    try!(socket.send_to(&payload, "127.0.0.1:48656"));
    Ok(())
}

pub fn abort(exit_code :i32, message :String) -> ! {
    update_telemetry(&Event {
        event_name: "hull_fatal_error".to_string(),
        event_data: CurrentTime {
            created_at: time::get_time().sec
        }
    }).ok();
    match stderr_write(message) {
        Ok(_) => exit(exit_code),
        Err(e) => unexpected_io_error(e),
    };
}

pub fn unexpected_io_error(err :std::io::Error) -> ! {
    println!("failure: {}", err.description().to_string());
    match err.raw_os_error() {
        Some(code) => exit(code),
        None => exit(1),
    }
}

pub fn get_hull_home() -> PathBuf {
    let mut path = None;

    match env::var("HULL_HOME") {
        Ok(res) => {
            path = Some(PathBuf::from(res));
        },
        Err(_) => {
            if cfg!(target_os = "mac_os") {
                // the expectation of how current_exe works is only valid for OS X
                match env::current_exe() {
                    Ok(res) => {
                        match res.parent() {
                            Some(r) => {
                                path = Some(r.to_path_buf());
                            },
                            None => (),
                        };
                    },
                    Err(_) => (),
                };
            }
        }
    };

    return path.unwrap_or(PathBuf::from("/etc/hull"));
}

/// Returns a shell PATH environment string minus a given directory
pub fn remove_dir_from_path(dir :String, path_str :String) -> String {
    let mut child_paths = Vec::new();
    for path in path_str.split(":") {
        if path != dir {
            child_paths.push(path);
        }
    }

    return child_paths.join(":");
}

/// Returns whether a command and hull's binary paths are the same
///
/// `binary_path` cannot have `.` or `..`. it doesn't need to be strictly absolute,
/// as it will follow the rules for `std::fs::canonicalize`, which will pre-pend the current
/// working directory if need be.
///
/// # Panics
///
/// Will panic if either `binary_path` or the command path is relative and do not resolve
pub fn paths_equivalent(binary_path :PathBuf, cur_cmd :String, cur_path :&Path) -> Result<bool, io::Error> {
    let command_path;

    if cur_cmd.contains("/") {
        let mut cur_path_buf = cur_path.to_path_buf();
        cur_path_buf.push(cur_cmd);
        command_path = try!(cur_path_buf.canonicalize());
    } else {
        command_path = PathBuf::from(cur_cmd);
    }

    debug!("comparing command_path:'{}' binary_path:'{}'",
            command_path.display(),
            binary_path.display()
    );

    // still need to canonicalize even if absolute
    // e.g. /tmp/ when canonicalize may become /private/tmp/ on some OS's
    let binary_path = binary_path.canonicalize().unwrap();

    return Ok(command_path == binary_path);
}

pub fn duration_in_millis(duration :Duration) -> f64 {
    return ((duration.as_secs() as f64) * 1_000.0) +
        ((duration.subsec_nanos() as f64) / 1_000_000.0);
}

#[cfg(test)]
mod tests {
    use std::env;
    use std::fs::{self, File};
    use std::path::PathBuf;
    use super::*;
    extern crate tempdir;
    use self::tempdir::TempDir;

    macro_rules! t {
        ($e:expr) => (match $e { Ok(n) => n, Err(e) => panic!("error: {}", e) })
    }

    fn in_tmpdir<F>(f: F) where F: FnOnce(&TempDir) {
        let tmpdir = t!(TempDir::new("test"));
        assert!(env::set_current_dir(tmpdir.path()).is_ok());

        f(&tmpdir);
        t!(tmpdir.close());
    }

    fn ensure_files_created(root :PathBuf, paths :&[PathBuf]) {
        for path in paths.into_iter() {
            let filename = &root.join(path);
            if path.to_string_lossy().contains("/") {
                let parent_dir = filename.parent().unwrap();
                // could check if directory exists before creating, but `.exists()` does not resolve
                // relative paths
                match fs::create_dir_all(parent_dir) {
                    Ok(_) => {},
                    Err(_) => {
                        // might get an error in case directory exists. ignore
                    },
                };
            }

            if !filename.exists() {
                debug!("creating: {}", filename.display());
                t!(File::create(filename));
            }
        }
    }

    #[test]
    fn remove_dir_from_path_valid_paths() {
        let inputs = [
            ["/home/user/.bin", "/home/user/.bin:/bin", "/bin"],
            ["/home/user/.bin", "/bin", "/bin"],
            ["/home/user/.bin", "/home/user/.bin:/bin:/home/user/.bin", "/bin"],
            ["/home/user/.bin", "", ""],
            ["", "/bin", "/bin"],
        ];

        for input in inputs.into_iter() {
            let dir = String::from(input[0]);
            let path_str = String::from(input[1]);
            let expected = input[2];

            assert_eq!(remove_dir_from_path(dir, path_str), expected);
        }
    }

    #[test]
    fn paths_equivalent_inputs() {
        let inputs = [
            ["prog", "./prog", "", "t"],
            ["foo/prog", "./foo/prog", "", "t"],
            ["foo/bar/prog", "./prog", "foo/bar", "t"],
            ["foo/prog", "../prog", "foo/bar", "t"],
        ];

        for input in inputs.into_iter() {

            in_tmpdir(|tmp_dir| {
                let binary_path = tmp_dir.path().join(input[0]);
                let cur_cmd = String::from(input[1]);
                let cur_path = tmp_dir.path().join(input[2]);
                let expected = input[3];

                let cmd_path = cur_path.join(cur_cmd.clone());

                ensure_files_created(
                    tmp_dir.path().to_path_buf(),
                    [
                        binary_path.clone(),
                        cmd_path,
                    ].as_ref()
                );

                let expectation = match expected {
                    "t" => true,
                    _ => false,
                };

                let observed = paths_equivalent(binary_path, cur_cmd, cur_path.as_path()).unwrap();
                assert_eq!(observed, expectation)
            });
        }
    }
}
<commit_msg>remove reliance on env:current_exe due to platform differences<commit_after>extern crate time;
extern crate serde;
extern crate serde_json;

use std::{self, env};
use std::error::Error;
use std::time::Duration;
use std::path::{Path, PathBuf};
use std::io::{self, Write};
use std::process::exit;
use std::net::UdpSocket;

include!(concat!(env!("OUT_DIR"), "/serde_types.rs"));

pub fn stderr_write(message :String) -> io::Result<()> {
    let stderr = std::io::stderr();
    let mut handle = stderr.lock();

    try!(handle.write(message.as_bytes()));
    try!(handle.write(b"\n"));
    Ok(())
}

pub fn update_telemetry<T>(value: &T) -> Result<(), io::Error>
    where T: serde::Serialize,
{
    let serialized = serde_json::to_string(value).unwrap();
    let payload = serialized.as_bytes();
    let socket = try!(UdpSocket::bind("127.0.0.1:0"));
    try!(socket.send_to(&payload, "127.0.0.1:48656"));
    Ok(())
}

pub fn abort(exit_code :i32, message :String) -> ! {
    update_telemetry(&Event {
        event_name: "hull_fatal_error".to_string(),
        event_data: CurrentTime {
            created_at: time::get_time().sec
        }
    }).ok();
    match stderr_write(message) {
        Ok(_) => exit(exit_code),
        Err(e) => unexpected_io_error(e),
    };
}

pub fn unexpected_io_error(err :std::io::Error) -> ! {
    println!("failure: {}", err.description().to_string());
    match err.raw_os_error() {
        Some(code) => exit(code),
        None => exit(1),
    }
}

pub fn get_hull_home() -> PathBuf {
    let mut path = None;

    match env::var("HULL_HOME") {
        Ok(res) => {
            path = Some(PathBuf::from(res));
        },
        Err(_) => (),
    };

    return path.unwrap_or(PathBuf::from("/etc/hull"));
}

/// Returns a shell PATH environment string minus a given directory
pub fn remove_dir_from_path(dir :String, path_str :String) -> String {
    let mut child_paths = Vec::new();
    for path in path_str.split(":") {
        if path != dir {
            child_paths.push(path);
        }
    }

    return child_paths.join(":");
}

/// Returns whether a command and hull's binary paths are the same
///
/// `binary_path` cannot have `.` or `..`. it doesn't need to be strictly absolute,
/// as it will follow the rules for `std::fs::canonicalize`, which will pre-pend the current
/// working directory if need be.
///
/// # Panics
///
/// Will panic if either `binary_path` or the command path is relative and do not resolve
pub fn paths_equivalent(binary_path :PathBuf, cur_cmd :String, cur_path :&Path) -> Result<bool, io::Error> {
    let command_path;

    if cur_cmd.contains("/") {
        let mut cur_path_buf = cur_path.to_path_buf();
        cur_path_buf.push(cur_cmd);
        command_path = try!(cur_path_buf.canonicalize());
    } else {
        command_path = PathBuf::from(cur_cmd);
    }

    debug!("comparing command_path:'{}' binary_path:'{}'",
            command_path.display(),
            binary_path.display()
    );

    // still need to canonicalize even if absolute
    // e.g. /tmp/ when canonicalize may become /private/tmp/ on some OS's
    let binary_path = binary_path.canonicalize().unwrap();

    return Ok(command_path == binary_path);
}

pub fn duration_in_millis(duration :Duration) -> f64 {
    return ((duration.as_secs() as f64) * 1_000.0) +
        ((duration.subsec_nanos() as f64) / 1_000_000.0);
}

#[cfg(test)]
mod tests {
    use std::env;
    use std::fs::{self, File};
    use std::path::PathBuf;
    use super::*;
    extern crate tempdir;
    use self::tempdir::TempDir;

    macro_rules! t {
        ($e:expr) => (match $e { Ok(n) => n, Err(e) => panic!("error: {}", e) })
    }

    fn in_tmpdir<F>(f: F) where F: FnOnce(&TempDir) {
        let tmpdir = t!(TempDir::new("test"));
        assert!(env::set_current_dir(tmpdir.path()).is_ok());

        f(&tmpdir);
        t!(tmpdir.close());
    }

    fn ensure_files_created(root :PathBuf, paths :&[PathBuf]) {
        for path in paths.into_iter() {
            let filename = &root.join(path);
            if path.to_string_lossy().contains("/") {
                let parent_dir = filename.parent().unwrap();
                // could check if directory exists before creating, but `.exists()` does not resolve
                // relative paths
                match fs::create_dir_all(parent_dir) {
                    Ok(_) => {},
                    Err(_) => {
                        // might get an error in case directory exists. ignore
                    },
                };
            }

            if !filename.exists() {
                debug!("creating: {}", filename.display());
                t!(File::create(filename));
            }
        }
    }

    #[test]
    fn remove_dir_from_path_valid_paths() {
        let inputs = [
            ["/home/user/.bin", "/home/user/.bin:/bin", "/bin"],
            ["/home/user/.bin", "/bin", "/bin"],
            ["/home/user/.bin", "/home/user/.bin:/bin:/home/user/.bin", "/bin"],
            ["/home/user/.bin", "", ""],
            ["", "/bin", "/bin"],
        ];

        for input in inputs.into_iter() {
            let dir = String::from(input[0]);
            let path_str = String::from(input[1]);
            let expected = input[2];

            assert_eq!(remove_dir_from_path(dir, path_str), expected);
        }
    }

    #[test]
    fn paths_equivalent_inputs() {
        let inputs = [
            ["prog", "./prog", "", "t"],
            ["foo/prog", "./foo/prog", "", "t"],
            ["foo/bar/prog", "./prog", "foo/bar", "t"],
            ["foo/prog", "../prog", "foo/bar", "t"],
        ];

        for input in inputs.into_iter() {

            in_tmpdir(|tmp_dir| {
                let binary_path = tmp_dir.path().join(input[0]);
                let cur_cmd = String::from(input[1]);
                let cur_path = tmp_dir.path().join(input[2]);
                let expected = input[3];

                let cmd_path = cur_path.join(cur_cmd.clone());

                ensure_files_created(
                    tmp_dir.path().to_path_buf(),
                    [
                        binary_path.clone(),
                        cmd_path,
                    ].as_ref()
                );

                let expectation = match expected {
                    "t" => true,
                    _ => false,
                };

                let observed = paths_equivalent(binary_path, cur_cmd, cur_path.as_path()).unwrap();
                assert_eq!(observed, expectation)
            });
        }
    }
}
<|endoftext|>


<commit_before>use ctxt::Context;
use driver::cmd::Args;
use gc::Collector;

pub struct Swiper {
    no_regions: usize,
    region_size_bits: usize,
    region_size: usize,
    regions: Vec<RegionStatus>,
}

impl Swiper {
    pub fn new(args: &Args) -> Swiper {
        let heap_size = args.flag_heap_size
            .map(|s| *s)
            .unwrap_or(32 * 1024 * 1024);
        let no_regions = heap_size / (1024 * 1024);

        Swiper {
            no_regions: no_regions,
            region_size_bits: 20,
            region_size: 1024 * 1024,
            regions: vec![RegionStatus::Free; no_regions]
        }
    }
}

impl Collector for Swiper {
    fn alloc(&self, ctxt: &Context, size: usize) -> *const u8 {
        unimplemented!()
    }

    fn collect(&self, ctxt: &Context) {
        unimplemented!();
    }
}

#[derive(Copy, Clone)]
enum RegionStatus {
    Young,
    Old,
    Huge,
    Free,
}<commit_msg>set minimal number of regions<commit_after>use std::cmp;

use ctxt::Context;
use driver::cmd::Args;
use gc::Collector;

pub struct Swiper {
    no_regions: usize,
    region_size_bits: usize,
    region_size: usize,
    regions: Vec<RegionStatus>,
}

impl Swiper {
    pub fn new(args: &Args) -> Swiper {
        let heap_size = args.flag_heap_size
            .map(|s| *s)
            .unwrap_or(32 * 1024 * 1024);
        let no_regions = cmp::min(heap_size / (1024 * 1024), 4);

        Swiper {
            no_regions: no_regions,
            region_size_bits: 20,
            region_size: 1024 * 1024,
            regions: vec![RegionStatus::Free; no_regions]
        }
    }
}

impl Collector for Swiper {
    fn alloc(&self, ctxt: &Context, size: usize) -> *const u8 {
        unimplemented!()
    }

    fn collect(&self, ctxt: &Context) {
        unimplemented!();
    }
}

#[derive(Copy, Clone)]
enum RegionStatus {
    Young,
    Old,
    Huge,
    Free,
}<|endoftext|>


<commit_before>extern crate cc;

fn main() {
    cc::Build::new()
        .cpp(true)
        .file("src/wrapper.cpp")
        .file("src/vendor/SPIRV-Cross/spirv_cfg.cpp")
        .file("src/vendor/SPIRV-Cross/spirv_cross.cpp")
        .file("src/vendor/SPIRV-Cross/spirv_glsl.cpp")
        .file("src/vendor/SPIRV-Cross/spirv_hlsl.cpp")
        .file("src/vendor/SPIRV-Cross/spirv_msl.cpp")
        .flag_if_supported("-std=c++14")
        .compile("spirv-cross-rust-wrapper");
}
<commit_msg>Set stdlib/c++ in build<commit_after>extern crate cc;

fn main() {
    cc::Build::new()
        .cpp(true)
        .cpp_set_stdlib("c++")
        .file("src/wrapper.cpp")
        .file("src/vendor/SPIRV-Cross/spirv_cfg.cpp")
        .file("src/vendor/SPIRV-Cross/spirv_cross.cpp")
        .file("src/vendor/SPIRV-Cross/spirv_glsl.cpp")
        .file("src/vendor/SPIRV-Cross/spirv_hlsl.cpp")
        .file("src/vendor/SPIRV-Cross/spirv_msl.cpp")
        .flag_if_supported("-std=c++14")
        .compile("spirv-cross-rust-wrapper");
}
<|endoftext|>