<commit_before>//! Two-step verification of HOTP/TOTP.
//!
//! # Examples
//!
//!
//! ## HOTP example
//! ```
//! extern crate otpauth;
//!
//! fn main() {
//!     let auth = otpauth::OtpAuth::new("python");
//!     let code = auth.hotp(4);
//!     assert_eq!(true, auth.valid_hotp(code, 0, 100));
//! }
//! ```
//!
//! ## TOTP example
//!
//! ```
//! extern crate otpauth;
//! extern crate time;
//!
//! fn main() {
//!     let auth = otpauth::OtpAuth::new("python");
//!     let timestamp1 = time::now().to_timespec().sec as usize;
//!     let code = auth.totp(30usize, timestamp1);
//!     let timestamp2 = time::now().to_timespec().sec as usize;
//!     assert_eq!(true, auth.valid_totp(code, 30usize, timestamp2));
//! }
//! ```
//!
extern crate crypto;
extern crate byteorder;

use std::io::Cursor;

use crypto::digest::Digest;
use crypto::mac::Mac;
use crypto::hmac::Hmac;
use crypto::sha1::Sha1;
use byteorder::{BigEndian, WriteBytesExt, ReadBytesExt};

pub struct OtpAuth {
    /// A secret token for the authentication
    pub secret: String,
}

impl OtpAuth {
    /// Constructs a new `OtpAuth`
    pub fn new(secret: &str) -> OtpAuth {
        OtpAuth {
            secret: secret.to_string(),
        }
    }

    /// Generate a TOTP code.
    ///
    /// A TOTP code is an extension of HOTP algorithm.
    ///
    /// ``period``: A period that a TOTP code is valid in seconds
    ///
    /// ``timestamp``: Create TOTP at this given timestamp
    pub fn totp(&self, period: usize, timestamp: usize) -> u32 {
        let counter = timestamp / period;
        self.hotp(counter)
    }

    /// Generate a HOTP code.
    ///
    /// ``counter``: HOTP is a counter based algorithm.
    pub fn hotp(&self, counter: usize) -> u32 {
        // Init Hmac
        let key = self.secret.clone().into_bytes();
        let mut hmac = Hmac::new(Sha1::new(), &key[..]);
        // Calc msg
        let mut wtr = vec![];
        // supress warning about unused_must_use
        let _ = wtr.write_u64::<BigEndian>(counter as u64);
        hmac.input(&wtr[..]);
        // Get digest
        let result = hmac.result();
        let digest = result.code();
        let ob = digest[19];
        let pos: usize = (ob & 15) as usize;
        let mut rdr = Cursor::new(digest[pos..pos+4].to_vec());
        let base = rdr.read_u32::<BigEndian>().unwrap() & 0x7fffffff;
        base % 1000000
    }

    /// Valid a TOTP code.
    ///
    /// ``code``: A number that is less than 6 characters.
    ///
    /// ``period``: A period that a TOTP code is valid in seconds
    ///
    /// ``timestamp``: Validate TOTP at this given timestamp
    pub fn valid_totp(&self, code: u32, period: usize, timestamp: usize) -> bool {
        let code_str = code.to_string();
        let code_bytes = code_str.as_bytes();
        if code_bytes.len() > 6 {
            return false;
        }
        let valid_code = self.totp(period, timestamp).to_string();
        let valid_bytes = valid_code.as_bytes();
        if code_bytes.len() != valid_code.len() {
            return false;
        }
        let mut rv = 0;
        for (a, b) in code_bytes.iter().zip(valid_bytes.iter()) {
            rv |= a ^ b;
        }
        rv == 0
    }

    /// Valid a HOTP code.
    ///
    /// ``code``: A number that is less than 6 characters.
    ///
    /// ``last``: Guess HOTP code from last + 1 range.
    ///
    /// ``trials``: Guest HOTP code end at last + trials + 1.
    pub fn valid_hotp(&self, code: u32, last: usize, trials: usize) -> bool {
        let code_str = code.to_string();
        let code_bytes = code_str.as_bytes();
        if code_bytes.len() > 6 {
            return false;
        }
        for i in last+1..last+trials+1 {
            let valid_code = self.hotp(i).to_string();
            let valid_bytes = valid_code.as_bytes();
            if code_bytes.len() != valid_code.len() {
                continue;
            }
            let mut rv = 0;
            for index in 0..code_bytes.len() {
                let a = code_bytes[index];
                let b = valid_bytes[index];
                rv |= a ^ b;
            }
            if rv == 0 {
                return true;
            }
        }
        false
    }
}
<commit_msg>Replace again<commit_after>//! Two-step verification of HOTP/TOTP.
//!
//! # Examples
//!
//!
//! ## HOTP example
//! ```
//! extern crate otpauth;
//!
//! fn main() {
//!     let auth = otpauth::OtpAuth::new("python");
//!     let code = auth.hotp(4);
//!     assert_eq!(true, auth.valid_hotp(code, 0, 100));
//! }
//! ```
//!
//! ## TOTP example
//!
//! ```
//! extern crate otpauth;
//! extern crate time;
//!
//! fn main() {
//!     let auth = otpauth::OtpAuth::new("python");
//!     let timestamp1 = time::now().to_timespec().sec as usize;
//!     let code = auth.totp(30usize, timestamp1);
//!     let timestamp2 = time::now().to_timespec().sec as usize;
//!     assert_eq!(true, auth.valid_totp(code, 30usize, timestamp2));
//! }
//! ```
//!
extern crate crypto;
extern crate byteorder;

use std::io::Cursor;

use crypto::digest::Digest;
use crypto::mac::Mac;
use crypto::hmac::Hmac;
use crypto::sha1::Sha1;
use byteorder::{BigEndian, WriteBytesExt, ReadBytesExt};

pub struct OtpAuth {
    /// A secret token for the authentication
    pub secret: String,
}

impl OtpAuth {
    /// Constructs a new `OtpAuth`
    pub fn new(secret: &str) -> OtpAuth {
        OtpAuth {
            secret: secret.to_string(),
        }
    }

    /// Generate a TOTP code.
    ///
    /// A TOTP code is an extension of HOTP algorithm.
    ///
    /// ``period``: A period that a TOTP code is valid in seconds
    ///
    /// ``timestamp``: Create TOTP at this given timestamp
    pub fn totp(&self, period: usize, timestamp: usize) -> u32 {
        let counter = timestamp / period;
        self.hotp(counter)
    }

    /// Generate a HOTP code.
    ///
    /// ``counter``: HOTP is a counter based algorithm.
    pub fn hotp(&self, counter: usize) -> u32 {
        // Init Hmac
        let key = self.secret.clone().into_bytes();
        let mut hmac = Hmac::new(Sha1::new(), &key[..]);
        // Calc msg
        let mut wtr = vec![];
        // supress warning about unused_must_use
        let _ = wtr.write_u64::<BigEndian>(counter as u64);
        hmac.input(&wtr[..]);
        // Get digest
        let result = hmac.result();
        let digest = result.code();
        let ob = digest[19];
        let pos: usize = (ob & 15) as usize;
        let mut rdr = Cursor::new(digest[pos..pos+4].to_vec());
        let base = rdr.read_u32::<BigEndian>().unwrap() & 0x7fffffff;
        base % 1000000
    }

    /// Valid a TOTP code.
    ///
    /// ``code``: A number that is less than 6 characters.
    ///
    /// ``period``: A period that a TOTP code is valid in seconds
    ///
    /// ``timestamp``: Validate TOTP at this given timestamp
    pub fn valid_totp(&self, code: u32, period: usize, timestamp: usize) -> bool {
        let code_str = code.to_string();
        let code_bytes = code_str.as_bytes();
        if code_bytes.len() > 6 {
            return false;
        }
        let valid_code = self.totp(period, timestamp).to_string();
        let valid_bytes = valid_code.as_bytes();
        if code_bytes.len() != valid_code.len() {
            return false;
        }
        let mut rv = 0;
        for (a, b) in code_bytes.iter().zip(valid_bytes.iter()) {
            rv |= a ^ b;
        }
        rv == 0
    }

    /// Valid a HOTP code.
    ///
    /// ``code``: A number that is less than 6 characters.
    ///
    /// ``last``: Guess HOTP code from last + 1 range.
    ///
    /// ``trials``: Guest HOTP code end at last + trials + 1.
    pub fn valid_hotp(&self, code: u32, last: usize, trials: usize) -> bool {
        let code_str = code.to_string();
        let code_bytes = code_str.as_bytes();
        if code_bytes.len() > 6 {
            return false;
        }
        for i in last+1..last+trials+1 {
            let valid_code = self.hotp(i).to_string();
            let valid_bytes = valid_code.as_bytes();
            if code_bytes.len() != valid_code.len() {
                continue;
            }
            let mut rv = 0;
            for (a, b) in code_bytes.iter().zip(valid_bytes.iter()) {
                rv |= a ^ b;
            }
            if rv == 0 {
                return true;
            }
        }
        false
    }
}
<|endoftext|>


<commit_before>#![feature(proc_macro)]

extern crate proc_macro;
extern crate syn;

#[macro_use]
extern crate quote;

use proc_macro::TokenStream;

fn output_struct(name: &syn::Ident) -> quote::Tokens {
    quote! {
        struct #name (u8);
        impl #name {
            pub fn get_bit() {

            }
        }
    }
}

#[derive(Debug)]
enum BitField {
    Single(u8),
    Range(std::ops::Range<u8>)
}

#[proc_macro_attribute]
pub fn register(_: TokenStream, input: TokenStream) -> TokenStream {
    use syn::*;

    println!("{}", input);

    let s = input.to_string();
    let ast = parse_derive_input(&s).unwrap();

    println!("ident: {}", ast.ident);

    let fields = match ast.body {
        Body::Enum(_) => panic!("enum not supported"),
        Body::Struct(x) => match x {
            VariantData::Struct(fields) => fields,
            _ => panic!("tuple and unit not supported")
        }
    };

    for field in &fields {
        let ident = field.ident.clone().unwrap();
        let ty = match field.clone().ty {
            Ty::Path(_, path) => path.segments[0].ident.clone(),
            _ => panic!("only path types supported"),
        };

        let mut from: Option<u8> = None;
        let mut to: Option<u8> = None;
        let mut at: Option<u8> = None;

        for attr in &field.attrs {
            if let MetaItem::List(attr_ident, attr_nest) = attr.clone().value {
                if attr_ident == "bitfield" {
                    for attr_nest_item in &attr_nest {
                        if let NestedMetaItem::MetaItem(nest_metaitem) = attr_nest_item.clone() {
                            if let MetaItem::NameValue(nv_ident, nv_lit) = nest_metaitem.clone() {
                                if let Lit::Int(nv_value, _) = nv_lit {
                                    match nv_ident.as_ref() {
                                        "at" => (at = Some(nv_value as u8)),
                                        "from" => (from = Some(nv_value as u8)),
                                        "to" => (to = Some(nv_value as u8)),
                                        _ => panic!("unsupported param name (use 'at' or 'from'/'to')"),
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        if (from.is_some() || to.is_some()) && at.is_some() {
            panic!("select 'at' or 'from'/'to' parameters, not both");
        }

        if from.is_some() ^ to.is_some() {
            panic!("select 'from' and 'to' parameters together");
        }

        if from.is_none() && to.is_none() && at.is_none() {
            panic!("select bit parameters (use #[bitfield(at=x or from=x to=y)])");
        }

        let bitfield: BitField = if from.is_some() && to.is_some() {
            BitField::Range(std::ops::Range{start: from.unwrap(), end: to.unwrap()})
        } else {
            BitField::Single(at.unwrap())
        };

        println!("field {} @{:?}: {}", ident, bitfield, ty);
    }

    // return input;
    return output_struct(&ast.ident).parse().unwrap();
}

/*
Struct(
    Struct([
        Field {
            ident: Some(Ident("foo")),
            vis: Inherited,
            attrs: [
                Attribute {
                    style: Outer,
                    value: List(
                        Ident("bitfield"),
                        [
                            MetaItem(
                                NameValue(
                                    Ident("at"), Int(0, Unsuffixed)
                                )
                            )
                        ]
                    ),
                    is_sugared_doc: false
                }
            ],
            ty: Path(
                None,
                Path {
                    global: false,
                    segments: [
                        PathSegment {
                            ident: Ident("u8"),
                            parameters: AngleBracketed(
                                AngleBracketedParameterData {
                                    lifetimes: [],
                                    types: [],
                                    bindings: []
                                }
                            )
                        }
                    ]
                }
            )
        }
    ])
)
*/<commit_msg>replace to match 2<commit_after>#![feature(proc_macro)]

extern crate proc_macro;
extern crate syn;

#[macro_use]
extern crate quote;

use proc_macro::TokenStream;

use syn::*;

#[derive(Debug)]
enum BitField {
    Single(u8),
    Range(std::ops::Range<u8>)
}

struct BitFields {
    bitfield: BitField,
    ident: Ident,
    ty: Ty
}

fn output_struct(name: &Ident, bitfields: &Vec<BitFields>) -> quote::Tokens {
    quote! {
        struct #name (u8);
        impl #name {
            pub fn get_bit() {

            }
        }
    }
}

#[proc_macro_attribute]
pub fn register(_: TokenStream, input: TokenStream) -> TokenStream {

    println!("{}", input);

    let s = input.to_string();
    let ast = parse_derive_input(&s).unwrap();

    println!("ident: {}", ast.ident);

    let fields = match ast.body {
        Body::Enum(_) => panic!("enum not supported"),
        Body::Struct(x) => match x {
            VariantData::Struct(fields) => fields,
            _ => panic!("tuple and unit not supported")
        }
    };

    let mut bitfields: Vec<BitFields> = vec![];

    for field in &fields {
        let ident = field.ident.clone().unwrap();
        let ty_str = match field.clone().ty {
            Ty::Path(_, path) => path.segments[0].ident.clone(),
            _ => panic!("only path types supported"),
        };

        let ty = field.clone().ty;

        let mut from: Option<u8> = None;
        let mut to: Option<u8> = None;
        let mut at: Option<u8> = None;

        for attr in &field.attrs {
            if let MetaItem::List(attr_ident, attr_nest) = attr.clone().value {
                if attr_ident == "bitfield" {
                    for attr_nest_item in &attr_nest {
                        match attr_nest_item.clone() {
                            NestedMetaItem::MetaItem(MetaItem::NameValue(nv_ident, Lit::Int(nv_value, _))) => {
                                match nv_ident.as_ref() {
                                    "at" => (at = Some(nv_value as u8)),
                                    "from" => (from = Some(nv_value as u8)),
                                    "to" => (to = Some(nv_value as u8)),
                                    _ => panic!("unsupported param name (use 'at' or 'from'/'to')"),
                                }
                            }
                            _ => {}
                        }
                    }
                }
            }
        }

        if (from.is_some() || to.is_some()) && at.is_some() {
            panic!("select 'at' or 'from'/'to' parameters, not both");
        }

        if from.is_some() ^ to.is_some() {
            panic!("select 'from' and 'to' parameters together");
        }

        if from.is_none() && to.is_none() && at.is_none() {
            panic!("select bit parameters (use #[bitfield(at=x or from=x to=y)])");
        }

        let bitfield: BitField = if from.is_some() && to.is_some() {
            BitField::Range(std::ops::Range{start: from.unwrap(), end: to.unwrap()})
        } else {
            BitField::Single(at.unwrap())
        };

        println!("field {} @{:?}: {}", ident, bitfield, ty_str);
    }

    // return input;
    return output_struct(&ast.ident).parse().unwrap();
}

/*
Struct(
    Struct([
        Field {
            ident: Some(Ident("foo")),
            vis: Inherited,
            attrs: [
                Attribute {
                    style: Outer,
                    value: List(
                        Ident("bitfield"),
                        [
                            MetaItem(
                                NameValue(
                                    Ident("at"), Int(0, Unsuffixed)
                                )
                            )
                        ]
                    ),
                    is_sugared_doc: false
                }
            ],
            ty: Path(
                None,
                Path {
                    global: false,
                    segments: [
                        PathSegment {
                            ident: Ident("u8"),
                            parameters: AngleBracketed(
                                AngleBracketedParameterData {
                                    lifetimes: [],
                                    types: [],
                                    bindings: []
                                }
                            )
                        }
                    ]
                }
            )
        }
    ])
)
*/<|endoftext|>


<commit_before>#![feature(vec_push_all)]
//#![feature(slice_bytes, convert)]

pub struct Buffer {
   data: Vec<u8>
}

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

    pub fn with_capacity(capa: usize) -> Buffer {
        Buffer{data: Vec::with_capacity(capa)}
    }

    #[inline(always)]
    pub fn as_mut_ref(&mut self) -> &mut Vec<u8> {
        &mut self.data
    }

    #[inline(always)]
    pub fn push(&mut self, byte: u8) {
       self.data.push(byte);
    }

    #[inline(always)]
    pub fn push_all(&mut self, bytes: &[u8]) {
        //use std::slice::bytes::copy_memory;
        use std::ptr;

        if bytes.is_empty() { return; }

        let remaining = self.data.capacity() - self.data.len();
        if remaining < bytes.len() {
            let missing = bytes.len() - remaining;
            self.data.reserve(missing);
        }

        unsafe {
            let end = self.data.len();
            self.data.set_len(end + bytes.len());
            //copy_memory(bytes, &mut self.data[end..]);
            ptr::copy_nonoverlapping(bytes.as_ptr(),
                                     self.data[end..].as_mut_ptr(),
                                     bytes.len());

        }
    }

    #[inline(always)]
    pub fn push_all_around(&mut self, around: u8, bytes: &[u8]) {
       self.data.push(around);
       self.data.push_all(bytes);
       self.data.push(around);
    }

    #[inline(always)]
    pub fn into_vec(self) -> Vec<u8> {
        self.data
    }
}

pub struct JsonEncoder {
    buffer: Buffer
}

impl JsonEncoder {
    #[inline]
    pub fn new() -> JsonEncoder {
        JsonEncoder{buffer: Buffer::new()}
    }

    #[inline]
    pub fn with_capacity(capa: usize) -> JsonEncoder {
        JsonEncoder{buffer: Buffer::with_capacity(capa)}
    }

    #[inline]
    pub fn encode_raw(&mut self, raw: &[u8]) {
        self.buffer.push_all(raw);
    }

    #[inline]
    pub fn into_vec(self) -> Vec<u8> {
        self.buffer.into_vec()
    }

    #[inline]
    pub fn with_buffer<F>(&mut self, mut f: F) where F: FnMut(&mut Buffer) {
        f(&mut self.buffer);
    }

    #[inline]
    pub fn encode_str_noescape(&mut self, raw_str: &str) {
        self.buffer.push_all_around(b'"', raw_str.as_bytes());
    }

    #[inline]
    fn escape_bytes(&mut self, bytes: &[u8]) {
        let mut start = 0;

        for (i, byte) in bytes.iter().enumerate() {
            let escaped = match *byte {
                b'"' => b"\\\"",
                b'\\' => b"\\\\",
                b'\x08' => b"\\b",
                b'\x0c' => b"\\f",
                b'\n' => b"\\n",
                b'\r' => b"\\r",
                b'\t' => b"\\t",
                _ => {
                    continue;
                }
            };

            if start < i {
                self.encode_raw(&bytes[start..i]);
            }

            self.encode_raw(escaped);

            start = i + 1;
        }

        if start != bytes.len() {
            self.encode_raw(&bytes[start..]);
        }
    }

    // encodes as decimal string
    #[inline]
    pub fn encode_decimal_str(&mut self, value: u64) {
        const CHARS: &'static [u8] = b"0123456789";
        const MAX_DIGITS: usize = 20;

        if value == 0 {
            self.buffer.push_all_around(b'"', b"0");
            return;
        }

        let mut digits: [u8; MAX_DIGITS] = [b'0'; MAX_DIGITS];
        let mut i = MAX_DIGITS;
        let mut n = value;
        while n > 0 {
            i -= 1;
            digits[i] = CHARS[(n % 10) as usize];
            n = n / 10;
        }

        self.buffer.push_all_around(b'"', &digits[i..]);
    }

    #[inline]
    pub fn encode_str(&mut self, s: &str) {
        self.buffer.push(b'"');
        self.escape_bytes(s.as_bytes());
        self.buffer.push(b'"');
    }

    #[inline]
    pub fn encode_i32(&mut self, value: i32) {
        if value == 0 {
            self.buffer.push(b'0');
        } else if value > 0 {
            self.encode_u31(value as u32);
        } else {
            self.buffer.push(b'-');
            self.encode_u31((-value) as u32);
        }
    }

    // encodes a 31-bit unsigned integer != 0
    #[inline]
    fn encode_u31(&mut self, value: u32) {
        const CHARS: &'static [u8] = b"0123456789";
        const MAX_DIGITS: usize = 10;
        debug_assert!(value != 0);

        let mut digits: [u8; MAX_DIGITS] = [b'0'; MAX_DIGITS];
        let mut i = MAX_DIGITS;
        let mut n = value;
        while n > 0 {
            i -= 1;
            digits[i] = CHARS[(n % 10) as usize];
            n = n / 10;
        }

        self.encode_raw(&digits[i..]);
    }

    #[inline]
    pub fn encode_obj<F, T>(&mut self, mut f: F) -> T where F: FnMut(&mut JsonObjectEncoder) -> T {
        self.buffer.push(b'{');
        let t = {
            f(&mut JsonObjectEncoder {js: self, needs_sep: false})
        };
        self.buffer.push(b'}');
        t
    }

    #[inline]
    pub fn encode_array<F, T>(&mut self, mut f: F) -> T where F: FnMut(&mut JsonArrayEncoder) -> T {
        self.buffer.push(b'[');
        let t = {
            f(&mut JsonArrayEncoder {js: self, needs_sep: false})
        };
        self.buffer.push(b']');
        t
    }

    #[inline]
    pub fn encode_array_nobrackets<F, T>(&mut self, mut f: F) -> T where F: FnMut(&mut JsonArrayEncoder) -> T {
        f(&mut JsonArrayEncoder {js: self, needs_sep: false})
    }

    #[inline]
    pub fn obj_single_str_field(name: &str, s: &str) -> Vec<u8> {
        let mut js = JsonEncoder::with_capacity(name.len() + s.len() + 2 + 2 + 1 + 2);
        js.encode_obj(|jso| jso.encode_field_str(name, s));
        js.into_vec()
    }

}

pub struct JsonObjectEncoder<'a> {
    js: &'a mut JsonEncoder,
    needs_sep: bool,
}

impl<'a> JsonObjectEncoder<'a> {
    // XXX: name MAY NOT include escapable characters
    #[inline]
    pub fn encode_field<F, T>(&mut self, name: &str, mut f: F) -> T where F: FnMut(&mut JsonEncoder) -> T {
        if self.needs_sep {
            self.js.buffer.push(b',');
        } else {
            self.needs_sep = true;
        }
        self.js.encode_str_noescape(name);
        self.js.buffer.push(b':');

        f(self.js)
    }

    #[inline]
    pub fn encode_field_array<F, T>(&mut self, name: &str, mut f: F) -> T where F: FnMut(&mut JsonArrayEncoder) -> T {
        self.encode_field(name, |js| js.encode_array(|jsa| f(jsa)))
    }

    #[inline]
    pub fn encode_field_i32(&mut self, name: &str, val: i32) {
        self.encode_field(name, |js| js.encode_i32(val));
    }

    #[inline]
    pub fn encode_field_str(&mut self, name: &str, s: &str) {
        self.encode_field(name, |js| js.encode_str(s));
    }

}

pub struct JsonArrayEncoder<'a> {
    js: &'a mut JsonEncoder,
    needs_sep: bool,
}

impl<'a> JsonArrayEncoder<'a> {
    #[inline]
    pub fn encode_elm<F, T>(&mut self, mut f: F) -> T where F: FnMut(&mut JsonEncoder) -> T {
        if self.needs_sep {
            self.js.buffer.push(b',');
        } else {
            self.needs_sep = true;
        }
        f(self.js)
    }

    #[inline]
    pub fn encode_elm_i32(&mut self, val: i32) {
        self.encode_elm(|js| js.encode_i32(val));
    }

    #[inline]
    pub fn encode_elm_str(&mut self, s: &str) {
        self.encode_elm(|js| js.encode_str(s));
    }

    #[inline]
    pub fn encode_elm_obj<F, T>(&mut self, mut f: F) -> T where F: FnMut(&mut JsonObjectEncoder) -> T {
        self.encode_elm(|js| js.encode_obj(|jso| f(jso)))
    }
}

#[test]
fn test_json_obj_encoder() {
    use std::str;

    let mut js = JsonEncoder::new();
    js.encode_obj(|_|{});
    assert_eq!(b"{}", &js.into_vec()[..]);

    let mut js = JsonEncoder::new();
    js.encode_obj(|jso| {
        jso.encode_field("total", |js| js.encode_i32(31));
    });
    assert_eq!(b"{\"total\":31}", &js.into_vec()[..]);

    let mut js = JsonEncoder::new();
    js.encode_obj(|jso| {
        jso.encode_field("total", |js| js.encode_i32(31));
        jso.encode_field("next", |js| js.encode_str("abc"));
    });
    assert_eq!(b"{\"total\":31,\"next\":\"abc\"}", &js.into_vec()[..]);

    let mut js = JsonEncoder::new();
    js.encode_obj(|jso| {
        jso.encode_field("total", |js| js.encode_i32(31));
        jso.encode_field("next", |js| js.encode_str("abc"));
        jso.encode_field("tags", |js| {
                js.encode_array(|jsa| {
                        jsa.encode_elm(|js| js.encode_i32(1));
                        jsa.encode_elm(|js| js.encode_i32(2));
                });
        });
    });
    assert_eq!("{\"total\":31,\"next\":\"abc\",\"tags\":[1,2]}", str::from_utf8(&js.into_vec()[..]).unwrap());

    let json = JsonEncoder::obj_single_str_field("total", "abcdef");
    assert_eq!(b"{\"total\":\"abcdef\"}", &json[..]);
}
<commit_msg>Refactor<commit_after>use std::ptr;

pub struct Buffer {
   data: Vec<u8>
}

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

    pub fn with_capacity(capa: usize) -> Buffer {
        Buffer{data: Vec::with_capacity(capa)}
    }

    #[inline(always)]
    pub fn as_mut_ref(&mut self) -> &mut Vec<u8> {
        &mut self.data
    }

    #[inline(always)]
    pub fn push(&mut self, byte: u8) {
       self.data.push(byte);
    }

    #[inline(always)]
    fn extend_back(&mut self, len: usize) -> &mut[u8] {
        debug_assert!(len > 0);

        let data_len = self.data.len();
        self.data.reserve(len);
        unsafe { self.data.set_len(data_len + len); }
        return &mut self.data[data_len..];
    }

    #[inline(always)]
    pub fn push_all(&mut self, bytes: &[u8]) {
        let len = bytes.len();
        if len > 0 {
            let ext = self.extend_back(len);
            unsafe {
                ptr::copy_nonoverlapping(bytes.as_ptr(),
                                         ext.as_mut_ptr(),
                                         len);
            }
        }
    }

    #[inline(always)]
    pub fn push_all_around(&mut self, around: u8, bytes: &[u8]) {
        let len = bytes.len();
        let ext = self.extend_back(2 + len);

        unsafe {
            ptr::write(ext.as_mut_ptr(), around);
            ptr::copy_nonoverlapping(bytes.as_ptr(),
                                     ext.as_mut_ptr().offset(1),
                                     len);
            ptr::write(ext[1+len..].as_mut_ptr(), around);
       }
    }

    #[inline(always)]
    pub fn into_vec(self) -> Vec<u8> {
        self.data
    }
}

pub struct JsonEncoder {
    buffer: Buffer
}

impl JsonEncoder {
    #[inline]
    pub fn new() -> JsonEncoder {
        JsonEncoder{buffer: Buffer::new()}
    }

    #[inline]
    pub fn with_capacity(capa: usize) -> JsonEncoder {
        JsonEncoder{buffer: Buffer::with_capacity(capa)}
    }

    #[inline]
    pub fn encode_raw(&mut self, raw: &[u8]) {
        self.buffer.push_all(raw);
    }

    #[inline]
    pub fn into_vec(self) -> Vec<u8> {
        self.buffer.into_vec()
    }

    #[inline]
    pub fn with_buffer<F>(&mut self, mut f: F) where F: FnMut(&mut Buffer) {
        f(&mut self.buffer);
    }

    #[inline]
    pub fn encode_str_noescape(&mut self, raw_str: &str) {
        self.buffer.push_all_around(b'"', raw_str.as_bytes());
    }

    #[inline]
    fn escape_bytes(&mut self, bytes: &[u8]) {
        let mut start = 0;

        for (i, byte) in bytes.iter().enumerate() {
            let escaped = match *byte {
                b'"' => b"\\\"",
                b'\\' => b"\\\\",
                b'\x08' => b"\\b",
                b'\x0c' => b"\\f",
                b'\n' => b"\\n",
                b'\r' => b"\\r",
                b'\t' => b"\\t",
                _ => {
                    continue;
                }
            };

            if start < i {
                self.encode_raw(&bytes[start..i]);
            }

            self.encode_raw(escaped);

            start = i + 1;
        }

        if start != bytes.len() {
            self.encode_raw(&bytes[start..]);
        }
    }

    // encodes as decimal string
    #[inline]
    pub fn encode_decimal_str(&mut self, value: u64) {
        const CHARS: &'static [u8] = b"0123456789";
        const MAX_DIGITS: usize = 20;

        if value == 0 {
            self.buffer.push_all_around(b'"', b"0");
            return;
        }

        let mut digits: [u8; MAX_DIGITS] = [b'0'; MAX_DIGITS];
        let mut i = MAX_DIGITS;
        let mut n = value;
        while n > 0 {
            i -= 1;
            digits[i] = CHARS[(n % 10) as usize];
            n = n / 10;
        }

        self.buffer.push_all_around(b'"', &digits[i..]);
    }

    #[inline]
    pub fn encode_str(&mut self, s: &str) {
        self.buffer.push(b'"');
        self.escape_bytes(s.as_bytes());
        self.buffer.push(b'"');
    }

    #[inline]
    pub fn encode_i32(&mut self, value: i32) {
        if value == 0 {
            self.buffer.push(b'0');
        } else if value > 0 {
            self.encode_u31(value as u32);
        } else {
            self.buffer.push(b'-');
            self.encode_u31((-value) as u32);
        }
    }

    // encodes a 31-bit unsigned integer != 0
    #[inline]
    fn encode_u31(&mut self, value: u32) {
        const CHARS: &'static [u8] = b"0123456789";
        const MAX_DIGITS: usize = 10;
        debug_assert!(value != 0);

        let mut digits: [u8; MAX_DIGITS] = [b'0'; MAX_DIGITS];
        let mut i = MAX_DIGITS;
        let mut n = value;
        while n > 0 {
            i -= 1;
            digits[i] = CHARS[(n % 10) as usize];
            n = n / 10;
        }

        self.encode_raw(&digits[i..]);
    }

    #[inline]
    pub fn encode_obj<F, T>(&mut self, mut f: F) -> T where F: FnMut(&mut JsonObjectEncoder) -> T {
        self.buffer.push(b'{');
        let t = {
            f(&mut JsonObjectEncoder {js: self, needs_sep: false})
        };
        self.buffer.push(b'}');
        t
    }

    #[inline]
    pub fn encode_array<F, T>(&mut self, mut f: F) -> T where F: FnMut(&mut JsonArrayEncoder) -> T {
        self.buffer.push(b'[');
        let t = {
            f(&mut JsonArrayEncoder {js: self, needs_sep: false})
        };
        self.buffer.push(b']');
        t
    }

    #[inline]
    pub fn encode_array_nobrackets<F, T>(&mut self, mut f: F) -> T where F: FnMut(&mut JsonArrayEncoder) -> T {
        f(&mut JsonArrayEncoder {js: self, needs_sep: false})
    }

    #[inline]
    pub fn obj_single_str_field(name: &str, s: &str) -> Vec<u8> {
        let mut js = JsonEncoder::with_capacity(name.len() + s.len() + 2 + 2 + 1 + 2);
        js.encode_obj(|jso| jso.encode_field_str(name, s));
        js.into_vec()
    }

}

pub struct JsonObjectEncoder<'a> {
    js: &'a mut JsonEncoder,
    needs_sep: bool,
}

impl<'a> JsonObjectEncoder<'a> {
    // XXX: name MAY NOT include escapable characters
    #[inline]
    pub fn encode_field<F, T>(&mut self, name: &str, mut f: F) -> T where F: FnMut(&mut JsonEncoder) -> T {
        if self.needs_sep {
            self.js.buffer.push(b',');
        } else {
            self.needs_sep = true;
        }
        self.js.encode_str_noescape(name);
        self.js.buffer.push(b':');

        f(self.js)
    }

    #[inline]
    pub fn encode_field_array<F, T>(&mut self, name: &str, mut f: F) -> T where F: FnMut(&mut JsonArrayEncoder) -> T {
        self.encode_field(name, |js| js.encode_array(|jsa| f(jsa)))
    }

    #[inline]
    pub fn encode_field_i32(&mut self, name: &str, val: i32) {
        self.encode_field(name, |js| js.encode_i32(val));
    }

    #[inline]
    pub fn encode_field_str(&mut self, name: &str, s: &str) {
        self.encode_field(name, |js| js.encode_str(s));
    }
}

pub struct JsonArrayEncoder<'a> {
    js: &'a mut JsonEncoder,
    needs_sep: bool,
}

impl<'a> JsonArrayEncoder<'a> {
    #[inline]
    pub fn encode_elm<F, T>(&mut self, mut f: F) -> T where F: FnMut(&mut JsonEncoder) -> T {
        if self.needs_sep {
            self.js.buffer.push(b',');
        } else {
            self.needs_sep = true;
        }
        f(self.js)
    }

    #[inline]
    pub fn encode_elm_i32(&mut self, val: i32) {
        self.encode_elm(|js| js.encode_i32(val));
    }

    #[inline]
    pub fn encode_elm_str(&mut self, s: &str) {
        self.encode_elm(|js| js.encode_str(s));
    }

    #[inline]
    pub fn encode_elm_obj<F, T>(&mut self, mut f: F) -> T where F: FnMut(&mut JsonObjectEncoder) -> T {
        self.encode_elm(|js| js.encode_obj(|jso| f(jso)))
    }
}

#[test]
fn test_json_obj_encoder() {
    use std::str;

    let mut js = JsonEncoder::new();
    js.encode_obj(|_|{});
    assert_eq!(b"{}", &js.into_vec()[..]);

    let mut js = JsonEncoder::new();
    js.encode_obj(|jso| {
        jso.encode_field("total", |js| js.encode_i32(31));
    });
    assert_eq!(b"{\"total\":31}", &js.into_vec()[..]);

    let mut js = JsonEncoder::new();
    js.encode_obj(|jso| {
        jso.encode_field("total", |js| js.encode_i32(31));
        jso.encode_field("next", |js| js.encode_str("abc"));
    });
    assert_eq!(b"{\"total\":31,\"next\":\"abc\"}", &js.into_vec()[..]);

    let mut js = JsonEncoder::new();
    js.encode_obj(|jso| {
        jso.encode_field("total", |js| js.encode_i32(31));
        jso.encode_field("next", |js| js.encode_str("abc"));
        jso.encode_field("tags", |js| {
                js.encode_array(|jsa| {
                        jsa.encode_elm(|js| js.encode_i32(1));
                        jsa.encode_elm(|js| js.encode_i32(2));
                });
        });
    });
    assert_eq!("{\"total\":31,\"next\":\"abc\",\"tags\":[1,2]}", str::from_utf8(&js.into_vec()[..]).unwrap());

    let json = JsonEncoder::obj_single_str_field("total", "abcdef");
    assert_eq!(b"{\"total\":\"abcdef\"}", &json[..]);

    let json = JsonEncoder::obj_single_str_field("total", "");
    assert_eq!(b"{\"total\":\"\"}", &json[..]);
}
<|endoftext|>


<commit_before>//! A library of Conflict-free Replicated Data Types.
//!
//! Conflict-free replicated data types (also called convergent and commutative
//! replicated data types) allow for concurrent updates to distributed replicas
//! with strong eventual consistency and without coordination.
//!
//! ###### Further Reading
//!
//! 1. [A comprehensive study of Convergent and Commutative Replicated Data Types](http://hal.inria.fr/docs/00/55/55/88/PDF/techreport.pdf) (Shapiro, et al.)
//! 2. [An Optimized Conflict-free Replicated Set](http://arxiv.org/pdf/1210.3368.pdf) (Bieniusa, et al.)

#![feature(phase)]

extern crate quickcheck;

#[phase(plugin, link)]
extern crate log;

pub mod counter;
pub mod register;
pub mod set;
pub mod test;

/// A Conflict-free Replicated Data Type.
///
/// Conflict-free replicated data types (also called convergent and commutative
/// replicated data types) allow for concurrent updates to distributed replicas
/// with strong eventual consistency and without coordination.
///
/// ###### Replication
///
/// Updates to CRDTs can be shared with replicas in two ways: state-based
/// replication and operation-based replication. With state-based replication,
/// the entire state of the mutated CRDT is merged into remote replicas in order
/// to restore consistency. With operation-based replication, only the mutating
/// operation is applied to remote replicas in order to restore consistency.
/// Operation-based replication is lighter weight in terms of the amount of
/// data which must be transmitted to replicas per mutation, but has the
/// requirement that all operations must be reliably broadcast and applied to
/// remote replicas. State-based replication schemes can maintain (eventual)
/// consistency merely by guaranteeing that state based replication will
/// (eventually) happen. Shapiro, et al. have shown that state-based CRDTs are
/// equivalent to operation-based CRDTs. The CRDTs exposed by this library
/// allow for either state-based or operation-based replication, or a mix of
/// both.
///
/// ###### Replica ID
///
/// Many CRDTs require a `uint` identifier, or replica ID, upon creation. The
/// replica ID **must** be unique among replicas, so it should be taken from
/// unique per-replica configuration, or from a source of strong coordination
/// such as [ZooKeeper](http://zookeeper.apache.org/) or
/// [etcd](https://github.com/coreos/etcd) (implementing a Rust client for these
/// services is left as an exercise for the reader).
///
/// ###### Transaction IDs
///
/// Many CRDTs require the user to provide a transaction ID when performing
/// mutating operations. Transaction IDs provided to an individual replica
/// **must** be monotonically increasing across operations. Transaction IDs
/// across replicas **must** be unique, and **should** be as close to globally
/// monotonically increasing as possible. Unlike replicas IDs, these
/// requirements do not require strong coordination among replicas. See
/// [Snowflake](https://github.com/twitter/snowflake) for an example of
/// distributed, uncoordinated ID generation which meets the requirements.
///
/// ###### Partial Ordering
///
/// Replicas of a CRDT are partially-ordered over the set of possible
/// operations. If all operations applied to replica `B` have been applied to
/// `A` (or, somewhat equivalently, if `B` has been merged into `A`), then
/// `A <= B`.
///
/// ###### Equality
///
/// Equality among CRDT replicas does not take into account the replica ID;
/// only the operation history is taken into account.
///
/// ###### Further Reading
///
/// 1. [A comprehensive study of Convergent and Commutative Replicated Data Types](http://hal.inria.fr/docs/00/55/55/88/PDF/techreport.pdf) (Shapiro, et al.)
/// 2. [An Optimized Conflict-free Replicated Set](http://arxiv.org/pdf/1210.3368.pdf) (Bieniusa, et al.)
pub trait Crdt<Operation> : PartialOrd + Clone {

    /// Merge a replica into this CRDT.
    ///
    /// This method is used to perform state-based replication.
    fn merge(&mut self, other: Self);

    /// Apply an increment operation to this CRDT.
    ///
    /// This method is used to perform operation-based replication.
    fn apply(&mut self, operation: Operation);
}
<commit_msg>cleanup docs<commit_after>//! A library of Conflict-free Replicated Data Types.
//!
//! ###### Further Reading
//!
//! 1. [A comprehensive study of Convergent and Commutative Replicated Data Types](http://hal.inria.fr/docs/00/55/55/88/PDF/techreport.pdf) (Shapiro, et al.)
//! 2. [An Optimized Conflict-free Replicated Set](http://arxiv.org/pdf/1210.3368.pdf) (Bieniusa, et al.)

#![feature(phase)]

extern crate quickcheck;

#[phase(plugin, link)]
extern crate log;

pub mod counter;
pub mod register;
pub mod set;
pub mod test;

/// A Conflict-free Replicated Data Type.
///
/// Conflict-free replicated data types (also called convergent and commutative
/// replicated data types) allow for concurrent updates to distributed replicas
/// with strong eventual consistency and without coordination.
///
/// ###### Replication
///
/// Updates to CRDTs can be shared with replicas in two ways: state-based
/// replication and operation-based replication. With state-based replication,
/// the entire state of the mutated CRDT is merged into remote replicas in order
/// to restore consistency. With operation-based replication, only the mutating
/// operation is applied to remote replicas in order to restore consistency.
/// Operation-based replication is lighter weight in terms of the amount of
/// data which must be transmitted to replicas per mutation, but has the
/// requirement that all operations must be reliably broadcast and applied to
/// remote replicas. State-based replication schemes can maintain (eventual)
/// consistency merely by guaranteeing that state based replication will
/// (eventually) happen. Shapiro, et al. have shown that state-based CRDTs are
/// equivalent to operation-based CRDTs. The CRDTs exposed by this library
/// allow for either state-based or operation-based replication, or a mix of
/// both.
///
/// ###### Replica ID
///
/// Many CRDTs require a `uint` identifier, or replica ID, upon creation. The
/// replica ID **must** be unique among replicas, so it should be taken from
/// unique per-replica configuration, or from a source of strong coordination
/// such as [ZooKeeper](http://zookeeper.apache.org/) or
/// [etcd](https://github.com/coreos/etcd) (implementing a Rust client for these
/// services is left as an exercise for the reader).
///
/// ###### Transaction IDs
///
/// Many CRDTs require the user to provide a transaction ID when performing
/// mutating operations. Transaction IDs provided to an individual replica
/// **must** be monotonically increasing across operations. Transaction IDs
/// across replicas **must** be unique, and **should** be as close to globally
/// monotonically increasing as possible. Unlike replicas IDs, these
/// requirements do not require strong coordination among replicas. See
/// [Snowflake](https://github.com/twitter/snowflake) for an example of
/// distributed, uncoordinated ID generation which meets the requirements.
///
/// ###### Partial Ordering
///
/// Replicas of a CRDT are partially-ordered over the set of possible
/// operations. If all operations applied to replica `B` have been applied to
/// `A` (or, somewhat equivalently, if `B` has been merged into `A`), then
/// `A <= B`.
///
/// ###### Equality
///
/// Equality among CRDT replicas does not take into account the replica ID;
/// only the operation history is taken into account.
pub trait Crdt<Operation> : PartialOrd + Clone {

    /// Merge a replica into this CRDT.
    ///
    /// This method is used to perform state-based replication.
    fn merge(&mut self, other: Self);

    /// Apply an operation to this CRDT.
    ///
    /// This method is used to perform operation-based replication.
    fn apply(&mut self, operation: Operation);
}
<|endoftext|>


<commit_before>
// Copyright 2017 The gltf Library Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern crate gl;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;

#[macro_use]
mod macros;

pub mod v1;
pub mod v2;

/// Error encountered when loading a glTF asset
#[derive(Debug)]
pub enum ImportError {
    /// Failure when deserializing a .gltf metadata file
    Deserialize(serde_json::error::Error),
    /// The .gltf data is invalid
    Invalid(String),
    /// Standard input / output error
    Io(std::io::Error),
    /// glTF version is not supported by the library
    Unsupported(Version),
}

/// Error encountered when converting a glTF asset from one version to another
#[derive(Clone, Debug)]
pub enum ConversionError {
    /// *Unimplemented*
    Unimplemented,
}

/// A imported glTF asset of generic version
pub enum Generic {
    /// A 1.x.x conforming asset
    V1(v1::Root),
    /// A 2.x.x conforming asset
    V2(v2::Root),
}

/// glTF specification version x.x.x
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Version(u32, u32, u32);

/// Attempts to parse the `asset.version` field of a .gltf file
fn detect_version(json: &str) -> Result<Version, String> {
    #[derive(Deserialize)]
    struct Asset {
        version: String,
    }

    #[derive(Deserialize)]
    struct Root {
        asset: Asset,
    }

    match serde_json::from_str::<Root>(&json) {
        Ok(root) => {
            let mut iter = root.asset
                .version
                .split(".")
                .filter_map(|s| s.parse().ok());
            let major = iter.next();
            let minor = iter.next().unwrap_or(0);
            let patch = iter.next().unwrap_or(0);
            match major {
                Some(n) => Ok(Version(n, minor, patch)),
                None => Err(format!("asset.version \"{}\" invalid",
                                    root.asset.version.to_owned())),
            }
        },
        Err(_) => Err("asset.version field missing".to_string()),
    }
}

/// Imports a glTF asset
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// let path = "glTF-Sample-Models/1.0/Box/glTF/Box.gltf";
/// let gltf = gltf::import(path).expect("Error importing glTF asset");
/// ```
pub fn import<P>(path: P) -> Result<Generic, ImportError>
    where P: AsRef<std::path::Path>
{
    use std::io::Read;
    let mut file = std::fs::File::open(path).map_err(ImportError::Io)?;
    let mut json = String::new();
    let _ = file.read_to_string(&mut json).map_err(ImportError::Io)?;
    match detect_version(&json) {
        Ok(Version(1, 0, 0)) => {
            let root = v1::Root::import_from_str(&json)?;
            Ok(Generic::V1(root))
        }
        Ok(Version(2, 0, 0)) => {
            let root = v2::Root::import_from_str(&json)?;
            Ok(Generic::V2(root))
        }
        Ok(other) => Err(ImportError::Unsupported(other)),
        Err(err) => Err(ImportError::Invalid(err)),
    }
}

impl Generic {
    /// Converts an imported asset to a 1.0 conforming version
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// let path = "glTF-Sample-Models/1.0/Box/glTF/Box.gltf";
    /// let gltf = gltf::import(path).expect("Error importing glTF asset")
    ///     .to_v1()
    ///     .expect("Error converting asset to glTF version 1.0");
    /// ```
    pub fn to_v1(self) -> Result<v1::Root, ConversionError> {
        match self {
            Generic::V1(root) => Ok(root),
            Generic::V2(_) => unimplemented!(),
        }
    }

    /// Converts a loaded asset to a 2.0 conforming version
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// let path = "glTF-Sample-Models/2.0/BoomBox/glTF/BoomBox.gltf";
    /// let gltf = gltf::import(path).expect("Error loading glTF asset")
    ///     .to_v2()
    ///     .expect("Error converting asset to glTF version 2.0");
    /// ```
    pub fn to_v2(self) -> Result<v2::Root, ConversionError> {
        match self {
            Generic::V1(_) => unimplemented!(),
            Generic::V2(root) => Ok(root),
        }
    }
}

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

    #[test]
    fn detect_version_100() {
        let json = "{\"asset\":{\"version\":\"1.0.0\"}}";
        assert_eq!(detect_version(&json), Ok(Version(1, 0, 0)));
    }

    #[test]
    fn detect_version_200() {
        let json = "{\"asset\":{\"version\":\"2.0.0\"}}";
        assert_eq!(detect_version(&json), Ok(Version(2, 0, 0)));
    }

    #[test]
    fn detect_missing_version() {
        let json = "{}";
        assert_eq!(detect_version(&json),
                   Err("asset.version field missing".to_string()));
    }

    #[test]
    fn allow_extra_fields() {
        let json = "{\"asset\":{\"version\":\"1.0.0\",\"foo\":{}},\"bar\":{}}";
        assert_eq!(detect_version(&json), Ok(Version(1, 0, 0)));
    }
}
<commit_msg>Made Version a private type.<commit_after>
// Copyright 2017 The gltf Library Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern crate gl;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;

#[macro_use]
mod macros;

pub mod v1;
pub mod v2;

/// Error encountered when loading a glTF asset
#[derive(Debug)]
pub enum ImportError {
    /// Failure when deserializing a .gltf metadata file
    Deserialize(serde_json::error::Error),
    /// The .gltf data is invalid
    Invalid(String),
    /// Standard input / output error
    Io(std::io::Error),
    /// glTF version is not supported by the library
    Unsupported(String),
}

/// Error encountered when converting a glTF asset from one version to another
#[derive(Clone, Debug)]
pub enum ConversionError {
    /// *Unimplemented*
    Unimplemented,
}

/// A imported glTF asset of generic version
pub enum Generic {
    /// A 1.x.x conforming asset
    V1(v1::Root),
    /// A 2.x.x conforming asset
    V2(v2::Root),
}

/// glTF specification version x.x.x
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
struct Version(u32, u32, u32);

/// Attempts to parse the `asset.version` field of a .gltf file
fn detect_version(json: &str) -> Result<Version, String> {
    #[derive(Deserialize)]
    struct Asset {
        version: String,
    }

    #[derive(Deserialize)]
    struct Root {
        asset: Asset,
    }

    match serde_json::from_str::<Root>(&json) {
        Ok(root) => {
            let mut iter = root.asset
                .version
                .split(".")
                .filter_map(|s| s.parse().ok());
            let major = iter.next();
            let minor = iter.next().unwrap_or(0);
            let patch = iter.next().unwrap_or(0);
            match major {
                Some(n) => Ok(Version(n, minor, patch)),
                None => Err(format!("asset.version \"{}\" invalid",
                                    root.asset.version.to_owned())),
            }
        },
        Err(_) => Err("asset.version field missing".to_string()),
    }
}

/// Imports a glTF asset
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// let path = "glTF-Sample-Models/1.0/Box/glTF/Box.gltf";
/// let gltf = gltf::import(path).expect("Error importing glTF asset");
/// ```
pub fn import<P>(path: P) -> Result<Generic, ImportError>
    where P: AsRef<std::path::Path>
{
    use std::io::Read;
    let mut file = std::fs::File::open(path).map_err(ImportError::Io)?;
    let mut json = String::new();
    let _ = file.read_to_string(&mut json).map_err(ImportError::Io)?;
    match detect_version(&json) {
        Ok(Version(1, 0, 0)) => {
            let root = v1::Root::import_from_str(&json)?;
            Ok(Generic::V1(root))
        }
        Ok(Version(2, 0, 0)) => {
            let root = v2::Root::import_from_str(&json)?;
            Ok(Generic::V2(root))
        }
        Ok(Version(major, minor, patch)) => {
            let trio = format!("{}.{}.{}", major, minor, patch);
            Err(ImportError::Unsupported(trio))
        }
        Err(err) => Err(ImportError::Invalid(err)),
    }
}

impl Generic {
    /// Converts an imported asset to a 1.0 conforming version
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// let path = "glTF-Sample-Models/1.0/Box/glTF/Box.gltf";
    /// let gltf = gltf::import(path).expect("Error importing glTF asset")
    ///     .to_v1()
    ///     .expect("Error converting asset to glTF version 1.0");
    /// ```
    pub fn to_v1(self) -> Result<v1::Root, ConversionError> {
        match self {
            Generic::V1(root) => Ok(root),
            Generic::V2(_) => unimplemented!(),
        }
    }

    /// Converts a loaded asset to a 2.0 conforming version
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// let path = "glTF-Sample-Models/2.0/BoomBox/glTF/BoomBox.gltf";
    /// let gltf = gltf::import(path).expect("Error loading glTF asset")
    ///     .to_v2()
    ///     .expect("Error converting asset to glTF version 2.0");
    /// ```
    pub fn to_v2(self) -> Result<v2::Root, ConversionError> {
        match self {
            Generic::V1(_) => unimplemented!(),
            Generic::V2(root) => Ok(root),
        }
    }
}

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

    #[test]
    fn detect_version_100() {
        let json = "{\"asset\":{\"version\":\"1.0.0\"}}";
        assert_eq!(detect_version(&json), Ok(Version(1, 0, 0)));
    }

    #[test]
    fn detect_version_200() {
        let json = "{\"asset\":{\"version\":\"2.0.0\"}}";
        assert_eq!(detect_version(&json), Ok(Version(2, 0, 0)));
    }

    #[test]
    fn detect_missing_version() {
        let json = "{}";
        assert_eq!(detect_version(&json),
                   Err("asset.version field missing".to_string()));
    }

    #[test]
    fn allow_extra_fields() {
        let json = "{\"asset\":{\"version\":\"1.0.0\",\"foo\":{}},\"bar\":{}}";
        assert_eq!(detect_version(&json), Ok(Version(1, 0, 0)));
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate pretty_assertions;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;

// we get an unused import when using macro use, but a
// "this has no effect without macro_use" message otherwise
#[allow(unused_imports)]
#[macro_use]
extern crate snapshot_proc_macro;

pub use snapshot_proc_macro::*;

use std::collections::HashMap;
use std::ffi::OsString;
use std::fmt::Debug;
use std::fs::{create_dir_all, File};
use std::io::BufReader;
use std::path::{Path, PathBuf};
use serde::Serialize;
use serde::de::DeserializeOwned;

pub trait Snapable {}
impl<T> Snapable for T where T: Debug + DeserializeOwned + Serialize {}

#[derive(Debug, Deserialize, PartialEq, Serialize)]
pub struct Snapshot<S: Snapable> {
    pub file: String,
    pub module_path: String,
    pub test_function: String,
    pub recorded_value: S,
}

impl<S> Snapshot<S>
    where S: Snapable + Debug + DeserializeOwned + PartialEq + Serialize
{
    pub fn check_snapshot(&self, manifest_dir: &str) {
        let SnapFileSpec {
            absolute_path,
            relative_path,
            ..
        } = self.path(manifest_dir);

        let snap_file = match File::open(&absolute_path) {
            Ok(f) => f,
            Err(why) => {
                panic!("Unable to open snapshot file {:?}: {:?}",
                       relative_path,
                       why.kind())
            }
        };

        let rdr = BufReader::new(snap_file);
        let mut module_snapshots: HashMap<String, Snapshot<serde_json::Value>> =
            match serde_json::from_reader(rdr) {
                Ok(ps) => ps,
                Err(why) => {
                    panic!("Unable to parse previous snapshot as the correct type:\n{:#?}",
                           why);
                }
            };

        let snap_key = self.module_key();
        let previous_snapshot = match module_snapshots.remove(&snap_key) {
            Some(s) => s,
            None => {
                panic!("Unable to find snapshot for test {:?} in {:?}",
                       snap_key,
                       relative_path)
            }
        };

        let previous_snapshot = match serde_json::from_value(previous_snapshot.recorded_value) {
            Ok(v) => {
                Snapshot {
                    recorded_value: v,
                    file: previous_snapshot.file,
                    test_function: previous_snapshot.test_function,
                    module_path: previous_snapshot.module_path,
                }
            }
            Err(why) => {
                panic!("Unable to parse existing snapshot as correct type: {:?}",
                       why)
            }
        };

        assert_eq!(self.file,
                   previous_snapshot.file,
                   "Filename for snapshot test function doesn't match recorded one");

        assert_eq!(self.module_path,
                   previous_snapshot.module_path,
                   "Module paths for snapshot test function doesn't match recorded one");

        assert_eq!(self.test_function,
                   previous_snapshot.test_function,
                   "Test function name doesn't match recorded one");

        assert_eq!(self.recorded_value,
                   previous_snapshot.recorded_value,
                   "Test output doesn't match recorded snapshot!");

        // just as a catch all in case we need other fields?
        assert_eq!(self, &previous_snapshot, "Snapshot metadata is corrupt!");
    }

    pub fn update_snapshot(&self, manifest_dir: &str) {
        let SnapFileSpec {
            dir: snap_dir,
            filename: snap_filename,
            absolute_path,
            relative_path,
        } = self.path(manifest_dir);

        let mut dir_to_create = PathBuf::from(manifest_dir);
        dir_to_create.push(snap_dir.clone());
        match create_dir_all(&dir_to_create) {
            Ok(_) => (),
            Err(why) => {
                panic!("Unable to create snapshots directory {:?}: {:?}",
                       snap_dir,
                       why.kind())
            }
        }

        let snap_file = match File::create(&absolute_path) {
            Ok(f) => f,
            Err(why) => {
                panic!("Unable to create snapshot file {:?}: {:?}",
                       relative_path,
                       why.kind())
            }
        };

        // TODO write snapshot to disk

        unimplemented!();
    }

    fn module_key(&self) -> String {
        let mut snapshot_key = self.module_path.to_owned();
        snapshot_key.push_str("::");
        snapshot_key.push_str(&self.test_function);
        snapshot_key
    }

    fn path(&self, manifest_dir: &str) -> SnapFileSpec {
        let file_path = &Path::new(&self.file);

        let mut components = file_path.components();

        // strip the filename
        let mut filename = components.next_back().unwrap().as_os_str().to_owned();
        filename.push(".snap");

        let mut dir = PathBuf::new();
        for directory in components {
            dir.push(directory.as_os_str());
        }

        dir.push("__snapshots__");

        let mut absolute_path = PathBuf::from(manifest_dir);
        absolute_path.push(dir.clone());
        absolute_path.push(filename.clone());

        let mut relative_path = PathBuf::from(dir.clone());
        relative_path.push(filename.clone());

        SnapFileSpec {
            dir,
            filename,
            absolute_path,
            relative_path,
        }
    }
}

struct SnapFileSpec {
    dir: PathBuf,
    filename: OsString,
    relative_path: PathBuf,
    absolute_path: PathBuf,
}
<commit_msg>Handle polymorphic snapshot types without resorting to catch-all assertion.<commit_after>#[macro_use]
extern crate pretty_assertions;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;

// we get an unused import when using macro use, but a
// "this has no effect without macro_use" message otherwise
#[allow(unused_imports)]
#[macro_use]
extern crate snapshot_proc_macro;

pub use snapshot_proc_macro::*;

use std::collections::HashMap;
use std::ffi::OsString;
use std::fmt::Debug;
use std::fs::{create_dir_all, File};
use std::io::BufReader;
use std::path::{Path, PathBuf};
use serde::Serialize;
use serde::de::DeserializeOwned;

pub trait Snapable {}
impl<T> Snapable for T where T: Debug + DeserializeOwned + Serialize {}

#[derive(Debug, Deserialize, PartialEq, Serialize)]
pub struct Snapshot<S: Snapable> {
    pub file: String,
    pub module_path: String,
    pub test_function: String,
    pub recorded_value: S,
}

impl<S> Snapshot<S>
    where S: Snapable + Debug + DeserializeOwned + PartialEq + Serialize
{
    pub fn check_snapshot(&self, manifest_dir: &str) {
        let SnapFileSpec {
            absolute_path,
            relative_path,
            ..
        } = self.path(manifest_dir);

        let snap_file = match File::open(&absolute_path) {
            Ok(f) => f,
            Err(why) => {
                panic!("Unable to open snapshot file {:?}: {:?}",
                       relative_path,
                       why.kind())
            }
        };

        let rdr = BufReader::new(snap_file);
        let mut module_snapshots: HashMap<String, Snapshot<serde_json::Value>> =
            match serde_json::from_reader(rdr) {
                Ok(ps) => ps,
                Err(why) => {
                    panic!("Unable to parse previous snapshot:\n{:#?}", why);
                }
            };

        let snap_key = self.module_key();
        let previous_snapshot = match module_snapshots.remove(&snap_key) {
            Some(s) => s,
            None => {
                panic!("Unable to find snapshot for test {:?} in {:?}",
                       snap_key,
                       relative_path)
            }
        };

        let Snapshot {
            recorded_value,
            file,
            module_path,
            test_function,
        } = previous_snapshot;

        match serde_json::from_value(recorded_value) {
            Ok(recorded_value) => {
                assert_eq!(self.file,
                           file,
                           "Filename for snapshot test function doesn't match recorded one");

                assert_eq!(self.module_path,
                           module_path,
                           "Module paths for snapshot test function doesn't match recorded one");

                assert_eq!(self.test_function,
                           test_function,
                           "Test function name doesn't match recorded one");

                assert_eq!(self.recorded_value,
                           recorded_value,
                           "Test output doesn't match recorded snapshot!");
            }
            Err(why) => {
                panic!("Unable to parse existing snapshot as correct type: {:?}",
                       why)
            }
        }
    }

    pub fn update_snapshot(&self, manifest_dir: &str) {
        let SnapFileSpec {
            dir: snap_dir,
            filename: snap_filename,
            absolute_path,
            relative_path,
        } = self.path(manifest_dir);

        let mut dir_to_create = PathBuf::from(manifest_dir);
        dir_to_create.push(snap_dir.clone());
        match create_dir_all(&dir_to_create) {
            Ok(_) => (),
            Err(why) => {
                panic!("Unable to create snapshots directory {:?}: {:?}",
                       snap_dir,
                       why.kind())
            }
        }

        let snap_file = match File::create(&absolute_path) {
            Ok(f) => f,
            Err(why) => {
                panic!("Unable to create snapshot file {:?}: {:?}",
                       relative_path,
                       why.kind())
            }
        };

        // TODO write snapshot to disk

        unimplemented!();
    }

    fn module_key(&self) -> String {
        let mut snapshot_key = self.module_path.to_owned();
        snapshot_key.push_str("::");
        snapshot_key.push_str(&self.test_function);
        snapshot_key
    }

    fn path(&self, manifest_dir: &str) -> SnapFileSpec {
        let file_path = &Path::new(&self.file);

        let mut components = file_path.components();

        // strip the filename
        let mut filename = components.next_back().unwrap().as_os_str().to_owned();
        filename.push(".snap");

        let mut dir = PathBuf::new();
        for directory in components {
            dir.push(directory.as_os_str());
        }

        dir.push("__snapshots__");

        let mut absolute_path = PathBuf::from(manifest_dir);
        absolute_path.push(dir.clone());
        absolute_path.push(filename.clone());

        let mut relative_path = PathBuf::from(dir.clone());
        relative_path.push(filename.clone());

        SnapFileSpec {
            dir,
            filename,
            absolute_path,
            relative_path,
        }
    }
}

struct SnapFileSpec {
    dir: PathBuf,
    filename: OsString,
    relative_path: PathBuf,
    absolute_path: PathBuf,
}
<|endoftext|>


<commit_before>extern crate libc;

use std::convert::From;
use std::error;
use std::ffi::CStr;
use std::fmt;
use std::fs::File;
use std::io;
use std::io::Read;
use std::path::Path;
use std::result;

use libc::{c_char, c_short, c_int};

/// The error type for SPC operations; either an io::Error, or an error
/// originating within the underlying snes_spc library. The latter case
/// is just exposed as a string containing the error message.
#[derive(Debug)]
pub enum SpcError {
    Io(io::Error),
    Internal(String)
}

impl fmt::Display for SpcError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            SpcError::Io(ref e) => write!(f, "IO error: {}", e),
            SpcError::Internal(ref e) => write!(f, "Internal SPC error: {}", e),
        }
    }
}

impl error::Error for SpcError {
    fn description(&self) -> &str {
        match *self {
            SpcError::Io(ref e) => e.description(),
            SpcError::Internal(ref e) => &e,
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            SpcError::Io(ref e) => Some(e),
            SpcError::Internal(_) => None
        }
    }
}

impl From<io::Error> for SpcError {
    fn from(err: io::Error) -> SpcError {
        SpcError::Io(err)
    }
}

impl From<String> for SpcError {
    fn from(err: String) -> SpcError {
        SpcError::Internal(err)
    }
}

/// Convert an ffi C-string into our error type. Deal with the rigmarole
/// of cloning into an owned string.
impl From<*const c_char> for SpcError {
    fn from(err: *const c_char) -> SpcError {
        unsafe {
            SpcError::Internal(String::from_utf8_lossy(
                CStr::from_ptr(err).to_bytes()).into_owned())
        }
    }
}

/// The result type for SPC operations that may fail.
pub type Result<T> = result::Result<T, SpcError>;

/// Convert a possibly null ffi C-string into our Result<()> type.
/// N.B.: this is not an implementation of `std::convert::From` because
/// Rust's coherency rules prohibit us from defining external traits for
/// `snes_spc::Result`, which is just an alias of `std::result::Result`.
/// This makes tiny kittens sad, but they try their best to understand.
fn result_from(err: *const c_char) -> Result<()> {
    if err.is_null() {
        Ok(())
    } else {
        Err(SpcError::from(err))
    }
}

/// A type for the internal library's opaque struct SNES_SPC
enum SpcHandle {}

#[link(name = "snes_spc")]
extern {
    // Instantiate a new SPC emulator and return a handle to it.
    fn spc_new() -> *mut SpcHandle;

    // Free an SPC emulator given its handle.
    fn spc_delete(spc: *mut SpcHandle);

    // Load SPC data into emulator.
    fn spc_load_spc(spc: *mut SpcHandle, data: *const u8, len: c_int)
        -> *const c_char;

    // Clear SPC echo buffer.
    fn spc_clear_echo(spc: *mut SpcHandle);

    // Emulate SPC output, recording `count` 16-bit samples to `out`
    fn spc_play(spc: *mut SpcHandle, count: c_int, out: *mut c_short)
        -> *const c_char;
}

/// A simple, safe wrapper around an opaque SNES_SPC handle.
pub struct SnesSpc {
    handle: *mut SpcHandle
}

/// SnesSpc's internal handle is never exposed except through its safe
/// implementation, so it should be save to move to another thread.
unsafe impl Send for SnesSpc {}

impl SnesSpc {
    pub fn new() -> SnesSpc {
        unsafe {
            SnesSpc {
                handle: spc_new()
            }
        }
    }

    /// Creates a new `SnesSpc` using a byte slice as its initial SPC data.
    pub fn from_data(data: &[u8]) -> Result<SnesSpc> {
        let mut spc = SnesSpc::new();
        try!(spc.load_spc(data));
        Ok(spc)
    }

    /// Creates a new SPC emulator initially loaded with the contents of a
    /// file at the given path.
    pub fn from_file<P: AsRef<Path>>(path: P) -> Result<SnesSpc> {
        let mut data = Vec::new();
        let mut file = try!(File::open(path));
        try!(file.read_to_end(&mut data));
        SnesSpc::from_data(&data)
    }

    /// Loads data into the SPC emulator.
    pub fn load_spc(&mut self, data: &[u8]) -> Result<()> {
        unsafe {
            result_from(spc_load_spc(
                self.handle, data.as_ptr(), data.len() as c_int))
        }
    }

    /// Clears the SPC emulator's echo buffer. This can be useful if loading
    /// SPC files that have garbage in the initial echo buffer.
    pub fn clear_echo(&mut self) {
        unsafe {
            spc_clear_echo(self.handle);
        }
    }

    /// Emulate a specified number of samples, storing them in a given buffer.
    pub fn play(&mut self, count: u32, out: &mut [i16]) -> Result<()> {
        unsafe {
            // TODO: check that out is big enough :)
            result_from(spc_play(self.handle, count as c_int, out.as_mut_ptr()))
        }
    }
}

#[test]
fn can_call_unsafe_api_without_exploding() {
    unsafe {
        let mut spc = spc_new();
        spc_delete(spc);
    }
}

#[test]
fn can_use_safe_wrapper_without_being_stabbed() {
    let mut spc = SnesSpc::new();
    spc.clear_echo();
    // Drop it!
}
<commit_msg>Add Drop impl for SnesSpc. Oopsie, how'd I leave that out? ;)<commit_after>extern crate libc;

use std::convert::From;
use std::error;
use std::ffi::CStr;
use std::fmt;
use std::fs::File;
use std::io;
use std::io::Read;
use std::path::Path;
use std::result;

use libc::{c_char, c_short, c_int};

/// The error type for SPC operations; either an io::Error, or an error
/// originating within the underlying snes_spc library. The latter case
/// is just exposed as a string containing the error message.
#[derive(Debug)]
pub enum SpcError {
    Io(io::Error),
    Internal(String)
}

impl fmt::Display for SpcError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            SpcError::Io(ref e) => write!(f, "IO error: {}", e),
            SpcError::Internal(ref e) => write!(f, "Internal SPC error: {}", e),
        }
    }
}

impl error::Error for SpcError {
    fn description(&self) -> &str {
        match *self {
            SpcError::Io(ref e) => e.description(),
            SpcError::Internal(ref e) => &e,
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            SpcError::Io(ref e) => Some(e),
            SpcError::Internal(_) => None
        }
    }
}

impl From<io::Error> for SpcError {
    fn from(err: io::Error) -> SpcError {
        SpcError::Io(err)
    }
}

impl From<String> for SpcError {
    fn from(err: String) -> SpcError {
        SpcError::Internal(err)
    }
}

/// Convert an ffi C-string into our error type. Deal with the rigmarole
/// of cloning into an owned string.
impl From<*const c_char> for SpcError {
    fn from(err: *const c_char) -> SpcError {
        unsafe {
            SpcError::Internal(String::from_utf8_lossy(
                CStr::from_ptr(err).to_bytes()).into_owned())
        }
    }
}

/// The result type for SPC operations that may fail.
pub type Result<T> = result::Result<T, SpcError>;

/// Convert a possibly null ffi C-string into our Result<()> type.
/// N.B.: this is not an implementation of `std::convert::From` because
/// Rust's coherency rules prohibit us from defining external traits for
/// `snes_spc::Result`, which is just an alias of `std::result::Result`.
/// This makes tiny kittens sad, but they try their best to understand.
fn result_from(err: *const c_char) -> Result<()> {
    if err.is_null() {
        Ok(())
    } else {
        Err(SpcError::from(err))
    }
}

/// A type for the internal library's opaque struct SNES_SPC
enum SpcHandle {}

#[link(name = "snes_spc")]
extern {
    // Instantiate a new SPC emulator and return a handle to it.
    fn spc_new() -> *mut SpcHandle;

    // Free an SPC emulator given its handle.
    fn spc_delete(spc: *mut SpcHandle);

    // Load SPC data into emulator.
    fn spc_load_spc(spc: *mut SpcHandle, data: *const u8, len: c_int)
        -> *const c_char;

    // Clear SPC echo buffer.
    fn spc_clear_echo(spc: *mut SpcHandle);

    // Emulate SPC output, recording `count` 16-bit samples to `out`
    fn spc_play(spc: *mut SpcHandle, count: c_int, out: *mut c_short)
        -> *const c_char;
}

/// A simple, safe wrapper around an opaque SNES_SPC handle.
pub struct SnesSpc {
    handle: *mut SpcHandle
}

/// SnesSpc's internal handle is never exposed except through its safe
/// implementation, so it should be save to move to another thread.
unsafe impl Send for SnesSpc {}

impl SnesSpc {
    pub fn new() -> SnesSpc {
        unsafe {
            SnesSpc {
                handle: spc_new()
            }
        }
    }

    /// Creates a new `SnesSpc` using a byte slice as its initial SPC data.
    pub fn from_data(data: &[u8]) -> Result<SnesSpc> {
        let mut spc = SnesSpc::new();
        try!(spc.load_spc(data));
        Ok(spc)
    }

    /// Creates a new SPC emulator initially loaded with the contents of a
    /// file at the given path.
    pub fn from_file<P: AsRef<Path>>(path: P) -> Result<SnesSpc> {
        let mut data = Vec::new();
        let mut file = try!(File::open(path));
        try!(file.read_to_end(&mut data));
        SnesSpc::from_data(&data)
    }

    /// Loads data into the SPC emulator.
    pub fn load_spc(&mut self, data: &[u8]) -> Result<()> {
        unsafe {
            result_from(spc_load_spc(
                self.handle, data.as_ptr(), data.len() as c_int))
        }
    }

    /// Clears the SPC emulator's echo buffer. This can be useful if loading
    /// SPC files that have garbage in the initial echo buffer.
    pub fn clear_echo(&mut self) {
        unsafe {
            spc_clear_echo(self.handle);
        }
    }

    /// Emulate a specified number of samples, storing them in a given buffer.
    pub fn play(&mut self, count: u32, out: &mut [i16]) -> Result<()> {
        unsafe {
            // TODO: check that out is big enough :)
            result_from(spc_play(self.handle, count as c_int, out.as_mut_ptr()))
        }
    }
}

impl Drop for SnesSpc {
    fn drop(&mut self) {
        unsafe {
            spc_delete(self.handle);
        }
    }
}

#[test]
fn can_call_unsafe_api_without_exploding() {
    unsafe {
        let mut spc = spc_new();
        spc_delete(spc);
    }
}

#[test]
fn can_use_safe_wrapper_without_being_stabbed() {
    let mut spc = SnesSpc::new();
    spc.clear_echo();
    // Drop it!
}
<|endoftext|>


<commit_before>//! libc - Raw FFI bindings to platforms' system libraries
//!
//! [Documentation for other platforms][pd].
//!
//! [pd]: https://rust-lang.github.io/libc/#platform-specific-documentation
#![crate_name = "libc"]
#![crate_type = "rlib"]
#![allow(
    renamed_and_removed_lints, // Keep this order.
    unknown_lints, // Keep this order.
    bad_style,
    overflowing_literals,
    improper_ctypes,
    // This lint is renamed but we run CI for old stable rustc so should be here.
    redundant_semicolon,
    redundant_semicolons
)]
#![cfg_attr(libc_deny_warnings, deny(warnings))]
// Attributes needed when building as part of the standard library
#![cfg_attr(
    feature = "rustc-dep-of-std",
    feature(cfg_target_vendor, link_cfg, no_core)
)]
#![cfg_attr(libc_thread_local, feature(thread_local))]
// Enable extra lints:
#![cfg_attr(feature = "extra_traits", deny(missing_debug_implementations))]
#![deny(missing_copy_implementations, safe_packed_borrows)]
#![cfg_attr(not(feature = "rustc-dep-of-std"), no_std)]
#![cfg_attr(feature = "rustc-dep-of-std", no_core)]
#![cfg_attr(
    any(feature = "rustc-dep-of-std", target_os = "redox"),
    feature(static_nobundle)
)]
#![cfg_attr(libc_const_extern_fn, feature(const_extern_fn))]

#[macro_use]
mod macros;

cfg_if! {
    if #[cfg(feature = "rustc-dep-of-std")] {
        extern crate rustc_std_workspace_core as core;
        #[allow(unused_imports)]
        use core::iter;
        #[allow(unused_imports)]
        use core::ops;
        #[allow(unused_imports)]
        use core::option;
    }
}

cfg_if! {
    if #[cfg(libc_priv_mod_use)] {
        #[cfg(libc_core_cvoid)]
        #[allow(unused_imports)]
        use core::ffi;
        #[allow(unused_imports)]
        use core::fmt;
        #[allow(unused_imports)]
        use core::hash;
        #[allow(unused_imports)]
        use core::num;
        #[allow(unused_imports)]
        use core::mem;
        #[doc(hidden)]
        #[allow(unused_imports)]
        use core::clone::Clone;
        #[doc(hidden)]
        #[allow(unused_imports)]
        use core::marker::Copy;
        #[doc(hidden)]
        #[allow(unused_imports)]
        use core::option::Option;
    } else {
        #[doc(hidden)]
        #[allow(unused_imports)]
        pub use core::fmt;
        #[doc(hidden)]
        #[allow(unused_imports)]
        pub use core::hash;
        #[doc(hidden)]
        #[allow(unused_imports)]
        pub use core::num;
        #[doc(hidden)]
        #[allow(unused_imports)]
        pub use core::mem;
        #[doc(hidden)]
        #[allow(unused_imports)]
        pub use core::clone::Clone;
        #[doc(hidden)]
        #[allow(unused_imports)]
        pub use core::marker::Copy;
        #[doc(hidden)]
        #[allow(unused_imports)]
        pub use core::option::Option;
    }
}

cfg_if! {
    if #[cfg(windows)] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod windows;
        pub use windows::*;
    } else if #[cfg(target_os = "cloudabi")] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod cloudabi;
        pub use cloudabi::*;
    } else if #[cfg(target_os = "fuchsia")] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod fuchsia;
        pub use fuchsia::*;
    } else if #[cfg(target_os = "switch")] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod switch;
        pub use switch::*;
    } else if #[cfg(target_os = "psp")] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod psp;
        pub use psp::*;
    } else if #[cfg(target_os = "vxworks")] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod vxworks;
        pub use vxworks::*;
    } else if #[cfg(unix)] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod unix;
        pub use unix::*;
    } else if #[cfg(target_os = "hermit")] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod hermit;
        pub use hermit::*;
    } else if #[cfg(all(target_env = "sgx", target_vendor = "fortanix"))] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod sgx;
        pub use sgx::*;
    } else if #[cfg(any(target_env = "wasi", target_os = "wasi"))] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod wasi;
        pub use wasi::*;
    } else {
        // non-supported targets: empty...
    }
}
<commit_msg>Fix build with rustc-dep-of-std in the latest nightly<commit_after>//! libc - Raw FFI bindings to platforms' system libraries
//!
//! [Documentation for other platforms][pd].
//!
//! [pd]: https://rust-lang.github.io/libc/#platform-specific-documentation
#![crate_name = "libc"]
#![crate_type = "rlib"]
#![allow(
    renamed_and_removed_lints, // Keep this order.
    unknown_lints, // Keep this order.
    bad_style,
    overflowing_literals,
    improper_ctypes,
    // This lint is renamed but we run CI for old stable rustc so should be here.
    redundant_semicolon,
    redundant_semicolons
)]
#![cfg_attr(libc_deny_warnings, deny(warnings))]
// Attributes needed when building as part of the standard library
#![cfg_attr(feature = "rustc-dep-of-std", feature(link_cfg, no_core))]
#![cfg_attr(libc_thread_local, feature(thread_local))]
// Enable extra lints:
#![cfg_attr(feature = "extra_traits", deny(missing_debug_implementations))]
#![deny(missing_copy_implementations, safe_packed_borrows)]
#![cfg_attr(not(feature = "rustc-dep-of-std"), no_std)]
#![cfg_attr(feature = "rustc-dep-of-std", no_core)]
#![cfg_attr(
    any(feature = "rustc-dep-of-std", target_os = "redox"),
    feature(static_nobundle)
)]
#![cfg_attr(libc_const_extern_fn, feature(const_extern_fn))]

#[macro_use]
mod macros;

cfg_if! {
    if #[cfg(feature = "rustc-dep-of-std")] {
        extern crate rustc_std_workspace_core as core;
        #[allow(unused_imports)]
        use core::iter;
        #[allow(unused_imports)]
        use core::ops;
        #[allow(unused_imports)]
        use core::option;
    }
}

cfg_if! {
    if #[cfg(libc_priv_mod_use)] {
        #[cfg(libc_core_cvoid)]
        #[allow(unused_imports)]
        use core::ffi;
        #[allow(unused_imports)]
        use core::fmt;
        #[allow(unused_imports)]
        use core::hash;
        #[allow(unused_imports)]
        use core::num;
        #[allow(unused_imports)]
        use core::mem;
        #[doc(hidden)]
        #[allow(unused_imports)]
        use core::clone::Clone;
        #[doc(hidden)]
        #[allow(unused_imports)]
        use core::marker::Copy;
        #[doc(hidden)]
        #[allow(unused_imports)]
        use core::option::Option;
    } else {
        #[doc(hidden)]
        #[allow(unused_imports)]
        pub use core::fmt;
        #[doc(hidden)]
        #[allow(unused_imports)]
        pub use core::hash;
        #[doc(hidden)]
        #[allow(unused_imports)]
        pub use core::num;
        #[doc(hidden)]
        #[allow(unused_imports)]
        pub use core::mem;
        #[doc(hidden)]
        #[allow(unused_imports)]
        pub use core::clone::Clone;
        #[doc(hidden)]
        #[allow(unused_imports)]
        pub use core::marker::Copy;
        #[doc(hidden)]
        #[allow(unused_imports)]
        pub use core::option::Option;
    }
}

cfg_if! {
    if #[cfg(windows)] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod windows;
        pub use windows::*;
    } else if #[cfg(target_os = "cloudabi")] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod cloudabi;
        pub use cloudabi::*;
    } else if #[cfg(target_os = "fuchsia")] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod fuchsia;
        pub use fuchsia::*;
    } else if #[cfg(target_os = "switch")] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod switch;
        pub use switch::*;
    } else if #[cfg(target_os = "psp")] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod psp;
        pub use psp::*;
    } else if #[cfg(target_os = "vxworks")] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod vxworks;
        pub use vxworks::*;
    } else if #[cfg(unix)] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod unix;
        pub use unix::*;
    } else if #[cfg(target_os = "hermit")] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod hermit;
        pub use hermit::*;
    } else if #[cfg(all(target_env = "sgx", target_vendor = "fortanix"))] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod sgx;
        pub use sgx::*;
    } else if #[cfg(any(target_env = "wasi", target_os = "wasi"))] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod wasi;
        pub use wasi::*;
    } else {
        // non-supported targets: empty...
    }
}
<|endoftext|>


<commit_before>#![feature(box_syntax)]
#![feature(zero_one)]

pub mod expr;
pub mod symbol;

use std::{fmt, iter};
use expr::NumType;

pub use expr::{Expr, Condition, ExprError};

/// Used to name symbols and variables.
pub trait Alphabet: fmt::Display + fmt::Debug + PartialEq + Eq + Clone {}

impl Alphabet for &'static str {}
impl Alphabet for char {}
impl Alphabet for u8 {}
impl Alphabet for u16 {}
impl Alphabet for u32 {}
impl Alphabet for u64 {}
impl Alphabet for usize {}

/// The common interface for Symbols. Basically this abstracts over
/// the argument implementation.
pub trait Symbol: Clone + PartialEq + fmt::Debug {
    type A: Alphabet;

    type T: NumType;

    fn symbol(&self) -> &Self::A;

    fn args(&self) -> &[Expr<Self::T>];

    fn from_result_iter<I, E>(symbol: Self::A, args_iter: I) -> Result<Self, E> where I: Iterator<Item = Result<Expr<Self::T>, E>>;

    fn new(symbol: Self::A) -> Self {
        Self::from_iter(symbol, iter::empty())
    }

    fn from_iter<I>(symbol: Self::A, args_iter: I) -> Self where I: Iterator<Item = Expr<Self::T>> {
        let res: Result<_, ()> = Self::from_result_iter(symbol, args_iter.map(|i| Ok(i)));
        res.unwrap()
    }

    fn evaluate(&self, bindings: &[Expr<Self::T>]) -> Result<Self, ExprError> {
        Self::from_result_iter((*self.symbol()).clone(),
                          self.args()
                              .iter()
                              .map(|expr| expr.evaluate(bindings).map(|ok| Expr::Const(ok))))

    }

    fn debug_fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let args = self.args();
        try!(write!(f, "{}", *self.symbol()));
        if args.is_empty() {
            return Ok(());
        }

        try!(write!(f, "("));
        for (i, expr) in args.iter().enumerate() {
            if i > 0 {
                try!(write!(f, ", "));
            }
            try!(write!(f, "{:?}", expr));
        }
        write!(f, ")")
    }
}

/// A list of Symbols.
#[derive(PartialEq, Eq)]
pub struct SymbolString<S:Symbol>(pub Vec<S>);

impl<S:Symbol> fmt::Debug for SymbolString<S> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for sym in self.0.iter() {
            try!(write!(f, "{:?}", sym));
        }
        Ok(())
    }
}

impl<S:Symbol> SymbolString<S> {
    fn from_result_iter<I, E>(symbol_iter: I) -> Result<SymbolString<S>, E>
        where I: Iterator<Item = Result<S, E>>
    {
        let mut symbols = Vec::with_capacity(symbol_iter.size_hint().0);
        for sym in symbol_iter.into_iter() {
            symbols.push(try!(sym));
        }
        Ok(SymbolString(symbols))
    }

    pub fn evaluate(&self, bindings: &[Expr<S::T>]) -> Result<SymbolString<S>, ExprError> {
        SymbolString::from_result_iter(self.0.iter().map(|sym| sym.evaluate(bindings)))
    }
}

#[derive(Debug)]
pub struct Rule<S: Symbol> {
    pub symbol: S::A,
    pub condition: Condition<S::T>,
    pub successor: SymbolString<S>,
}

#[derive(Debug, Eq, PartialEq)]
pub enum RuleError {
    SymbolMismatch,
    ConditionFalse,
    ConditionFailed,
    ExprFailed(ExprError),
}

impl<S:Symbol> Rule<S> {
    pub fn new(symbol: S::A, successor: SymbolString<S>) -> Rule<S> {
        Rule {
            symbol: symbol,
            condition: Condition::True,
            successor: successor,
        }
    }

    pub fn new_conditional(symbol: S::A,
                           successor: SymbolString<S>,
                           condition: Condition<S::T>)
                           -> Rule<S> {
        Rule {
            symbol: symbol,
            condition: condition,
            successor: successor,
        }
    }

    /// Apply the rule to the given (constant) symbol and if possible, produce
    /// a successor.
    pub fn apply(&self, sym: &S) -> Result<SymbolString<S>, RuleError> {
        let args = sym.args();
        if self.symbol.eq(sym.symbol()) {
            match self.condition.evaluate(args) {
                Ok(true) => {
                    match self.successor.evaluate(args) {
                        Ok(symstr) => Ok(symstr),
                        Err(e) => Err(RuleError::ExprFailed(e)),
                    }
                }
                Ok(false) => {
                    Err(RuleError::ConditionFalse)
                }
                _ => {
                    Err(RuleError::ConditionFailed)
                }
            }
        } else {
            Err(RuleError::SymbolMismatch)
        }
    }
}

#[test]
fn test_rule_apply() {
    use symbol::DSym;
    let p = DSym::new_parametric("P", vec![Expr::Const(123u32)]);
    let rule = Rule::new("A", SymbolString(vec![p.clone()]));
    assert_eq!(Err(RuleError::SymbolMismatch),
               rule.apply(&DSym::new("P")));
    assert_eq!(Ok(SymbolString(vec![DSym::new_parametric("P", vec![Expr::Const(123u32)])])),
               rule.apply(&DSym::new("A")));

    let rule = Rule::new_conditional("A", SymbolString(vec![p.clone()]), Condition::False);
    assert_eq!(Err(RuleError::ConditionFalse),
               rule.apply(&DSym::new("A")));
}

#[derive(Debug)]
pub struct System<S: Symbol> {
    rules: Vec<Rule<S>>,
}

impl<S:Symbol> System<S> {
    pub fn new() -> System<S> {
        System { rules: vec![] }
    }

    pub fn add_rule(&mut self, rule: Rule<S>) {
        self.rules.push(rule);
    }

    /// Apply first matching rule and return expanded successor.
    fn apply_first_rule(&self, sym: &S) -> Option<SymbolString<S>> {
        for rule in self.rules.iter() {
            if let Ok(successor) = rule.apply(sym) {
                return Some(successor);
            }
        }
        return None;
    }

    /// Apply in parallel the first matching rule to each symbol in the string.
    /// Returns the total number of rule applications.
    pub fn develop_step(&self, axiom: &SymbolString<S>) -> (SymbolString<S>, usize) {
        let mut expanded = Vec::new();
        let mut rule_applications = 0;

        for sym in axiom.0.iter() {
            match self.apply_first_rule(sym) {
                Some(successor) => {
                    expanded.extend(successor.0);
                    rule_applications += 1;
                    // XXX: Count rule applications of the matching rule.
                }
                None => {
                    expanded.push(sym.clone());
                }
            }
        }

        (SymbolString(expanded), rule_applications)
    }

    /// Develop the system starting with `axiom` up to `max_iterations`. Return iteration count.
    pub fn develop(&self,
                   axiom: SymbolString<S>,
                   max_iterations: usize)
                   -> (SymbolString<S>, usize) {
        let mut current = axiom;

        for iter in 0..max_iterations {
            let (next, rule_applications) = self.develop_step(&current);
            if rule_applications == 0 {
                return (current, iter);
            }
            current = next;
        }
        return (current, max_iterations);
    }
}
<commit_msg>derive(Clone) for SymbolString<commit_after>#![feature(box_syntax)]
#![feature(zero_one)]

pub mod expr;
pub mod symbol;

use std::{fmt, iter};
use expr::NumType;

pub use expr::{Expr, Condition, ExprError};

/// Used to name symbols and variables.
pub trait Alphabet: fmt::Display + fmt::Debug + PartialEq + Eq + Clone {}

impl Alphabet for &'static str {}
impl Alphabet for char {}
impl Alphabet for u8 {}
impl Alphabet for u16 {}
impl Alphabet for u32 {}
impl Alphabet for u64 {}
impl Alphabet for usize {}

/// The common interface for Symbols. Basically this abstracts over
/// the argument implementation.
pub trait Symbol: Clone + PartialEq + fmt::Debug {
    type A: Alphabet;

    type T: NumType;

    fn symbol(&self) -> &Self::A;

    fn args(&self) -> &[Expr<Self::T>];

    fn from_result_iter<I, E>(symbol: Self::A, args_iter: I) -> Result<Self, E> where I: Iterator<Item = Result<Expr<Self::T>, E>>;

    fn new(symbol: Self::A) -> Self {
        Self::from_iter(symbol, iter::empty())
    }

    fn from_iter<I>(symbol: Self::A, args_iter: I) -> Self where I: Iterator<Item = Expr<Self::T>> {
        let res: Result<_, ()> = Self::from_result_iter(symbol, args_iter.map(|i| Ok(i)));
        res.unwrap()
    }

    fn evaluate(&self, bindings: &[Expr<Self::T>]) -> Result<Self, ExprError> {
        Self::from_result_iter((*self.symbol()).clone(),
                          self.args()
                              .iter()
                              .map(|expr| expr.evaluate(bindings).map(|ok| Expr::Const(ok))))

    }

    fn debug_fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let args = self.args();
        try!(write!(f, "{}", *self.symbol()));
        if args.is_empty() {
            return Ok(());
        }

        try!(write!(f, "("));
        for (i, expr) in args.iter().enumerate() {
            if i > 0 {
                try!(write!(f, ", "));
            }
            try!(write!(f, "{:?}", expr));
        }
        write!(f, ")")
    }
}

/// A list of Symbols.
#[derive(PartialEq, Eq, Clone)]
pub struct SymbolString<S:Symbol>(pub Vec<S>);

impl<S:Symbol> fmt::Debug for SymbolString<S> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for sym in self.0.iter() {
            try!(write!(f, "{:?}", sym));
        }
        Ok(())
    }
}

impl<S:Symbol> SymbolString<S> {
    fn from_result_iter<I, E>(symbol_iter: I) -> Result<SymbolString<S>, E>
        where I: Iterator<Item = Result<S, E>>
    {
        let mut symbols = Vec::with_capacity(symbol_iter.size_hint().0);
        for sym in symbol_iter.into_iter() {
            symbols.push(try!(sym));
        }
        Ok(SymbolString(symbols))
    }

    pub fn evaluate(&self, bindings: &[Expr<S::T>]) -> Result<SymbolString<S>, ExprError> {
        SymbolString::from_result_iter(self.0.iter().map(|sym| sym.evaluate(bindings)))
    }
}

#[derive(Debug)]
pub struct Rule<S: Symbol> {
    pub symbol: S::A,
    pub condition: Condition<S::T>,
    pub successor: SymbolString<S>,
}

#[derive(Debug, Eq, PartialEq)]
pub enum RuleError {
    SymbolMismatch,
    ConditionFalse,
    ConditionFailed,
    ExprFailed(ExprError),
}

impl<S:Symbol> Rule<S> {
    pub fn new(symbol: S::A, successor: SymbolString<S>) -> Rule<S> {
        Rule {
            symbol: symbol,
            condition: Condition::True,
            successor: successor,
        }
    }

    pub fn new_conditional(symbol: S::A,
                           successor: SymbolString<S>,
                           condition: Condition<S::T>)
                           -> Rule<S> {
        Rule {
            symbol: symbol,
            condition: condition,
            successor: successor,
        }
    }

    /// Apply the rule to the given (constant) symbol and if possible, produce
    /// a successor.
    pub fn apply(&self, sym: &S) -> Result<SymbolString<S>, RuleError> {
        let args = sym.args();
        if self.symbol.eq(sym.symbol()) {
            match self.condition.evaluate(args) {
                Ok(true) => {
                    match self.successor.evaluate(args) {
                        Ok(symstr) => Ok(symstr),
                        Err(e) => Err(RuleError::ExprFailed(e)),
                    }
                }
                Ok(false) => {
                    Err(RuleError::ConditionFalse)
                }
                _ => {
                    Err(RuleError::ConditionFailed)
                }
            }
        } else {
            Err(RuleError::SymbolMismatch)
        }
    }
}

#[test]
fn test_rule_apply() {
    use symbol::DSym;
    let p = DSym::new_parametric("P", vec![Expr::Const(123u32)]);
    let rule = Rule::new("A", SymbolString(vec![p.clone()]));
    assert_eq!(Err(RuleError::SymbolMismatch),
               rule.apply(&DSym::new("P")));
    assert_eq!(Ok(SymbolString(vec![DSym::new_parametric("P", vec![Expr::Const(123u32)])])),
               rule.apply(&DSym::new("A")));

    let rule = Rule::new_conditional("A", SymbolString(vec![p.clone()]), Condition::False);
    assert_eq!(Err(RuleError::ConditionFalse),
               rule.apply(&DSym::new("A")));
}

#[derive(Debug)]
pub struct System<S: Symbol> {
    rules: Vec<Rule<S>>,
}

impl<S:Symbol> System<S> {
    pub fn new() -> System<S> {
        System { rules: vec![] }
    }

    pub fn add_rule(&mut self, rule: Rule<S>) {
        self.rules.push(rule);
    }

    /// Apply first matching rule and return expanded successor.
    fn apply_first_rule(&self, sym: &S) -> Option<SymbolString<S>> {
        for rule in self.rules.iter() {
            if let Ok(successor) = rule.apply(sym) {
                return Some(successor);
            }
        }
        return None;
    }

    /// Apply in parallel the first matching rule to each symbol in the string.
    /// Returns the total number of rule applications.
    pub fn develop_step(&self, axiom: &SymbolString<S>) -> (SymbolString<S>, usize) {
        let mut expanded = Vec::new();
        let mut rule_applications = 0;

        for sym in axiom.0.iter() {
            match self.apply_first_rule(sym) {
                Some(successor) => {
                    expanded.extend(successor.0);
                    rule_applications += 1;
                    // XXX: Count rule applications of the matching rule.
                }
                None => {
                    expanded.push(sym.clone());
                }
            }
        }

        (SymbolString(expanded), rule_applications)
    }

    /// Develop the system starting with `axiom` up to `max_iterations`. Return iteration count.
    pub fn develop(&self,
                   axiom: SymbolString<S>,
                   max_iterations: usize)
                   -> (SymbolString<S>, usize) {
        let mut current = axiom;

        for iter in 0..max_iterations {
            let (next, rule_applications) = self.develop_step(&current);
            if rule_applications == 0 {
                return (current, iter);
            }
            current = next;
        }
        return (current, max_iterations);
    }
}
<|endoftext|>