<commit_before>#![feature(os)]

extern crate civet;
extern crate conduit;
extern crate "conduit-static" as conduit_static;

use std::os;
use std::sync::mpsc::channel;

use civet::{Config, Server};
use conduit_static::Static;

fn main() {
    let handler = Static::new(os::getcwd().unwrap());
    let _a = Server::start(Config { port: 8888, threads: 50 }, handler);
    let (_tx, rx) = channel::<()>();
    rx.recv().unwrap();
}
<commit_msg>Update to rust master<commit_after>#![feature(env)]

extern crate civet;
extern crate conduit;
extern crate "conduit-static" as conduit_static;

use std::env;
use std::sync::mpsc::channel;

use civet::{Config, Server};
use conduit_static::Static;

fn main() {
    let handler = Static::new(env::current_dir().unwrap());
    let _a = Server::start(Config { port: 8888, threads: 50 }, handler);
    let (_tx, rx) = channel::<()>();
    rx.recv().unwrap();
}
<|endoftext|>


<commit_before>// Copyright 2017 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! An implementation of `MemoryDB` database.
use std::clone::Clone;
use std::collections::btree_map::{BTreeMap, Range};
use std::iter::Peekable;

use super::{Database, Snapshot, Patch, Change, Iterator, Iter, Result};

/// Database implementation that stores all the data in memory.
///
/// It's mainly used for testing and not designed to be efficient.
#[derive(Default, Clone, Debug)]
pub struct MemoryDB {
    map: BTreeMap<Vec<u8>, Vec<u8>>,
}

/// An iterator over the entries of a `MemoryDB`.
struct MemoryDBIter<'a> {
    iter: Peekable<Range<'a, Vec<u8>, Vec<u8>>>,
}

impl MemoryDB {
    /// Creates a new, empty database.
    pub fn new() -> MemoryDB {
        MemoryDB { map: BTreeMap::new() }
    }
}

impl Database for MemoryDB {
    fn clone(&self) -> Box<Database> {
        Box::new(Clone::clone(self))
    }

    fn snapshot(&self) -> Box<Snapshot> {
        Box::new(Clone::clone(self))
    }

    fn merge(&mut self, patch: Patch) -> Result<()> {
        for (key, change) in patch {
            match change {
                Change::Put(value) => {
                    self.map.insert(key, value);
                }
                Change::Delete => {
                    self.map.remove(&key);
                }
            }
        }
        Ok(())
    }
}

impl Snapshot for MemoryDB {
    fn get(&self, key: &[u8]) -> Option<Vec<u8>> {
        self.map.get(key).cloned()
    }

    fn contains(&self, key: &[u8]) -> bool {
        self.map.contains_key(key)
    }

    fn iter<'a>(&'a self, from: &[u8]) -> Iter<'a> {
        use std::collections::Bound::*;
        let range = (Included(from), Unbounded);
        Box::new(MemoryDBIter {
            iter: self.map.range::<[u8], _>(range).peekable(),
        })
    }
}

impl<'a> Iterator for MemoryDBIter<'a> {
    fn next(&mut self) -> Option<(&[u8], &[u8])> {
        self.iter.next().map(|(k, v)| (k.as_slice(), v.as_slice()))
    }

    fn peek(&mut self) -> Option<(&[u8], &[u8])> {
        self.iter.peek().map(|&(k, v)| (k.as_slice(), v.as_slice()))
    }
}
<commit_msg>Share blockchain state using MemoryDB<commit_after>// Copyright 2017 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! An implementation of `MemoryDB` database.
use std::sync::{Arc, RwLock, RwLockReadGuard};
use std::clone::Clone;
use std::collections::btree_map::{BTreeMap, Range};
use std::iter::Peekable;

use super::{Database, Snapshot, Patch, Change, Iterator, Iter, Result};

/// Database implementation that stores all the data in memory.
///
/// It's mainly used for testing and not designed to be efficient.
#[derive(Default, Clone, Debug)]
pub struct MemoryDB {
    map: Arc<RwLock<BTreeMap<Vec<u8>, Vec<u8>>>>,
}

/// An iterator over the entries of a `MemoryDB`.
struct MemoryDBIter<'a> {
    iter: Peekable<Range<'a, Vec<u8>, Vec<u8>>>,
    _guard: RwLockReadGuard<'a, BTreeMap<Vec<u8>, Vec<u8>>>
}

impl MemoryDB {
    /// Creates a new, empty database.
    pub fn new() -> MemoryDB {
        MemoryDB { map: Arc::new(RwLock::new(BTreeMap::new())) }
    }
}

impl Database for MemoryDB {
    fn clone(&self) -> Box<Database> {
        Box::new(Clone::clone(self))
    }

    fn snapshot(&self) -> Box<Snapshot> {
        Box::new(Clone::clone(self))
    }

    fn merge(&mut self, patch: Patch) -> Result<()> {
        for (key, change) in patch {
            match change {
                Change::Put(value) => {
                    self.map.write().unwrap().insert(key, value);
                }
                Change::Delete => {
                    self.map.write().unwrap().remove(&key);
                }
            }
        }
        Ok(())
    }
}

impl Snapshot for MemoryDB {
    fn get(&self, key: &[u8]) -> Option<Vec<u8>> {
        self.map.read().unwrap().get(key).cloned()
    }

    fn contains(&self, key: &[u8]) -> bool {
        self.map.read().unwrap().contains_key(key)
    }

    fn iter<'a>(&'a self, from: &[u8]) -> Iter<'a> {
        use std::collections::Bound::{Included, Unbounded};
        use std::mem::transmute;
        let range = (Included(from), Unbounded);
        let guard = self.map.read().unwrap();

        Box::new(MemoryDBIter {
            iter: unsafe { transmute(guard.range::<[u8], _>(range).peekable()) },
            _guard: guard
        })
    }
}

impl<'a> Iterator for MemoryDBIter<'a> {
    fn next(&mut self) -> Option<(&[u8], &[u8])> {
        self.iter.next().map(|(k, v)| (k.as_slice(), v.as_slice()))
    }

    fn peek(&mut self) -> Option<(&[u8], &[u8])> {
        self.iter.peek().map(|&(k, v)| (k.as_slice(), v.as_slice()))
    }
}
<|endoftext|>


<commit_before>fn main() {
    println!("Hello, world!");
}
<commit_msg>Added initial working code for lexer<commit_after>use std::fs::File;
use std::io::Read;
use std::env;

#[derive(Debug,Clone)]
enum Lexeme{
    Let, Function, If, Else, ElseIf, Do, While, For, In, Loop, StringType, BooleanType, DecimalType, Read, Write, Print, Return, Continue, Break, True, False, Arrow, GreaterEqual, LesserEqual, IsEqual, Greater, Lesser, Plus, Minus, Divide, Multiply, Equal, OpenCurly, CloseCurly, OpenParenthesis, CloseParenthesis, OpenSquare, CloseSquare, Colon, Semicolon, Range,  NewLine, DecimalValue(String), StringValue(String),  Variable(String)
}

#[allow(dead_code)]
struct RiverLexer<'a>{
    index: usize,
    src: String,

    whitespace: String,
    terminals: Vec<&'a str>,
    terminal_values: Vec<Lexeme>
}

#[allow(dead_code)]
impl<'a> RiverLexer<'a>{
    fn new(src: String) -> RiverLexer<'a>{
        RiverLexer{
            index:0, src: src,

            whitespace: String::from(" \t"),
            terminals: vec!["let", "fn", "if", "else", "elseif", "do", "while", "for", "in", "loop", "String", "Boolean", "Decimal", "read", "write", "print", "return", "continue", "break", "true", "false", "->",  ">=", "<=", "==", ">", "<", "+", "-", "/", "*", "=", "{", "}", "(", ")", "[", "]", ":", ";", "..", "\n"],
            terminal_values: vec![Lexeme::Let, Lexeme::Function, Lexeme::If, Lexeme::Else, Lexeme::ElseIf, Lexeme::Do, Lexeme::While, Lexeme::For, Lexeme::In, Lexeme::Loop, Lexeme::StringType, Lexeme::BooleanType, Lexeme::DecimalType, Lexeme::Read, Lexeme::Write, Lexeme::Print, Lexeme::Return, Lexeme::Continue, Lexeme::Break, Lexeme::True, Lexeme::False, Lexeme::Arrow, Lexeme::GreaterEqual, Lexeme::LesserEqual, Lexeme::IsEqual, Lexeme::Greater, Lexeme::Lesser, Lexeme::Plus, Lexeme::Minus, Lexeme::Divide, Lexeme::Multiply, Lexeme::Equal, Lexeme::OpenCurly, Lexeme::CloseCurly, Lexeme::OpenParenthesis, Lexeme::CloseParenthesis, Lexeme::OpenSquare, Lexeme::CloseSquare, Lexeme::Colon, Lexeme::Semicolon, Lexeme::Range, Lexeme::NewLine]
        }
    }

    fn get_char(&self) -> char{
        self.src.chars().nth(self.index).unwrap()
    }

    fn look_ahead(&self, length: usize) -> &str{
        &self.src[self.index..self.index+length]
    }

    fn whitespace(&mut self){
        while self.whitespace.contains(self.get_char()) {
            self.index+=1;
        }
    }

    fn var_sub(&mut self, var_name: &mut String){
        while self.get_char().is_alphanumeric() {
            var_name.push(self.get_char());
            self.index+=1;
        }
    }

    fn var(&mut self) -> Lexeme{
        let mut var_name = String::new();

        if self.get_char().is_alphabetic() {
            var_name.push(self.get_char());
            self.index+=1;
            self.var_sub(&mut var_name);
        }
        Lexeme::Variable(var_name)
    }

    fn num_sub(&mut self, number: &mut String){
        while self.get_char().is_numeric() {
            number.push(self.get_char());
            self.index+=1;
        }
    }

    fn num(&mut self) -> Lexeme{
        let mut number = String::new();

        self.num_sub(&mut number);

        Lexeme::DecimalValue(number)
    }

    fn string(&mut self) -> Lexeme{
        let mut string = String::new();
        let mut prev_char = ' ';
        self.index+=1;
        while self.get_char() != '\"' || prev_char=='\\' {
            string.push(self.get_char());
            prev_char = self.get_char();
            self.index+=1;
        }
        self.index+=1;
        Lexeme::StringValue(string)
    }

    fn analyze(&mut self) -> Vec<Lexeme>{
        let mut lexemes = Vec::<Lexeme>::new();

        while self.index<self.src.len()-1 {
            let mut basic_lexeme = false;

            self.whitespace();
            for i in 0..self.terminals.len(){
                if self.terminals[i].len()+self.index < self.src.len() && self.look_ahead(self.terminals[i].len()) == self.terminals[i] {
                    lexemes.push(self.terminal_values[i].clone());
                    self.index+=self.terminals[i].len();
                    basic_lexeme= true;
                    break;
                }
            }
            if !basic_lexeme {
                if self.get_char().is_numeric() {
                    lexemes.push(self.num());
                } else if self.get_char() == '\"' {
                    lexemes.push(self.string());
                } else if self.get_char().is_alphabetic() {
                    lexemes.push(self.var());
                }else {
                    println!("Syntax error.");
                    println!("{}/{}",self.index, self.src.len());
                }
            }
        }
        lexemes
    }
}

fn main(){
    let args: Vec<String> = env::args().collect();
    if args.len()!=2 {
        println!("Usage: {} <source code.rvr>\n", args[0]);
        return;
    }
    let mut srcfile = File::open(&args[1]).unwrap();
    let mut contents: Vec<u8> = Vec::new();

    // Read file into byte vector
    srcfile.read_to_end(&mut contents).unwrap();

    // Turn byte vector into string
    let src = String::from_utf8(contents).unwrap();

    println!("Source code:\n{}", src);

    let mut rl = RiverLexer::new(src);
    let lxs = rl.analyze();

    println!("Lexemes:");
    for i in lxs {
        println!("{:?}", i);
    }
}
<|endoftext|>


<commit_before>// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

use std::num::ParseIntError;

/// Trait for parsing integers.
///
/// Strings beginning with the common and classic prefixes `0x`, `0o`, `0b` or `0` are parsed
/// as hex, octal, binary, and octal (classic).  Anything else is parsed as decimal.
/// A leading `+` or `-` is permitted.  Any string parsed by `strtol(3)` or `strtoul(3)`
/// will be parsed successfully.
pub trait ParseInt: Sized {
    fn from_str_radix(src: &str, radix: u32) -> Result<Self, ParseIntError>;

    fn from_str(src: &str) -> Result<Self, ParseIntError> {
        let (val, negative) = if let Some(v) = src.strip_prefix('-') {
            (v, true)
        } else if let Some(v) = src.strip_prefix('+') {
            (v, false)
        } else {
            (src, false)
        };

        let (radix, digits) = match val.get(0..2) {
            Some("0x") | Some("0X") => (16, &val[2..]),
            Some("0o") | Some("0O") => (8, &val[2..]),
            Some("0b") | Some("0B") => (2, &val[2..]),
            _ if val.starts_with('0') => (8, val),
            _ => (10, val),
        };

        if negative {
            let mut digits = digits.to_string();
            digits.insert(0, '-');
            Self::from_str_radix(&digits, radix)
        } else {
            Self::from_str_radix(digits, radix)
        }
    }
}

macro_rules! impl_parse_int {
    ($ty:ident) => {
        impl ParseInt for $ty {
            fn from_str_radix(src: &str, radix: u32) -> Result<Self, ParseIntError> {
                $ty::from_str_radix(src, radix)
            }
        }
    };
}

impl_parse_int!(i8);
impl_parse_int!(u8);
impl_parse_int!(i16);
impl_parse_int!(u16);
impl_parse_int!(i32);
impl_parse_int!(u32);
impl_parse_int!(i64);
impl_parse_int!(u64);
impl_parse_int!(isize);
impl_parse_int!(usize);

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

    #[test]
    fn test_i8() {
        assert_eq!(i8::from_str("0"), Ok(0));
        assert_eq!(i8::from_str("-1"), Ok(-1));
        assert_eq!(i8::from_str("+100"), Ok(100));
        assert_eq!(i8::from_str("-128"), Ok(-128));
        assert_eq!(i8::from_str("0x10"), Ok(16));
        assert_eq!(i8::from_str("-0x10"), Ok(-16));
        assert_eq!(i8::from_str("0o10"), Ok(8));
        assert_eq!(i8::from_str("-0o10"), Ok(-8));
        assert_eq!(i8::from_str("0b10"), Ok(2));
        assert_eq!(i8::from_str("-0b10"), Ok(-2));
        assert_eq!(i8::from_str("012"), Ok(10));
        assert!(i8::from_str("128").is_err());
        assert!(i8::from_str("-129").is_err());
    }

    #[test]
    fn test_u8() {
        assert_eq!(u8::from_str("0"), Ok(0));
        assert_eq!(u8::from_str("+100"), Ok(100));
        assert_eq!(u8::from_str("128"), Ok(128));
        assert_eq!(u8::from_str("255"), Ok(255));
        assert_eq!(u8::from_str("0x10"), Ok(16));
        assert_eq!(u8::from_str("0xFF"), Ok(255));
        assert_eq!(u8::from_str("0o10"), Ok(8));
        assert_eq!(u8::from_str("0b10000000"), Ok(128));
        assert_eq!(u8::from_str("012"), Ok(10));
        assert!(u8::from_str("-1").is_err());
        assert!(u8::from_str("256").is_err());
    }

    #[test]
    fn test_i16() {
        assert_eq!(i16::from_str("0"), Ok(0));
        assert_eq!(i16::from_str("-1"), Ok(-1));
        assert_eq!(i16::from_str("+32767"), Ok(32767));
        assert_eq!(i16::from_str("-32768"), Ok(-32768));
        assert_eq!(i16::from_str("0x3fff"), Ok(16383));
        assert_eq!(i16::from_str("-0x10"), Ok(-16));
        assert_eq!(i16::from_str("0o10"), Ok(8));
        assert_eq!(i16::from_str("-0o10"), Ok(-8));
        assert_eq!(i16::from_str("0b10"), Ok(2));
        assert_eq!(i16::from_str("-0b10"), Ok(-2));
        assert_eq!(i16::from_str("012"), Ok(10));
        assert!(i16::from_str("32768").is_err());
        assert!(i16::from_str("-32769").is_err());
    }

    #[test]
    fn test_u16() {
        assert_eq!(u16::from_str("0"), Ok(0));
        assert_eq!(u16::from_str("+100"), Ok(100));
        assert_eq!(u16::from_str("32768"), Ok(32768));
        assert_eq!(u16::from_str("65535"), Ok(65535));
        assert_eq!(u16::from_str("0x10"), Ok(16));
        assert_eq!(u16::from_str("0xFF"), Ok(255));
        assert_eq!(u16::from_str("0o10"), Ok(8));
        assert_eq!(u16::from_str("0b1000000000000000"), Ok(32768));
        assert_eq!(u16::from_str("012"), Ok(10));
        assert!(u16::from_str("-1").is_err());
        assert!(u16::from_str("65536").is_err());
    }

    #[test]
    fn test_i32() {
        assert_eq!(i32::from_str("0"), Ok(0));
        assert_eq!(i32::from_str("-1"), Ok(-1));
        assert_eq!(i32::from_str("+2147483647"), Ok(2147483647));
        assert_eq!(i32::from_str("-2147483648"), Ok(-2147483648));
        assert_eq!(i32::from_str("0x7fffffff"), Ok(2147483647));
        assert_eq!(i32::from_str("-0x10"), Ok(-16));
        assert_eq!(i32::from_str("0o10"), Ok(8));
        assert_eq!(i32::from_str("-0o10"), Ok(-8));
        assert_eq!(i32::from_str("0b10"), Ok(2));
        assert_eq!(i32::from_str("-0b10"), Ok(-2));
        assert_eq!(i32::from_str("012"), Ok(10));
        assert!(i32::from_str("2147483648").is_err());
        assert!(i32::from_str("-2147483649").is_err());
    }

    #[test]
    fn test_u32() {
        assert_eq!(u32::from_str("0"), Ok(0));
        assert_eq!(u32::from_str("+100"), Ok(100));
        assert_eq!(u32::from_str("2147483648"), Ok(2147483648));
        assert_eq!(u32::from_str("4294967295"), Ok(4294967295));
        assert_eq!(u32::from_str("0x10"), Ok(16));
        assert_eq!(u32::from_str("0xFF"), Ok(255));
        assert_eq!(u32::from_str("0o10"), Ok(8));
        assert_eq!(u32::from_str("012"), Ok(10));
        assert_eq!(
            u32::from_str("0b10000000000000000000000000000000"),
            Ok(2147483648)
        );
        assert!(u32::from_str("-1").is_err());
        assert!(u32::from_str("4294967296").is_err());
    }

    #[test]
    fn test_i64() {
        assert_eq!(i64::from_str("0"), Ok(0));
        assert_eq!(i64::from_str("-1"), Ok(-1));
        assert_eq!(
            i64::from_str("+9223372036854775807"),
            Ok(9223372036854775807)
        );
        assert_eq!(
            i64::from_str("-9223372036854775808"),
            Ok(-9223372036854775808)
        );
        assert_eq!(i64::from_str("0x7fffffff"), Ok(2147483647));
        assert_eq!(i64::from_str("-0x10"), Ok(-16));
        assert_eq!(i64::from_str("0o10"), Ok(8));
        assert_eq!(i64::from_str("-0o10"), Ok(-8));
        assert_eq!(i64::from_str("0b10"), Ok(2));
        assert_eq!(i64::from_str("-0b10"), Ok(-2));
        assert_eq!(i64::from_str("012"), Ok(10));
        assert!(i64::from_str("9223372036854775808").is_err());
        assert!(i64::from_str("-9223372036854775809").is_err());
    }

    #[test]
    fn test_u64() {
        assert_eq!(u64::from_str("0"), Ok(0));
        assert_eq!(u64::from_str("+100"), Ok(100));
        assert_eq!(
            u64::from_str("+9223372036854775808"),
            Ok(9223372036854775808)
        );
        assert_eq!(
            u64::from_str("18446744073709551615"),
            Ok(18446744073709551615)
        );
        assert_eq!(u64::from_str("0x10"), Ok(16));
        assert_eq!(u64::from_str("0xFF"), Ok(255));
        assert_eq!(u64::from_str("0o10"), Ok(8));
        assert_eq!(
            u64::from_str("0b10000000000000000000000000000000"),
            Ok(2147483648)
        );
        assert_eq!(u64::from_str("012"), Ok(10));
        assert!(u64::from_str("-1").is_err());
        assert!(u64::from_str("18446744073709551616").is_err());
    }

    #[test]
    fn test_isize() {
        // Since isize's size is target defined, we don't bother with
        // trying to test large values and assume the tests for the
        // other integer types will cover the values for isize.
        assert_eq!(isize::from_str("0"), Ok(0));
        assert_eq!(isize::from_str("-1"), Ok(-1));
        assert_eq!(isize::from_str("0x7f"), Ok(127));
        assert_eq!(isize::from_str("-0x10"), Ok(-16));
        assert_eq!(isize::from_str("0o10"), Ok(8));
        assert_eq!(isize::from_str("-0o10"), Ok(-8));
        assert_eq!(isize::from_str("0b10"), Ok(2));
        assert_eq!(isize::from_str("-0b10"), Ok(-2));
        assert_eq!(isize::from_str("012"), Ok(10));
    }

    #[test]
    fn test_usize() {
        // Since usize's size is target defined, we don't bother with
        // trying to test large values and assume the tests for the
        // other integer types will cover the values for usize.
        assert_eq!(usize::from_str("0"), Ok(0));
        assert_eq!(usize::from_str("+100"), Ok(100));
        assert_eq!(usize::from_str("0x10"), Ok(16));
        assert_eq!(usize::from_str("0xFF"), Ok(255));
        assert_eq!(usize::from_str("0o10"), Ok(8));
        assert_eq!(usize::from_str("012"), Ok(10));
        assert!(usize::from_str("-1").is_err());
    }
}
<commit_msg>[opentitantool] Support different error types in `ParseInt`<commit_after>// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

use std::num;
use thiserror::Error;

#[derive(Error, Debug, Clone, Eq, PartialEq)]
pub enum ParseIntError {
    #[error(transparent)]
    ParseIntError(#[from] num::ParseIntError),
}

/// Trait for parsing integers.
///
/// Strings beginning with the common and classic prefixes `0x`, `0o`, `0b` or `0` are parsed
/// as hex, octal, binary, and octal (classic).  Anything else is parsed as decimal.
/// A leading `+` or `-` is permitted.  Any string parsed by `strtol(3)` or `strtoul(3)`
/// will be parsed successfully.
pub trait ParseInt: Sized {
    type FromStrRadixErr: Into<ParseIntError>;

    fn from_str_radix(src: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr>;

    fn from_str(src: &str) -> Result<Self, ParseIntError> {
        let (val, negative) = if let Some(v) = src.strip_prefix('-') {
            (v, true)
        } else if let Some(v) = src.strip_prefix('+') {
            (v, false)
        } else {
            (src, false)
        };

        let (radix, digits) = match val.get(0..2) {
            Some("0x") | Some("0X") => (16, &val[2..]),
            Some("0o") | Some("0O") => (8, &val[2..]),
            Some("0b") | Some("0B") => (2, &val[2..]),
            _ if val.starts_with('0') => (8, val),
            _ => (10, val),
        };

        if negative {
            let mut digits = digits.to_string();
            digits.insert(0, '-');
            Self::from_str_radix(&digits, radix).map_err(Self::FromStrRadixErr::into)
        } else {
            Self::from_str_radix(digits, radix).map_err(Self::FromStrRadixErr::into)
        }
    }
}

macro_rules! impl_parse_int {
    ($ty:ident) => {
        impl ParseInt for $ty {
            type FromStrRadixErr = num::ParseIntError;

            fn from_str_radix(src: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
                $ty::from_str_radix(src, radix)
            }
        }
    };
}

impl_parse_int!(i8);
impl_parse_int!(u8);
impl_parse_int!(i16);
impl_parse_int!(u16);
impl_parse_int!(i32);
impl_parse_int!(u32);
impl_parse_int!(i64);
impl_parse_int!(u64);
impl_parse_int!(isize);
impl_parse_int!(usize);

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

    #[test]
    fn test_i8() {
        assert_eq!(i8::from_str("0"), Ok(0));
        assert_eq!(i8::from_str("-1"), Ok(-1));
        assert_eq!(i8::from_str("+100"), Ok(100));
        assert_eq!(i8::from_str("-128"), Ok(-128));
        assert_eq!(i8::from_str("0x10"), Ok(16));
        assert_eq!(i8::from_str("-0x10"), Ok(-16));
        assert_eq!(i8::from_str("0o10"), Ok(8));
        assert_eq!(i8::from_str("-0o10"), Ok(-8));
        assert_eq!(i8::from_str("0b10"), Ok(2));
        assert_eq!(i8::from_str("-0b10"), Ok(-2));
        assert_eq!(i8::from_str("012"), Ok(10));
        assert!(i8::from_str("128").is_err());
        assert!(i8::from_str("-129").is_err());
    }

    #[test]
    fn test_u8() {
        assert_eq!(u8::from_str("0"), Ok(0));
        assert_eq!(u8::from_str("+100"), Ok(100));
        assert_eq!(u8::from_str("128"), Ok(128));
        assert_eq!(u8::from_str("255"), Ok(255));
        assert_eq!(u8::from_str("0x10"), Ok(16));
        assert_eq!(u8::from_str("0xFF"), Ok(255));
        assert_eq!(u8::from_str("0o10"), Ok(8));
        assert_eq!(u8::from_str("0b10000000"), Ok(128));
        assert_eq!(u8::from_str("012"), Ok(10));
        assert!(u8::from_str("-1").is_err());
        assert!(u8::from_str("256").is_err());
    }

    #[test]
    fn test_i16() {
        assert_eq!(i16::from_str("0"), Ok(0));
        assert_eq!(i16::from_str("-1"), Ok(-1));
        assert_eq!(i16::from_str("+32767"), Ok(32767));
        assert_eq!(i16::from_str("-32768"), Ok(-32768));
        assert_eq!(i16::from_str("0x3fff"), Ok(16383));
        assert_eq!(i16::from_str("-0x10"), Ok(-16));
        assert_eq!(i16::from_str("0o10"), Ok(8));
        assert_eq!(i16::from_str("-0o10"), Ok(-8));
        assert_eq!(i16::from_str("0b10"), Ok(2));
        assert_eq!(i16::from_str("-0b10"), Ok(-2));
        assert_eq!(i16::from_str("012"), Ok(10));
        assert!(i16::from_str("32768").is_err());
        assert!(i16::from_str("-32769").is_err());
    }

    #[test]
    fn test_u16() {
        assert_eq!(u16::from_str("0"), Ok(0));
        assert_eq!(u16::from_str("+100"), Ok(100));
        assert_eq!(u16::from_str("32768"), Ok(32768));
        assert_eq!(u16::from_str("65535"), Ok(65535));
        assert_eq!(u16::from_str("0x10"), Ok(16));
        assert_eq!(u16::from_str("0xFF"), Ok(255));
        assert_eq!(u16::from_str("0o10"), Ok(8));
        assert_eq!(u16::from_str("0b1000000000000000"), Ok(32768));
        assert_eq!(u16::from_str("012"), Ok(10));
        assert!(u16::from_str("-1").is_err());
        assert!(u16::from_str("65536").is_err());
    }

    #[test]
    fn test_i32() {
        assert_eq!(i32::from_str("0"), Ok(0));
        assert_eq!(i32::from_str("-1"), Ok(-1));
        assert_eq!(i32::from_str("+2147483647"), Ok(2147483647));
        assert_eq!(i32::from_str("-2147483648"), Ok(-2147483648));
        assert_eq!(i32::from_str("0x7fffffff"), Ok(2147483647));
        assert_eq!(i32::from_str("-0x10"), Ok(-16));
        assert_eq!(i32::from_str("0o10"), Ok(8));
        assert_eq!(i32::from_str("-0o10"), Ok(-8));
        assert_eq!(i32::from_str("0b10"), Ok(2));
        assert_eq!(i32::from_str("-0b10"), Ok(-2));
        assert_eq!(i32::from_str("012"), Ok(10));
        assert!(i32::from_str("2147483648").is_err());
        assert!(i32::from_str("-2147483649").is_err());
    }

    #[test]
    fn test_u32() {
        assert_eq!(u32::from_str("0"), Ok(0));
        assert_eq!(u32::from_str("+100"), Ok(100));
        assert_eq!(u32::from_str("2147483648"), Ok(2147483648));
        assert_eq!(u32::from_str("4294967295"), Ok(4294967295));
        assert_eq!(u32::from_str("0x10"), Ok(16));
        assert_eq!(u32::from_str("0xFF"), Ok(255));
        assert_eq!(u32::from_str("0o10"), Ok(8));
        assert_eq!(u32::from_str("012"), Ok(10));
        assert_eq!(
            u32::from_str("0b10000000000000000000000000000000"),
            Ok(2147483648)
        );
        assert!(u32::from_str("-1").is_err());
        assert!(u32::from_str("4294967296").is_err());
    }

    #[test]
    fn test_i64() {
        assert_eq!(i64::from_str("0"), Ok(0));
        assert_eq!(i64::from_str("-1"), Ok(-1));
        assert_eq!(
            i64::from_str("+9223372036854775807"),
            Ok(9223372036854775807)
        );
        assert_eq!(
            i64::from_str("-9223372036854775808"),
            Ok(-9223372036854775808)
        );
        assert_eq!(i64::from_str("0x7fffffff"), Ok(2147483647));
        assert_eq!(i64::from_str("-0x10"), Ok(-16));
        assert_eq!(i64::from_str("0o10"), Ok(8));
        assert_eq!(i64::from_str("-0o10"), Ok(-8));
        assert_eq!(i64::from_str("0b10"), Ok(2));
        assert_eq!(i64::from_str("-0b10"), Ok(-2));
        assert_eq!(i64::from_str("012"), Ok(10));
        assert!(i64::from_str("9223372036854775808").is_err());
        assert!(i64::from_str("-9223372036854775809").is_err());
    }

    #[test]
    fn test_u64() {
        assert_eq!(u64::from_str("0"), Ok(0));
        assert_eq!(u64::from_str("+100"), Ok(100));
        assert_eq!(
            u64::from_str("+9223372036854775808"),
            Ok(9223372036854775808)
        );
        assert_eq!(
            u64::from_str("18446744073709551615"),
            Ok(18446744073709551615)
        );
        assert_eq!(u64::from_str("0x10"), Ok(16));
        assert_eq!(u64::from_str("0xFF"), Ok(255));
        assert_eq!(u64::from_str("0o10"), Ok(8));
        assert_eq!(
            u64::from_str("0b10000000000000000000000000000000"),
            Ok(2147483648)
        );
        assert_eq!(u64::from_str("012"), Ok(10));
        assert!(u64::from_str("-1").is_err());
        assert!(u64::from_str("18446744073709551616").is_err());
    }

    #[test]
    fn test_isize() {
        // Since isize's size is target defined, we don't bother with
        // trying to test large values and assume the tests for the
        // other integer types will cover the values for isize.
        assert_eq!(isize::from_str("0"), Ok(0));
        assert_eq!(isize::from_str("-1"), Ok(-1));
        assert_eq!(isize::from_str("0x7f"), Ok(127));
        assert_eq!(isize::from_str("-0x10"), Ok(-16));
        assert_eq!(isize::from_str("0o10"), Ok(8));
        assert_eq!(isize::from_str("-0o10"), Ok(-8));
        assert_eq!(isize::from_str("0b10"), Ok(2));
        assert_eq!(isize::from_str("-0b10"), Ok(-2));
        assert_eq!(isize::from_str("012"), Ok(10));
    }

    #[test]
    fn test_usize() {
        // Since usize's size is target defined, we don't bother with
        // trying to test large values and assume the tests for the
        // other integer types will cover the values for usize.
        assert_eq!(usize::from_str("0"), Ok(0));
        assert_eq!(usize::from_str("+100"), Ok(100));
        assert_eq!(usize::from_str("0x10"), Ok(16));
        assert_eq!(usize::from_str("0xFF"), Ok(255));
        assert_eq!(usize::from_str("0o10"), Ok(8));
        assert_eq!(usize::from_str("012"), Ok(10));
        assert!(usize::from_str("-1").is_err());
    }
}
<|endoftext|>


<commit_before>/// Brainfuck language interpreter
/// As specified here: http://www.muppetlabs.com/~breadbox/bf/
#[macro_use]
extern crate clap;

use std::process;
use std::path::{Path};
use std::io;
use std::io::prelude::*;
use std::fs::File;
use std::collections::VecDeque;
use std::thread;
use std::time::Duration;

use clap::{Arg, App};

macro_rules! exit_with_error(
    ($($arg:tt)*) => { {
        writeln!(&mut ::std::io::stderr(), $($arg)*)
            .expect("Failed while printing to stderr");
        process::exit(1);
    } }
);

macro_rules! println_stderr(
    ($($arg:tt)*) => { {
        let r = writeln!(&mut ::std::io::stderr(), $($arg)*);
        r.expect("failed printing to stderr");
    } }
);

fn main() {
    let args = App::new(crate_name!())
        .version(crate_version!())
        .version_short("v")
        .author(crate_authors!())
        .about("Brainfuck interpreter companion to the brain language compiler")
        .arg(Arg::with_name("input-file")
            .help("The brainfuck file to process. Should contain brainfuck instructions")
            .value_name("file")
            .takes_value(true)
            .required(true)
        )
        .arg(Arg::with_name("debug-enabled")
            .short("D")
            .long("debug")
            .help("Enables debug mode which outputs debugging information to stderr")
        )
        .arg(Arg::with_name("delay")
            .long("delay")
            .takes_value(true)
            .help("Delays execution of each instruction by this amount in ms")
        )
        .get_matches();

    let source_path = Path::new(args.value_of("input-file").unwrap());
    if !source_path.exists() || !source_path.is_file() {
        exit_with_error!("Not a valid file: '{}'", source_path.display());
    }

    let debug_mode = args.is_present("debug-enabled");

    let delay: u64 = if let Some(delay_str) = args.value_of("delay") {
        delay_str.parse().unwrap_or_else(|e: std::num::ParseIntError| exit_with_error!("Invalid delay: {}", e))
    } else {
        0
    };

    let f = File::open(source_path).unwrap_or_else(|e| {
        exit_with_error!("Could not open source file: {}", e);
    });

    let program = f.bytes().map(
        |c| c.expect("Fatal: Could not read char") as char
    ).collect::<Vec<char>>();

    interpret(program, debug_mode, delay);
}

fn interpret(program: Vec<char>, debug: bool, delay: u64) {
    let mut buffer: VecDeque<u8> = VecDeque::new();
    // Make sure there is at least one cell to begin with
    buffer.push_back(0u8);

    // p is the position "pointer" in the buffer
    let mut p: usize = 0;
    // i is the instruction index in the program
    let mut i: usize = 0;

    loop {
        if i >= program.len() {
            break;
        }
        let c = program[i];
        i += 1;

        match c {
            '>' => {
                p += 1;
                if p >= buffer.len() {
                    buffer.push_back(0u8);
                }
            },
            '<' => {
                if p == 0 {
                    buffer.push_front(0u8);
                }
                else {
                    p -= 1;
                }
            },
            '+' => buffer[p] = buffer[p].wrapping_add(1),
            '-' => buffer[p] = buffer[p].wrapping_sub(1),
            '.' => print!("{}", buffer[p] as char),
            ',' => {
                let chr = io::stdin().bytes().next();
                if chr.is_none() {
                    break;
                }
                buffer[p] = chr.unwrap().expect("Could not read input");
            },
            '[' => {
                if buffer[p] == 0 {
                    i = find_matching(&program, i - 1) + 1;
                }
            },
            ']' => {
                if buffer[p] != 0 {
                    i = find_matching(&program, i - 1) + 1;
                }
            },
            _ => continue,
        }

        if debug {
            println_stderr!("{{\"lastInstructionIndex\": {}, \"lastInstruction\": \"{}\", \"currentPointer\": {}, \"memory\": \"{}\"}}", i-1, c, p,
                buffer.iter().fold(String::new(), |acc, v| format!("{} {}", acc, v)));
        }

        thread::sleep(Duration::from_millis(delay));
    }
}

/// Finds the matching '[' or ']' for the given position within the program
/// panics if a match is not found
fn find_matching(program: &Vec<char>, start: usize) -> usize {
    let direction: isize = match program[start] {
        '[' => 1,
        ']' => -1,
        _ => unreachable!(),
    };

    let mut count = direction;
    let mut current = start;
    loop {
        if (direction < 0 && current == 0) || (direction > 0 && current >= program.len() - 1) {
            panic!("Could not find matching parenthesis for instruction {}", start);
        }
        current = (current as isize + direction) as usize;
        let c = program[current];

        count = match c {
            '[' => count + 1,
            ']' => count - 1,
            _ => count,
        };

        if count == 0 {
            break;
        }
    }

    current
}
<commit_msg>brainfuck now panics if EOF is reached while we're waiting to receive characters<commit_after>/// Brainfuck language interpreter
/// As specified here: http://www.muppetlabs.com/~breadbox/bf/
#[macro_use]
extern crate clap;

use std::process;
use std::path::{Path};
use std::io;
use std::io::prelude::*;
use std::fs::File;
use std::collections::VecDeque;
use std::thread;
use std::time::Duration;

use clap::{Arg, App};

macro_rules! exit_with_error(
    ($($arg:tt)*) => { {
        writeln!(&mut ::std::io::stderr(), $($arg)*)
            .expect("Failed while printing to stderr");
        process::exit(1);
    } }
);

macro_rules! println_stderr(
    ($($arg:tt)*) => { {
        let r = writeln!(&mut ::std::io::stderr(), $($arg)*);
        r.expect("failed printing to stderr");
    } }
);

fn main() {
    let args = App::new(crate_name!())
        .version(crate_version!())
        .version_short("v")
        .author(crate_authors!())
        .about("Brainfuck interpreter companion to the brain language compiler")
        .arg(Arg::with_name("input-file")
            .help("The brainfuck file to process. Should contain brainfuck instructions")
            .value_name("file")
            .takes_value(true)
            .required(true)
        )
        .arg(Arg::with_name("debug-enabled")
            .short("D")
            .long("debug")
            .help("Enables debug mode which outputs debugging information to stderr")
        )
        .arg(Arg::with_name("delay")
            .long("delay")
            .takes_value(true)
            .help("Delays execution of each instruction by this amount in ms")
        )
        .get_matches();

    let source_path = Path::new(args.value_of("input-file").unwrap());
    if !source_path.exists() || !source_path.is_file() {
        exit_with_error!("Not a valid file: '{}'", source_path.display());
    }

    let debug_mode = args.is_present("debug-enabled");

    let delay: u64 = if let Some(delay_str) = args.value_of("delay") {
        delay_str.parse().unwrap_or_else(|e: std::num::ParseIntError| exit_with_error!("Invalid delay: {}", e))
    } else {
        0
    };

    let f = File::open(source_path).unwrap_or_else(|e| {
        exit_with_error!("Could not open source file: {}", e);
    });

    let program = f.bytes().map(
        |c| c.expect("Fatal: Could not read char") as char
    ).collect::<Vec<char>>();

    interpret(program, debug_mode, delay);
}

fn interpret(program: Vec<char>, debug: bool, delay: u64) {
    let mut buffer: VecDeque<u8> = VecDeque::new();
    // Make sure there is at least one cell to begin with
    buffer.push_back(0u8);

    // p is the position "pointer" in the buffer
    let mut p: usize = 0;
    // i is the instruction index in the program
    let mut i: usize = 0;

    loop {
        if i >= program.len() {
            break;
        }
        let c = program[i];
        i += 1;

        match c {
            '>' => {
                p += 1;
                if p >= buffer.len() {
                    buffer.push_back(0u8);
                }
            },
            '<' => {
                if p == 0 {
                    buffer.push_front(0u8);
                }
                else {
                    p -= 1;
                }
            },
            '+' => buffer[p] = buffer[p].wrapping_add(1),
            '-' => buffer[p] = buffer[p].wrapping_sub(1),
            '.' => print!("{}", buffer[p] as char),
            ',' => {
                let chr = io::stdin().bytes().next();
                if chr.is_none() {
                    panic!("EOF while attempting to read character");
                }
                buffer[p] = chr.unwrap().expect("Could not read input");
            },
            '[' => {
                if buffer[p] == 0 {
                    i = find_matching(&program, i - 1) + 1;
                }
            },
            ']' => {
                if buffer[p] != 0 {
                    i = find_matching(&program, i - 1) + 1;
                }
            },
            _ => continue,
        }

        if debug {
            println_stderr!("{{\"lastInstructionIndex\": {}, \"lastInstruction\": \"{}\", \"currentPointer\": {}, \"memory\": \"{}\"}}", i-1, c, p,
                buffer.iter().fold(String::new(), |acc, v| format!("{} {}", acc, v)));
        }

        thread::sleep(Duration::from_millis(delay));
    }
}

/// Finds the matching '[' or ']' for the given position within the program
/// panics if a match is not found
fn find_matching(program: &Vec<char>, start: usize) -> usize {
    let direction: isize = match program[start] {
        '[' => 1,
        ']' => -1,
        _ => unreachable!(),
    };

    let mut count = direction;
    let mut current = start;
    loop {
        if (direction < 0 && current == 0) || (direction > 0 && current >= program.len() - 1) {
            panic!("Could not find matching parenthesis for instruction {}", start);
        }
        current = (current as isize + direction) as usize;
        let c = program[current];

        count = match c {
            '[' => count + 1,
            ']' => count - 1,
            _ => count,
        };

        if count == 0 {
            break;
        }
    }

    current
}
<|endoftext|>


<commit_before>// Copyright 2015-2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Inspired by Paul Woolcock's cargo-fmt (https://github.com/pwoolcoc/cargo-fmt/)

#![cfg(not(test))]
#![deny(warnings)]

extern crate getopts;
extern crate serde_json as json;

use std::env;
use std::io::Write;
use std::path::PathBuf;
use std::process::{Command, ExitStatus};
use std::str;
use std::collections::HashSet;
use std::iter::FromIterator;

use json::Value;

use getopts::{Options, Matches};

fn main() {
    let exit_status = execute();
    std::io::stdout().flush().unwrap();
    std::process::exit(exit_status);
}

fn execute() -> i32 {
    let success = 0;
    let failure = 1;

    let mut opts = getopts::Options::new();
    opts.optflag("h", "help", "show this message");
    opts.optflag("q", "quiet", "no output printed to stdout");
    opts.optflag("v", "verbose", "use verbose output");
    opts.optmulti(
        "p",
        "package",
        "specify package to format (only usable in workspaces)",
        "<package>",
    );
    opts.optflag("", "all", "format all packages (only usable in workspaces)");

    // If there is any invalid argument passed to `cargo fmt`, return without formatting.
    if let Some(arg) = env::args()
        .skip(2)
        .take_while(|a| a != "--")
        .find(|a| !a.starts_with('-'))
    {
        print_usage(&opts, &format!("Invalid argument: `{}`.", arg));
        return failure;
    }

    let matches = match opts.parse(env::args().skip(1).take_while(|a| a != "--")) {
        Ok(m) => m,
        Err(e) => {
            print_usage(&opts, &e.to_string());
            return failure;
        }
    };

    let verbosity = match (matches.opt_present("v"), matches.opt_present("q")) {
        (false, false) => Verbosity::Normal,
        (false, true) => Verbosity::Quiet,
        (true, false) => Verbosity::Verbose,
        (true, true) => {
            print_usage(&opts, "quiet mode and verbose mode are not compatible");
            return failure;
        }
    };

    if matches.opt_present("h") {
        print_usage(&opts, "");
        return success;
    }

    let workspace_hitlist = WorkspaceHitlist::from_matches(&matches);

    match format_crate(verbosity, workspace_hitlist) {
        Err(e) => {
            print_usage(&opts, &e.to_string());
            failure
        }
        Ok(status) => {
            if status.success() {
                success
            } else {
                status.code().unwrap_or(failure)
            }
        }
    }
}

fn print_usage(opts: &Options, reason: &str) {
    let msg = format!("{}\nusage: cargo fmt [options]", reason);
    println!(
        "{}\nThis utility formats all bin and lib files of the current crate using rustfmt. \
         Arguments after `--` are passed to rustfmt.",
        opts.usage(&msg)
    );
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Verbosity {
    Verbose,
    Normal,
    Quiet,
}

fn format_crate(
    verbosity: Verbosity,
    workspace_hitlist: WorkspaceHitlist,
) -> Result<ExitStatus, std::io::Error> {
    let targets = get_targets(workspace_hitlist)?;

    // Currently only bin and lib files get formatted
    let files: Vec<_> = targets
        .into_iter()
        .filter(|t| t.kind.should_format())
        .inspect(|t| if verbosity == Verbosity::Verbose {
            println!("[{:?}] {:?}", t.kind, t.path)
        })
        .map(|t| t.path)
        .collect();

    format_files(&files, &get_fmt_args(), verbosity)
}

fn get_fmt_args() -> Vec<String> {
    // All arguments after -- are passed to rustfmt
    env::args().skip_while(|a| a != "--").skip(1).collect()
}

#[derive(Debug)]
enum TargetKind {
    Lib, // dylib, staticlib, lib
    Bin, // bin
    Example, // example file
    Test, // test file
    Bench, // bench file
    CustomBuild, // build script
    Other, // plugin,...
}

impl TargetKind {
    fn should_format(&self) -> bool {
        match *self {
            TargetKind::Lib | TargetKind::Bin | TargetKind::Example | TargetKind::Test |
            TargetKind::Bench | TargetKind::CustomBuild => true,
            _ => false,
        }
    }
}

#[derive(Debug)]
pub struct Target {
    path: PathBuf,
    kind: TargetKind,
}

#[derive(Debug, PartialEq, Eq)]
pub enum WorkspaceHitlist {
    All,
    Some(Vec<String>),
    None,
}

impl WorkspaceHitlist {
    pub fn get_some<'a>(&'a self) -> Option<&'a [String]> {
        if let &WorkspaceHitlist::Some(ref hitlist) = self {
            Some(&hitlist)
        } else {
            None
        }
    }

    pub fn from_matches(matches: &Matches) -> WorkspaceHitlist {
        match (matches.opt_present("all"), matches.opt_present("p")) {
            (false, false) => WorkspaceHitlist::None,
            (true, _) => WorkspaceHitlist::All,
            (false, true) => WorkspaceHitlist::Some(matches.opt_strs("p")),
        }
    }
}

// Returns a vector of all compile targets of a crate
fn get_targets(workspace_hitlist: WorkspaceHitlist) -> Result<Vec<Target>, std::io::Error> {
    let mut targets: Vec<Target> = vec![];
    if workspace_hitlist == WorkspaceHitlist::None {
        let output = Command::new("cargo").arg("read-manifest").output()?;
        if output.status.success() {
            // None of the unwraps should fail if output of `cargo read-manifest` is correct
            let data = &String::from_utf8(output.stdout).unwrap();
            let json: Value = json::from_str(data).unwrap();
            let json_obj = json.as_object().unwrap();
            let jtargets = json_obj.get("targets").unwrap().as_array().unwrap();
            for jtarget in jtargets {
                targets.push(target_from_json(jtarget));
            }

            return Ok(targets);
        }
        return Err(std::io::Error::new(
            std::io::ErrorKind::NotFound,
            str::from_utf8(&output.stderr).unwrap(),
        ));
    }
    // This happens when cargo-fmt is not used inside a crate or
    // is used inside a workspace.
    // To ensure backward compatability, we only use `cargo metadata` for workspaces.
    // TODO: Is it possible only use metadata or read-manifest
    let output = Command::new("cargo")
        .arg("metadata")
        .arg("--no-deps")
        .output()?;
    if output.status.success() {
        let data = &String::from_utf8(output.stdout).unwrap();
        let json: Value = json::from_str(data).unwrap();
        let json_obj = json.as_object().unwrap();
        let mut hitlist: HashSet<&String> = if workspace_hitlist != WorkspaceHitlist::All {
            HashSet::from_iter(workspace_hitlist.get_some().unwrap())
        } else {
            HashSet::new() // Unused
        };
        let members: Vec<&Value> = json_obj
            .get("packages")
            .unwrap()
            .as_array()
            .unwrap()
            .into_iter()
            .filter(|member| if workspace_hitlist == WorkspaceHitlist::All {
                true
            } else {
                let member_obj = member.as_object().unwrap();
                let member_name = member_obj.get("name").unwrap().as_str().unwrap();
                hitlist.take(&member_name.to_string()).is_some()
            })
            .collect();
        if hitlist.len() != 0 {
            // Mimick cargo of only outputting one <package> spec.
            return Err(std::io::Error::new(
                std::io::ErrorKind::InvalidInput,
                format!(
                    "package `{}` is not a member of the workspace",
                    hitlist.iter().next().unwrap()
                ),
            ));
        }
        for member in members {
            let member_obj = member.as_object().unwrap();
            let jtargets = member_obj.get("targets").unwrap().as_array().unwrap();
            for jtarget in jtargets {
                targets.push(target_from_json(jtarget));
            }
        }
        return Ok(targets);
    }
    Err(std::io::Error::new(
        std::io::ErrorKind::NotFound,
        str::from_utf8(&output.stderr).unwrap(),
    ))

}

fn target_from_json(jtarget: &Value) -> Target {
    let jtarget = jtarget.as_object().unwrap();
    let path = PathBuf::from(jtarget.get("src_path").unwrap().as_str().unwrap());
    let kinds = jtarget.get("kind").unwrap().as_array().unwrap();
    let kind = match kinds[0].as_str().unwrap() {
        "bin" => TargetKind::Bin,
        "lib" | "dylib" | "staticlib" | "cdylib" | "rlib" => TargetKind::Lib,
        "test" => TargetKind::Test,
        "example" => TargetKind::Example,
        "bench" => TargetKind::Bench,
        "custom-build" => TargetKind::CustomBuild,
        _ => TargetKind::Other,
    };

    Target {
        path: path,
        kind: kind,
    }
}

fn format_files(
    files: &[PathBuf],
    fmt_args: &[String],
    verbosity: Verbosity,
) -> Result<ExitStatus, std::io::Error> {
    let stdout = if verbosity == Verbosity::Quiet {
        std::process::Stdio::null()
    } else {
        std::process::Stdio::inherit()
    };
    if verbosity == Verbosity::Verbose {
        print!("rustfmt");
        for a in fmt_args.iter() {
            print!(" {}", a);
        }
        for f in files.iter() {
            print!(" {}", f.display());
        }
        println!("");
    }
    let mut command = Command::new("rustfmt")
        .stdout(stdout)
        .args(files)
        .args(fmt_args)
        .spawn()
        .map_err(|e| match e.kind() {
            std::io::ErrorKind::NotFound => {
                std::io::Error::new(
                    std::io::ErrorKind::Other,
                    "Could not run rustfmt, please make sure it is in your PATH.",
                )
            }
            _ => e,
        })?;
    command.wait()
}
<commit_msg>Handle proc-macro crates in cargo-fmt<commit_after>// Copyright 2015-2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Inspired by Paul Woolcock's cargo-fmt (https://github.com/pwoolcoc/cargo-fmt/)

#![cfg(not(test))]
#![deny(warnings)]

extern crate getopts;
extern crate serde_json as json;

use std::env;
use std::io::Write;
use std::path::PathBuf;
use std::process::{Command, ExitStatus};
use std::str;
use std::collections::HashSet;
use std::iter::FromIterator;

use json::Value;

use getopts::{Options, Matches};

fn main() {
    let exit_status = execute();
    std::io::stdout().flush().unwrap();
    std::process::exit(exit_status);
}

fn execute() -> i32 {
    let success = 0;
    let failure = 1;

    let mut opts = getopts::Options::new();
    opts.optflag("h", "help", "show this message");
    opts.optflag("q", "quiet", "no output printed to stdout");
    opts.optflag("v", "verbose", "use verbose output");
    opts.optmulti(
        "p",
        "package",
        "specify package to format (only usable in workspaces)",
        "<package>",
    );
    opts.optflag("", "all", "format all packages (only usable in workspaces)");

    // If there is any invalid argument passed to `cargo fmt`, return without formatting.
    if let Some(arg) = env::args()
        .skip(2)
        .take_while(|a| a != "--")
        .find(|a| !a.starts_with('-'))
    {
        print_usage(&opts, &format!("Invalid argument: `{}`.", arg));
        return failure;
    }

    let matches = match opts.parse(env::args().skip(1).take_while(|a| a != "--")) {
        Ok(m) => m,
        Err(e) => {
            print_usage(&opts, &e.to_string());
            return failure;
        }
    };

    let verbosity = match (matches.opt_present("v"), matches.opt_present("q")) {
        (false, false) => Verbosity::Normal,
        (false, true) => Verbosity::Quiet,
        (true, false) => Verbosity::Verbose,
        (true, true) => {
            print_usage(&opts, "quiet mode and verbose mode are not compatible");
            return failure;
        }
    };

    if matches.opt_present("h") {
        print_usage(&opts, "");
        return success;
    }

    let workspace_hitlist = WorkspaceHitlist::from_matches(&matches);

    match format_crate(verbosity, workspace_hitlist) {
        Err(e) => {
            print_usage(&opts, &e.to_string());
            failure
        }
        Ok(status) => {
            if status.success() {
                success
            } else {
                status.code().unwrap_or(failure)
            }
        }
    }
}

fn print_usage(opts: &Options, reason: &str) {
    let msg = format!("{}\nusage: cargo fmt [options]", reason);
    println!(
        "{}\nThis utility formats all bin and lib files of the current crate using rustfmt. \
         Arguments after `--` are passed to rustfmt.",
        opts.usage(&msg)
    );
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Verbosity {
    Verbose,
    Normal,
    Quiet,
}

fn format_crate(
    verbosity: Verbosity,
    workspace_hitlist: WorkspaceHitlist,
) -> Result<ExitStatus, std::io::Error> {
    let targets = get_targets(workspace_hitlist)?;

    // Currently only bin and lib files get formatted
    let files: Vec<_> = targets
        .into_iter()
        .filter(|t| t.kind.should_format())
        .inspect(|t| if verbosity == Verbosity::Verbose {
            println!("[{:?}] {:?}", t.kind, t.path)
        })
        .map(|t| t.path)
        .collect();

    format_files(&files, &get_fmt_args(), verbosity)
}

fn get_fmt_args() -> Vec<String> {
    // All arguments after -- are passed to rustfmt
    env::args().skip_while(|a| a != "--").skip(1).collect()
}

#[derive(Debug)]
enum TargetKind {
    Lib, // dylib, staticlib, lib
    Bin, // bin
    Example, // example file
    Test, // test file
    Bench, // bench file
    CustomBuild, // build script
    ProcMacro, // a proc macro implementation
    Other, // plugin,...
}

impl TargetKind {
    fn should_format(&self) -> bool {
        match *self {
            TargetKind::Lib | TargetKind::Bin | TargetKind::Example | TargetKind::Test |
            TargetKind::Bench | TargetKind::CustomBuild | TargetKind::ProcMacro => true,
            _ => false,
        }
    }
}

#[derive(Debug)]
pub struct Target {
    path: PathBuf,
    kind: TargetKind,
}

#[derive(Debug, PartialEq, Eq)]
pub enum WorkspaceHitlist {
    All,
    Some(Vec<String>),
    None,
}

impl WorkspaceHitlist {
    pub fn get_some<'a>(&'a self) -> Option<&'a [String]> {
        if let &WorkspaceHitlist::Some(ref hitlist) = self {
            Some(&hitlist)
        } else {
            None
        }
    }

    pub fn from_matches(matches: &Matches) -> WorkspaceHitlist {
        match (matches.opt_present("all"), matches.opt_present("p")) {
            (false, false) => WorkspaceHitlist::None,
            (true, _) => WorkspaceHitlist::All,
            (false, true) => WorkspaceHitlist::Some(matches.opt_strs("p")),
        }
    }
}

// Returns a vector of all compile targets of a crate
fn get_targets(workspace_hitlist: WorkspaceHitlist) -> Result<Vec<Target>, std::io::Error> {
    let mut targets: Vec<Target> = vec![];
    if workspace_hitlist == WorkspaceHitlist::None {
        let output = Command::new("cargo").arg("read-manifest").output()?;
        if output.status.success() {
            // None of the unwraps should fail if output of `cargo read-manifest` is correct
            let data = &String::from_utf8(output.stdout).unwrap();
            let json: Value = json::from_str(data).unwrap();
            let json_obj = json.as_object().unwrap();
            let jtargets = json_obj.get("targets").unwrap().as_array().unwrap();
            for jtarget in jtargets {
                targets.push(target_from_json(jtarget));
            }

            return Ok(targets);
        }
        return Err(std::io::Error::new(
            std::io::ErrorKind::NotFound,
            str::from_utf8(&output.stderr).unwrap(),
        ));
    }
    // This happens when cargo-fmt is not used inside a crate or
    // is used inside a workspace.
    // To ensure backward compatability, we only use `cargo metadata` for workspaces.
    // TODO: Is it possible only use metadata or read-manifest
    let output = Command::new("cargo")
        .arg("metadata")
        .arg("--no-deps")
        .output()?;
    if output.status.success() {
        let data = &String::from_utf8(output.stdout).unwrap();
        let json: Value = json::from_str(data).unwrap();
        let json_obj = json.as_object().unwrap();
        let mut hitlist: HashSet<&String> = if workspace_hitlist != WorkspaceHitlist::All {
            HashSet::from_iter(workspace_hitlist.get_some().unwrap())
        } else {
            HashSet::new() // Unused
        };
        let members: Vec<&Value> = json_obj
            .get("packages")
            .unwrap()
            .as_array()
            .unwrap()
            .into_iter()
            .filter(|member| if workspace_hitlist == WorkspaceHitlist::All {
                true
            } else {
                let member_obj = member.as_object().unwrap();
                let member_name = member_obj.get("name").unwrap().as_str().unwrap();
                hitlist.take(&member_name.to_string()).is_some()
            })
            .collect();
        if hitlist.len() != 0 {
            // Mimick cargo of only outputting one <package> spec.
            return Err(std::io::Error::new(
                std::io::ErrorKind::InvalidInput,
                format!(
                    "package `{}` is not a member of the workspace",
                    hitlist.iter().next().unwrap()
                ),
            ));
        }
        for member in members {
            let member_obj = member.as_object().unwrap();
            let jtargets = member_obj.get("targets").unwrap().as_array().unwrap();
            for jtarget in jtargets {
                targets.push(target_from_json(jtarget));
            }
        }
        return Ok(targets);
    }
    Err(std::io::Error::new(
        std::io::ErrorKind::NotFound,
        str::from_utf8(&output.stderr).unwrap(),
    ))

}

fn target_from_json(jtarget: &Value) -> Target {
    let jtarget = jtarget.as_object().unwrap();
    let path = PathBuf::from(jtarget.get("src_path").unwrap().as_str().unwrap());
    let kinds = jtarget.get("kind").unwrap().as_array().unwrap();
    let kind = match kinds[0].as_str().unwrap() {
        "bin" => TargetKind::Bin,
        "lib" | "dylib" | "staticlib" | "cdylib" | "rlib" => TargetKind::Lib,
        "test" => TargetKind::Test,
        "example" => TargetKind::Example,
        "bench" => TargetKind::Bench,
        "custom-build" => TargetKind::CustomBuild,
        "proc-macro" => TargetKind::ProcMacro,
        _ => TargetKind::Other,
    };

    Target {
        path: path,
        kind: kind,
    }
}

fn format_files(
    files: &[PathBuf],
    fmt_args: &[String],
    verbosity: Verbosity,
) -> Result<ExitStatus, std::io::Error> {
    let stdout = if verbosity == Verbosity::Quiet {
        std::process::Stdio::null()
    } else {
        std::process::Stdio::inherit()
    };
    if verbosity == Verbosity::Verbose {
        print!("rustfmt");
        for a in fmt_args.iter() {
            print!(" {}", a);
        }
        for f in files.iter() {
            print!(" {}", f.display());
        }
        println!("");
    }
    let mut command = Command::new("rustfmt")
        .stdout(stdout)
        .args(files)
        .args(fmt_args)
        .spawn()
        .map_err(|e| match e.kind() {
            std::io::ErrorKind::NotFound => {
                std::io::Error::new(
                    std::io::ErrorKind::Other,
                    "Could not run rustfmt, please make sure it is in your PATH.",
                )
            }
            _ => e,
        })?;
    command.wait()
}
<|endoftext|>


<commit_before>use std::ops::{Index, IndexMut};

#[macro_use]
extern crate quick_error;

extern crate nalgebra;
use nalgebra::{DMat};

extern crate image;
use image::{ImageBuffer, Luma, DynamicImage};

extern crate rand;
use rand::{StdRng, Rng, SeedableRng, Closed01};

type FloatType = f64;
type Mat = DMat<FloatType>;

fn horizontal_line<I: Iterator<Item = usize>>(row: usize, cols: I) -> Mat {
    let mut factor: Mat = DMat::new_zeros(10, 10);
    for col in cols {
        *factor.index_mut((row, col)) = 1.;
    }
    factor
}

fn vertical_line<I: Iterator<Item = usize>>(rows: I, col: usize) -> Mat {
    let mut factor: Mat = DMat::new_zeros(10, 10);
    for row in rows {
        *factor.index_mut((row, col)) = 1.;
    }
    factor
}

fn mat_to_image(mat: &Mat) -> DynamicImage {
    let mut image_buffer
        = ImageBuffer::new(mat.ncols() as u32, mat.nrows() as u32);
    for (x, y, pixel) in image_buffer.enumerate_pixels_mut() {
        let value = mat.index((y as usize, x as usize));
        let byte = (*value * 255.).round() as u8;
        *pixel = Luma([byte]);
    }
    DynamicImage::ImageLuma8(image_buffer)
}

quick_error! {
    #[derive(Debug)]
    pub enum ImageSaveError {
        Io(err: std::io::Error) {}
        Image(err: image::ImageError) {}
    }
}

fn save_as_png(mat: &Mat, filename: &str) -> Result<(), ImageSaveError> {
    let image = mat_to_image(&mat);
    let path = std::path::Path::new(filename);
    let mut file = try!(std::fs::File::create(&path)
                        .map_err(ImageSaveError::Io));
    image.save(&mut file, image::PNG).map_err(ImageSaveError::Image)
}

fn main() {
    let mut factors: Vec<Mat> = Vec::new();

    factors.push(horizontal_line(9, 0..5));
    for row in (0..9).rev() {
        factors.push(horizontal_line(row, 0..10));
    }

    factors.push(vertical_line(5..10, 0));
    for col in 1..10 {
        factors.push(vertical_line(0..10, col));
    }

    println!("factors:\n");
    for (i, factor) in factors.iter().enumerate() {
        save_as_png(&factor, &format!("factor-{}.png", i)[..]).unwrap();
        println!("{:?}", factor);
    }

    let mut horizontal_evolving: Vec<Mat> = Vec::new();
    for start_col in 0..6 {
        horizontal_evolving.push(horizontal_line(9, start_col..(start_col + 5)));
    }

    println!("short horizontal bar that moves from left to right:\n");
    for (i, factor) in horizontal_evolving.iter().enumerate() {
        save_as_png(&factor, &format!("horizontal-{}.png", i)[..]).unwrap();
        println!("{:?}", factor);
    }

    let mut vertical_evolving: Vec<Mat> = Vec::new();
    for start_row in (0..6).rev() {
        vertical_evolving.push(vertical_line(start_row..(start_row + 5), 0));
    }

    println!("short vertical bar that moves from bottom to top:\n");
    for (i, factor) in vertical_evolving.iter().enumerate() {
        save_as_png(&factor, &format!("vertical-{}.png", i)[..]).unwrap();
        println!("{:?}", factor);
    }

    let seed: &[_] = &[1, 2, 3, 4];
    let mut rng: StdRng = SeedableRng::from_seed(seed);

    for _ in 0..10 {
        let Closed01(val) = rng.gen::<Closed01<f64>>();
        println!("{}", val);
    }
}
<commit_msg>generate linear combination<commit_after>use std::ops::{Index, IndexMut, Mul, Add};

#[macro_use]
extern crate quick_error;

extern crate nalgebra;
use nalgebra::{DMat};

extern crate image;
use image::{ImageBuffer, Luma, DynamicImage};

extern crate rand;
use rand::{StdRng, Rng, SeedableRng, Closed01};

type FloatType = f64;
type Mat = DMat<FloatType>;

fn horizontal_line<I: Iterator<Item = usize>>(row: usize, cols: I) -> Mat {
    let mut factor: Mat = DMat::new_zeros(10, 10);
    for col in cols {
        *factor.index_mut((row, col)) = 1.;
    }
    factor
}

fn vertical_line<I: Iterator<Item = usize>>(rows: I, col: usize) -> Mat {
    let mut factor: Mat = DMat::new_zeros(10, 10);
    for row in rows {
        *factor.index_mut((row, col)) = 1.;
    }
    factor
}

fn mat_to_image(mat: &Mat) -> DynamicImage {
    let mut image_buffer
        = ImageBuffer::new(mat.ncols() as u32, mat.nrows() as u32);
    for (x, y, pixel) in image_buffer.enumerate_pixels_mut() {
        let value = mat.index((y as usize, x as usize));
        let byte = (*value * 255.).round() as u8;
        *pixel = Luma([byte]);
    }
    DynamicImage::ImageLuma8(image_buffer)
}

quick_error! {
    #[derive(Debug)]
    pub enum ImageSaveError {
        Io(err: std::io::Error) {}
        Image(err: image::ImageError) {}
    }
}

fn save_as_png(mat: &Mat, filename: &str) -> Result<(), ImageSaveError> {
    let image = mat_to_image(&mat);
    let path = std::path::Path::new(filename);
    let mut file = try!(std::fs::File::create(&path)
                        .map_err(ImageSaveError::Io));
    image.save(&mut file, image::PNG).map_err(ImageSaveError::Image)
}

fn linear_combination(factors: &[Mat], coefficients: &[FloatType]) -> Mat {
    assert!(0 < factors.len());
    assert_eq!(factors.len(), coefficients.len());
    let nrows = factors[0].nrows();
    let ncols = factors[0].ncols();
    let mut result = DMat::new_zeros(nrows, ncols);
    for (factor, coefficient) in factors.iter().zip(coefficients.iter()) {
        assert_eq!(factor.nrows(), nrows);
        assert_eq!(factor.ncols(), ncols);
        result = result.add(factor.clone().mul(coefficient.clone()));
    }
    // result.div(factors.len() as FloatType)
    result
}

fn main() {
    let mut factors: Vec<Mat> = Vec::new();

    factors.push(horizontal_line(9, 0..5));
    for row in (0..9).rev() {
        factors.push(horizontal_line(row, 0..10));
    }

    factors.push(vertical_line(5..10, 0));
    for col in 1..10 {
        factors.push(vertical_line(0..10, col));
    }

    println!("factors:\n");
    for (i, factor) in factors.iter().enumerate() {
        save_as_png(&factor, &format!("factor-{}.png", i)[..]).unwrap();
        println!("{:?}", factor);
    }

    let mut horizontal_evolving: Vec<Mat> = Vec::new();
    for start_col in 0..6 {
        horizontal_evolving.push(horizontal_line(9, start_col..(start_col + 5)));
    }

    println!("short horizontal bar that moves from left to right:\n");
    for (i, factor) in horizontal_evolving.iter().enumerate() {
        save_as_png(&factor, &format!("horizontal-{}.png", i)[..]).unwrap();
        println!("{:?}", factor);
    }

    let mut vertical_evolving: Vec<Mat> = Vec::new();
    for start_row in (0..6).rev() {
        vertical_evolving.push(vertical_line(start_row..(start_row + 5), 0));
    }

    println!("short vertical bar that moves from bottom to top:\n");
    for (i, factor) in vertical_evolving.iter().enumerate() {
        save_as_png(&factor, &format!("vertical-{}.png", i)[..]).unwrap();
        println!("{:?}", factor);
    }

    let seed: &[_] = &[1, 2, 3, 4];
    let mut rng: StdRng = SeedableRng::from_seed(seed);

    for _ in 0..10 {
        let Closed01(val) = rng.gen::<Closed01<f64>>();
        println!("{}", val);
    }

    let coefficients: Vec<FloatType> = vec![
        0.5,
        0.5,
        0.5,
        0.5,
        0.5,
        0.5,
        0.0,
        0.0,
        0.0,
        0.0,
        0.0,
        0.5,
        0.0,
        0.0,
        0.0,
        0.5,
        0.5,
        0.5,
        0.0,
        0.0,
    ];
    let combination = linear_combination(&factors[..], &coefficients[..]);
    save_as_png(&combination, "combination.png").unwrap();

    // save_as_png(&factors[0].clone().add(factors[1].clone().mul(0.5)), "combination.png").unwrap();
}
<|endoftext|>


<commit_before>//! Functions to choose good boundaries for block splitting. Deflate allows encoding
//! the data in multiple blocks, with a separate Huffman tree for each block. The
//! Huffman tree itself requires some bytes to encode, so by choosing certain
//! blocks, you can either hurt, or enhance compression. These functions choose good
//! ones that enhance it.

use std::io::Write;
use std::mem::{transmute, uninitialized};
use std::ptr::null_mut;

use libc::{c_void, size_t};
use libc::funcs::c95::stdlib::{free, malloc};

use super::Options;

use deflate::calculate_block_size;
use lz77::{BlockState, LZ77Store, lz77_greedy, clean_lz77_store};
use util;

/// The "f" for the FindMinimum function below.
/// i: the current parameter of f(i)
/// context: for your implementation
type FindMinimumFun = unsafe fn(i: usize, context: *const c_void) -> f64;

/// Finds minimum of function f(i) where is is of type size_t, f(i) is of type
/// double, i is in range start-end (excluding end).
unsafe fn find_minimum(f: FindMinimumFun, context: *const c_void, start: usize, end: usize) -> usize {
    if end - start < 1024 {
        let mut best: f64 = util::LARGE_FLOAT;
        let mut result = start;
        for i in start..end {
            let v = f(i, context);
            if v < best {
                best = v;
                result = i;
            }
        }
        result
    } else {
        // Try to find minimum faster by recursively checking multiple points.

        // Good value: 9.
        const NUM: usize = 9;

        let mut p: [usize; NUM] = uninitialized();
        let mut vp: [f64; NUM] = uninitialized();
        let mut lastbest: f64 = util::LARGE_FLOAT;
        let mut pos = start;

        let mut start = start;
        let mut end = end;
        loop {
            if end - start <= NUM {
                break;
            }

            for i in 0..NUM {
                p[i] = start + (i + 1) * ((end - start) / (NUM + 1));
                vp[i] = f(p[i], context);
            }
            let mut besti: usize = 0;
            let mut best: f64 = vp[0];
            for i in 1..NUM {
                if vp[i] < best {
                    best = vp[i];
                    besti = i;
                }
            }
            if best > lastbest {
                break;
            }

            start = if besti == 0 { start } else { p[besti - 1] };
            end = if besti == NUM - 1 { end } else { p[besti + 1] };

            pos = p[besti];
            lastbest = best;
        }
        pos
    }
}

/**
 * Returns estimated cost of a block in bits.  It includes the size to encode the
 * tree and the size to encode all literal, length and distance symbols and their
 * extra bits.
 *
 * litlens: lz77 lit/lengths
 * dists: ll77 distances
 * lstart: start of block
 * lend: end of block (not inclusive)
 */
unsafe fn estimate_cost(litlens: *const u16, dists: *const u16, lstart: usize, lend: usize) -> f64 {
    calculate_block_size(litlens, dists, lstart, lend, 2)
}

struct SplitCostContext {
    litlens: *const u16,
    dists: *const u16,
    _llsize: usize,
    start: usize,
    end: usize,
}

/// Gets the cost which is the sum of the cost of the left and the right section
/// of the data.
/// type: FindMinimumFun
unsafe fn split_cost(i: usize, context: *const c_void) -> f64 {
    let c: *const SplitCostContext = transmute(context);
    estimate_cost((*c).litlens, (*c).dists, (*c).start, i) + estimate_cost((*c).litlens, (*c).dists, i, (*c).end)
}

unsafe fn add_sorted(value: usize, out: &mut Vec<usize>) {
    out.push(value);
    let mut i: usize = 0;
    while i + 1 < out.len() {
        if out[i] > value {
            let mut j: usize = out.len() - 1;
            while j > i {
                out[j] = out[j - 1];
                j -= 1;
            }
            out[i] = value;
            break;
        }
        i += 1;
    }
}

/// Prints the block split points as decimal and hex values in the terminal.
unsafe fn print_block_split_points(litlens: *const u16, dists: *const u16, llsize: usize, lz77splitpoints: &Vec<usize>) {
    let mut splitpoints: Vec<usize> = Vec::new();

    // The input is given as lz77 indices, but we want to see the uncompressed
    // index values.
    let mut pos: usize = 0;
    if lz77splitpoints.len() > 0 {
        for i in 0..llsize {
            let length: usize = if *dists.offset(i as isize) == 0 { 1 } else { *litlens.offset(i as isize) as usize };
            if lz77splitpoints[splitpoints.len()] == i {
                splitpoints.push(pos);
                if splitpoints.len() == lz77splitpoints.len() {
                    break;
                }
            }
            pos += length;
        }
    }
    assert_eq!(splitpoints.len(), lz77splitpoints.len());

    print_err!("block split points: ");
    for i in 0..splitpoints.len() {
        print_err!("{} ", splitpoints[i] as i32);
    }
    print_err!("(hex:");
    for i in 0..splitpoints.len() {
        print_err!(" {:x}", splitpoints[i] as i32);
    }
    println_err!(")");
}

/// Finds next block to try to split, the largest of the available ones.
/// The largest is chosen to make sure that if only a limited amount of blocks is
/// requested, their sizes are spread evenly.
/// llsize: the size of the LL77 data, which is the size of the done array here.
/// done: array indicating which blocks starting at that position are no longer
///     splittable (splitting them increases rather than decreases cost).
/// splitpoints: the splitpoints found so far.
/// npoints: the amount of splitpoints found so far.
/// lstart: output variable, giving start of block.
/// lend: output variable, giving end of block.
/// returns 1 if a block was found, 0 if no block found (all are done).
unsafe fn find_largest_splittable_block(llsize: usize, done: *const u8, splitpoints: &Vec<usize>, lstart: *mut usize, lend: *mut usize) -> bool {
    let mut longest: usize = 0;
    let mut found = false;
    for i in 0..splitpoints.len()+1 {
        let start: usize = if i == 0 { 0 } else { splitpoints[i - 1] };
        let end: usize = if i == splitpoints.len() { llsize - 1 } else { splitpoints[i] };
        if *done.offset(start as isize) == 0 && end - start > longest {
            *lstart = start;
            *lend = end;
            found = true;
            longest = end - start;
        }
    }
    found
}

/// Does blocksplitting on LZ77 data.
/// The output splitpoints are indices in the LZ77 data.
/// litlens: lz77 lit/lengths
/// dists: lz77 distances
/// llsize: size of litlens and dists
/// maxblocks: set a limit to the amount of blocks. Set to 0 to mean no limit.
pub unsafe fn block_split_lz77(options: *const Options, litlens: *const u16, dists: *const u16, llsize: usize, maxblocks: usize, splitpoints: &mut Vec<usize>) {
    if llsize < 10 {
        // This code fails on tiny files.
        return;
    }

    let done: *mut u8 = transmute(malloc(llsize as size_t));
    if done.is_null() {
        panic!("Allocation failed!");
    }
    for i in 0..llsize {
        *done.offset(i as isize) = 0;
    }

    let mut lstart: usize = 0;
    let mut lend: usize = llsize;
    let mut numblocks: usize = 1;
    loop {
        if maxblocks > 0 && numblocks >= maxblocks {
            break;
        }

        let mut c = SplitCostContext {
            litlens: litlens,
            dists: dists,
            _llsize: llsize,
            start: lstart,
            end: lend,
        };
        assert!(lstart < lend);
        let llpos: usize = find_minimum(split_cost, &mut c as *mut _ as *mut c_void, lstart + 1, lend);

        assert!(llpos > lstart);
        assert!(llpos < lend);

        let splitcost: f64 = estimate_cost(litlens, dists, lstart, llpos) + estimate_cost(litlens, dists, llpos, lend);
        let origcost: f64 = estimate_cost(litlens, dists, lstart, lend);

        if splitcost > origcost || llpos == lstart + 1 || llpos == lend {
            *done.offset(lstart as isize) = 1;
        } else {
            add_sorted(llpos, splitpoints);
            numblocks += 1;
        }

        if !find_largest_splittable_block(llsize, done, splitpoints, &mut lstart, &mut lend) {
            // No further split will probably reduce compression.
            break;
        }

        if lend - lstart < 10 {
            break;
        }
    }

    if (*options).verbose {
        print_block_split_points(litlens, dists, llsize, splitpoints);
    }

    free(transmute(done));
}

/**
 * Does blocksplitting on uncompressed data.
 * The output splitpoints are indices in the uncompressed bytes.
 *
 * options: general program options.
 * in: uncompressed input data
 * instart: where to start splitting
 * inend: where to end splitting (not inclusive)
 * maxblocks: maximum amount of blocks to split into, or 0 for no limit
 * splitpoints: dynamic array to put the resulting split point coordinates into.
 *   The coordinates are indices in the input array.
 * npoints: pointer to amount of splitpoints, for the dynamic array. The amount of
 *   blocks is the amount of splitpoitns + 1.
 */
pub unsafe fn block_split(options: *const Options, in_: &[u8], instart: usize, inend: usize, maxblocks: usize, splitpoints: &mut Vec<usize>) {
    let s = BlockState::new(options, instart, inend, null_mut());
    let mut lz77splitpoints: Vec<usize> = Vec::new();
    let mut store = LZ77Store::new();

    splitpoints.clear();

    // Unintuitively, Using a simple LZ77 method here instead of ZopfliLZ77Optimal
    // results in better blocks.
    lz77_greedy(&s, in_, instart, inend, &mut store);

    block_split_lz77(options, store.litlens, store.dists, store.size, maxblocks, &mut lz77splitpoints);

    // Convert LZ77 positions to positions in the uncompressed input.
    let mut pos: usize = instart;
    if lz77splitpoints.len() > 0 {
        for i in 0..store.size {
            let length: usize = if *store.dists.offset(i as isize) == 0 { 1 } else { *store.litlens.offset(i as isize) as usize };
            if lz77splitpoints[splitpoints.len()] == i {
                splitpoints.push(pos);
                if splitpoints.len() == lz77splitpoints.len() {
                    break;
                }
            }
            pos += length;
        }
    }
    assert_eq!(splitpoints.len(), lz77splitpoints.len());

    clean_lz77_store(&mut store);
}

/// Divides the input into equal blocks, does not even take LZ77 lengths into
/// account.
pub unsafe fn block_split_simple(_in: &[u8], instart: usize, inend: usize, blocksize: usize, splitpoints: &mut Vec<usize>) {
    let mut i: usize = instart;
    while i < inend {
        splitpoints.push(i);
        i += blocksize;
    }
}
<commit_msg>Use a closure instead of passing around a "context"<commit_after>//! Functions to choose good boundaries for block splitting. Deflate allows encoding
//! the data in multiple blocks, with a separate Huffman tree for each block. The
//! Huffman tree itself requires some bytes to encode, so by choosing certain
//! blocks, you can either hurt, or enhance compression. These functions choose good
//! ones that enhance it.

use std::io::Write;
use std::mem::{transmute, uninitialized};
use std::ptr::null_mut;

use libc::size_t;
use libc::funcs::c95::stdlib::{free, malloc};

use super::Options;

use deflate::calculate_block_size;
use lz77::{BlockState, LZ77Store, lz77_greedy, clean_lz77_store};
use util;

/// Finds minimum of function f(i) where is is of type size_t, f(i) is of type
/// double, i is in range start-end (excluding end).
unsafe fn find_minimum<F>(f: F, start: usize, end: usize) -> usize
    where F: Fn(usize) -> f64 {

    if end - start < 1024 {
        let mut best: f64 = util::LARGE_FLOAT;
        let mut result = start;
        for i in start..end {
            let v = f(i);
            if v < best {
                best = v;
                result = i;
            }
        }
        result
    } else {
        // Try to find minimum faster by recursively checking multiple points.

        // Good value: 9.
        const NUM: usize = 9;

        let mut p: [usize; NUM] = uninitialized();
        let mut vp: [f64; NUM] = uninitialized();
        let mut lastbest: f64 = util::LARGE_FLOAT;
        let mut pos = start;

        let mut start = start;
        let mut end = end;
        loop {
            if end - start <= NUM {
                break;
            }

            for i in 0..NUM {
                p[i] = start + (i + 1) * ((end - start) / (NUM + 1));
                vp[i] = f(p[i]);
            }
            let mut besti: usize = 0;
            let mut best: f64 = vp[0];
            for i in 1..NUM {
                if vp[i] < best {
                    best = vp[i];
                    besti = i;
                }
            }
            if best > lastbest {
                break;
            }

            start = if besti == 0 { start } else { p[besti - 1] };
            end = if besti == NUM - 1 { end } else { p[besti + 1] };

            pos = p[besti];
            lastbest = best;
        }
        pos
    }
}

/**
 * Returns estimated cost of a block in bits.  It includes the size to encode the
 * tree and the size to encode all literal, length and distance symbols and their
 * extra bits.
 *
 * litlens: lz77 lit/lengths
 * dists: ll77 distances
 * lstart: start of block
 * lend: end of block (not inclusive)
 */
unsafe fn estimate_cost(litlens: *const u16, dists: *const u16, lstart: usize, lend: usize) -> f64 {
    calculate_block_size(litlens, dists, lstart, lend, 2)
}

struct SplitCostContext {
    litlens: *const u16,
    dists: *const u16,
    _llsize: usize,
    start: usize,
    end: usize,
}

/// Gets the cost which is the sum of the cost of the left and the right section
/// of the data.
/// type: FindMinimumFun
unsafe fn split_cost(i: usize, c: &SplitCostContext) -> f64 {
    estimate_cost(c.litlens, c.dists, c.start, i) + estimate_cost(c.litlens, c.dists, i, c.end)
}

unsafe fn add_sorted(value: usize, out: &mut Vec<usize>) {
    out.push(value);
    let mut i: usize = 0;
    while i + 1 < out.len() {
        if out[i] > value {
            let mut j: usize = out.len() - 1;
            while j > i {
                out[j] = out[j - 1];
                j -= 1;
            }
            out[i] = value;
            break;
        }
        i += 1;
    }
}

/// Prints the block split points as decimal and hex values in the terminal.
unsafe fn print_block_split_points(litlens: *const u16, dists: *const u16, llsize: usize, lz77splitpoints: &Vec<usize>) {
    let mut splitpoints: Vec<usize> = Vec::new();

    // The input is given as lz77 indices, but we want to see the uncompressed
    // index values.
    let mut pos: usize = 0;
    if lz77splitpoints.len() > 0 {
        for i in 0..llsize {
            let length: usize = if *dists.offset(i as isize) == 0 { 1 } else { *litlens.offset(i as isize) as usize };
            if lz77splitpoints[splitpoints.len()] == i {
                splitpoints.push(pos);
                if splitpoints.len() == lz77splitpoints.len() {
                    break;
                }
            }
            pos += length;
        }
    }
    assert_eq!(splitpoints.len(), lz77splitpoints.len());

    print_err!("block split points: ");
    for i in 0..splitpoints.len() {
        print_err!("{} ", splitpoints[i] as i32);
    }
    print_err!("(hex:");
    for i in 0..splitpoints.len() {
        print_err!(" {:x}", splitpoints[i] as i32);
    }
    println_err!(")");
}

/// Finds next block to try to split, the largest of the available ones.
/// The largest is chosen to make sure that if only a limited amount of blocks is
/// requested, their sizes are spread evenly.
/// llsize: the size of the LL77 data, which is the size of the done array here.
/// done: array indicating which blocks starting at that position are no longer
///     splittable (splitting them increases rather than decreases cost).
/// splitpoints: the splitpoints found so far.
/// npoints: the amount of splitpoints found so far.
/// lstart: output variable, giving start of block.
/// lend: output variable, giving end of block.
/// returns 1 if a block was found, 0 if no block found (all are done).
unsafe fn find_largest_splittable_block(llsize: usize, done: *const u8, splitpoints: &Vec<usize>, lstart: *mut usize, lend: *mut usize) -> bool {
    let mut longest: usize = 0;
    let mut found = false;
    for i in 0..splitpoints.len()+1 {
        let start: usize = if i == 0 { 0 } else { splitpoints[i - 1] };
        let end: usize = if i == splitpoints.len() { llsize - 1 } else { splitpoints[i] };
        if *done.offset(start as isize) == 0 && end - start > longest {
            *lstart = start;
            *lend = end;
            found = true;
            longest = end - start;
        }
    }
    found
}

/// Does blocksplitting on LZ77 data.
/// The output splitpoints are indices in the LZ77 data.
/// litlens: lz77 lit/lengths
/// dists: lz77 distances
/// llsize: size of litlens and dists
/// maxblocks: set a limit to the amount of blocks. Set to 0 to mean no limit.
pub unsafe fn block_split_lz77(options: *const Options, litlens: *const u16, dists: *const u16, llsize: usize, maxblocks: usize, splitpoints: &mut Vec<usize>) {
    if llsize < 10 {
        // This code fails on tiny files.
        return;
    }

    let done: *mut u8 = transmute(malloc(llsize as size_t));
    if done.is_null() {
        panic!("Allocation failed!");
    }
    for i in 0..llsize {
        *done.offset(i as isize) = 0;
    }

    let mut lstart: usize = 0;
    let mut lend: usize = llsize;
    let mut numblocks: usize = 1;
    loop {
        if maxblocks > 0 && numblocks >= maxblocks {
            break;
        }

        let c = SplitCostContext {
            litlens: litlens,
            dists: dists,
            _llsize: llsize,
            start: lstart,
            end: lend,
        };
        assert!(lstart < lend);
        let llpos: usize = find_minimum(|i| split_cost(i, &c), lstart + 1, lend);

        assert!(llpos > lstart);
        assert!(llpos < lend);

        let splitcost: f64 = estimate_cost(litlens, dists, lstart, llpos) + estimate_cost(litlens, dists, llpos, lend);
        let origcost: f64 = estimate_cost(litlens, dists, lstart, lend);

        if splitcost > origcost || llpos == lstart + 1 || llpos == lend {
            *done.offset(lstart as isize) = 1;
        } else {
            add_sorted(llpos, splitpoints);
            numblocks += 1;
        }

        if !find_largest_splittable_block(llsize, done, splitpoints, &mut lstart, &mut lend) {
            // No further split will probably reduce compression.
            break;
        }

        if lend - lstart < 10 {
            break;
        }
    }

    if (*options).verbose {
        print_block_split_points(litlens, dists, llsize, splitpoints);
    }

    free(transmute(done));
}

/**
 * Does blocksplitting on uncompressed data.
 * The output splitpoints are indices in the uncompressed bytes.
 *
 * options: general program options.
 * in: uncompressed input data
 * instart: where to start splitting
 * inend: where to end splitting (not inclusive)
 * maxblocks: maximum amount of blocks to split into, or 0 for no limit
 * splitpoints: dynamic array to put the resulting split point coordinates into.
 *   The coordinates are indices in the input array.
 * npoints: pointer to amount of splitpoints, for the dynamic array. The amount of
 *   blocks is the amount of splitpoitns + 1.
 */
pub unsafe fn block_split(options: *const Options, in_: &[u8], instart: usize, inend: usize, maxblocks: usize, splitpoints: &mut Vec<usize>) {
    let s = BlockState::new(options, instart, inend, null_mut());
    let mut lz77splitpoints: Vec<usize> = Vec::new();
    let mut store = LZ77Store::new();

    splitpoints.clear();

    // Unintuitively, Using a simple LZ77 method here instead of ZopfliLZ77Optimal
    // results in better blocks.
    lz77_greedy(&s, in_, instart, inend, &mut store);

    block_split_lz77(options, store.litlens, store.dists, store.size, maxblocks, &mut lz77splitpoints);

    // Convert LZ77 positions to positions in the uncompressed input.
    let mut pos: usize = instart;
    if lz77splitpoints.len() > 0 {
        for i in 0..store.size {
            let length: usize = if *store.dists.offset(i as isize) == 0 { 1 } else { *store.litlens.offset(i as isize) as usize };
            if lz77splitpoints[splitpoints.len()] == i {
                splitpoints.push(pos);
                if splitpoints.len() == lz77splitpoints.len() {
                    break;
                }
            }
            pos += length;
        }
    }
    assert_eq!(splitpoints.len(), lz77splitpoints.len());

    clean_lz77_store(&mut store);
}

/// Divides the input into equal blocks, does not even take LZ77 lengths into
/// account.
pub unsafe fn block_split_simple(_in: &[u8], instart: usize, inend: usize, blocksize: usize, splitpoints: &mut Vec<usize>) {
    let mut i: usize = instart;
    while i < inend {
        splitpoints.push(i);
        i += blocksize;
    }
}
<|endoftext|>


<commit_before>use super::*;

pub(super) fn opt_generic_arg_list(p: &mut Parser, colon_colon_required: bool) {
    let m;
    if p.at(T![::]) && p.nth(2) == T![<] {
        m = p.start();
        p.bump(T![::]);
        p.bump(T![<]);
    } else if !colon_colon_required && p.at(T![<]) && p.nth(1) != T![=] {
        m = p.start();
        p.bump(T![<]);
    } else {
        return;
    }

    while !p.at(EOF) && !p.at(T![>]) {
        generic_arg(p);
        if !p.at(T![>]) && !p.expect(T![,]) {
            break;
        }
    }
    p.expect(T![>]);
    m.complete(p, GENERIC_ARG_LIST);
}

// test type_arg
// type A = B<'static, i32, 1, { 2 }, Item=u64, true, false>;
fn generic_arg(p: &mut Parser) {
    let m = p.start();
    match p.current() {
        LIFETIME_IDENT => {
            lifetime(p);
            m.complete(p, LIFETIME_ARG);
        }
        // test associated_type_bounds
        // fn print_all<T: Iterator<Item, Item::Item, Item::<true>, Item: Display, Item<'a> = Item>>(printables: T) {}
        IDENT if [T![<], T![=], T![:]].contains(&p.nth(1)) => {
            let path_ty = p.start();
            let path = p.start();
            let path_seg = p.start();
            name_ref(p);
            opt_generic_arg_list(p, false);
            match p.current() {
                // NameRef<...> =
                T![=] => {
                    p.bump_any();
                    types::type_(p);

                    path_seg.abandon(p);
                    path.abandon(p);
                    path_ty.abandon(p);
                    m.complete(p, ASSOC_TYPE_ARG);
                }
                T![:] if p.nth(1) == T![:] => {
                    // NameRef::, this is a path type
                    path_seg.complete(p, PATH_SEGMENT);
                    let qual = path.complete(p, PATH);
                    opt_generic_arg_list(p, false);
                    paths::type_path_for_qualifier(p, qual);
                    path_ty.complete(p, PATH_TYPE);
                    m.complete(p, TYPE_ARG);
                }
                // NameRef<...>:
                T![:] => {
                    generic_params::bounds(p);

                    path_seg.abandon(p);
                    path.abandon(p);
                    path_ty.abandon(p);
                    m.complete(p, ASSOC_TYPE_ARG);
                }
                // NameRef, this is a single segment path type
                _ => {
                    path_seg.complete(p, PATH_SEGMENT);
                    path.complete(p, PATH);
                    path_ty.complete(p, PATH_TYPE);
                    m.complete(p, TYPE_ARG);
                }
            }
        }
        T!['{'] => {
            expressions::block_expr(p);
            m.complete(p, CONST_ARG);
        }
        k if k.is_literal() => {
            expressions::literal(p);
            m.complete(p, CONST_ARG);
        }
        T![true] | T![false] => {
            expressions::literal(p);
            m.complete(p, CONST_ARG);
        }
        // test const_generic_negated_literal
        // fn f() { S::<-1> }
        T![-] => {
            let lm = p.start();
            p.bump(T![-]);
            expressions::literal(p);
            lm.complete(p, PREFIX_EXPR);
            m.complete(p, CONST_ARG);
        }
        _ => {
            types::type_(p);
            m.complete(p, TYPE_ARG);
        }
    }
}

pub(super) fn const_arg(p: &mut Parser) {
    let m = p.start();
    // FIXME: duplicates the code above
    match p.current() {
        T!['{'] => {
            expressions::block_expr(p);
            m.complete(p, CONST_ARG);
        }
        k if k.is_literal() => {
            expressions::literal(p);
            m.complete(p, CONST_ARG);
        }
        T![true] | T![false] => {
            expressions::literal(p);
            m.complete(p, CONST_ARG);
        }
        T![-] => {
            let lm = p.start();
            p.bump(T![-]);
            expressions::literal(p);
            lm.complete(p, PREFIX_EXPR);
            m.complete(p, CONST_ARG);
        }
        _ => {
            let lm = p.start();
            paths::use_path(p);
            lm.complete(p, PATH_EXPR);
            m.complete(p, CONST_ARG);
        }
    }
}
<commit_msg>fix: correctly handle jointness<commit_after>use super::*;

pub(super) fn opt_generic_arg_list(p: &mut Parser, colon_colon_required: bool) {
    let m;
    if p.at(T![::]) && p.nth(2) == T![<] {
        m = p.start();
        p.bump(T![::]);
        p.bump(T![<]);
    } else if !colon_colon_required && p.at(T![<]) && p.nth(1) != T![=] {
        m = p.start();
        p.bump(T![<]);
    } else {
        return;
    }

    while !p.at(EOF) && !p.at(T![>]) {
        generic_arg(p);
        if !p.at(T![>]) && !p.expect(T![,]) {
            break;
        }
    }
    p.expect(T![>]);
    m.complete(p, GENERIC_ARG_LIST);
}

// test type_arg
// type A = B<'static, i32, 1, { 2 }, Item=u64, true, false>;
fn generic_arg(p: &mut Parser) {
    let m = p.start();
    match p.current() {
        LIFETIME_IDENT => {
            lifetime(p);
            m.complete(p, LIFETIME_ARG);
        }
        // test associated_type_bounds
        // fn print_all<T: Iterator<Item, Item::Item, Item::<true>, Item: Display, Item<'a> = Item>>(printables: T) {}
        IDENT if [T![<], T![=], T![:]].contains(&p.nth(1)) => {
            let path_ty = p.start();
            let path = p.start();
            let path_seg = p.start();
            name_ref(p);
            opt_generic_arg_list(p, false);
            match p.current() {
                // NameRef<...> =
                T![=] => {
                    p.bump_any();
                    types::type_(p);

                    path_seg.abandon(p);
                    path.abandon(p);
                    path_ty.abandon(p);
                    m.complete(p, ASSOC_TYPE_ARG);
                }
                T![:] if p.at(T![::]) => {
                    // NameRef::, this is a path type
                    path_seg.complete(p, PATH_SEGMENT);
                    let qual = path.complete(p, PATH);
                    opt_generic_arg_list(p, false);
                    paths::type_path_for_qualifier(p, qual);
                    path_ty.complete(p, PATH_TYPE);
                    m.complete(p, TYPE_ARG);
                }
                // NameRef<...>:
                T![:] => {
                    generic_params::bounds(p);

                    path_seg.abandon(p);
                    path.abandon(p);
                    path_ty.abandon(p);
                    m.complete(p, ASSOC_TYPE_ARG);
                }
                // NameRef, this is a single segment path type
                _ => {
                    path_seg.complete(p, PATH_SEGMENT);
                    path.complete(p, PATH);
                    path_ty.complete(p, PATH_TYPE);
                    m.complete(p, TYPE_ARG);
                }
            }
        }
        T!['{'] => {
            expressions::block_expr(p);
            m.complete(p, CONST_ARG);
        }
        k if k.is_literal() => {
            expressions::literal(p);
            m.complete(p, CONST_ARG);
        }
        T![true] | T![false] => {
            expressions::literal(p);
            m.complete(p, CONST_ARG);
        }
        // test const_generic_negated_literal
        // fn f() { S::<-1> }
        T![-] => {
            let lm = p.start();
            p.bump(T![-]);
            expressions::literal(p);
            lm.complete(p, PREFIX_EXPR);
            m.complete(p, CONST_ARG);
        }
        _ => {
            types::type_(p);
            m.complete(p, TYPE_ARG);
        }
    }
}

pub(super) fn const_arg(p: &mut Parser) {
    let m = p.start();
    // FIXME: duplicates the code above
    match p.current() {
        T!['{'] => {
            expressions::block_expr(p);
            m.complete(p, CONST_ARG);
        }
        k if k.is_literal() => {
            expressions::literal(p);
            m.complete(p, CONST_ARG);
        }
        T![true] | T![false] => {
            expressions::literal(p);
            m.complete(p, CONST_ARG);
        }
        T![-] => {
            let lm = p.start();
            p.bump(T![-]);
            expressions::literal(p);
            lm.complete(p, PREFIX_EXPR);
            m.complete(p, CONST_ARG);
        }
        _ => {
            let lm = p.start();
            paths::use_path(p);
            lm.complete(p, PATH_EXPR);
            m.complete(p, CONST_ARG);
        }
    }
}
<|endoftext|>