<commit_before>pub mod build;
pub mod parse;

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

use rustc_serialize::json::Json;
use chrono::{DateTime, UTC};
use abra::{Term, Token};
use abra::analysis::AnalyzerSpec;
use abra::analysis::registry::AnalyzerRegistry;
use abra::analysis::tokenizers::TokenizerSpec;
use abra::analysis::filters::FilterSpec;
use abra::similarity::SimilarityModel;
use abra::schema::FieldRef;

// TEMPORARY
fn get_standard_analyzer() -> AnalyzerSpec {
    AnalyzerSpec {
        tokenizer: TokenizerSpec::Standard,
        filters: vec![
            FilterSpec::Lowercase,
            FilterSpec::ASCIIFolding,
        ]
    }
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum FieldType {
    String,
    Integer,
    Boolean,
    Date,
}

impl Default for FieldType {
    fn default() -> FieldType {
        FieldType::String
    }
}

#[derive(Debug, Clone, PartialEq)]
pub struct FieldSearchOptions {
    pub analyzer: AnalyzerSpec,
    pub similarity_model: SimilarityModel,
}

impl Default for FieldSearchOptions {
    fn default() -> FieldSearchOptions {
        FieldSearchOptions {
            analyzer: get_standard_analyzer(),
            similarity_model: SimilarityModel::Bm25 {
                k1: 1.2,
                b: 0.75,
            },
        }
    }
}

#[derive(Debug, PartialEq)]
pub struct FieldMapping {
    pub data_type: FieldType,
    pub index_ref: Option<FieldRef>,
    is_stored: bool,
    pub is_in_all: bool,
    boost: f64,
    base_analyzer: AnalyzerSpec,
    index_analyzer: Option<AnalyzerSpec>,
    search_analyzer: Option<AnalyzerSpec>,
}

impl Default for FieldMapping {
    fn default() -> FieldMapping {
        FieldMapping {
            data_type: FieldType::default(),
            index_ref: None,
            is_stored: false,
            is_in_all: true,
            boost: 1.0f64,
            base_analyzer: get_standard_analyzer(),
            index_analyzer: None,
            search_analyzer: None,
        }
    }
}

impl FieldMapping {
    pub fn index_analyzer(&self) -> &AnalyzerSpec {
        if let Some(ref index_analyzer) = self.index_analyzer {
            index_analyzer
        } else {
            &self.base_analyzer
        }
    }

    pub fn search_analyzer(&self) -> &AnalyzerSpec {
        if let Some(ref search_analyzer) = self.search_analyzer {
            search_analyzer
        } else {
            &self.base_analyzer
        }
    }

    pub fn get_search_options(&self) -> FieldSearchOptions {
        FieldSearchOptions {
            analyzer: self.search_analyzer().clone(),
            .. FieldSearchOptions::default()
        }
    }

    pub fn process_value_for_index(&self, value: Json) -> Option<Vec<Token>> {
        if value == Json::Null {
            return None;
        }

        match self.data_type {
            FieldType::String => {
                match value {
                    Json::String(string) => {
                        // Analyze string
                        let tokens = self.index_analyzer().initialise(&string);
                        Some(tokens.collect::<Vec<Token>>())
                    }
                    Json::I64(num) => self.process_value_for_index(Json::String(num.to_string())),
                    Json::U64(num) => self.process_value_for_index(Json::String(num.to_string())),
                    Json::F64(num) => self.process_value_for_index(Json::String(num.to_string())),
                    Json::Array(array) => {
                        // Pack any strings into a vec, ignore nulls. Quit if we see anything else
                        let mut strings = Vec::new();

                        for item in array {
                            match item {
                                Json::String(string) => strings.push(string),
                                Json::Null => {}
                                _ => {
                                    return None;
                                }
                            }
                        }

                        self.process_value_for_index(Json::String(strings.join(" ")))
                    }
                    _ => None,
                }
            }
            FieldType::Integer => {
                match value {
                    Json::U64(num) => Some(vec![Token{term: Term::I64(num as i64), position: 1}]),
                    Json::I64(num) => Some(vec![Token{term: Term::I64(num), position: 1}]),
                    _ => None,
                }
            }
            FieldType::Boolean => Some(vec![Token{term: Term::Boolean(parse_boolean(&value)), position: 1}]),
            FieldType::Date => {
                match value {
                    Json::String(string) => {
                        let date_parsed = match string.parse::<DateTime<UTC>>() {
                            Ok(date_parsed) => date_parsed,
                            Err(_) => {
                                // TODO: Handle this properly
                                return None;
                            }
                        };

                        Some(vec![Token{term: Term::DateTime(date_parsed), position: 1}])
                    }
                    Json::U64(_) => {
                        // TODO needs to be interpreted as milliseconds since epoch
                        // This would really help: https://github.com/lifthrasiir/rust-chrono/issues/74
                        None
                    }
                    _ => None
                }
            }
        }
    }
}

#[derive(Debug, PartialEq)]
pub struct Mapping {
    pub fields: HashMap<String, FieldMapping>,
}

impl Mapping {
    pub fn from_json(analyzers: &AnalyzerRegistry, json: &Json) -> Mapping {
        let json = json.as_object().unwrap();
        let properties_json = json.get("properties").unwrap().as_object().unwrap();

        // Parse fields
        let mut fields = HashMap::new();
        for (field_name, field_mapping_json) in properties_json.iter() {
            fields.insert(field_name.clone(),
                          FieldMapping::from_json(analyzers, field_mapping_json));
        }

        // Insert _all field
        if !fields.contains_key("_all") {
            // TODO: Support disabling the _all field
            fields.insert("_all".to_string(), FieldMapping {
                data_type: FieldType::String,
                is_stored: false,
                is_in_all: false,
                .. FieldMapping::default()
            });
        }

        Mapping { fields: fields }
    }
}

fn parse_boolean(json: &Json) -> bool {
    match *json {
        Json::Boolean(val) => val,
        Json::String(ref s) => {
            match s.as_ref() {
                "yes" => true,
                "no" => false,
                _ => {
                    warn!("bad boolean value {:?}", s);
                    false
                }
            }
        }
        _ => {
            // TODO: Raise error
            warn!("bad boolean value {:?}", json);
            false
        }
    }
}

impl FieldMapping {
    pub fn from_json(analyzers: &AnalyzerRegistry, json: &Json) -> FieldMapping {
        let json = json.as_object().unwrap();
        let mut field_mapping = FieldMapping::default();

        for (key, value) in json.iter() {
            match key.as_ref() {
                "type" => {
                    let type_name = value.as_string().unwrap();

                    field_mapping.data_type = match type_name.as_ref() {
                        "string" => FieldType::String,
                        "integer" => FieldType::Integer,
                        "boolean" => FieldType::Boolean,
                        "date" => FieldType::Date,
                        _ => {
                            // TODO; make this an error
                            warn!("unimplemented type name! {}", type_name);
                            FieldType::default()
                        }
                    };
                }
                "index" => {
                    let index = value.as_string().unwrap();
                    if index == "not_analyzed" {
                        field_mapping.index_analyzer = None;
                        field_mapping.search_analyzer = None;
                    } else {
                        // TODO: Implement other variants and make this an error
                        warn!("unimplemented index setting! {}", index);
                    }
                }
                "analyzer" => {
                    if let Some(ref s) = value.as_string() {
                        match analyzers.get(*s) {
                            Some(analyzer) => {
                                field_mapping.base_analyzer = analyzer.clone();
                            }
                            None => warn!("unknown analyzer! {}", s)
                        }
                    }
                }
                "index_analyzer" => {
                    if let Some(ref s) = value.as_string() {
                        match analyzers.get(*s) {
                            Some(analyzer) => {
                                field_mapping.index_analyzer = Some(analyzer.clone());
                            }
                            None => warn!("unknown analyzer! {}", s)
                        }
                    }
                }
                "search_analyzer" => {
                    if let Some(ref s) = value.as_string() {
                        match analyzers.get(*s) {
                            Some(analyzer) => {
                                field_mapping.search_analyzer = Some(analyzer.clone());
                            }
                            None => warn!("unknown analyzer! {}", s)
                        }
                    }
                }
                "boost" => {
                    field_mapping.boost = value.as_f64().unwrap();
                }
                "store" => {
                    field_mapping.is_stored = parse_boolean(value);
                }
                "include_in_all" => {
                    field_mapping.is_in_all = parse_boolean(value);
                }
                _ => warn!("unimplemented field mapping key! {}", key),
            }

        }

        field_mapping
    }
}

#[derive(Debug)]
pub struct MappingRegistry {
    mappings: HashMap<String, Mapping>,
}

impl MappingRegistry {
    pub fn new() -> MappingRegistry {
        MappingRegistry {
            mappings: HashMap::new(),
        }
    }

    pub fn get_field(&self, name: &str) -> Option<&FieldMapping> {
        for mapping in self.mappings.values() {
            if let Some(ref field_mapping) = mapping.fields.get(name) {
                return Some(field_mapping);
            }
        }

        None
    }
}

impl Deref for MappingRegistry {
    type Target = HashMap<String, Mapping>;

    fn deref(&self) -> &HashMap<String, Mapping> {
        &self.mappings
    }
}

impl DerefMut for MappingRegistry {
    fn deref_mut(&mut self) -> &mut HashMap<String, Mapping> {
        &mut self.mappings
    }
}
<commit_msg>Remove old mapping parser<commit_after>pub mod build;
pub mod parse;

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

use rustc_serialize::json::Json;
use chrono::{DateTime, UTC};
use abra::{Term, Token};
use abra::analysis::AnalyzerSpec;
use abra::analysis::registry::AnalyzerRegistry;
use abra::analysis::tokenizers::TokenizerSpec;
use abra::analysis::filters::FilterSpec;
use abra::similarity::SimilarityModel;
use abra::schema::FieldRef;

// TEMPORARY
fn get_standard_analyzer() -> AnalyzerSpec {
    AnalyzerSpec {
        tokenizer: TokenizerSpec::Standard,
        filters: vec![
            FilterSpec::Lowercase,
            FilterSpec::ASCIIFolding,
        ]
    }
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum FieldType {
    String,
    Integer,
    Boolean,
    Date,
}

impl Default for FieldType {
    fn default() -> FieldType {
        FieldType::String
    }
}

#[derive(Debug, Clone, PartialEq)]
pub struct FieldSearchOptions {
    pub analyzer: AnalyzerSpec,
    pub similarity_model: SimilarityModel,
}

impl Default for FieldSearchOptions {
    fn default() -> FieldSearchOptions {
        FieldSearchOptions {
            analyzer: get_standard_analyzer(),
            similarity_model: SimilarityModel::Bm25 {
                k1: 1.2,
                b: 0.75,
            },
        }
    }
}

#[derive(Debug, PartialEq)]
pub struct FieldMapping {
    pub data_type: FieldType,
    pub index_ref: Option<FieldRef>,
    is_stored: bool,
    pub is_in_all: bool,
    boost: f64,
    base_analyzer: AnalyzerSpec,
    index_analyzer: Option<AnalyzerSpec>,
    search_analyzer: Option<AnalyzerSpec>,
}

impl Default for FieldMapping {
    fn default() -> FieldMapping {
        FieldMapping {
            data_type: FieldType::default(),
            index_ref: None,
            is_stored: false,
            is_in_all: true,
            boost: 1.0f64,
            base_analyzer: get_standard_analyzer(),
            index_analyzer: None,
            search_analyzer: None,
        }
    }
}

impl FieldMapping {
    pub fn index_analyzer(&self) -> &AnalyzerSpec {
        if let Some(ref index_analyzer) = self.index_analyzer {
            index_analyzer
        } else {
            &self.base_analyzer
        }
    }

    pub fn search_analyzer(&self) -> &AnalyzerSpec {
        if let Some(ref search_analyzer) = self.search_analyzer {
            search_analyzer
        } else {
            &self.base_analyzer
        }
    }

    pub fn get_search_options(&self) -> FieldSearchOptions {
        FieldSearchOptions {
            analyzer: self.search_analyzer().clone(),
            .. FieldSearchOptions::default()
        }
    }

    pub fn process_value_for_index(&self, value: Json) -> Option<Vec<Token>> {
        if value == Json::Null {
            return None;
        }

        match self.data_type {
            FieldType::String => {
                match value {
                    Json::String(string) => {
                        // Analyze string
                        let tokens = self.index_analyzer().initialise(&string);
                        Some(tokens.collect::<Vec<Token>>())
                    }
                    Json::I64(num) => self.process_value_for_index(Json::String(num.to_string())),
                    Json::U64(num) => self.process_value_for_index(Json::String(num.to_string())),
                    Json::F64(num) => self.process_value_for_index(Json::String(num.to_string())),
                    Json::Array(array) => {
                        // Pack any strings into a vec, ignore nulls. Quit if we see anything else
                        let mut strings = Vec::new();

                        for item in array {
                            match item {
                                Json::String(string) => strings.push(string),
                                Json::Null => {}
                                _ => {
                                    return None;
                                }
                            }
                        }

                        self.process_value_for_index(Json::String(strings.join(" ")))
                    }
                    _ => None,
                }
            }
            FieldType::Integer => {
                match value {
                    Json::U64(num) => Some(vec![Token{term: Term::I64(num as i64), position: 1}]),
                    Json::I64(num) => Some(vec![Token{term: Term::I64(num), position: 1}]),
                    _ => None,
                }
            }
            FieldType::Boolean => Some(vec![Token{term: Term::Boolean(parse_boolean(&value)), position: 1}]),
            FieldType::Date => {
                match value {
                    Json::String(string) => {
                        let date_parsed = match string.parse::<DateTime<UTC>>() {
                            Ok(date_parsed) => date_parsed,
                            Err(_) => {
                                // TODO: Handle this properly
                                return None;
                            }
                        };

                        Some(vec![Token{term: Term::DateTime(date_parsed), position: 1}])
                    }
                    Json::U64(_) => {
                        // TODO needs to be interpreted as milliseconds since epoch
                        // This would really help: https://github.com/lifthrasiir/rust-chrono/issues/74
                        None
                    }
                    _ => None
                }
            }
        }
    }
}

#[derive(Debug, PartialEq)]
pub struct Mapping {
    pub fields: HashMap<String, FieldMapping>,
}

#[derive(Debug)]
pub struct MappingRegistry {
    mappings: HashMap<String, Mapping>,
}

fn parse_boolean(json: &Json) -> bool {
    match *json {
        Json::Boolean(val) => val,
        Json::String(ref s) => {
            match s.as_ref() {
                "yes" => true,
                "no" => false,
                _ => {
                    warn!("bad boolean value {:?}", s);
                    false
                }
           }
        }
        _ => {
            // TODO: Raise error
            warn!("bad boolean value {:?}", json);
            false
        }
    }
}

impl MappingRegistry {
    pub fn new() -> MappingRegistry {
        MappingRegistry {
            mappings: HashMap::new(),
        }
    }

    pub fn get_field(&self, name: &str) -> Option<&FieldMapping> {
        for mapping in self.mappings.values() {
            if let Some(ref field_mapping) = mapping.fields.get(name) {
                return Some(field_mapping);
            }
        }

        None
    }
}

impl Deref for MappingRegistry {
    type Target = HashMap<String, Mapping>;

    fn deref(&self) -> &HashMap<String, Mapping> {
        &self.mappings
    }
}

impl DerefMut for MappingRegistry {
    fn deref_mut(&mut self) -> &mut HashMap<String, Mapping> {
        &mut self.mappings
    }
}
<|endoftext|>


<commit_before>// {
//   Derived from : Bjoern Hoehrmann work
//   Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
//   See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.

pub const UTF8_ACCEPT: u32 = 0;
pub const UTF8_REJECT: u32 = 1;

static UTF8D: &'static [u8] = &[
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 00..1f
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 20..3f
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 40..5f
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 60..7f
  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, // 80..9f
  7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, // a0..bf
  8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // c0..df
  0xa,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x3,0x3, // e0..ef
  0xb,0x6,0x6,0x6,0x5,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, // f0..ff
  0x0,0x1,0x2,0x3,0x5,0x8,0x7,0x1,0x1,0x1,0x4,0x6,0x1,0x1,0x1,0x1, // s0..s0
  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1, // s1..s2
  1,2,1,1,1,1,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1, // s3..s4
  1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,1,1,1,1, // s5..s6
  1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // s7..s8
];

/*
    state UTF8_ACCEPT => initial state or decoding successful
    state UTF8_REJECT => error
    state other => intermediate states need more inputs
*/
#[inline]
pub fn decode_byte(state: &mut u32, byte: u8, codep: &mut u32) -> u32 {

    let cp_type = UTF8D[byte as usize] as u32;

    *codep = if *state != UTF8_ACCEPT {
        (byte & 0x3f) as u32 | (*codep << 6)
    } else {
        (0xff >> cp_type) as u32 & (byte as u32)
    };

    *state = UTF8D[256 + (*state * 16) as usize + cp_type as usize] as u32;
    *state
}

// }

#[inline]
pub fn is_codepoint_start(byte: u8) -> bool {

    if byte < 0x80 {
        return true;
    }

    if byte >= 0xC2 && byte <= 0xDF {
        return true;
    }

    if byte >= 0xC2 && byte <= 0xDF {
        return true;
    }

    if byte >= 0xE0 && byte <= 0xEC {
        return true;
    }

    if byte >= 0xED && byte <= 0xEF {
        return true;
    }

    if byte >= 0xF0 && byte <= 0xF4 {
        return true;
    }

    false
}

// return 0 on error, or the number of written bytes
pub fn encode(codepoint: u32, out: &mut [u8; 4]) -> usize {
    if codepoint < 0x80 {
        out[0] = (codepoint & 0x7F) as u8;
        return 1;
    }

    if codepoint < 0x800 {
        out[0] = 0xC0 | (codepoint >> 6) as u8;
        out[1] = 0x80 | (codepoint & 0x3F) as u8;
        return 2;
    }

    if codepoint < 0xFFFF {
        out[0] = 0xE0 | (codepoint >> 12) as u8;
        out[1] = 0x80 | (codepoint >> 6) as u8;
        out[2] = 0x80 | (codepoint & 0x3F) as u8;
        return 3;
    }

    if codepoint < 0x10FFFF {
        out[0] = 0xF0 | (codepoint >> 18) as u8;
        out[1] = 0x80 | (codepoint >> 12) as u8;
        out[2] = 0x80 | (codepoint >> 6) as u8;
        out[3] = 0x80 | (codepoint & 0x3F) as u8;
        return 4;
    }

    0
}

// TODO: change this with temporary (cp, offset, size) until from_offset
pub fn get_previous_codepoint_start(data: &[u8], from_offset: u64) -> u64 {

    // TODO: replace vec by array
    let mut vec = Vec::with_capacity(8);

    // rewind upto 4 bytes
    // and decode forward / save offset
    let mut off = if from_offset > 4 { from_offset - 4 } else { 0 };
    while off != from_offset {
        let (cp, _, size) = get_codepoint(data, off);
        vec.push((cp, size, off));
        off += size as u64;
    }

    if vec.len() != 0 {
        vec[vec.len() - 1].2
    } else {
        from_offset
    }
}

pub fn get_next_codepoint_start(data: &[u8], from_offset: u64) -> u64 {
    let (_, _, size) = get_codepoint(data, from_offset);
    from_offset + size as u64
}

pub fn get_codepoint(data: &[u8], from_offset: u64) -> (char, u64, usize) {

    let mut state = 0;
    let mut codep = 0;
    let mut size = 0;

    for off in from_offset as usize..data.len() {

        let b = data[off];

        size += 1;
        state = decode_byte(&mut state, b, &mut codep);
        match state {
            0 => {
                break;
            }
            1 => {
                // decode error : invalid sequence
                codep = 0xfffd;
                size = 1; // force restart @ next byte
                break;
            }
            _ => {}
        }
    }

    // TODO return Result<(char, usize), status> -> state != 1|0 -> need mode data
    (::core::codec::text::u32_to_char(codep), from_offset, size)
}

pub fn get_prev_codepoint(data: &[u8], from_offset: u64) -> (char, u64, usize) {
    let offset = get_previous_codepoint_start(data, from_offset);
    get_codepoint(data, offset)
}

#[test]
fn test_codec_encode() {

    let expect_cp: [u8; 4] = [0xe2, 0x82, 0xac, 0x00];
    let mut mut_cp: [u8; 4] = [0x00, 0x00, 0x00, 0x00];

    let n = encode(0x20ac as u32, &mut mut_cp);
    assert_eq!(n, 3);
    assert_eq!(mut_cp, expect_cp);

}

#[test]
fn test_codec_decode() {

    use core::codec::text::u32_to_char;

    let mut state: u32 = 0;
    let mut codep: u32 = 0;

    let sequence: [u8; 4] = [0xe2, 0x82, 0xac, 0x00];
    for b in &sequence {
        println!("decode byte '{:x}'", *b);
        state = decode_byte(&mut state, *b, &mut codep);
        match state {
            UTF8_ACCEPT => {
                break;
            }
            UTF8_REJECT => {
                println!("invalid utf8 sequence");
                break;
            }
            _ => {
                continue;
            }
        }
    }

    println!("decoded codepoint value {:x}", codep);
    let c = u32_to_char(codep);
    println!("decoded codepoint char {}", c);

    assert_eq!(codep, 0x20ac);
}

#[test]
fn test2_codec_decode() {

    let data: [u8; 27] = [0xe2, 0x82, 0xac, 0xe2, 0x82, 0x61, 0x0a, 0x82, 0xac, 0xe2, 0x82, 0x61,
                          0x0a, 0xac, 0xe2, 0x82, 0x61, 0x0a, 0xe2, 0x82, 0x61, 0x0a, 0x82, 0x61,
                          0x0a, 0x61, 0x0a];

    let mut state: u32 = 0;
    let mut codep: u32 = 0;

    for b in &data {
        println!("decode byte '{:x}'", *b);
        state = decode_byte(&mut state, *b, &mut codep);
        println!("state  '{}'", state);
        match state {
            UTF8_ACCEPT => {
                println!("decoded cp = '{:?}'", codep);
                state = 0;
                codep = 0;
            }
            UTF8_REJECT => {
                println!("invalid utf8 sequence, restart");
                state = 0;
                codep = 0;
                state = decode_byte(&mut state, *b, &mut codep);
                match state {
                    UTF8_ACCEPT => {
                        println!("decoded cp = '{:?}'", codep);
                        state = 0;
                        codep = 0;
                    }
                    UTF8_REJECT => {
                        println!("invalid utf8 sequence, restart");
                        state = 0;
                        codep = 0;
                    }
                    _ => {}

                }
            }

            _ => {
                continue;
            }
        }
    }
}
<commit_msg>utf8 : fn get_previous_codepoint_start(...) : replace vec by array<commit_after>// {
//   Derived from : Bjoern Hoehrmann work
//   Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
//   See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.

pub const UTF8_ACCEPT: u32 = 0;
pub const UTF8_REJECT: u32 = 1;

static UTF8D: &'static [u8] = &[
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 00..1f
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 20..3f
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 40..5f
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 60..7f
  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, // 80..9f
  7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, // a0..bf
  8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // c0..df
  0xa,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x3,0x3, // e0..ef
  0xb,0x6,0x6,0x6,0x5,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, // f0..ff
  0x0,0x1,0x2,0x3,0x5,0x8,0x7,0x1,0x1,0x1,0x4,0x6,0x1,0x1,0x1,0x1, // s0..s0
  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1, // s1..s2
  1,2,1,1,1,1,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1, // s3..s4
  1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,1,1,1,1, // s5..s6
  1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // s7..s8
];

/*
    state UTF8_ACCEPT => initial state or decoding successful
    state UTF8_REJECT => error
    state other => intermediate states need more inputs
*/
#[inline]
pub fn decode_byte(state: &mut u32, byte: u8, codep: &mut u32) -> u32 {

    let cp_type = UTF8D[byte as usize] as u32;

    *codep = if *state != UTF8_ACCEPT {
        (byte & 0x3f) as u32 | (*codep << 6)
    } else {
        (0xff >> cp_type) as u32 & (byte as u32)
    };

    *state = UTF8D[256 + (*state * 16) as usize + cp_type as usize] as u32;
    *state
}

// }

#[inline]
pub fn is_codepoint_start(byte: u8) -> bool {

    if byte < 0x80 {
        return true;
    }

    if byte >= 0xC2 && byte <= 0xDF {
        return true;
    }

    if byte >= 0xC2 && byte <= 0xDF {
        return true;
    }

    if byte >= 0xE0 && byte <= 0xEC {
        return true;
    }

    if byte >= 0xED && byte <= 0xEF {
        return true;
    }

    if byte >= 0xF0 && byte <= 0xF4 {
        return true;
    }

    false
}

// return 0 on error, or the number of written bytes
pub fn encode(codepoint: u32, out: &mut [u8; 4]) -> usize {
    if codepoint < 0x80 {
        out[0] = (codepoint & 0x7F) as u8;
        return 1;
    }

    if codepoint < 0x800 {
        out[0] = 0xC0 | (codepoint >> 6) as u8;
        out[1] = 0x80 | (codepoint & 0x3F) as u8;
        return 2;
    }

    if codepoint < 0xFFFF {
        out[0] = 0xE0 | (codepoint >> 12) as u8;
        out[1] = 0x80 | (codepoint >> 6) as u8;
        out[2] = 0x80 | (codepoint & 0x3F) as u8;
        return 3;
    }

    if codepoint < 0x10FFFF {
        out[0] = 0xF0 | (codepoint >> 18) as u8;
        out[1] = 0x80 | (codepoint >> 12) as u8;
        out[2] = 0x80 | (codepoint >> 6) as u8;
        out[3] = 0x80 | (codepoint & 0x3F) as u8;
        return 4;
    }

    0
}

// TODO: change this with temporary (cp, offset, size) until from_offset
pub fn get_previous_codepoint_start(data: &[u8], from_offset: u64) -> u64 {

    //                 cp    size   offset
    let mut cp_info: [(char, usize, u64); 8] = [('\0', 0, 0),
                                                ('\0', 0, 0),
                                                ('\0', 0, 0),
                                                ('\0', 0, 0),
                                                ('\0', 0, 0),
                                                ('\0', 0, 0),
                                                ('\0', 0, 0),
                                                ('\0', 0, 0)];
    let mut nr_cpinfo = 0;

    // rewind upto 4 bytes
    // and decode forward / save offset
    let mut off = if from_offset > 4 { from_offset - 4 } else { 0 };
    while off != from_offset {
        let (cp, _, size) = get_codepoint(data, off);

        cp_info[nr_cpinfo] = (cp, size, off);
        nr_cpinfo += 1;

        off += size as u64;
    }

    if nr_cpinfo != 0 {
        cp_info[nr_cpinfo - 1].2
    } else {
        from_offset
    }
}

pub fn get_next_codepoint_start(data: &[u8], from_offset: u64) -> u64 {
    let (_, _, size) = get_codepoint(data, from_offset);
    from_offset + size as u64
}

pub fn get_codepoint(data: &[u8], from_offset: u64) -> (char, u64, usize) {

    let mut state = 0;
    let mut codep = 0;
    let mut size = 0;

    for off in from_offset as usize..data.len() {

        let b = data[off];

        size += 1;
        state = decode_byte(&mut state, b, &mut codep);
        match state {
            0 => {
                break;
            }
            1 => {
                // decode error : invalid sequence
                codep = 0xfffd;
                size = 1; // force restart @ next byte
                break;
            }
            _ => {}
        }
    }

    // TODO return Result<(char, usize), status> -> state != 1|0 -> need mode data
    (::core::codec::text::u32_to_char(codep), from_offset, size)
}

pub fn get_prev_codepoint(data: &[u8], from_offset: u64) -> (char, u64, usize) {
    let offset = get_previous_codepoint_start(data, from_offset);
    get_codepoint(data, offset)
}

#[test]
fn test_codec_encode() {

    let expect_cp: [u8; 4] = [0xe2, 0x82, 0xac, 0x00];
    let mut mut_cp: [u8; 4] = [0x00, 0x00, 0x00, 0x00];

    let n = encode(0x20ac as u32, &mut mut_cp);
    assert_eq!(n, 3);
    assert_eq!(mut_cp, expect_cp);

}

#[test]
fn test_codec_decode() {

    use core::codec::text::u32_to_char;

    let mut state: u32 = 0;
    let mut codep: u32 = 0;

    let sequence: [u8; 4] = [0xe2, 0x82, 0xac, 0x00];
    for b in &sequence {
        println!("decode byte '{:x}'", *b);
        state = decode_byte(&mut state, *b, &mut codep);
        match state {
            UTF8_ACCEPT => {
                break;
            }
            UTF8_REJECT => {
                println!("invalid utf8 sequence");
                break;
            }
            _ => {
                continue;
            }
        }
    }

    println!("decoded codepoint value {:x}", codep);
    let c = u32_to_char(codep);
    println!("decoded codepoint char {}", c);

    assert_eq!(codep, 0x20ac);
}

#[test]
fn test2_codec_decode() {

    let data: [u8; 27] = [0xe2, 0x82, 0xac, 0xe2, 0x82, 0x61, 0x0a, 0x82, 0xac, 0xe2, 0x82, 0x61,
                          0x0a, 0xac, 0xe2, 0x82, 0x61, 0x0a, 0xe2, 0x82, 0x61, 0x0a, 0x82, 0x61,
                          0x0a, 0x61, 0x0a];

    let mut state: u32 = 0;
    let mut codep: u32 = 0;

    for b in &data {
        println!("decode byte '{:x}'", *b);
        state = decode_byte(&mut state, *b, &mut codep);
        println!("state  '{}'", state);
        match state {
            UTF8_ACCEPT => {
                println!("decoded cp = '{:?}'", codep);
                state = 0;
                codep = 0;
            }
            UTF8_REJECT => {
                println!("invalid utf8 sequence, restart");
                state = 0;
                codep = 0;
                state = decode_byte(&mut state, *b, &mut codep);
                match state {
                    UTF8_ACCEPT => {
                        println!("decoded cp = '{:?}'", codep);
                        state = 0;
                        codep = 0;
                    }
                    UTF8_REJECT => {
                        println!("invalid utf8 sequence, restart");
                        state = 0;
                        codep = 0;
                    }
                    _ => {}

                }
            }

            _ => {
                continue;
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

#![feature(custom_test_frameworks)]
#![test_runner(datatest::runner)]

#[macro_use]
extern crate lazy_static;

use functional_tests::{
    checker::{check, Directive},
    config::{
        global::{Config as GlobalConfig, Entry as GlobalConfigEntry},
        transaction::{
            is_new_transaction, Config as TransactionConfig, Entry as TransactionConfigEntry,
        },
    },
    errors::*,
    evaluator::{eval, Transaction},
};
use regex::{Captures, Regex};
use std::collections::BTreeMap;
use vm_runtime_tests::account::AccountData;

fn substitute_addresses(accounts: &BTreeMap<String, AccountData>, text: &str) -> Result<String> {
    lazy_static! {
        static ref PAT: Regex = Regex::new(r"\{\{([A-Za-z][A-Za-z0-9]*)\}\}").unwrap();
    }
    Ok(PAT
        .replace_all(text, |caps: &Captures| {
            let name = &caps[1];
            match accounts.get(name) {
                Some(data) => format!("0x{}", data.address()),
                None => panic!(
                    "account '{}' does not exist, cannot substitute address",
                    name
                ),
            }
        })
        .to_string())
}

fn parse_input(s: &str) -> Result<(GlobalConfig, Vec<Directive>, Vec<Transaction>)> {
    let mut global_config = vec![];
    let mut directives = vec![];
    let mut text = vec![];
    let mut transaction_config = vec![];
    let mut transactions = vec![];

    for line in s.lines() {
        if is_new_transaction(line) {
            // TODO: check empty
            transactions.push((transaction_config, text));
            text = vec![];
            transaction_config = vec![];
            continue;
        }
        if let Ok(entry) = line.parse::<GlobalConfigEntry>() {
            global_config.push(entry);
            continue;
        }
        if let Ok(entry) = line.parse::<TransactionConfigEntry>() {
            transaction_config.push(entry);
            continue;
        }
        if let Ok(directive) = line.parse::<Directive>() {
            directives.push(directive);
            continue;
        }
        text.push(line.to_string());
    }
    transactions.push((transaction_config, text));

    let global_config = GlobalConfig::build(&global_config)?;
    let transactions = transactions
        .iter()
        .map(|(config, text)| {
            let config = TransactionConfig::build(&global_config, &config)?;
            Ok(Transaction {
                config,
                program: substitute_addresses(&global_config.accounts, &text.join("\n"))?,
            })
        })
        .collect::<Result<Vec<_>>>()?;
    println!("{:?}", transactions);
    Ok((global_config, directives, transactions))
}

// Runs all tests under the test/testsuite directory.
#[datatest::files("tests/testsuite", { input in r".*\.mvir" })]
fn functional_tests(input: &str) -> Result<()> {
    let (config, directives, transactions) = parse_input(input)?;
    let res = eval(&config, &transactions)?;
    if let Err(e) = check(&res, &directives) {
        println!("{:#?}", res);
        return Err(e);
    }
    Ok(())
}
<commit_msg>[functional tests] return String instead of Result<String> in substitute_addresses<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

#![feature(custom_test_frameworks)]
#![test_runner(datatest::runner)]

#[macro_use]
extern crate lazy_static;

use functional_tests::{
    checker::{check, Directive},
    config::{
        global::{Config as GlobalConfig, Entry as GlobalConfigEntry},
        transaction::{
            is_new_transaction, Config as TransactionConfig, Entry as TransactionConfigEntry,
        },
    },
    errors::*,
    evaluator::{eval, Transaction},
};
use regex::{Captures, Regex};
use std::collections::BTreeMap;
use vm_runtime_tests::account::AccountData;

fn substitute_addresses(accounts: &BTreeMap<String, AccountData>, text: &str) -> String {
    lazy_static! {
        static ref PAT: Regex = Regex::new(r"\{\{([A-Za-z][A-Za-z0-9]*)\}\}").unwrap();
    }
    PAT.replace_all(text, |caps: &Captures| {
        let name = &caps[1];
        match accounts.get(name) {
            Some(data) => format!("0x{}", data.address()),
            // TODO: find a way to return an error instead of panicking
            None => panic!(
                "account '{}' does not exist, cannot substitute address",
                name
            ),
        }
    })
    .to_string()
}

fn parse_input(s: &str) -> Result<(GlobalConfig, Vec<Directive>, Vec<Transaction>)> {
    let mut global_config = vec![];
    let mut directives = vec![];
    let mut text = vec![];
    let mut transaction_config = vec![];
    let mut transactions = vec![];

    for line in s.lines() {
        if is_new_transaction(line) {
            // TODO: check empty
            transactions.push((transaction_config, text));
            text = vec![];
            transaction_config = vec![];
            continue;
        }
        if let Ok(entry) = line.parse::<GlobalConfigEntry>() {
            global_config.push(entry);
            continue;
        }
        if let Ok(entry) = line.parse::<TransactionConfigEntry>() {
            transaction_config.push(entry);
            continue;
        }
        if let Ok(directive) = line.parse::<Directive>() {
            directives.push(directive);
            continue;
        }
        text.push(line.to_string());
    }
    transactions.push((transaction_config, text));

    let global_config = GlobalConfig::build(&global_config)?;
    let transactions = transactions
        .iter()
        .map(|(config, text)| {
            let config = TransactionConfig::build(&global_config, &config)?;
            Ok(Transaction {
                config,
                program: substitute_addresses(&global_config.accounts, &text.join("\n")),
            })
        })
        .collect::<Result<Vec<_>>>()?;
    println!("{:?}", transactions);
    Ok((global_config, directives, transactions))
}

// Runs all tests under the test/testsuite directory.
#[datatest::files("tests/testsuite", { input in r".*\.mvir" })]
fn functional_tests(input: &str) -> Result<()> {
    let (config, directives, transactions) = parse_input(input)?;
    let res = eval(&config, &transactions)?;
    if let Err(e) = check(&res, &directives) {
        println!("{:#?}", res);
        return Err(e);
    }
    Ok(())
}
<|endoftext|>


<commit_before>use std::option::Option;
use std::ops::Deref;

use rocksdb::{DB, Writable, DBIterator, Direction, IteratorMode, DBVector, WriteBatch};
use rocksdb::rocksdb::Snapshot;
use protobuf;
use byteorder::{ByteOrder, BigEndian};

use raftserver::{Result, other};

pub fn new_engine(path: &str) -> Result<DB> {
    // TODO: set proper options here,
    let db = try!(DB::open_default(path));
    Ok(db)
}

pub enum DBValue {
    DBVector(DBVector),
    Box(Box<[u8]>),
}

impl Deref for DBValue {
    type Target = [u8];
    fn deref(&self) -> &[u8] {
        match *self {
            DBValue::DBVector(ref v) => return v,
            DBValue::Box(ref v) => return v,
        }
    }
}

pub trait Retriever {
    fn get_value(&self, key: &[u8]) -> Result<Option<DBValue>>;
    fn new_iterator(&self, start_key: &[u8]) -> DBIterator;

    fn get_msg<M>(&self, key: &[u8]) -> Result<Option<M>>
        where M: protobuf::Message + protobuf::MessageStatic
    {
        let value = try!(self.get_value(key));

        if value.is_none() {
            return Ok(None);
        }

        let mut m = M::new();
        try!(m.merge_from_bytes(&value.unwrap()));
        Ok(Some(m))
    }

    fn get_u64(&self, key: &[u8]) -> Result<Option<u64>> {
        let value = try!(self.get_value(key));

        if value.is_none() {
            return Ok(None);
        }

        let value = value.unwrap();
        if value.len() != 8 {
            return Err(other(format!("need 8 bytes, but only got {}", value.len())));
        }

        let n = BigEndian::read_u64(&value);
        Ok(Some(n))
    }

    fn get_i64(&self, key: &[u8]) -> Result<Option<i64>> {
        let r = try!(self.get_u64(key));
        match r {
            None => Ok(None),
            Some(n) => Ok(Some(n as i64)),
        }
    }

    // scan scans database using an iterator in range [start_key, end_key), calls function f for
    // each iteration, if f returns false, terminates this scan.
    fn scan<F>(&self, start_key: &[u8], end_key: &[u8], f: &mut F) -> Result<()>
        where F: FnMut(&[u8], &[u8]) -> Result<bool>
    {
        let mut it = self.new_iterator(start_key);

        while let Some((key, value)) = it.next() {
            if key.as_ref() >= end_key {
                break;
            }

            let r = try!(f(key.as_ref(), value.as_ref()));
            if !r {
                break;
            }
        }

        Ok(())
    }
}

impl Retriever for DB {
    fn get_value(&self, key: &[u8]) -> Result<Option<DBValue>> {
        let v = try!(self.get(key));
        Ok(v.map(|e| DBValue::DBVector(e)))
    }

    fn new_iterator(&self, start_key: &[u8]) -> DBIterator {
        self.iterator(IteratorMode::From(start_key, Direction::forward))
    }
}

impl<'a> Retriever for Snapshot<'a> {
    fn get_value(&self, key: &[u8]) -> Result<Option<DBValue>> {
        let mut it = self.iterator(IteratorMode::From(key, Direction::forward));
        if let Some((seek_key, value)) = it.next() {
            if seek_key.as_ref() == key {
                return Ok(Some(DBValue::Box(value)));
            }
        }
        Ok(None)
    }

    fn new_iterator(&self, start_key: &[u8]) -> DBIterator {
        self.iterator(IteratorMode::From(start_key, Direction::forward))
    }
}

pub trait Mutator : Writable{
    fn put_msg<M: protobuf::Message>(&self, key: &[u8], m: &M) -> Result<()> {
        let value = try!(m.write_to_bytes());
        try!(self.put(key, &value));
        Ok(())
    }

    fn put_u64(&self, key: &[u8], n: u64) -> Result<()> {
        let mut value = vec![0;8];
        BigEndian::write_u64(&mut value, n);
        try!(self.put(key, &value));
        Ok(())
    }

    fn put_i64(&self, key: &[u8], n: i64) -> Result<()> {
        self.put_u64(key, n as u64)
    }
}

impl Mutator for DB {}
impl Mutator for WriteBatch {}

#[cfg(test)]
mod tests {
    use tempdir::TempDir;
    use rocksdb::Writable;

    use super::*;
    use raftserver::Result;
    use proto::metapb::Region;

    #[test]
    fn test_base() {
        let path = TempDir::new("var").unwrap();
        let engine = new_engine(path.path().to_str().unwrap()).unwrap();

        let mut r = Region::new();
        r.set_region_id(10);

        let key = b"key";
        engine.put_msg(key, &r).unwrap();

        let snap = engine.snapshot();

        let mut r1: Region = engine.get_msg(key).unwrap().unwrap();
        assert_eq!(r, r1);

        let mut r2: Region = snap.get_msg(key).unwrap().unwrap();
        assert_eq!(r, r2);

        r.set_region_id(11);
        engine.put_msg(key, &r).unwrap();
        r1 = engine.get_msg(key).unwrap().unwrap();
        r2 = snap.get_msg(key).unwrap().unwrap();
        assert!(r1 != r2);

        let b: Option<Region> = engine.get_msg(b"missing_key").unwrap();
        assert!(b.is_none());

        engine.put_i64(key, -1).unwrap();
        assert_eq!(engine.get_i64(key).unwrap(), Some(-1));
        assert!(engine.get_i64(b"missing_key").unwrap().is_none());

        engine.put_u64(key, 1).unwrap();
        assert_eq!(engine.get_u64(key).unwrap(), Some(1));
    }

    #[test]
    fn test_scan() {
        let path = TempDir::new("var").unwrap();
        let engine = new_engine(path.path().to_str().unwrap()).unwrap();

        engine.put(b"a1", b"v1").unwrap();
        engine.put(b"a2", b"v2").unwrap();

        let mut data = vec![];
        engine.scan(b"",
                    &[0xFF, 0xFF],
                    &mut |key, value| -> Result<bool> {
                        data.push((key.to_vec(), value.to_vec()));
                        Ok(true)
                    })
              .unwrap();

        assert_eq!(data.len(), 2);

        data.clear();
        let mut index = 0;
        engine.scan(b"",
                    &[0xFF, 0xFF],
                    &mut |key, value| -> Result<bool> {
                        data.push((key.to_vec(), value.to_vec()));
                        index += 1;
                        Ok(index != 1)
                    })
              .unwrap();

        assert_eq!(data.len(), 1);

        let snap = engine.snapshot();

        engine.put(b"a3", b"v3").unwrap();

        data.clear();

        snap.scan(b"",
                  &[0xFF, 0xFF],
                  &mut |key, value| -> Result<bool> {
                      data.push((key.to_vec(), value.to_vec()));
                      Ok(true)
                  })
            .unwrap();

        assert_eq!(data.len(), 2);
    }
}
<commit_msg>raftserver: add test.<commit_after>use std::option::Option;
use std::ops::Deref;

use rocksdb::{DB, Writable, DBIterator, Direction, IteratorMode, DBVector, WriteBatch};
use rocksdb::rocksdb::Snapshot;
use protobuf;
use byteorder::{ByteOrder, BigEndian};

use raftserver::{Result, other};

pub fn new_engine(path: &str) -> Result<DB> {
    // TODO: set proper options here,
    let db = try!(DB::open_default(path));
    Ok(db)
}

pub enum DBValue {
    DBVector(DBVector),
    Box(Box<[u8]>),
}

impl Deref for DBValue {
    type Target = [u8];
    fn deref(&self) -> &[u8] {
        match *self {
            DBValue::DBVector(ref v) => return v,
            DBValue::Box(ref v) => return v,
        }
    }
}

pub trait Retriever {
    fn get_value(&self, key: &[u8]) -> Result<Option<DBValue>>;
    fn new_iterator(&self, start_key: &[u8]) -> DBIterator;

    fn get_msg<M>(&self, key: &[u8]) -> Result<Option<M>>
        where M: protobuf::Message + protobuf::MessageStatic
    {
        let value = try!(self.get_value(key));

        if value.is_none() {
            return Ok(None);
        }

        let mut m = M::new();
        try!(m.merge_from_bytes(&value.unwrap()));
        Ok(Some(m))
    }

    fn get_u64(&self, key: &[u8]) -> Result<Option<u64>> {
        let value = try!(self.get_value(key));

        if value.is_none() {
            return Ok(None);
        }

        let value = value.unwrap();
        if value.len() != 8 {
            return Err(other(format!("need 8 bytes, but only got {}", value.len())));
        }

        let n = BigEndian::read_u64(&value);
        Ok(Some(n))
    }

    fn get_i64(&self, key: &[u8]) -> Result<Option<i64>> {
        let r = try!(self.get_u64(key));
        match r {
            None => Ok(None),
            Some(n) => Ok(Some(n as i64)),
        }
    }

    // scan scans database using an iterator in range [start_key, end_key), calls function f for
    // each iteration, if f returns false, terminates this scan.
    fn scan<F>(&self, start_key: &[u8], end_key: &[u8], f: &mut F) -> Result<()>
        where F: FnMut(&[u8], &[u8]) -> Result<bool>
    {
        let mut it = self.new_iterator(start_key);

        while let Some((key, value)) = it.next() {
            if key.as_ref() >= end_key {
                break;
            }

            let r = try!(f(key.as_ref(), value.as_ref()));
            if !r {
                break;
            }
        }

        Ok(())
    }
}

impl Retriever for DB {
    fn get_value(&self, key: &[u8]) -> Result<Option<DBValue>> {
        let v = try!(self.get(key));
        Ok(v.map(|e| DBValue::DBVector(e)))
    }

    fn new_iterator(&self, start_key: &[u8]) -> DBIterator {
        self.iterator(IteratorMode::From(start_key, Direction::forward))
    }
}

impl<'a> Retriever for Snapshot<'a> {
    fn get_value(&self, key: &[u8]) -> Result<Option<DBValue>> {
        let mut it = self.iterator(IteratorMode::From(key, Direction::forward));
        if let Some((seek_key, value)) = it.next() {
            if seek_key.as_ref() == key {
                return Ok(Some(DBValue::Box(value)));
            }
        }
        Ok(None)
    }

    fn new_iterator(&self, start_key: &[u8]) -> DBIterator {
        self.iterator(IteratorMode::From(start_key, Direction::forward))
    }
}

pub trait Mutator : Writable{
    fn put_msg<M: protobuf::Message>(&self, key: &[u8], m: &M) -> Result<()> {
        let value = try!(m.write_to_bytes());
        try!(self.put(key, &value));
        Ok(())
    }

    fn put_u64(&self, key: &[u8], n: u64) -> Result<()> {
        let mut value = vec![0;8];
        BigEndian::write_u64(&mut value, n);
        try!(self.put(key, &value));
        Ok(())
    }

    fn put_i64(&self, key: &[u8], n: i64) -> Result<()> {
        self.put_u64(key, n as u64)
    }
}

impl Mutator for DB {}
impl Mutator for WriteBatch {}

#[cfg(test)]
mod tests {
    use tempdir::TempDir;
    use rocksdb::Writable;

    use super::*;
    use raftserver::Result;
    use proto::metapb::Region;

    #[test]
    fn test_base() {
        let path = TempDir::new("var").unwrap();
        let engine = new_engine(path.path().to_str().unwrap()).unwrap();

        let mut r = Region::new();
        r.set_region_id(10);

        let key = b"key";
        engine.put_msg(key, &r).unwrap();

        let snap = engine.snapshot();

        let mut r1: Region = engine.get_msg(key).unwrap().unwrap();
        assert_eq!(r, r1);

        let mut r2: Region = snap.get_msg(key).unwrap().unwrap();
        assert_eq!(r, r2);

        r.set_region_id(11);
        engine.put_msg(key, &r).unwrap();
        r1 = engine.get_msg(key).unwrap().unwrap();
        r2 = snap.get_msg(key).unwrap().unwrap();
        assert!(r1 != r2);

        let b: Option<Region> = engine.get_msg(b"missing_key").unwrap();
        assert!(b.is_none());

        engine.put_i64(key, -1).unwrap();
        assert_eq!(engine.get_i64(key).unwrap(), Some(-1));
        assert!(engine.get_i64(b"missing_key").unwrap().is_none());

        let snap = engine.snapshot();
        assert_eq!(snap.get_i64(key).unwrap(), Some(-1));
        assert!(snap.get_i64(b"missing_key").unwrap().is_none());

        engine.put_u64(key, 1).unwrap();
        assert_eq!(engine.get_u64(key).unwrap(), Some(1));
        assert_eq!(snap.get_i64(key).unwrap(), Some(-1));
    }

    #[test]
    fn test_scan() {
        let path = TempDir::new("var").unwrap();
        let engine = new_engine(path.path().to_str().unwrap()).unwrap();

        engine.put(b"a1", b"v1").unwrap();
        engine.put(b"a2", b"v2").unwrap();

        let mut data = vec![];
        engine.scan(b"",
                    &[0xFF, 0xFF],
                    &mut |key, value| -> Result<bool> {
                        data.push((key.to_vec(), value.to_vec()));
                        Ok(true)
                    })
              .unwrap();

        assert_eq!(data.len(), 2);

        data.clear();
        let mut index = 0;
        engine.scan(b"",
                    &[0xFF, 0xFF],
                    &mut |key, value| -> Result<bool> {
                        data.push((key.to_vec(), value.to_vec()));
                        index += 1;
                        Ok(index != 1)
                    })
              .unwrap();

        assert_eq!(data.len(), 1);

        let snap = engine.snapshot();

        engine.put(b"a3", b"v3").unwrap();

        data.clear();

        snap.scan(b"",
                  &[0xFF, 0xFF],
                  &mut |key, value| -> Result<bool> {
                      data.push((key.to_vec(), value.to_vec()));
                      Ok(true)
                  })
            .unwrap();

        assert_eq!(data.len(), 2);
    }
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;
use rustc_serialize::json::{ToJson, Json};
use postgres;
use uuid::Uuid;
use error::Error;
use chrono::{NaiveDateTime, UTC, DateTime};
use super::{conn, PaginatedCollection};
use Track;
use Playlist;

static PROPS: [&'static str; 8]  = ["id",
                                    "url",
                                    "title",
                                    "description",
                                    "visual_url",
                                    "locale",
                                    "created_at",
                                    "updated_at"];

fn props_str() -> String {
    PROPS.join(",")
}

#[derive(Debug, Clone)]
pub struct Entry {
    pub id:          Uuid,
    pub url:         String,
    pub title:       Option<String>,
    pub description: Option<String>,
    pub visual_url:  Option<String>,
    pub locale:      Option<String>,
    pub created_at:  NaiveDateTime,
    pub updated_at:  NaiveDateTime,
    pub tracks:      Vec<Track>,
    pub playlists:   Vec<Playlist>,
}

impl ToJson for Entry {
    fn to_json(&self) -> Json {
        let created_at = DateTime::<UTC>::from_utc(self.created_at  , UTC);
        let updated_at = DateTime::<UTC>::from_utc(self.updated_at  , UTC);
        let mut d      = BTreeMap::new();
        let tracks     = Json::Array(self.tracks.iter().map(|x| x.to_json()).collect());
        let playlists  = Json::Array(self.playlists.iter().map(|x| x.to_json()).collect());
        let albums     = Json::Array(self.albums.iter().map(|x| x.to_json()).collect());
        d.insert("id".to_string()         , self.id.to_string().to_json());
        d.insert("url".to_string()        , self.url.to_json());
        d.insert("title".to_string()      , self.title.to_json());
        d.insert("description".to_string(), self.description.to_json());
        d.insert("visual_url".to_string() , self.visual_url.to_json());
        d.insert("locale".to_string()     , self.locale.to_json());
        d.insert("created_at".to_string() , created_at.to_rfc3339().to_json());
        d.insert("updated_at".to_string() , updated_at.to_rfc3339().to_json());
        d.insert("tracks".to_string()     , tracks);
        d.insert("playlists".to_string()  , playlists);
        d.insert("albums".to_string()     , albums);
        Json::Object(d)
    }
}

impl Entry {
    fn rows_to_entries(rows: postgres::rows::Rows) -> Vec<Entry> {
        let mut entries = Vec::new();
        for row in rows.iter() {
            entries.push(Entry {
                id:          row.get(0),
                url:         row.get(1),
                title:       row.get(2),
                description: row.get(3),
                visual_url:  row.get(4),
                locale:      row.get(5),
                created_at:  row.get(6),
                updated_at:  row.get(7),
                tracks:      Track::find_by_entry_id(row.get(0)),
                playlists:   Playlist::find_by_entry_id(row.get(0)),
            })
        }
        entries
    }

    pub fn find_by_id(id: String) -> Result<Entry, Error> {
        let conn = conn().unwrap();
        let stmt = conn.prepare(
            &format!("SELECT {} FROM entries
                        WHERE id = $1", props_str())).unwrap();
        let rows = stmt.query(&[&id]).unwrap();
        let entries = Entry::rows_to_entries(rows);
        if entries.len() > 0 {
            return Ok(entries[0].clone());
        }
        return Err(Error::NotFound)
    }

    pub fn find_by_url(url: &str) -> Result<Entry, Error> {
        let conn = conn().unwrap();
        let stmt = conn.prepare(
            &format!("SELECT {} FROM entries
                        WHERE url = $1", props_str())).unwrap();
        let rows = stmt.query(&[&url]).unwrap();
        let entries = Entry::rows_to_entries(rows);
        if entries.len() > 0 {
            return Ok(entries[0].clone());
        }
        return Err(Error::NotFound)
    }

    pub fn find(page: i64, per_page: i64) -> PaginatedCollection<Entry> {
        let conn = conn().unwrap();
        let stmt = conn.prepare(
            &format!("SELECT {} FROM entries
                        ORDER BY updated_at DESC
                        LIMIT $2 OFFSET $1", props_str())).unwrap();
        let offset = page * per_page;
        let rows = stmt.query(&[&offset, &per_page]).unwrap();
        let entries = Entry::rows_to_entries(rows);
        let mut total: i64 = 0;
        for row in conn.query("SELECT COUNT(*) FROM entries", &[]).unwrap().iter() {
            total = row.get(0);
        }
        PaginatedCollection {
            page:     page,
            per_page: per_page,
            total:    total,
            items:    entries,
        }
    }

    pub fn find_or_create_by_url(url: String) -> Result<Entry, Error> {
        match Entry::find_by_url(&url) {
            Ok(entry) => Ok(entry),
            Err(_)    => Entry::create_by_url(url)
        }
    }

    pub fn create_by_url(url: String) -> Result<Entry, Error> {
        let conn = conn().unwrap();
        let stmt = conn.prepare("INSERT INTO entries (url) VALUES ($1) RETURNING id").unwrap();
        for row in stmt.query(&[&url]).unwrap().iter() {
            let entry = Entry {
                id:          row.get(0),
                url:         url,
                title:       None,
                description: None,
                visual_url:  None,
                locale:      None,
                created_at:  UTC::now().naive_utc(),
                updated_at:  UTC::now().naive_utc(),
                tracks:      Vec::new(),
                playlists:   Vec::new(),
            };
            return Ok(entry);
        }
        Err(Error::Unexpected)
    }

    pub fn add_track(&mut self, track: Track) {
        let conn = conn().unwrap();
        let stmt = conn.prepare("INSERT INTO track_entries (track_id, entry_id)
                                 VALUES ($1, $2)").unwrap();
        stmt.query(&[&track.id, &self.id]).unwrap();
        self.tracks.push(track);
    }

    pub fn add_playlist(&mut self, playlist: Playlist) {
        let conn = conn().unwrap();
        let stmt = conn.prepare("INSERT INTO playlist_entries (playlist_id, entry_id)
                                 VALUES ($1, $2)").unwrap();
        stmt.query(&[&playlist.id, &self.id]).unwrap();
        self.playlists.push(playlist);
    }

    pub fn save(&mut self) -> Result<(), Error> {
        self.updated_at = UTC::now().naive_utc();
        let conn = conn().unwrap();
        let stmt = conn.prepare("UPDATE entries SET
                                   url         = $2,
                                   title       = $3,
                                   description = $4,
                                   visual_url  = $5,
                                   locale      = $6,
                                   created_at  = $7,
                                   updated_at  = $8
                                 WHERE id = $1").unwrap();
        let result = stmt.query(&[&self.id,
                                  &self.url,
                                  &self.title,
                                  &self.description,
                                  &self.visual_url,
                                  &self.locale,
                                  &self.created_at,
                                  &self.updated_at]);
        try!(result);
        Ok(())
    }
}
<commit_msg>Entry conforms Model trait<commit_after>use std::collections::BTreeMap;
use rustc_serialize::json::{ToJson, Json};
use postgres;
use uuid::Uuid;
use error::Error;
use chrono::{NaiveDateTime, UTC, DateTime};
use super::{conn, Model};
use model::enclosure::Enclosure;
use Track;
use Playlist;
use Album;

static PROPS: [&'static str; 8]  = ["id",
                                    "url",
                                    "title",
                                    "description",
                                    "visual_url",
                                    "locale",
                                    "created_at",
                                    "updated_at"];

#[derive(Debug, Clone)]
pub struct Entry {
    pub id:          Uuid,
    pub url:         String,
    pub title:       Option<String>,
    pub description: Option<String>,
    pub visual_url:  Option<String>,
    pub locale:      Option<String>,
    pub created_at:  NaiveDateTime,
    pub updated_at:  NaiveDateTime,
    pub tracks:      Vec<Track>,
    pub playlists:   Vec<Playlist>,
    pub albums:      Vec<Album>,
}

impl ToJson for Entry {
    fn to_json(&self) -> Json {
        let created_at = DateTime::<UTC>::from_utc(self.created_at  , UTC);
        let updated_at = DateTime::<UTC>::from_utc(self.updated_at  , UTC);
        let mut d      = BTreeMap::new();
        let tracks     = Json::Array(self.tracks.iter().map(|x| x.to_json()).collect());
        let playlists  = Json::Array(self.playlists.iter().map(|x| x.to_json()).collect());
        let albums     = Json::Array(self.albums.iter().map(|x| x.to_json()).collect());
        d.insert("id".to_string()         , self.id.to_string().to_json());
        d.insert("url".to_string()        , self.url.to_json());
        d.insert("title".to_string()      , self.title.to_json());
        d.insert("description".to_string(), self.description.to_json());
        d.insert("visual_url".to_string() , self.visual_url.to_json());
        d.insert("locale".to_string()     , self.locale.to_json());
        d.insert("created_at".to_string() , created_at.to_rfc3339().to_json());
        d.insert("updated_at".to_string() , updated_at.to_rfc3339().to_json());
        d.insert("tracks".to_string()     , tracks);
        d.insert("playlists".to_string()  , playlists);
        d.insert("albums".to_string()     , albums);
        Json::Object(d)
    }
}

impl Model for Entry {
    fn table_name() -> String {
        "entries".to_string()
    }
    fn props_str(prefix: &str) -> String {
        PROPS
            .iter()
            .map(|&p| format!("{}{}", prefix, p))
            .collect::<Vec<String>>().join(",")
    }
    fn rows_to_items(rows: postgres::rows::Rows) -> Vec<Entry> {
        let mut entries = Vec::new();
        for row in rows.iter() {
            entries.push(Entry {
                id:          row.get(0),
                url:         row.get(1),
                title:       row.get(2),
                description: row.get(3),
                visual_url:  row.get(4),
                locale:      row.get(5),
                created_at:  row.get(6),
                updated_at:  row.get(7),
                tracks:      Track::find_by_entry_id(row.get(0)),
                playlists:   Playlist::find_by_entry_id(row.get(0)),
                albums:      Album::find_by_entry_id(row.get(0)),
            })
        }
        entries
    }
    fn create(&self) -> Result<Entry, Error> {
        let conn = try!(conn());
        let stmt = try!(conn.prepare("INSERT INTO entries (url) VALUES ($1) RETURNING id"));
        let rows = try!(stmt.query(&[&self.url]));
        let mut entry = self.clone();
        for row in rows.iter() {
            entry.id = row.get(0);
        }
        Ok(entry)
    }
    fn save(&mut self) -> Result<(), Error> {
        self.updated_at = UTC::now().naive_utc();
        let conn = try!(conn());
        let stmt = try!(conn.prepare("UPDATE entries SET
                                   url         = $2,
                                   title       = $3,
                                   description = $4,
                                   visual_url  = $5,
                                   locale      = $6,
                                   created_at  = $7,
                                   updated_at  = $8
                                 WHERE id = $1"));
        let result = stmt.query(&[&self.id,
                                  &self.url,
                                  &self.title,
                                  &self.description,
                                  &self.visual_url,
                                  &self.locale,
                                  &self.created_at,
                                  &self.updated_at]);
        try!(result);
        Ok(())
    }
}

impl Entry {
    pub fn new(url: String) -> Result<Entry, Error> {
        let conn = try!(conn());
        let stmt = try!(conn.prepare("INSERT INTO entries (url) VALUES ($1) RETURNING id"));
        let rows = try!(stmt.query(&[&url]));
        for row in rows.iter() {
            let entry = Entry {
                id:          row.get(0),
                url:         url,
                title:       None,
                description: None,
                visual_url:  None,
                locale:      None,
                created_at:  UTC::now().naive_utc(),
                updated_at:  UTC::now().naive_utc(),
                tracks:      Vec::new(),
                playlists:   Vec::new(),
                albums:      Vec::new(),
            };
            return Ok(entry);
        }
        Err(Error::Unexpected)
    }

    pub fn find_by_url(url: &str) -> Result<Entry, Error> {
        let conn = try!(conn());
        let stmt = try!(conn.prepare(
            &format!("SELECT {} FROM entries
                        WHERE url = $1", Self::props_str(""))));
        let rows = try!(stmt.query(&[&url]));
        let entries = Entry::rows_to_items(rows);
        if entries.len() > 0 {
            return Ok(entries[0].clone());
        }
        return Err(Error::NotFound)
    }

    pub fn find_or_create_by_url(url: String) -> Result<Entry, Error> {
        match Entry::find_by_url(&url) {
            Ok(entry) => Ok(entry),
            Err(_)    => Entry::create_by_url(url)
        }
    }

    pub fn create_by_url(url: String) -> Result<Entry, Error> {
        let conn = try!(conn());
        let stmt = try!(conn.prepare("INSERT INTO entries (url) VALUES ($1) RETURNING id"));
        let rows = try!(stmt.query(&[&url]));
        for row in rows.iter() {
            let entry = Entry {
                id:          row.get(0),
                url:         url,
                title:       None,
                description: None,
                visual_url:  None,
                locale:      None,
                created_at:  UTC::now().naive_utc(),
                updated_at:  UTC::now().naive_utc(),
                tracks:      Vec::new(),
                playlists:   Vec::new(),
                albums:      Vec::new(),
            };
            return Ok(entry);
        }
        Err(Error::Unexpected)
    }

    pub fn add_track(&mut self, track: Track) -> Result<(), Error> {
        let conn = try!(conn());
        let stmt = try!(conn.prepare("INSERT INTO track_entries (track_id, entry_id)
                                 VALUES ($1, $2)"));
        try!(stmt.query(&[&track.id, &self.id]));
        self.tracks.push(track);
        Ok(())
    }

    pub fn add_playlist(&mut self, playlist: Playlist) -> Result<(), Error> {
        let conn = try!(conn());
        let stmt = try!(conn.prepare("INSERT INTO playlist_entries (playlist_id, entry_id)
                                 VALUES ($1, $2)"));
        try!(stmt.query(&[&playlist.id, &self.id]));
        self.playlists.push(playlist);
        Ok(())
    }

    pub fn add_album(&mut self, album: Album) -> Result<(), Error> {
        let conn = try!(conn());
        let stmt = try!(conn.prepare("INSERT INTO album_entries (album_id, entry_id)
                                 VALUES ($1, $2)"));
        try!(stmt.query(&[&album.id, &self.id]));
        self.albums.push(album);
        Ok(())
    }
}
<|endoftext|>


<commit_before>//  y
//  2 _|_|_
//  1 _|_|_
//  0  | |
//    0 1 2 x
use std::collections::LinkedList;
use std::io::stdin;

struct Step {
    loc: Loc,
    who: i8
}

struct Loc {
    x: i8,
    y: i8,
}

struct EachRecord {
    win: Vec<Loc>,
    draw: Vec<Loc>,
    lose: Vec<Loc>
}
fn main() {
    let mut table : LinkedList<Step> = LinkedList::new();
    let mut record : [EachRecord; 19683];
    loop {
        if end_check(&table) {
            table.clear();
        }
        print(&table);
        let mut input = String::new();
        match stdin().read_line(&mut input) {
            Ok(_) => {},
            Err(_) => continue,
        };
        let tmp: Vec<&str> = input.trim().split(' ').collect();
        let x = tmp[0].parse::<i8>().unwrap();
        let y = tmp[1].parse::<i8>().unwrap();
        check(&mut table, x, y, 1);
    }
}

fn check(table: &mut LinkedList<Step>, x: i8, y: i8, who: i8) {
    table.push_back(Step { loc: Loc{x:x, y:y}, who: who});
}

fn end_check(table: &LinkedList<Step>) -> bool {
    return table.len() > 8;
}

fn add2record(table: &[[i8; 3]; 3], record: &mut [EachRecord; 19683]) {
    // Step(x, y, who) -> EachRecord[table]:
    //                      win: Vec<Loc NextStep>,  draw: Vec<Loc>,  lose: Vec<Loc>
    let t = table_status(table);
}

fn table_status(table: &[[i8; 3]; 3]) -> i8 {
    // ret
    // 0 = unfinished
    // 1 = win 0
    // 2 = win 1
    // 3 = draw

    // xxx * 3 x      x
    //         x * 3   x  * 3
    //         x        x
    let t1 = test1(&table);
    let t2 = test2(&table);
    let t3 = test3(&table);
    return 0;
}

fn test1(table: &[[i8; 3]; 3]) -> i8 {
    for i in 0 .. 3 {
        if table[i][0] != 0 &&
           table[i][0] == table[i][1] &&
           table[i][1] == table[i][2] {
            return table[i][0];
        }
    }
    return 0;
}

fn test2(table: &[[i8; 3]; 3]) -> i8 {
    for i in 0 .. 3 {
        if table[0][i] != 0 &&
           table[1][i] == table[0][i] &&
           table[2][i] == table[1][i] {
            return table[0][i];
        }
    }
    return 0;
}

fn test3(table: &[[i8; 3]; 3]) -> i8 {
    //  y
    //  2 *|_|*
    //  1 _|*|_
    //  0 *| |*
    //    0 1 2 x
    if table[0][0] != 0 && table[0][0] == table[1][1] && table[1][1] == table[2][2] {
        return table[0][0];
    } else if table[2][0] != 0 && table[2][0] == table[1][1] && table[1][1] == table[0][2] {
        return table[2][0];
    } else {
        return 0;
    }
}

fn steplist2array(table: &LinkedList<Step>) -> [[i8; 3]; 3] {
    let mut t : [[i8; 3]; 3] = [[0, 0, 0], [0, 0, 0], [0, 0, 0]];
    for i in table.iter() {
        t[i.loc.x as usize][i.loc.y as usize] = i.who;
    }
    return t;
}

fn print(table: &LinkedList<Step>) {
    let t = steplist2array(&table);
    for y in (0..3).rev() {
        for x in 0..3 {
            print!("{}", t[x][y]);
        }
        println!();
    }
}<commit_msg>Script commit at 01/04/2017  0:00:01 UTC+8<commit_after>//  y
//  2 _|_|_
//  1 _|_|_
//  0  | |
//    0 1 2 x
use std::collections::LinkedList;
use std::io::stdin;

struct Step {
    loc: Loc,
    who: i8
}

struct Loc {
    x: i8,
    y: i8,
}

struct EachRecord {
    win: Vec<Loc>,
    draw: Vec<Loc>,
    lose: Vec<Loc>
}

fn main() {
    let mut table : LinkedList<Step> = LinkedList::new();
    let mut record : [EachRecord; 19683];
    loop {
        if end_check(&table) {
            table.clear();
        }
        print(&table);
        let mut input = String::new();
        match stdin().read_line(&mut input) {
            Ok(_) => {},
            Err(_) => continue,
        };
        let tmp: Vec<&str> = input.trim().split(' ').collect();
        let x = tmp[0].parse::<i8>().unwrap();
        let y = tmp[1].parse::<i8>().unwrap();
        check(&mut table, x, y, 1);
    }
}

fn check(table: &mut LinkedList<Step>, x: i8, y: i8, who: i8) {
    table.push_back(Step { loc: Loc{x:x, y:y}, who: who});
}

fn end_check(table: &LinkedList<Step>) -> bool {
    return table.len() > 8;
}

fn add2record(table: &[[i8; 3]; 3], record: &mut [EachRecord; 19683]) {
    // Step(x, y, who) -> EachRecord[table]:
    //                      win: Vec<Loc NextStep>,  draw: Vec<Loc>,  lose: Vec<Loc>
    let t = table_status(table);
}

fn table_status(table: &[[i8; 3]; 3]) -> i8 {
    // ret
    // 0 = unfinished
    // 1 = win 0
    // 2 = win 1
    // 3 = draw

    // xxx * 3 x      x
    //         x * 3   x  * 3
    //         x        x
    let t1 = test1(&table);
    let t2 = test2(&table);
    let t3 = test3(&table);
    return 0;
}

fn test1(table: &[[i8; 3]; 3]) -> i8 {
    for i in 0 .. 3 {
        if table[i][0] != 0 &&
           table[i][0] == table[i][1] &&
           table[i][1] == table[i][2] {
            return table[i][0];
        }
    }
    return 0;
}

fn test2(table: &[[i8; 3]; 3]) -> i8 {
    for i in 0 .. 3 {
        if table[0][i] != 0 &&
           table[1][i] == table[0][i] &&
           table[2][i] == table[1][i] {
            return table[0][i];
        }
    }
    return 0;
}

fn test3(table: &[[i8; 3]; 3]) -> i8 {
    //  y
    //  2 *|_|*
    //  1 _|*|_
    //  0 *| |*
    //    0 1 2 x
    if table[0][0] != 0 && table[0][0] == table[1][1] && table[1][1] == table[2][2] {
        return table[0][0];
    } else if table[2][0] != 0 && table[2][0] == table[1][1] && table[1][1] == table[0][2] {
        return table[2][0];
    } else {
        return 0;
    }
}

fn steplist2array(table: &LinkedList<Step>) -> [[i8; 3]; 3] {
    let mut t : [[i8; 3]; 3] = [[0, 0, 0], [0, 0, 0], [0, 0, 0]];
    for i in table.iter() {
        t[i.loc.x as usize][i.loc.y as usize] = i.who;
    }
    return t;
}

fn print(table: &LinkedList<Step>) {
    let t = steplist2array(&table);
    for y in (0..3).rev() {
        for x in 0..3 {
            print!("{}", t[x][y]);
        }
        println!();
    }
}<|endoftext|>


<commit_before>/// Quasi-quotation macro that accepts input like the [`quote!`] macro but uses
/// type inference to figure out a return type for those tokens.
///
/// [`quote!`]: https://docs.rs/quote/0.4/quote/index.html
///
/// The return type can be any syntax tree node that implements the [`Synom`]
/// trait.
///
/// [`Synom`]: synom/trait.Synom.html
///
/// ```
/// #[macro_use]
/// extern crate syn;
///
/// #[macro_use]
/// extern crate quote;
///
/// use syn::Stmt;
///
/// fn main() {
///     let name = quote!(v);
///     let ty = quote!(u8);
///
///     let stmt: Stmt = parse_quote! {
///         let #name: #ty = Default::default();
///     };
///
///     println!("{:#?}", stmt);
/// }
/// ```
///
/// *This macro is available if Syn is built with the `"parsing"` feature,
/// although interpolation of syntax tree nodes into the quoted tokens is only
/// supported if Syn is built with the `"printing"` feature as well.*
///
/// # Example
///
/// The following helper function adds a bound `T: HeapSize` to every type
/// parameter `T` in the input generics.
///
/// ```
/// # #[macro_use]
/// # extern crate syn;
/// #
/// # #[macro_use]
/// # extern crate quote;
/// #
/// # use syn::{Generics, GenericParam};
/// #
/// // Add a bound `T: HeapSize` to every type parameter T.
/// fn add_trait_bounds(mut generics: Generics) -> Generics {
///     for param in &mut generics.params {
///         if let GenericParam::Type(ref mut type_param) = *param {
///             type_param.bounds.push(parse_quote!(HeapSize));
///         }
///     }
///     generics
/// }
/// #
/// # fn main() {}
/// ```
///
/// # Special cases
///
/// This macro can parse the following additional types as a special case even
/// though they do not implement the `Synom` trait.
///
/// - [`Attribute`] — parses one attribute, allowing either outer like `#[...]`
///   or inner like `#![...]`
/// - [`Punctuated<T, P>`] — parses zero or more `T` separated by punctuation
///   `P` with optional trailing punctuation
///
/// [`Attribute`]: struct.Attribute.html
/// [`Punctuated<T, P>`]: punctuated/struct.Punctuated.html
///
/// # Panics
///
/// Panics if the tokens fail to parse as the expected syntax tree type. The
/// caller is responsible for ensuring that the input tokens are syntactically
/// valid.
#[macro_export]
macro_rules! parse_quote {
    ($($tt:tt)*) => {
        $crate::parse_quote::parse($crate::parse_quote::From::from(quote!($($tt)*)))
    };
}

////////////////////////////////////////////////////////////////////////////////
// Can parse any type that implements Synom.

use buffer::Cursor;
use proc_macro2::TokenStream;
use synom::{PResult, Parser, Synom};

// Not public API.
#[doc(hidden)]
pub use std::convert::From;

// Not public API.
#[doc(hidden)]
pub fn parse<T: ParseQuote>(token_stream: TokenStream) -> T {
    let parser = T::parse;
    match parser.parse2(token_stream) {
        Ok(t) => t,
        Err(err) => match T::description() {
            Some(s) => panic!("failed to parse {}: {}", s, err),
            None => panic!("{}", err),
        },
    }
}

// Not public API.
#[doc(hidden)]
pub trait ParseQuote: Sized {
    fn parse(input: Cursor) -> PResult<Self>;
    fn description() -> Option<&'static str>;
}

impl<T> ParseQuote for T
where
    T: Synom,
{
    fn parse(input: Cursor) -> PResult<Self> {
        <T as Synom>::parse(input)
    }

    fn description() -> Option<&'static str> {
        <T as Synom>::description()
    }
}

////////////////////////////////////////////////////////////////////////////////
// Any other types that we want `parse_quote!` to be able to parse.

use punctuated::Punctuated;

#[cfg(any(feature = "full", feature = "derive"))]
use Attribute;

impl<T, P> ParseQuote for Punctuated<T, P>
where
    T: Synom,
    P: Synom,
{
    named!(parse -> Self, call!(Punctuated::parse_terminated));

    fn description() -> Option<&'static str> {
        Some("punctuated sequence")
    }
}

#[cfg(any(feature = "full", feature = "derive"))]
impl ParseQuote for Attribute {
    named!(parse -> Self, alt!(
        call!(Attribute::old_parse_outer)
        |
        call!(Attribute::old_parse_inner)
    ));

    fn description() -> Option<&'static str> {
        Some("attribute")
    }
}
<commit_msg>Remove ParseQuote for Punctuated<commit_after>/// Quasi-quotation macro that accepts input like the [`quote!`] macro but uses
/// type inference to figure out a return type for those tokens.
///
/// [`quote!`]: https://docs.rs/quote/0.4/quote/index.html
///
/// The return type can be any syntax tree node that implements the [`Synom`]
/// trait.
///
/// [`Synom`]: synom/trait.Synom.html
///
/// ```
/// #[macro_use]
/// extern crate syn;
///
/// #[macro_use]
/// extern crate quote;
///
/// use syn::Stmt;
///
/// fn main() {
///     let name = quote!(v);
///     let ty = quote!(u8);
///
///     let stmt: Stmt = parse_quote! {
///         let #name: #ty = Default::default();
///     };
///
///     println!("{:#?}", stmt);
/// }
/// ```
///
/// *This macro is available if Syn is built with the `"parsing"` feature,
/// although interpolation of syntax tree nodes into the quoted tokens is only
/// supported if Syn is built with the `"printing"` feature as well.*
///
/// # Example
///
/// The following helper function adds a bound `T: HeapSize` to every type
/// parameter `T` in the input generics.
///
/// ```
/// # #[macro_use]
/// # extern crate syn;
/// #
/// # #[macro_use]
/// # extern crate quote;
/// #
/// # use syn::{Generics, GenericParam};
/// #
/// // Add a bound `T: HeapSize` to every type parameter T.
/// fn add_trait_bounds(mut generics: Generics) -> Generics {
///     for param in &mut generics.params {
///         if let GenericParam::Type(ref mut type_param) = *param {
///             type_param.bounds.push(parse_quote!(HeapSize));
///         }
///     }
///     generics
/// }
/// #
/// # fn main() {}
/// ```
///
/// # Special cases
///
/// This macro can parse the following additional types as a special case even
/// though they do not implement the `Synom` trait.
///
/// - [`Attribute`] — parses one attribute, allowing either outer like `#[...]`
///   or inner like `#![...]`
/// - [`Punctuated<T, P>`] — parses zero or more `T` separated by punctuation
///   `P` with optional trailing punctuation
///
/// [`Attribute`]: struct.Attribute.html
/// [`Punctuated<T, P>`]: punctuated/struct.Punctuated.html
///
/// # Panics
///
/// Panics if the tokens fail to parse as the expected syntax tree type. The
/// caller is responsible for ensuring that the input tokens are syntactically
/// valid.
#[macro_export]
macro_rules! parse_quote {
    ($($tt:tt)*) => {
        $crate::parse_quote::parse($crate::parse_quote::From::from(quote!($($tt)*)))
    };
}

////////////////////////////////////////////////////////////////////////////////
// Can parse any type that implements Synom.

use buffer::Cursor;
use proc_macro2::TokenStream;
use synom::{PResult, Parser, Synom};

// Not public API.
#[doc(hidden)]
pub use std::convert::From;

// Not public API.
#[doc(hidden)]
pub fn parse<T: ParseQuote>(token_stream: TokenStream) -> T {
    let parser = T::parse;
    match parser.parse2(token_stream) {
        Ok(t) => t,
        Err(err) => match T::description() {
            Some(s) => panic!("failed to parse {}: {}", s, err),
            None => panic!("{}", err),
        },
    }
}

// Not public API.
#[doc(hidden)]
pub trait ParseQuote: Sized {
    fn parse(input: Cursor) -> PResult<Self>;
    fn description() -> Option<&'static str>;
}

impl<T> ParseQuote for T
where
    T: Synom,
{
    fn parse(input: Cursor) -> PResult<Self> {
        <T as Synom>::parse(input)
    }

    fn description() -> Option<&'static str> {
        <T as Synom>::description()
    }
}

////////////////////////////////////////////////////////////////////////////////
// Any other types that we want `parse_quote!` to be able to parse.

#[cfg(any(feature = "full", feature = "derive"))]
use Attribute;

#[cfg(any(feature = "full", feature = "derive"))]
impl ParseQuote for Attribute {
    named!(parse -> Self, alt!(
        call!(Attribute::old_parse_outer)
        |
        call!(Attribute::old_parse_inner)
    ));

    fn description() -> Option<&'static str> {
        Some("attribute")
    }
}
<|endoftext|>


<commit_before>use super::cpuid;
use phf;

use core::fmt::{Write, Result, Error};
use core::str;

pub mod intel;

const MODEL_LEN: usize = 30;

#[derive(Default)]
struct ModelWriter {
    buffer: [u8; MODEL_LEN],
    index: usize
}

impl ModelWriter {
    fn as_str(&self) -> &str {
        str::from_utf8(&self.buffer[..self.index]).unwrap()
    }
}

impl Write for ModelWriter {
    fn write_str(&mut self, s: &str) -> Result {
        // TODO: There exists probably a more efficient way of doing this:
        for c in s.chars() {
            if self.index >= self.buffer.len() {
                return Err(Error)
            }
            self.buffer[self.index] = c as u8;
            self.index += 1;
        }
        Ok(())
    }
}

// Format must be a string literal
macro_rules! get_counters {
    ($format:expr) => ({
        let cpuid = cpuid::CpuId::new();

        cpuid.get_vendor_info().map_or(None, |vf| {
            cpuid.get_feature_info().map_or(None, |fi| {
                let vendor = vf.as_string();
                let (family, extended_model, model) = (fi.family_id(), fi.extended_model_id(), fi.model_id());

                let mut writer: ModelWriter = Default::default();
                // Should work as long as it fits in MODEL_LEN bytes:
                write!(writer, $format, vendor, family, extended_model, model).unwrap();
                let key = writer.as_str();

                intel::counters::COUNTER_MAP.get(key)
            })
        })
    });
}

/// Return all core performance counters for the running micro-architecture.
pub fn core_counters() -> Option<&'static phf::Map<&'static str, intel::description::IntelPerformanceCounterDescription>> {
    get_counters!("{}-{}-{:X}{:X}-core")
}

/// Return all uncore performance counters for the running micro-architecture.
pub fn uncore_counters() -> Option<&'static phf::Map<&'static str, intel::description::IntelPerformanceCounterDescription>> {
    get_counters!("{}-{}-{:X}{:X}-uncore")
}

#[test]
fn counter_test() {
    core_counters().map(|cc| {
        cc.get("INST_RETIRED.ANY").map(|p| {
            assert!(p.event_name == "INST_RETIRED.ANY");
        });
    });
}<commit_msg>Comment.<commit_after>use super::cpuid;
use phf;

use core::fmt::{Write, Result, Error};
use core::str;

pub mod intel;

const MODEL_LEN: usize = 30;

#[derive(Default)]
struct ModelWriter {
    buffer: [u8; MODEL_LEN],
    index: usize
}

impl ModelWriter {
    fn as_str(&self) -> &str {
        str::from_utf8(&self.buffer[..self.index]).unwrap()
    }
}

impl Write for ModelWriter {
    fn write_str(&mut self, s: &str) -> Result {
        // TODO: There exists probably a more efficient way of doing this:
        for c in s.chars() {
            if self.index >= self.buffer.len() {
                return Err(Error)
            }
            self.buffer[self.index] = c as u8;
            self.index += 1;
        }
        Ok(())
    }
}

// Format must be a string literal
macro_rules! get_counters {
    ($format:expr) => ({
        let cpuid = cpuid::CpuId::new();

        cpuid.get_vendor_info().map_or(None, |vf| {
            cpuid.get_feature_info().map_or(None, |fi| {
                let vendor = vf.as_string();
                let (family, extended_model, model) = (fi.family_id(), fi.extended_model_id(), fi.model_id());

                let mut writer: ModelWriter = Default::default();
                // Should work as long as it fits in MODEL_LEN bytes:
                write!(writer, $format, vendor, family, extended_model, model).unwrap();
                let key = writer.as_str();

                intel::counters::COUNTER_MAP.get(key)
            })
        })
    });
}

/// Return all core performance counters for the running micro-architecture.
pub fn core_counters() -> Option<&'static phf::Map<&'static str, intel::description::IntelPerformanceCounterDescription>> {
    get_counters!("{}-{}-{:X}{:X}-core")
}

/// Return all uncore performance counters for the running micro-architecture.
pub fn uncore_counters() -> Option<&'static phf::Map<&'static str, intel::description::IntelPerformanceCounterDescription>> {
    get_counters!("{}-{}-{:X}{:X}-uncore")
}

#[test]
fn counter_test() {
    // Note: This will silently fail in case the counter is not available.
    core_counters().map(|cc| {
        cc.get("INST_RETIRED.ANY").map(|p| {
            assert!(p.event_name == "INST_RETIRED.ANY");
        });
    });
}<|endoftext|>


<commit_before>extern crate reqwest;
extern crate serde;
extern crate serde_json;
extern crate regex;

use std::io::Read;
use std::num::ParseFloatError;

use irc::client::prelude::*;
use irc::error::Error as IrcError;

use self::reqwest::Client;
use self::reqwest::header::Connection;
use self::serde_json::Value;

use plugin::*;

#[derive(PluginName, Debug)]
pub struct Currency;

struct ConvertionRequest<'a> {
    value: f64,
    source: &'a str,
    target: &'a str,
}

macro_rules! try_option {
    ($e:expr) => {
        match $e {
            Some(v) => v,
            None    => { return None; }
        }
    }
}

impl<'a> ConvertionRequest<'a> {
    fn send(&self) -> Option<f64> {

        let response = Client::new()
            .get("https://api.fixer.io/latest")
            .form(&[("base", self.source)])
            .header(Connection::close())
            .send();

        match response {
            Ok(mut response) => {
                let mut body = String::new();
                try_option!(response.read_to_string(&mut body).ok());

                let convertion_rates: Result<Value, _> = serde_json::from_str(&body);
                match convertion_rates {
                    Ok(convertion_rates) => {

                        let rates: &Value = try_option!(convertion_rates.get("rates"));
                        let target_rate: &Value =
                            try_option!(rates.get(self.target.to_uppercase()));
                        Some(self.value * try_option!(target_rate.as_f64()))
                    }
                    Err(_) => None,
                }
            }
            Err(_) => None,
        }
    }
}

impl Currency {
    pub fn new() -> Currency {
        Currency {}
    }

    fn eval_command<'a>(&self, tokens: &'a [String]) -> Result<ConvertionRequest<'a>, ParseFloatError> {
        Ok(ConvertionRequest {
            value: tokens[0].parse()?,
            source: &tokens[1],
            target: &tokens[2],
        })
    }

    fn convert(&self, server: &IrcServer, command: PluginCommand) -> Result<(), IrcError> {

        if command.tokens.len() < 3 {
            return self.invalid_command(server, &command);
        }

        let request = match self.eval_command(&command.tokens) {
            Ok(request) => request,
            Err(_) => {
                return self.invalid_command(server, &command);
            }
        };

        match request.send() {
            Some(response) => {
                let response = format!("{} {} => {:.4} {}",
                                       request.value,
                                       request.source.to_lowercase(),
                                       response / 1.00000000,
                                       request.target.to_lowercase());

                server.send_privmsg(&command.target, &response)
            }
            None => server.send_notice(&command.source, "Error while converting given currency"),
        }
    }

    fn help(&self, server: &IrcServer, command: &mut PluginCommand) -> Result<(), IrcError> {
        let help = format!("usage: {} currency value from_currency to_currency\r\n\
                            example: 1.5 eur usd\r\n\
                            available currencies: AUD, BGN, BRL, CAD, \
                            CHF, CNY, CZK, DKK, GBP, HKD, HRK, HUF, \
                            IDR, ILS, INR, JPY, KRW, MXN, MYR, NOK, \
                            NZD, PHP, PLN, RON, RUB, SEK, SGD, THB, \
                            TRY, USD, ZAR",
                           server.current_nickname());

        server.send_notice(&command.source, &help)
    }

    fn invalid_command(&self, server: &IrcServer, command: &PluginCommand) -> Result<(), IrcError> {
        let help = format!("Incorrect Command. \
                           Send \"{} help currency\" for help.",
                           server.current_nickname());

        server.send_notice(&command.source, &help)
    }
}

impl Plugin for Currency {
    fn is_allowed(&self, _: &IrcServer, _: &Message) -> bool {
        false
    }

    fn execute(&mut self, _: &IrcServer, _: &Message) -> Result<(), IrcError> {
        Ok(())
    }

    fn command(&mut self, server: &IrcServer, mut command: PluginCommand) -> Result<(), IrcError> {

        if command.tokens.is_empty() {
            return self.invalid_command(server, &command);
        }

        match command.tokens[0].as_ref() {
            "help" => self.help(server, &mut command),
            _ => self.convert(server, command),
        }
    }
}

#[cfg(test)]
mod tests {}
<commit_msg>Fix currency response on bad command<commit_after>extern crate reqwest;
extern crate serde;
extern crate serde_json;
extern crate regex;

use std::io::Read;
use std::num::ParseFloatError;

use irc::client::prelude::*;
use irc::error::Error as IrcError;

use self::reqwest::Client;
use self::reqwest::header::Connection;
use self::serde_json::Value;

use plugin::*;

#[derive(PluginName, Debug)]
pub struct Currency;

struct ConvertionRequest<'a> {
    value: f64,
    source: &'a str,
    target: &'a str,
}

macro_rules! try_option {
    ($e:expr) => {
        match $e {
            Some(v) => v,
            None    => { return None; }
        }
    }
}

impl<'a> ConvertionRequest<'a> {
    fn send(&self) -> Option<f64> {

        let response = Client::new()
            .get("https://api.fixer.io/latest")
            .form(&[("base", self.source)])
            .header(Connection::close())
            .send();

        match response {
            Ok(mut response) => {
                let mut body = String::new();
                try_option!(response.read_to_string(&mut body).ok());

                let convertion_rates: Result<Value, _> = serde_json::from_str(&body);
                match convertion_rates {
                    Ok(convertion_rates) => {

                        let rates: &Value = try_option!(convertion_rates.get("rates"));
                        let target_rate: &Value =
                            try_option!(rates.get(self.target.to_uppercase()));
                        Some(self.value * try_option!(target_rate.as_f64()))
                    }
                    Err(_) => None,
                }
            }
            Err(_) => None,
        }
    }
}

impl Currency {
    pub fn new() -> Currency {
        Currency {}
    }

    fn eval_command<'a>(&self, tokens: &'a [String]) -> Result<ConvertionRequest<'a>, ParseFloatError> {
        Ok(ConvertionRequest {
            value: tokens[0].parse()?,
            source: &tokens[1],
            target: &tokens[2],
        })
    }

    fn convert(&self, server: &IrcServer, command: PluginCommand) -> Result<(), IrcError> {

        if command.tokens.len() < 3 {
            return self.invalid_command(server, &command);
        }

        let request = match self.eval_command(&command.tokens) {
            Ok(request) => request,
            Err(_) => {
                return self.invalid_command(server, &command);
            }
        };

        match request.send() {
            Some(response) => {
                let response = format!("{} {} => {:.4} {}",
                                       request.value,
                                       request.source.to_lowercase(),
                                       response / 1.00000000,
                                       request.target.to_lowercase());

                server.send_privmsg(&command.target, &response)
            }
            None => server.send_notice(&command.source, "Error while converting given currency"),
        }
    }

    fn help(&self, server: &IrcServer, command: &mut PluginCommand) -> Result<(), IrcError> {
        let help = format!("usage: {} currency value from_currency to_currency\r\n\
                            example: 1.5 eur usd\r\n\
                            available currencies: AUD, BGN, BRL, CAD, \
                            CHF, CNY, CZK, DKK, GBP, HKD, HRK, HUF, \
                            IDR, ILS, INR, JPY, KRW, MXN, MYR, NOK, \
                            NZD, PHP, PLN, RON, RUB, SEK, SGD, THB, \
                            TRY, USD, ZAR",
                           server.current_nickname());

        server.send_notice(&command.source, &help)
    }

    fn invalid_command(&self, server: &IrcServer, command: &PluginCommand) -> Result<(), IrcError> {
        let help = format!("Incorrect Command. \
                           Send \"{} currency help\" for help.",
                           server.current_nickname());

        server.send_notice(&command.source, &help)
    }
}

impl Plugin for Currency {
    fn is_allowed(&self, _: &IrcServer, _: &Message) -> bool {
        false
    }

    fn execute(&mut self, _: &IrcServer, _: &Message) -> Result<(), IrcError> {
        Ok(())
    }

    fn command(&mut self, server: &IrcServer, mut command: PluginCommand) -> Result<(), IrcError> {

        if command.tokens.is_empty() {
            return self.invalid_command(server, &command);
        }

        match command.tokens[0].as_ref() {
            "help" => self.help(server, &mut command),
            _ => self.convert(server, command),
        }
    }
}

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


<commit_before>pub fn format_fasta(id: &str, maybe_desc: Option<String>,
                    seq: &str, width: usize) -> String {
    let mut ret = ">".to_owned() + id;

    if let Some(desc) = maybe_desc {
        ret.push(' ');
        ret.push_str(&desc);
    }

    ret.push('\n');

    if seq.len() == 0 {
        ret.push('\n');
    } else {
        let mut count = 0;
        for c in seq.chars() {
            ret.push(c);
            count += 1;
            if count % width == 0 {
                ret.push('\n');
            }
        }

        if count % width != 0 {
            ret.push('\n');
        }
    }

    ret
}

#[test]
fn test_format_fasta() {
    assert!(format_fasta("id1", None, "", 8) == ">id1\n");
    assert!(format_fasta("id2", Some("desc1".to_owned()), "atgc", 4) ==
            ">id2 desc1\natgc\n");
    assert!(format_fasta("id3", None, "atgc", 4) == "atgc");
    let input1 = "acgtacgattattaccggttacgcatccgtgtaaca";
    let expected1 = "acgtacga\nttattacc\nggttacgc\natccgtgt\naaca\n";
    assert!(format_fasta("id4", Some("desc4".to_owned()), input1, 8) == expected1);
    let input2 = "acgtacgattattaccggttacgcatccgtgt";
    let expected2 = "acgtacga\nttattacc\nggttacgc\natccgtgt\n";
    assert!(format_fasta("id5", None, input2, 8) == expected2);
}
<commit_msg>Fix failing tests<commit_after>pub fn format_fasta(id: &str, maybe_desc: Option<String>,
                    seq: &str, width: usize) -> String {
    let mut ret = ">".to_owned() + id;

    if let Some(desc) = maybe_desc {
        ret.push(' ');
        ret.push_str(&desc);
    }

    ret.push('\n');

    if seq.len() == 0 {
        ret.push('\n');
    } else {
        let mut count = 0;
        for c in seq.chars() {
            ret.push(c);
            count += 1;
            if count % width == 0 {
                ret.push('\n');
            }
        }

        if count % width != 0 {
            ret.push('\n');
        }
    }

    ret
}

#[test]
fn test_format_fasta() {
    assert!(format_fasta("id1", None, "", 8) == ">id1\n\n");
    assert!(format_fasta("id2", Some("desc1".to_owned()), "atgc", 4) ==
            ">id2 desc1\natgc\n");
    assert!(format_fasta("id3", None, "atgc", 4) == ">id3\natgc\n");
    let input1 = "acgtacgattattaccggttacgcatccgtgtaaca";
    let expected1 = ">id4 desc4\nacgtacga\nttattacc\nggttacgc\natccgtgt\naaca\n";
    assert!(format_fasta("id4", Some("desc4".to_owned()), input1, 8) == expected1);
    let input2 = "acgtacgattattaccggttacgcatccgtgt";
    let expected2 = ">id5\nacgtacga\nttattacc\nggttacgc\natccgtgt\n";
    assert!(format_fasta("id5", None, input2, 8) == expected2);
}
<|endoftext|>