<commit_before>#[doc = "Unsafe pointer utility functions"];

export addr_of;
export mut_addr_of;
export offset;
export mut_offset;
export null;
export is_null;
export is_not_null;
export memcpy;
export memmove;

import libc::c_void;

#[nolink]
#[abi = "cdecl"]
native mod libc_ {
    #[rust_stack]
    fn memcpy(dest: *c_void, src: *c_void, n: libc::size_t) -> *c_void;
    #[rust_stack]
    fn memmove(dest: *c_void, src: *c_void, n: libc::size_t) -> *c_void;
}

#[abi = "rust-intrinsic"]
native mod rusti {
    fn addr_of<T>(val: T) -> *T;
}

#[doc = "Get an unsafe pointer to a value"]
#[inline(always)]
fn addr_of<T>(val: T) -> *T { rusti::addr_of(val) }

#[doc = "Get an unsafe mut pointer to a value"]
#[inline(always)]
fn mut_addr_of<T>(val: T) -> *mut T unsafe {
    unsafe::reinterpret_cast(rusti::addr_of(val))
}

#[doc = "Calculate the offset from a pointer"]
#[inline(always)]
fn offset<T>(ptr: *T, count: uint) -> *T unsafe {
    (ptr as uint + count * sys::size_of::<T>()) as *T
}

#[doc = "Calculate the offset from a mut pointer"]
#[inline(always)]
fn mut_offset<T>(ptr: *mut T, count: uint) -> *mut T {
    (ptr as uint + count * sys::size_of::<T>()) as *mut T
}

#[doc = "Create an unsafe null pointer"]
#[inline(always)]
pure fn null<T>() -> *T unsafe { ret unsafe::reinterpret_cast(0u); }

#[doc = "Returns true if the pointer is equal to the null pointer"]
pure fn is_null<T>(ptr: *const T) -> bool { ptr == null() }

#[doc = "Returns true if the pointer is not equal to the null pointer"]
pure fn is_not_null<T>(ptr: *const T) -> bool { !is_null(ptr) }

#[doc = "
Copies data from one location to another

Copies `count` elements (not bytes) from `src` to `dst`. The source
and destination may not overlap.
"]
#[inline(always)]
unsafe fn memcpy<T>(dst: *T, src: *T, count: uint) {
    let n = count * sys::size_of::<T>();
    libc_::memcpy(dst as *c_void, src as *c_void, n);
}

#[doc = "
Copies data from one location to another

Copies `count` elements (not bytes) from `src` to `dst`. The source
and destination may overlap.
"]
#[inline(always)]
unsafe fn memmove<T>(dst: *T, src: *T, count: uint)  {
    let n = count * sys::size_of::<T>();
    libc_::memmove(dst as *c_void, src as *c_void, n);
}

#[test]
fn test() unsafe {
    type pair = {mut fst: int, mut snd: int};
    let p = {mut fst: 10, mut snd: 20};
    let pptr: *mut pair = mut_addr_of(p);
    let iptr: *mut int = unsafe::reinterpret_cast(pptr);
    assert (*iptr == 10);;
    *iptr = 30;
    assert (*iptr == 30);
    assert (p.fst == 30);;

    *pptr = {mut fst: 50, mut snd: 60};
    assert (*iptr == 50);
    assert (p.fst == 50);
    assert (p.snd == 60);

    let v0 = [32000u16, 32001u16, 32002u16];
    let v1 = [0u16, 0u16, 0u16];

    ptr::memcpy(ptr::offset(vec::unsafe::to_ptr(v1), 1u),
                ptr::offset(vec::unsafe::to_ptr(v0), 1u), 1u);
    assert (v1[0] == 0u16 && v1[1] == 32001u16 && v1[2] == 0u16);
    ptr::memcpy(vec::unsafe::to_ptr(v1),
                ptr::offset(vec::unsafe::to_ptr(v0), 2u), 1u);
    assert (v1[0] == 32002u16 && v1[1] == 32001u16 && v1[2] == 0u16);
    ptr::memcpy(ptr::offset(vec::unsafe::to_ptr(v1), 2u),
                vec::unsafe::to_ptr(v0), 1u);
    assert (v1[0] == 32002u16 && v1[1] == 32001u16 && v1[2] == 32000u16);
}<commit_msg>Add ptr::position and ptr::buf_len, close #2183.<commit_after>#[doc = "Unsafe pointer utility functions"];

export addr_of;
export mut_addr_of;
export offset;
export mut_offset;
export null;
export is_null;
export is_not_null;
export memcpy;
export memmove;

import libc::c_void;

#[nolink]
#[abi = "cdecl"]
native mod libc_ {
    #[rust_stack]
    fn memcpy(dest: *c_void, src: *c_void, n: libc::size_t) -> *c_void;
    #[rust_stack]
    fn memmove(dest: *c_void, src: *c_void, n: libc::size_t) -> *c_void;
}

#[abi = "rust-intrinsic"]
native mod rusti {
    fn addr_of<T>(val: T) -> *T;
}

#[doc = "Get an unsafe pointer to a value"]
#[inline(always)]
fn addr_of<T>(val: T) -> *T { rusti::addr_of(val) }

#[doc = "Get an unsafe mut pointer to a value"]
#[inline(always)]
fn mut_addr_of<T>(val: T) -> *mut T unsafe {
    unsafe::reinterpret_cast(rusti::addr_of(val))
}

#[doc = "Calculate the offset from a pointer"]
#[inline(always)]
fn offset<T>(ptr: *T, count: uint) -> *T unsafe {
    (ptr as uint + count * sys::size_of::<T>()) as *T
}

#[doc = "Calculate the offset from a mut pointer"]
#[inline(always)]
fn mut_offset<T>(ptr: *mut T, count: uint) -> *mut T {
    (ptr as uint + count * sys::size_of::<T>()) as *mut T
}

#[doc = "Return the offset of the first null pointer in `buf`."]
#[inline(always)]
unsafe fn buf_len<T>(buf: **T) -> uint {
    position(buf) {|i| i == null() }
}

#[doc = "Return the first offset `i` such that `f(buf[i]) == true`."]
#[inline(always)]
unsafe fn position<T>(buf: *T, f: fn(T) -> bool) -> uint {
    let mut i = 0u;
    loop {
        if f(*offset(buf, i)) { ret i; }
        else { i += 1u; }
    }
}

#[doc = "Create an unsafe null pointer"]
#[inline(always)]
pure fn null<T>() -> *T unsafe { ret unsafe::reinterpret_cast(0u); }

#[doc = "Returns true if the pointer is equal to the null pointer"]
pure fn is_null<T>(ptr: *const T) -> bool { ptr == null() }

#[doc = "Returns true if the pointer is not equal to the null pointer"]
pure fn is_not_null<T>(ptr: *const T) -> bool { !is_null(ptr) }

#[doc = "
Copies data from one location to another

Copies `count` elements (not bytes) from `src` to `dst`. The source
and destination may not overlap.
"]
#[inline(always)]
unsafe fn memcpy<T>(dst: *T, src: *T, count: uint) {
    let n = count * sys::size_of::<T>();
    libc_::memcpy(dst as *c_void, src as *c_void, n);
}

#[doc = "
Copies data from one location to another

Copies `count` elements (not bytes) from `src` to `dst`. The source
and destination may overlap.
"]
#[inline(always)]
unsafe fn memmove<T>(dst: *T, src: *T, count: uint)  {
    let n = count * sys::size_of::<T>();
    libc_::memmove(dst as *c_void, src as *c_void, n);
}

#[test]
fn test() unsafe {
    type pair = {mut fst: int, mut snd: int};
    let p = {mut fst: 10, mut snd: 20};
    let pptr: *mut pair = mut_addr_of(p);
    let iptr: *mut int = unsafe::reinterpret_cast(pptr);
    assert (*iptr == 10);;
    *iptr = 30;
    assert (*iptr == 30);
    assert (p.fst == 30);;

    *pptr = {mut fst: 50, mut snd: 60};
    assert (*iptr == 50);
    assert (p.fst == 50);
    assert (p.snd == 60);

    let v0 = [32000u16, 32001u16, 32002u16];
    let v1 = [0u16, 0u16, 0u16];

    ptr::memcpy(ptr::offset(vec::unsafe::to_ptr(v1), 1u),
                ptr::offset(vec::unsafe::to_ptr(v0), 1u), 1u);
    assert (v1[0] == 0u16 && v1[1] == 32001u16 && v1[2] == 0u16);
    ptr::memcpy(vec::unsafe::to_ptr(v1),
                ptr::offset(vec::unsafe::to_ptr(v0), 2u), 1u);
    assert (v1[0] == 32002u16 && v1[1] == 32001u16 && v1[2] == 0u16);
    ptr::memcpy(ptr::offset(vec::unsafe::to_ptr(v1), 2u),
                vec::unsafe::to_ptr(v0), 1u);
    assert (v1[0] == 32002u16 && v1[1] == 32001u16 && v1[2] == 32000u16);
}

#[test]
fn test_position() unsafe {
    import str::as_c_str;
    import libc::c_char;

    let s = "hello";
    assert 2u == as_c_str(s) {|p| position(p) {|c| c == 'l' as c_char} };
    assert 4u == as_c_str(s) {|p| position(p) {|c| c == 'o' as c_char} };
    assert 5u == as_c_str(s) {|p| position(p) {|c| c == 0 as c_char } };
}

#[test]
fn test_buf_len() unsafe {
    let s0 = "hello";
    let s1 = "there";
    let s2 = "thing";
    str::as_c_str(s0) {|p0|
        str::as_c_str(s1) {|p1|
            str::as_c_str(s2) {|p2|
                let v = [p0, p1, p2, null()];
                vec::as_buf(v) {|vp|
                    assert buf_len(vp) == 3u;
                }
            }
        }
    }
}<|endoftext|>


<commit_before>
/// A `Reader` is a single process parsing an input source.
/// A lisp dialect allows us to only have a single unified
/// Reader (Parser + Lexer), where as other languages typically
/// have separate constructs for these which make things like
/// macros a lot harder.
///
/// We don't use iterators here, we just store the index position
/// and the current, and previous values.
///
/// Rust supports unicode, so does Moon. Each index is a character, **not**
/// a byte.
pub struct Reader {

}<commit_msg>added basics of the reader system<commit_after>
/// A `Reader` is a single process parsing an input source.
/// A lisp dialect allows us to only have a single unified
/// Reader (Parser + Lexer), where as other languages typically
/// have separate constructs for these which make things like
/// macros a lot harder.
///
/// We don't use iterators here, we just store the index position
/// and the current, and previous values.
///
/// Rust supports unicode, so does Moon. Each index is a character, **not**
/// a byte.
pub struct Reader<'a> {

    // Current character position in the stream.
    pos: int,

    // Input stream of characters. This is currently just a string, however, it would be
    // better to have a `Stream` trait being implemented by various protocols
    // (strings, statics, files, stdin, etc...)
    stream: &'a str,

    current: char,
    previous: char
}

impl<'a> Reader<'a> {
    pub fn new(stream: &'a str) -> Reader<'a> {
        Reader {
            pos: 0,
            stream: stream,
            current: ' ',
            previous: ' '
        }
    }
}<|endoftext|>


<commit_before>use ast::AST;
use env::Env;
use runtime::Error;
use values::Value;
use values::ArgumentsType;
use primitives;
use special_forms;
use memory::Memory;

use std::rc::Rc;

pub fn eval(value: &AST, env: &mut Env, memory: &mut Memory) -> Result<Rc<Value>, Error> {
    match value {
        &AST::Atom(ref atom) =>
            eval_variable(atom, env),
        &AST::Bool(b) =>
            Ok(memory.boolean(b)),
        &AST::Integer(i) =>
            Ok(memory.integer(i)),
        &AST::List(ref list) =>
            eval_list(list, env, memory),
        _ =>
            Err(Error::IrreducibleValue(value.clone())),
    }
}

fn eval_list(list: &Vec<AST>, env: &mut Env, mem: &mut Memory) -> Result<Rc<Value>, Error> {
    if list.is_empty() {
        return Ok(mem.empty_list());
    }

    let head = list.head().unwrap();
    let tail = list.tail();

    if is_quoted(head) {
        return Err(Error::UnappliableValue(Value::from_ast(head)));
    }

    if let &AST::Atom(ref special_form) = head {
        let args = tail;

        match special_form.as_slice() {
            "and"    => return special_forms::and(args, env, mem),
            "define" => return special_forms::define(args, env, mem),
            "if"     => return special_forms::if_(args, env, mem),
            "lambda" => return special_forms::lambda(args, None, mem),
            "or"     => return special_forms::or(args, env, mem),
            "quote"  => return special_forms::quote(args, mem),
            _        => (),
        }
    }

    let fun  = try!(eval(head, env, mem));
    let args = try!(eval_args(tail, env, mem));

    match fun.deref() {
        &Value::Fn(ref _name, ArgumentsType::Any, ref args_names, ref body) =>
            apply_any(&args_names[0], args, body, env, mem),
        &Value::Fn(ref name, ArgumentsType::Fixed, ref args_names, ref body) =>
            apply_fixed(name, args_names, args, body, env, mem),
        &Value::Fn(ref name, ArgumentsType::Variable, ref args_names, ref body) =>
            apply_var(name, args_names, args, body, env, mem),
        &Value::PrimitiveFn(ref name) =>
            primitives::apply(name, args, mem),
        fun =>
            Err(Error::UnappliableValue(fun.clone()))
    }
}

fn eval_args(args: &[AST], env: &mut Env, mem: &mut Memory) -> Result<Vec<Rc<Value>>, Error> {
    let mut out = Vec::with_capacity(args.len());

    for arg in args.iter() {
        let evald_arg = try!(eval(arg, env, mem));
        out.push(evald_arg);
    }

    Ok(out)
}

fn eval_variable(name: &String, env: &mut Env) -> Result<Rc<Value>, Error> {
    match env.get(name) {
        Some(value) => Ok(value),
        None        => Err(Error::UnboundVariable(name.clone())),
    }
}

fn apply_fixed(name: &Option<String>, arg_names: &Vec<String>, arg_values: Vec<Rc<Value>>, body: &Vec<AST>, env: &Env, mem: &mut Memory) -> Result<Rc<Value>, Error> {
    if arg_names.len() != arg_values.len() {
        return Err(Error::BadArity(name.clone()));
    }

    let mut inner_env = Env::wraps(env);
    for (name, value) in arg_names.iter().zip(arg_values.iter()) {
        inner_env.set(name.clone(), value.clone());
    }

    eval_sequence(body, &mut inner_env, mem)
}

fn apply_var(name: &Option<String>, arg_names: &Vec<String>, arg_values: Vec<Rc<Value>>, body: &Vec<AST>, env: &Env, mem: &mut Memory) -> Result<Rc<Value>, Error> {
    let fixed_arg_names = arg_names.slice(0, arg_names.len() - 1);

    if fixed_arg_names.len() > arg_values.len() {
        return Err(Error::BadArity(name.clone()));
    }

    let mut inner_env = Env::wraps(env);
    for (name, value) in fixed_arg_names.iter().zip(arg_values.iter()) {
        inner_env.set(name.clone(), value.clone());
    }

    let var_args = arg_values.iter()
        .skip(fixed_arg_names.len())
        .map(|value| value.deref().clone())
        .collect();

    inner_env.set(
        arg_names.last().unwrap().clone(),
        mem.list(var_args)
    );

    eval_sequence(body, &mut inner_env, mem)
}

fn apply_any(arg_name: &String, args: Vec<Rc<Value>>, body: &Vec<AST>, env: &Env, mem: &mut Memory) -> Result<Rc<Value>, Error> {
    let args = args.iter().map(|value| value.deref().clone()).collect();

    let mut inner_env = Env::wraps(env);
    inner_env.set(arg_name.clone(), mem.list(args));

    eval_sequence(body, &mut inner_env, mem)
}

fn eval_sequence(seq: &Vec<AST>, env: &mut Env, mem: &mut Memory) -> Result<Rc<Value>, Error> {
    let mut result = mem.empty_list();

    for expr in seq.iter() {
        result = try!(eval(expr, env, mem));
    }

    Ok(result)
}

fn is_quoted(value: &AST) -> bool {
    match value {
        &AST::List(ref list) =>
            match list[0] {
                AST::Atom(ref a) if a.as_slice() == "quote" =>
                    true,
                _ =>
                    false
            },
        _ =>
            false
    }
}
<commit_msg>Refactored `eval::apply` a bit after latest changes.<commit_after>use ast::AST;
use env::Env;
use runtime::Error;
use values::Value;
use values::ArgumentsType;
use primitives;
use special_forms;
use memory::Memory;

use std::rc::Rc;

pub fn eval(value: &AST, env: &mut Env, memory: &mut Memory) -> Result<Rc<Value>, Error> {
    match value {
        &AST::Atom(ref atom) =>
            eval_variable(atom, env),
        &AST::Bool(b) =>
            Ok(memory.boolean(b)),
        &AST::Integer(i) =>
            Ok(memory.integer(i)),
        &AST::List(ref list) =>
            eval_list(list, env, memory),
        _ =>
            Err(Error::IrreducibleValue(value.clone())),
    }
}

fn eval_list(list: &Vec<AST>, env: &mut Env, mem: &mut Memory) -> Result<Rc<Value>, Error> {
    if list.is_empty() {
        return Ok(mem.empty_list());
    }

    let head = list.head().unwrap();
    let tail = list.tail();

    if is_quoted(head) {
        return Err(Error::UnappliableValue(Value::from_ast(head)));
    }

    if let &AST::Atom(ref special_form) = head {
        let args = tail;

        match special_form.as_slice() {
            "and"    => return special_forms::and(args, env, mem),
            "define" => return special_forms::define(args, env, mem),
            "if"     => return special_forms::if_(args, env, mem),
            "lambda" => return special_forms::lambda(args, None, mem),
            "or"     => return special_forms::or(args, env, mem),
            "quote"  => return special_forms::quote(args, mem),
            _        => (),
        }
    }

    let fun  = try!(eval(head, env, mem));
    let args = try!(eval_args(tail, env, mem));

    match fun.deref() {
        &Value::Fn(ref name, args_type, ref args_names, ref body) =>
            apply(name, args_type, args_names, args, body, env, mem),
        &Value::PrimitiveFn(ref name) =>
            primitives::apply(name, args, mem),
        fun =>
            Err(Error::UnappliableValue(fun.clone()))
    }
}

fn eval_args(args: &[AST], env: &mut Env, mem: &mut Memory) -> Result<Vec<Rc<Value>>, Error> {
    let mut out = Vec::with_capacity(args.len());

    for arg in args.iter() {
        let evald_arg = try!(eval(arg, env, mem));
        out.push(evald_arg);
    }

    Ok(out)
}

fn eval_variable(name: &String, env: &mut Env) -> Result<Rc<Value>, Error> {
    match env.get(name) {
        Some(value) => Ok(value),
        None        => Err(Error::UnboundVariable(name.clone())),
    }
}

fn apply(name: &Option<String>, args_type: ArgumentsType, arg_names: &Vec<String>, arg_values: Vec<Rc<Value>>, body: &Vec<AST>, env: &mut Env, mem: &mut Memory) -> Result<Rc<Value>, Error> {
    let mut inner_env = Env::wraps(env);

    match args_type {
        ArgumentsType::Any => {
            let args = arg_values.iter().map(|value| value.deref().clone()).collect();

            inner_env.set(arg_names[0].clone(), mem.list(args));
        }
        ArgumentsType::Fixed => {
            if arg_names.len() != arg_values.len() {
                return Err(Error::BadArity(name.clone()));
            }

            for (name, value) in arg_names.iter().zip(arg_values.iter()) {
                inner_env.set(name.clone(), value.clone());
            }
        }
        ArgumentsType::Variable => {
            let fixed_arg_names = arg_names.slice(0, arg_names.len() - 1);

            if fixed_arg_names.len() > arg_values.len() {
                return Err(Error::BadArity(name.clone()));
            }

            for (name, value) in fixed_arg_names.iter().zip(arg_values.iter()) {
                inner_env.set(name.clone(), value.clone());
            }

            let var_args = arg_values.iter()
                .skip(fixed_arg_names.len())
                .map(|value| value.deref().clone())
                .collect();

            inner_env.set(
                arg_names.last().unwrap().clone(),
                mem.list(var_args)
            );
        }
    };

    eval_sequence(body, &mut inner_env, mem)
}

fn eval_sequence(seq: &Vec<AST>, env: &mut Env, mem: &mut Memory) -> Result<Rc<Value>, Error> {
    let mut result = mem.empty_list();

    for expr in seq.iter() {
        result = try!(eval(expr, env, mem));
    }

    Ok(result)
}

fn is_quoted(value: &AST) -> bool {
    match value {
        &AST::List(ref list) =>
            match list[0] {
                AST::Atom(ref a) if a.as_slice() == "quote" =>
                    true,
                _ =>
                    false
            },
        _ =>
            false
    }
}
<|endoftext|>


<commit_before>use std::ffi::OsStr;
use std::ffi::OsString;

pub use std::io::SeekFrom;

use os_str_bytes::RawOsStr;

#[derive(Default, Clone, Debug, PartialEq, Eq)]
pub(crate) struct RawArgs {
    items: Vec<OsString>,
}

impl RawArgs {
    pub fn cursor(&self) -> ArgCursor {
        ArgCursor::new()
    }

    pub fn next(&self, cursor: &mut ArgCursor) -> Option<ParsedArg<'_>> {
        self.next_os(cursor).map(ParsedArg::new)
    }

    pub fn next_os(&self, cursor: &mut ArgCursor) -> Option<&OsStr> {
        let next = self.items.get(cursor.cursor).map(|s| s.as_os_str());
        cursor.cursor = cursor.cursor.saturating_add(1);
        next
    }

    pub fn peek(&self, cursor: &ArgCursor) -> Option<ParsedArg<'_>> {
        self.peek_os(cursor).map(ParsedArg::new)
    }

    pub fn peek_os(&self, cursor: &ArgCursor) -> Option<&OsStr> {
        self.items.get(cursor.cursor).map(|s| s.as_os_str())
    }

    pub fn remaining(&self, cursor: &mut ArgCursor) -> impl Iterator<Item = &OsStr> {
        let remaining = self.items[cursor.cursor..].iter().map(|s| s.as_os_str());
        cursor.cursor = self.items.len();
        remaining
    }

    pub fn seek(&self, cursor: &mut ArgCursor, pos: SeekFrom) {
        let pos = match pos {
            SeekFrom::Start(pos) => pos,
            SeekFrom::End(pos) => (self.items.len() as i64).saturating_add(pos).max(0) as u64,
            SeekFrom::Current(pos) => (cursor.cursor as i64).saturating_add(pos).max(0) as u64,
        };
        let pos = (pos as usize).min(self.items.len());
        cursor.cursor = pos;
    }

    /// Inject arguments before the [`RawArgs::next`]
    pub fn insert(&mut self, cursor: &ArgCursor, insert_items: &[&str]) {
        self.items.splice(
            cursor.cursor..cursor.cursor,
            insert_items.iter().map(OsString::from),
        );
    }
}

impl<I, T> From<I> for RawArgs
where
    I: Iterator<Item = T>,
    T: Into<OsString>,
{
    fn from(val: I) -> Self {
        Self {
            items: val.map(|x| x.into()).collect(),
        }
    }
}

#[derive(Default, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub(crate) struct ArgCursor {
    cursor: usize,
}

impl ArgCursor {
    fn new() -> Self {
        Default::default()
    }
}

#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub(crate) struct ParsedArg<'s> {
    inner: std::borrow::Cow<'s, RawOsStr>,
    utf8: Option<&'s str>,
}

impl<'s> ParsedArg<'s> {
    fn new(inner: &'s OsStr) -> Self {
        let utf8 = inner.to_str();
        let inner = RawOsStr::new(inner);
        Self { inner, utf8 }
    }

    pub fn is_stdio(&self) -> bool {
        self.inner.as_ref() == "-"
    }

    pub fn is_escape(&self) -> bool {
        self.inner.as_ref() == "--"
    }

    pub fn is_number(&self) -> bool {
        self.to_value()
            .map(|s| s.parse::<f64>().is_ok())
            .unwrap_or_default()
    }

    /// Treat as a long-flag
    ///
    /// **NOTE:** May return an empty flag.  Check [`ParsedArg::is_escape`] to separately detect `--`.
    pub fn to_long(&self) -> Option<(&RawOsStr, Option<&RawOsStr>)> {
        let remainder = self.inner.as_ref().strip_prefix("--")?;
        let parts = if let Some((p0, p1)) = remainder.split_once("=") {
            (p0, Some(p1))
        } else {
            (remainder, None)
        };
        Some(parts)
    }

    /// Can treat as a long-flag
    ///
    /// **NOTE:** May return an empty flag.  Check [`ParsedArg::is_escape`] to separately detect `--`.
    pub fn is_long(&self) -> bool {
        self.inner.as_ref().starts_with("--")
    }

    /// Treat as a short-flag
    ///
    /// **NOTE:** Maybe return an empty flag.  Check [`ParsedArg::is_stdio`] to separately detect
    /// `-`.
    pub fn to_short(&self) -> Option<ShortFlags<'_>> {
        if let Some(remainder_os) = self.inner.as_ref().strip_prefix('-') {
            if remainder_os.starts_with('-') {
                None
            } else {
                let remainder = self.utf8.map(|s| &s[1..]);
                Some(ShortFlags::new(remainder_os, remainder))
            }
        } else {
            None
        }
    }

    /// Can treat as a short-flag
    ///
    /// **NOTE:** Maybe return an empty flag.  Check [`ParsedArg::is_stdio`] to separately detect
    /// `-`.
    pub fn is_short(&self) -> bool {
        self.inner.as_ref().starts_with('-') && !self.is_long()
    }

    /// Treat as a value
    ///
    /// **NOTE:** May return a flag or an escape.
    pub fn to_value_os(&self) -> &RawOsStr {
        self.inner.as_ref()
    }

    /// Treat as a value
    ///
    /// **NOTE:** May return a flag or an escape.
    pub fn to_value(&self) -> Option<&str> {
        self.utf8
    }

    /// Safely print an argument that may contain non-UTF8 content
    ///
    /// This may perform lossy conversion, depending on the platform. If you would like an implementation which escapes the path please use Debug instead.
    pub fn display(&self) -> impl std::fmt::Display + '_ {
        self.inner.to_str_lossy()
    }
}

#[derive(Clone, Debug)]
pub(crate) struct ShortFlags<'s> {
    inner: &'s RawOsStr,
    utf8_prefix: std::str::CharIndices<'s>,
    invalid_suffix: Option<&'s RawOsStr>,
}

impl<'s> ShortFlags<'s> {
    fn new(inner: &'s RawOsStr, utf8: Option<&'s str>) -> Self {
        let (utf8_prefix, invalid_suffix) = if let Some(utf8) = utf8 {
            (utf8, None)
        } else {
            split_nonutf8_once(inner)
        };
        let utf8_prefix = utf8_prefix.char_indices();
        Self {
            inner,
            utf8_prefix,
            invalid_suffix,
        }
    }

    pub fn advance_by(&mut self, n: usize) -> Result<(), usize> {
        for i in 0..n {
            self.next().ok_or(i)?.map_err(|_| i)?;
        }
        Ok(())
    }

    pub fn is_empty(&self) -> bool {
        self.invalid_suffix.is_none() && self.utf8_prefix.as_str().is_empty()
    }

    pub fn is_number(&self) -> bool {
        self.invalid_suffix.is_none() && self.utf8_prefix.as_str().parse::<f64>().is_ok()
    }

    pub fn next_flag(&mut self) -> Option<Result<char, &'s RawOsStr>> {
        if let Some((_, flag)) = self.utf8_prefix.next() {
            return Some(Ok(flag));
        }

        if let Some(suffix) = self.invalid_suffix {
            self.invalid_suffix = None;
            return Some(Err(suffix));
        }

        None
    }

    pub fn next_value_os(&mut self) -> Option<&'s RawOsStr> {
        if let Some((index, _)) = self.utf8_prefix.next() {
            self.utf8_prefix = "".char_indices();
            self.invalid_suffix = None;
            return Some(&self.inner[index..]);
        }

        if let Some(suffix) = self.invalid_suffix {
            self.invalid_suffix = None;
            return Some(suffix);
        }

        None
    }
}

impl<'s> Iterator for ShortFlags<'s> {
    type Item = Result<char, &'s RawOsStr>;

    fn next(&mut self) -> Option<Self::Item> {
        self.next_flag()
    }
}

fn split_nonutf8_once(b: &RawOsStr) -> (&str, Option<&RawOsStr>) {
    match std::str::from_utf8(b.as_raw_bytes()) {
        Ok(s) => (s, None),
        Err(err) => {
            let (valid, after_valid) = b.split_at(err.valid_up_to());
            let valid = std::str::from_utf8(valid.as_raw_bytes()).unwrap();
            (valid, Some(after_valid))
        }
    }
}
<commit_msg>docs(lex): Specify how it all works<commit_after>use std::ffi::OsStr;
use std::ffi::OsString;

pub use std::io::SeekFrom;

use os_str_bytes::RawOsStr;

/// Command-line arguments
#[derive(Default, Clone, Debug, PartialEq, Eq)]
pub(crate) struct RawArgs {
    items: Vec<OsString>,
}

impl RawArgs {
    /// Create a cursor for walking the arguments
    pub fn cursor(&self) -> ArgCursor {
        ArgCursor::new()
    }

    /// Advance the cursor, returning the next [`ParsedArgs`]
    pub fn next(&self, cursor: &mut ArgCursor) -> Option<ParsedArg<'_>> {
        self.next_os(cursor).map(ParsedArg::new)
    }

    /// Advance the cursor, returning a raw argument value.
    pub fn next_os(&self, cursor: &mut ArgCursor) -> Option<&OsStr> {
        let next = self.items.get(cursor.cursor).map(|s| s.as_os_str());
        cursor.cursor = cursor.cursor.saturating_add(1);
        next
    }

    /// Return the next [`ParsedArgs`]
    pub fn peek(&self, cursor: &ArgCursor) -> Option<ParsedArg<'_>> {
        self.peek_os(cursor).map(ParsedArg::new)
    }

    /// Return a raw argument value.
    pub fn peek_os(&self, cursor: &ArgCursor) -> Option<&OsStr> {
        self.items.get(cursor.cursor).map(|s| s.as_os_str())
    }

    /// Return all remaining raw arguments, advancing the cursor to the end
    pub fn remaining(&self, cursor: &mut ArgCursor) -> impl Iterator<Item = &OsStr> {
        let remaining = self.items[cursor.cursor..].iter().map(|s| s.as_os_str());
        cursor.cursor = self.items.len();
        remaining
    }

    /// Adjust the cursor's position
    pub fn seek(&self, cursor: &mut ArgCursor, pos: SeekFrom) {
        let pos = match pos {
            SeekFrom::Start(pos) => pos,
            SeekFrom::End(pos) => (self.items.len() as i64).saturating_add(pos).max(0) as u64,
            SeekFrom::Current(pos) => (cursor.cursor as i64).saturating_add(pos).max(0) as u64,
        };
        let pos = (pos as usize).min(self.items.len());
        cursor.cursor = pos;
    }

    /// Inject arguments before the [`RawArgs::next`]
    pub fn insert(&mut self, cursor: &ArgCursor, insert_items: &[&str]) {
        self.items.splice(
            cursor.cursor..cursor.cursor,
            insert_items.iter().map(OsString::from),
        );
    }
}

impl<I, T> From<I> for RawArgs
where
    I: Iterator<Item = T>,
    T: Into<OsString>,
{
    fn from(val: I) -> Self {
        Self {
            items: val.map(|x| x.into()).collect(),
        }
    }
}

/// Position within [`RawArgs`]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub(crate) struct ArgCursor {
    cursor: usize,
}

impl ArgCursor {
    fn new() -> Self {
        Self { cursor: 0 }
    }
}

/// Command-line Argument
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub(crate) struct ParsedArg<'s> {
    inner: std::borrow::Cow<'s, RawOsStr>,
    utf8: Option<&'s str>,
}

impl<'s> ParsedArg<'s> {
    fn new(inner: &'s OsStr) -> Self {
        let utf8 = inner.to_str();
        let inner = RawOsStr::new(inner);
        Self { inner, utf8 }
    }

    /// Does the argument look like a stdio argument (`-`)
    pub fn is_stdio(&self) -> bool {
        self.inner.as_ref() == "-"
    }

    /// Does the argument look like an argument escape (`--`)
    pub fn is_escape(&self) -> bool {
        self.inner.as_ref() == "--"
    }

    /// Does the argument look like a number
    pub fn is_number(&self) -> bool {
        self.to_value()
            .map(|s| s.parse::<f64>().is_ok())
            .unwrap_or_default()
    }

    /// Treat as a long-flag
    ///
    /// **NOTE:** May return an empty flag.  Check [`ParsedArg::is_escape`] to separately detect `--`.
    pub fn to_long(&self) -> Option<(&RawOsStr, Option<&RawOsStr>)> {
        let remainder = self.inner.as_ref().strip_prefix("--")?;
        let parts = if let Some((p0, p1)) = remainder.split_once("=") {
            (p0, Some(p1))
        } else {
            (remainder, None)
        };
        Some(parts)
    }

    /// Can treat as a long-flag
    ///
    /// **NOTE:** May return an empty flag.  Check [`ParsedArg::is_escape`] to separately detect `--`.
    pub fn is_long(&self) -> bool {
        self.inner.as_ref().starts_with("--")
    }

    /// Treat as a short-flag
    ///
    /// **NOTE:** Maybe return an empty flag.  Check [`ParsedArg::is_stdio`] to separately detect
    /// `-`.
    pub fn to_short(&self) -> Option<ShortFlags<'_>> {
        if let Some(remainder_os) = self.inner.as_ref().strip_prefix('-') {
            if remainder_os.starts_with('-') {
                None
            } else {
                let remainder = self.utf8.map(|s| &s[1..]);
                Some(ShortFlags::new(remainder_os, remainder))
            }
        } else {
            None
        }
    }

    /// Can treat as a short-flag
    ///
    /// **NOTE:** Maybe return an empty flag.  Check [`ParsedArg::is_stdio`] to separately detect
    /// `-`.
    pub fn is_short(&self) -> bool {
        self.inner.as_ref().starts_with('-') && !self.is_long()
    }

    /// Treat as a value
    ///
    /// **NOTE:** May return a flag or an escape.
    pub fn to_value_os(&self) -> &RawOsStr {
        self.inner.as_ref()
    }

    /// Treat as a value
    ///
    /// **NOTE:** May return a flag or an escape.
    pub fn to_value(&self) -> Option<&str> {
        self.utf8
    }

    /// Safely print an argument that may contain non-UTF8 content
    ///
    /// This may perform lossy conversion, depending on the platform. If you would like an implementation which escapes the path please use Debug instead.
    pub fn display(&self) -> impl std::fmt::Display + '_ {
        self.inner.to_str_lossy()
    }
}

/// Walk through short flags within a [`ParsedArg`]
#[derive(Clone, Debug)]
pub(crate) struct ShortFlags<'s> {
    inner: &'s RawOsStr,
    utf8_prefix: std::str::CharIndices<'s>,
    invalid_suffix: Option<&'s RawOsStr>,
}

impl<'s> ShortFlags<'s> {
    fn new(inner: &'s RawOsStr, utf8: Option<&'s str>) -> Self {
        let (utf8_prefix, invalid_suffix) = if let Some(utf8) = utf8 {
            (utf8, None)
        } else {
            split_nonutf8_once(inner)
        };
        let utf8_prefix = utf8_prefix.char_indices();
        Self {
            inner,
            utf8_prefix,
            invalid_suffix,
        }
    }

    /// Move the iterator forward by `n` short flags
    pub fn advance_by(&mut self, n: usize) -> Result<(), usize> {
        for i in 0..n {
            self.next().ok_or(i)?.map_err(|_| i)?;
        }
        Ok(())
    }

    /// No short flags left
    pub fn is_empty(&self) -> bool {
        self.invalid_suffix.is_none() && self.utf8_prefix.as_str().is_empty()
    }

    /// Does the short flag look like a number
    ///
    /// Ideally call this before doing any iterator
    pub fn is_number(&self) -> bool {
        self.invalid_suffix.is_none() && self.utf8_prefix.as_str().parse::<f64>().is_ok()
    }

    /// Advance the iterator, returning the next short flag on success
    ///
    /// On error, returns the invalid-UTF8 value
    pub fn next_flag(&mut self) -> Option<Result<char, &'s RawOsStr>> {
        if let Some((_, flag)) = self.utf8_prefix.next() {
            return Some(Ok(flag));
        }

        if let Some(suffix) = self.invalid_suffix {
            self.invalid_suffix = None;
            return Some(Err(suffix));
        }

        None
    }

    /// Advance the iterator, returning everything left as a value
    pub fn next_value_os(&mut self) -> Option<&'s RawOsStr> {
        if let Some((index, _)) = self.utf8_prefix.next() {
            self.utf8_prefix = "".char_indices();
            self.invalid_suffix = None;
            return Some(&self.inner[index..]);
        }

        if let Some(suffix) = self.invalid_suffix {
            self.invalid_suffix = None;
            return Some(suffix);
        }

        None
    }
}

impl<'s> Iterator for ShortFlags<'s> {
    type Item = Result<char, &'s RawOsStr>;

    fn next(&mut self) -> Option<Self::Item> {
        self.next_flag()
    }
}

fn split_nonutf8_once(b: &RawOsStr) -> (&str, Option<&RawOsStr>) {
    match std::str::from_utf8(b.as_raw_bytes()) {
        Ok(s) => (s, None),
        Err(err) => {
            let (valid, after_valid) = b.split_at(err.valid_up_to());
            let valid = std::str::from_utf8(valid.as_raw_bytes()).unwrap();
            (valid, Some(after_valid))
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::HashSet;

use syn;
use syn::punctuated::{Pair, Punctuated};

use internals::ast::{Container, Data};
use internals::{attr, ungroup};

use proc_macro2::Span;

// Remove the default from every type parameter because in the generated impls
// they look like associated types: "error: associated type bindings are not
// allowed here".
pub fn without_defaults(generics: &syn::Generics) -> syn::Generics {
    syn::Generics {
        params: generics
            .params
            .iter()
            .map(|param| match param {
                syn::GenericParam::Type(param) => syn::GenericParam::Type(syn::TypeParam {
                    eq_token: None,
                    default: None,
                    ..param.clone()
                }),
                _ => param.clone(),
            })
            .collect(),
        ..generics.clone()
    }
}

pub fn with_where_predicates(
    generics: &syn::Generics,
    predicates: &[syn::WherePredicate],
) -> syn::Generics {
    let mut generics = generics.clone();
    generics
        .make_where_clause()
        .predicates
        .extend(predicates.iter().cloned());
    generics
}

pub fn with_where_predicates_from_fields(
    cont: &Container,
    generics: &syn::Generics,
    from_field: fn(&attr::Field) -> Option<&[syn::WherePredicate]>,
) -> syn::Generics {
    let predicates = cont
        .data
        .all_fields()
        .flat_map(|field| from_field(&field.attrs))
        .flat_map(|predicates| predicates.to_vec());

    let mut generics = generics.clone();
    generics.make_where_clause().predicates.extend(predicates);
    generics
}

pub fn with_where_predicates_from_variants(
    cont: &Container,
    generics: &syn::Generics,
    from_variant: fn(&attr::Variant) -> Option<&[syn::WherePredicate]>,
) -> syn::Generics {
    let variants = match &cont.data {
        Data::Enum(variants) => variants,
        Data::Struct(_, _) => {
            return generics.clone();
        }
    };

    let predicates = variants
        .iter()
        .flat_map(|variant| from_variant(&variant.attrs))
        .flat_map(|predicates| predicates.to_vec());

    let mut generics = generics.clone();
    generics.make_where_clause().predicates.extend(predicates);
    generics
}

// Puts the given bound on any generic type parameters that are used in fields
// for which filter returns true.
//
// For example, the following struct needs the bound `A: Serialize, B:
// Serialize`.
//
//     struct S<'b, A, B: 'b, C> {
//         a: A,
//         b: Option<&'b B>
//         #[serde(skip_serializing)]
//         c: C,
//     }
pub fn with_bound(
    cont: &Container,
    generics: &syn::Generics,
    filter: fn(&attr::Field, Option<&attr::Variant>) -> bool,
    bound: &syn::Path,
) -> syn::Generics {
    struct FindTyParams<'ast> {
        // Set of all generic type parameters on the current struct (A, B, C in
        // the example). Initialized up front.
        all_type_params: HashSet<syn::Ident>,

        // Set of generic type parameters used in fields for which filter
        // returns true (A and B in the example). Filled in as the visitor sees
        // them.
        relevant_type_params: HashSet<syn::Ident>,

        // Fields whose type is an associated type of one of the generic type
        // parameters.
        associated_type_usage: Vec<&'ast syn::TypePath>,
    }

    impl<'ast> FindTyParams<'ast> {
        fn visit_field(&mut self, field: &'ast syn::Field) {
            if let syn::Type::Path(ty) = ungroup(&field.ty) {
                if let Some(Pair::Punctuated(t, _)) = ty.path.segments.pairs().next() {
                    if self.all_type_params.contains(&t.ident) {
                        self.associated_type_usage.push(ty);
                    }
                }
            }
            self.visit_type(&field.ty);
        }

        fn visit_path(&mut self, path: &'ast syn::Path) {
            if let Some(seg) = path.segments.last() {
                if seg.ident == "PhantomData" {
                    // Hardcoded exception, because PhantomData<T> implements
                    // Serialize and Deserialize whether or not T implements it.
                    return;
                }
            }
            if path.leading_colon.is_none() && path.segments.len() == 1 {
                let id = &path.segments[0].ident;
                if self.all_type_params.contains(id) {
                    self.relevant_type_params.insert(id.clone());
                }
            }
            for segment in &path.segments {
                self.visit_path_segment(segment);
            }
        }

        // Everything below is simply traversing the syntax tree.

        fn visit_type(&mut self, ty: &'ast syn::Type) {
            match ty {
                syn::Type::Array(ty) => self.visit_type(&ty.elem),
                syn::Type::BareFn(ty) => {
                    for arg in &ty.inputs {
                        self.visit_type(&arg.ty);
                    }
                    self.visit_return_type(&ty.output);
                }
                syn::Type::Group(ty) => self.visit_type(&ty.elem),
                syn::Type::ImplTrait(ty) => {
                    for bound in &ty.bounds {
                        self.visit_type_param_bound(bound);
                    }
                }
                syn::Type::Macro(ty) => self.visit_macro(&ty.mac),
                syn::Type::Paren(ty) => self.visit_type(&ty.elem),
                syn::Type::Path(ty) => {
                    if let Some(qself) = &ty.qself {
                        self.visit_type(&qself.ty);
                    }
                    self.visit_path(&ty.path);
                }
                syn::Type::Ptr(ty) => self.visit_type(&ty.elem),
                syn::Type::Reference(ty) => self.visit_type(&ty.elem),
                syn::Type::Slice(ty) => self.visit_type(&ty.elem),
                syn::Type::TraitObject(ty) => {
                    for bound in &ty.bounds {
                        self.visit_type_param_bound(bound);
                    }
                }
                syn::Type::Tuple(ty) => {
                    for elem in &ty.elems {
                        self.visit_type(elem);
                    }
                }

                syn::Type::Infer(_) | syn::Type::Never(_) | syn::Type::Verbatim(_) => {}

                #[cfg(test)]
                syn::Type::__TestExhaustive(_) => unimplemented!(),
                #[cfg(not(test))]
                _ => {}
            }
        }

        fn visit_path_segment(&mut self, segment: &'ast syn::PathSegment) {
            self.visit_path_arguments(&segment.arguments);
        }

        fn visit_path_arguments(&mut self, arguments: &'ast syn::PathArguments) {
            match arguments {
                syn::PathArguments::None => {}
                syn::PathArguments::AngleBracketed(arguments) => {
                    for arg in &arguments.args {
                        match arg {
                            syn::GenericArgument::Type(arg) => self.visit_type(arg),
                            syn::GenericArgument::Binding(arg) => self.visit_type(&arg.ty),
                            syn::GenericArgument::Lifetime(_)
                            | syn::GenericArgument::Constraint(_)
                            | syn::GenericArgument::Const(_) => {}
                        }
                    }
                }
                syn::PathArguments::Parenthesized(arguments) => {
                    for argument in &arguments.inputs {
                        self.visit_type(argument);
                    }
                    self.visit_return_type(&arguments.output);
                }
            }
        }

        fn visit_return_type(&mut self, return_type: &'ast syn::ReturnType) {
            match return_type {
                syn::ReturnType::Default => {}
                syn::ReturnType::Type(_, output) => self.visit_type(output),
            }
        }

        fn visit_type_param_bound(&mut self, bound: &'ast syn::TypeParamBound) {
            match bound {
                syn::TypeParamBound::Trait(bound) => self.visit_path(&bound.path),
                syn::TypeParamBound::Lifetime(_) => {}
            }
        }

        // Type parameter should not be considered used by a macro path.
        //
        //     struct TypeMacro<T> {
        //         mac: T!(),
        //         marker: PhantomData<T>,
        //     }
        fn visit_macro(&mut self, _mac: &'ast syn::Macro) {}
    }

    let all_type_params = generics
        .type_params()
        .map(|param| param.ident.clone())
        .collect();

    let mut visitor = FindTyParams {
        all_type_params,
        relevant_type_params: HashSet::new(),
        associated_type_usage: Vec::new(),
    };
    match &cont.data {
        Data::Enum(variants) => {
            for variant in variants.iter() {
                let relevant_fields = variant
                    .fields
                    .iter()
                    .filter(|field| filter(&field.attrs, Some(&variant.attrs)));
                for field in relevant_fields {
                    visitor.visit_field(field.original);
                }
            }
        }
        Data::Struct(_, fields) => {
            for field in fields.iter().filter(|field| filter(&field.attrs, None)) {
                visitor.visit_field(field.original);
            }
        }
    }

    let relevant_type_params = visitor.relevant_type_params;
    let associated_type_usage = visitor.associated_type_usage;
    let new_predicates = generics
        .type_params()
        .map(|param| param.ident.clone())
        .filter(|id| relevant_type_params.contains(id))
        .map(|id| syn::TypePath {
            qself: None,
            path: id.into(),
        })
        .chain(associated_type_usage.into_iter().cloned())
        .map(|bounded_ty| {
            syn::WherePredicate::Type(syn::PredicateType {
                lifetimes: None,
                // the type parameter that is being bounded e.g. T
                bounded_ty: syn::Type::Path(bounded_ty),
                colon_token: <Token![:]>::default(),
                // the bound e.g. Serialize
                bounds: vec![syn::TypeParamBound::Trait(syn::TraitBound {
                    paren_token: None,
                    modifier: syn::TraitBoundModifier::None,
                    lifetimes: None,
                    path: bound.clone(),
                })]
                .into_iter()
                .collect(),
            })
        });

    let mut generics = generics.clone();
    generics
        .make_where_clause()
        .predicates
        .extend(new_predicates);
    generics
}

pub fn with_self_bound(
    cont: &Container,
    generics: &syn::Generics,
    bound: &syn::Path,
) -> syn::Generics {
    let mut generics = generics.clone();
    generics
        .make_where_clause()
        .predicates
        .push(syn::WherePredicate::Type(syn::PredicateType {
            lifetimes: None,
            // the type that is being bounded e.g. MyStruct<'a, T>
            bounded_ty: type_of_item(cont),
            colon_token: <Token![:]>::default(),
            // the bound e.g. Default
            bounds: vec![syn::TypeParamBound::Trait(syn::TraitBound {
                paren_token: None,
                modifier: syn::TraitBoundModifier::None,
                lifetimes: None,
                path: bound.clone(),
            })]
            .into_iter()
            .collect(),
        }));
    generics
}

pub fn with_lifetime_bound(generics: &syn::Generics, lifetime: &str) -> syn::Generics {
    let bound = syn::Lifetime::new(lifetime, Span::call_site());
    let def = syn::LifetimeDef {
        attrs: Vec::new(),
        lifetime: bound.clone(),
        colon_token: None,
        bounds: Punctuated::new(),
    };

    let params = Some(syn::GenericParam::Lifetime(def))
        .into_iter()
        .chain(generics.params.iter().cloned().map(|mut param| {
            match &mut param {
                syn::GenericParam::Lifetime(param) => {
                    param.bounds.push(bound.clone());
                }
                syn::GenericParam::Type(param) => {
                    param
                        .bounds
                        .push(syn::TypeParamBound::Lifetime(bound.clone()));
                }
                syn::GenericParam::Const(_) => {}
            }
            param
        }))
        .collect();

    syn::Generics {
        params,
        ..generics.clone()
    }
}

fn type_of_item(cont: &Container) -> syn::Type {
    syn::Type::Path(syn::TypePath {
        qself: None,
        path: syn::Path {
            leading_colon: None,
            segments: vec![syn::PathSegment {
                ident: cont.ident.clone(),
                arguments: syn::PathArguments::AngleBracketed(
                    syn::AngleBracketedGenericArguments {
                        colon2_token: None,
                        lt_token: <Token![<]>::default(),
                        args: cont
                            .generics
                            .params
                            .iter()
                            .map(|param| match param {
                                syn::GenericParam::Type(param) => {
                                    syn::GenericArgument::Type(syn::Type::Path(syn::TypePath {
                                        qself: None,
                                        path: param.ident.clone().into(),
                                    }))
                                }
                                syn::GenericParam::Lifetime(param) => {
                                    syn::GenericArgument::Lifetime(param.lifetime.clone())
                                }
                                syn::GenericParam::Const(_) => {
                                    panic!("Serde does not support const generics yet");
                                }
                            })
                            .collect(),
                        gt_token: <Token![>]>::default(),
                    },
                ),
            }]
            .into_iter()
            .collect(),
        },
    })
}
<commit_msg>Resolve flat_map_option pedantic clippy lint<commit_after>use std::collections::HashSet;

use syn;
use syn::punctuated::{Pair, Punctuated};

use internals::ast::{Container, Data};
use internals::{attr, ungroup};

use proc_macro2::Span;

// Remove the default from every type parameter because in the generated impls
// they look like associated types: "error: associated type bindings are not
// allowed here".
pub fn without_defaults(generics: &syn::Generics) -> syn::Generics {
    syn::Generics {
        params: generics
            .params
            .iter()
            .map(|param| match param {
                syn::GenericParam::Type(param) => syn::GenericParam::Type(syn::TypeParam {
                    eq_token: None,
                    default: None,
                    ..param.clone()
                }),
                _ => param.clone(),
            })
            .collect(),
        ..generics.clone()
    }
}

pub fn with_where_predicates(
    generics: &syn::Generics,
    predicates: &[syn::WherePredicate],
) -> syn::Generics {
    let mut generics = generics.clone();
    generics
        .make_where_clause()
        .predicates
        .extend(predicates.iter().cloned());
    generics
}

pub fn with_where_predicates_from_fields(
    cont: &Container,
    generics: &syn::Generics,
    from_field: fn(&attr::Field) -> Option<&[syn::WherePredicate]>,
) -> syn::Generics {
    let predicates = cont
        .data
        .all_fields()
        .filter_map(|field| from_field(&field.attrs))
        .flat_map(|predicates| predicates.to_vec());

    let mut generics = generics.clone();
    generics.make_where_clause().predicates.extend(predicates);
    generics
}

pub fn with_where_predicates_from_variants(
    cont: &Container,
    generics: &syn::Generics,
    from_variant: fn(&attr::Variant) -> Option<&[syn::WherePredicate]>,
) -> syn::Generics {
    let variants = match &cont.data {
        Data::Enum(variants) => variants,
        Data::Struct(_, _) => {
            return generics.clone();
        }
    };

    let predicates = variants
        .iter()
        .filter_map(|variant| from_variant(&variant.attrs))
        .flat_map(|predicates| predicates.to_vec());

    let mut generics = generics.clone();
    generics.make_where_clause().predicates.extend(predicates);
    generics
}

// Puts the given bound on any generic type parameters that are used in fields
// for which filter returns true.
//
// For example, the following struct needs the bound `A: Serialize, B:
// Serialize`.
//
//     struct S<'b, A, B: 'b, C> {
//         a: A,
//         b: Option<&'b B>
//         #[serde(skip_serializing)]
//         c: C,
//     }
pub fn with_bound(
    cont: &Container,
    generics: &syn::Generics,
    filter: fn(&attr::Field, Option<&attr::Variant>) -> bool,
    bound: &syn::Path,
) -> syn::Generics {
    struct FindTyParams<'ast> {
        // Set of all generic type parameters on the current struct (A, B, C in
        // the example). Initialized up front.
        all_type_params: HashSet<syn::Ident>,

        // Set of generic type parameters used in fields for which filter
        // returns true (A and B in the example). Filled in as the visitor sees
        // them.
        relevant_type_params: HashSet<syn::Ident>,

        // Fields whose type is an associated type of one of the generic type
        // parameters.
        associated_type_usage: Vec<&'ast syn::TypePath>,
    }

    impl<'ast> FindTyParams<'ast> {
        fn visit_field(&mut self, field: &'ast syn::Field) {
            if let syn::Type::Path(ty) = ungroup(&field.ty) {
                if let Some(Pair::Punctuated(t, _)) = ty.path.segments.pairs().next() {
                    if self.all_type_params.contains(&t.ident) {
                        self.associated_type_usage.push(ty);
                    }
                }
            }
            self.visit_type(&field.ty);
        }

        fn visit_path(&mut self, path: &'ast syn::Path) {
            if let Some(seg) = path.segments.last() {
                if seg.ident == "PhantomData" {
                    // Hardcoded exception, because PhantomData<T> implements
                    // Serialize and Deserialize whether or not T implements it.
                    return;
                }
            }
            if path.leading_colon.is_none() && path.segments.len() == 1 {
                let id = &path.segments[0].ident;
                if self.all_type_params.contains(id) {
                    self.relevant_type_params.insert(id.clone());
                }
            }
            for segment in &path.segments {
                self.visit_path_segment(segment);
            }
        }

        // Everything below is simply traversing the syntax tree.

        fn visit_type(&mut self, ty: &'ast syn::Type) {
            match ty {
                syn::Type::Array(ty) => self.visit_type(&ty.elem),
                syn::Type::BareFn(ty) => {
                    for arg in &ty.inputs {
                        self.visit_type(&arg.ty);
                    }
                    self.visit_return_type(&ty.output);
                }
                syn::Type::Group(ty) => self.visit_type(&ty.elem),
                syn::Type::ImplTrait(ty) => {
                    for bound in &ty.bounds {
                        self.visit_type_param_bound(bound);
                    }
                }
                syn::Type::Macro(ty) => self.visit_macro(&ty.mac),
                syn::Type::Paren(ty) => self.visit_type(&ty.elem),
                syn::Type::Path(ty) => {
                    if let Some(qself) = &ty.qself {
                        self.visit_type(&qself.ty);
                    }
                    self.visit_path(&ty.path);
                }
                syn::Type::Ptr(ty) => self.visit_type(&ty.elem),
                syn::Type::Reference(ty) => self.visit_type(&ty.elem),
                syn::Type::Slice(ty) => self.visit_type(&ty.elem),
                syn::Type::TraitObject(ty) => {
                    for bound in &ty.bounds {
                        self.visit_type_param_bound(bound);
                    }
                }
                syn::Type::Tuple(ty) => {
                    for elem in &ty.elems {
                        self.visit_type(elem);
                    }
                }

                syn::Type::Infer(_) | syn::Type::Never(_) | syn::Type::Verbatim(_) => {}

                #[cfg(test)]
                syn::Type::__TestExhaustive(_) => unimplemented!(),
                #[cfg(not(test))]
                _ => {}
            }
        }

        fn visit_path_segment(&mut self, segment: &'ast syn::PathSegment) {
            self.visit_path_arguments(&segment.arguments);
        }

        fn visit_path_arguments(&mut self, arguments: &'ast syn::PathArguments) {
            match arguments {
                syn::PathArguments::None => {}
                syn::PathArguments::AngleBracketed(arguments) => {
                    for arg in &arguments.args {
                        match arg {
                            syn::GenericArgument::Type(arg) => self.visit_type(arg),
                            syn::GenericArgument::Binding(arg) => self.visit_type(&arg.ty),
                            syn::GenericArgument::Lifetime(_)
                            | syn::GenericArgument::Constraint(_)
                            | syn::GenericArgument::Const(_) => {}
                        }
                    }
                }
                syn::PathArguments::Parenthesized(arguments) => {
                    for argument in &arguments.inputs {
                        self.visit_type(argument);
                    }
                    self.visit_return_type(&arguments.output);
                }
            }
        }

        fn visit_return_type(&mut self, return_type: &'ast syn::ReturnType) {
            match return_type {
                syn::ReturnType::Default => {}
                syn::ReturnType::Type(_, output) => self.visit_type(output),
            }
        }

        fn visit_type_param_bound(&mut self, bound: &'ast syn::TypeParamBound) {
            match bound {
                syn::TypeParamBound::Trait(bound) => self.visit_path(&bound.path),
                syn::TypeParamBound::Lifetime(_) => {}
            }
        }

        // Type parameter should not be considered used by a macro path.
        //
        //     struct TypeMacro<T> {
        //         mac: T!(),
        //         marker: PhantomData<T>,
        //     }
        fn visit_macro(&mut self, _mac: &'ast syn::Macro) {}
    }

    let all_type_params = generics
        .type_params()
        .map(|param| param.ident.clone())
        .collect();

    let mut visitor = FindTyParams {
        all_type_params,
        relevant_type_params: HashSet::new(),
        associated_type_usage: Vec::new(),
    };
    match &cont.data {
        Data::Enum(variants) => {
            for variant in variants.iter() {
                let relevant_fields = variant
                    .fields
                    .iter()
                    .filter(|field| filter(&field.attrs, Some(&variant.attrs)));
                for field in relevant_fields {
                    visitor.visit_field(field.original);
                }
            }
        }
        Data::Struct(_, fields) => {
            for field in fields.iter().filter(|field| filter(&field.attrs, None)) {
                visitor.visit_field(field.original);
            }
        }
    }

    let relevant_type_params = visitor.relevant_type_params;
    let associated_type_usage = visitor.associated_type_usage;
    let new_predicates = generics
        .type_params()
        .map(|param| param.ident.clone())
        .filter(|id| relevant_type_params.contains(id))
        .map(|id| syn::TypePath {
            qself: None,
            path: id.into(),
        })
        .chain(associated_type_usage.into_iter().cloned())
        .map(|bounded_ty| {
            syn::WherePredicate::Type(syn::PredicateType {
                lifetimes: None,
                // the type parameter that is being bounded e.g. T
                bounded_ty: syn::Type::Path(bounded_ty),
                colon_token: <Token![:]>::default(),
                // the bound e.g. Serialize
                bounds: vec![syn::TypeParamBound::Trait(syn::TraitBound {
                    paren_token: None,
                    modifier: syn::TraitBoundModifier::None,
                    lifetimes: None,
                    path: bound.clone(),
                })]
                .into_iter()
                .collect(),
            })
        });

    let mut generics = generics.clone();
    generics
        .make_where_clause()
        .predicates
        .extend(new_predicates);
    generics
}

pub fn with_self_bound(
    cont: &Container,
    generics: &syn::Generics,
    bound: &syn::Path,
) -> syn::Generics {
    let mut generics = generics.clone();
    generics
        .make_where_clause()
        .predicates
        .push(syn::WherePredicate::Type(syn::PredicateType {
            lifetimes: None,
            // the type that is being bounded e.g. MyStruct<'a, T>
            bounded_ty: type_of_item(cont),
            colon_token: <Token![:]>::default(),
            // the bound e.g. Default
            bounds: vec![syn::TypeParamBound::Trait(syn::TraitBound {
                paren_token: None,
                modifier: syn::TraitBoundModifier::None,
                lifetimes: None,
                path: bound.clone(),
            })]
            .into_iter()
            .collect(),
        }));
    generics
}

pub fn with_lifetime_bound(generics: &syn::Generics, lifetime: &str) -> syn::Generics {
    let bound = syn::Lifetime::new(lifetime, Span::call_site());
    let def = syn::LifetimeDef {
        attrs: Vec::new(),
        lifetime: bound.clone(),
        colon_token: None,
        bounds: Punctuated::new(),
    };

    let params = Some(syn::GenericParam::Lifetime(def))
        .into_iter()
        .chain(generics.params.iter().cloned().map(|mut param| {
            match &mut param {
                syn::GenericParam::Lifetime(param) => {
                    param.bounds.push(bound.clone());
                }
                syn::GenericParam::Type(param) => {
                    param
                        .bounds
                        .push(syn::TypeParamBound::Lifetime(bound.clone()));
                }
                syn::GenericParam::Const(_) => {}
            }
            param
        }))
        .collect();

    syn::Generics {
        params,
        ..generics.clone()
    }
}

fn type_of_item(cont: &Container) -> syn::Type {
    syn::Type::Path(syn::TypePath {
        qself: None,
        path: syn::Path {
            leading_colon: None,
            segments: vec![syn::PathSegment {
                ident: cont.ident.clone(),
                arguments: syn::PathArguments::AngleBracketed(
                    syn::AngleBracketedGenericArguments {
                        colon2_token: None,
                        lt_token: <Token![<]>::default(),
                        args: cont
                            .generics
                            .params
                            .iter()
                            .map(|param| match param {
                                syn::GenericParam::Type(param) => {
                                    syn::GenericArgument::Type(syn::Type::Path(syn::TypePath {
                                        qself: None,
                                        path: param.ident.clone().into(),
                                    }))
                                }
                                syn::GenericParam::Lifetime(param) => {
                                    syn::GenericArgument::Lifetime(param.lifetime.clone())
                                }
                                syn::GenericParam::Const(_) => {
                                    panic!("Serde does not support const generics yet");
                                }
                            })
                            .collect(),
                        gt_token: <Token![>]>::default(),
                    },
                ),
            }]
            .into_iter()
            .collect(),
        },
    })
}
<|endoftext|>


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

//! Mesh loading.
//!
//! A `Mesh` describes the geometry of an object. All or part of a `Mesh` can be drawn with a
//! single draw call. A `Mesh` consists of a series of vertices, each with a certain amount of
//! user-specified attributes. These attributes are fed into shader programs. The easiest way to
//! create a mesh is to use the `#[vertex_format]` attribute on a struct, upload them into a
//! `Buffer`, and then use `Mesh::from`.

use gfx_core::handle;
use gfx_core::{Primitive, Resources, VertexCount};
use gfx_core::draw::InstanceOption;
use gfx_core::factory::{Bind, BufferRole, Factory};

/// Description of a subset of `Mesh` data to render.
///
/// Only vertices between `start` and `end` are rendered. The
/// source of the vertex data is dependent on the `kind` value.
///
/// The `primitive` defines how the mesh contents are interpreted.
/// For example,  `Point` typed vertex slice can be used to do shape
/// blending, while still rendereing it as an indexed `TriangleList`.
#[derive(Clone, Debug, PartialEq)]
pub struct Slice<R: Resources> {
    /// Start index of vertices to draw.
    pub start: VertexCount,
    /// End index of vertices to draw.
    pub end: VertexCount,
    /// Instancing configuration.
    pub instances: InstanceOption,
    /// Source of the vertex ordering when drawing.
    pub kind: SliceKind<R>,
}

impl<R: Resources> Slice<R> {
    /// Get the number of primitives in this slice.
    pub fn get_prim_count(&self, prim: Primitive) -> u32 {
        use gfx_core::Primitive::*;
        let nv = (self.end - self.start) as u32;
        match prim {
            PointList => nv,
            LineList => nv / 2,
            LineStrip => (nv-1),
            TriangleList => nv / 3,
            TriangleStrip => (nv-2) / 3,
        }
    }
}

/// Source of vertex ordering for a slice
#[derive(Clone, Debug, PartialEq)]
pub enum SliceKind<R: Resources> {
    /// Render vertex data directly from the `Mesh`'s buffer.
    Vertex,
    /// The `Index*` buffer contains a list of indices into the `Mesh`
    /// data, so every vertex attribute does not need to be duplicated, only
    /// its position in the `Mesh`. The base index is added to this index
    /// before fetching the vertex from the buffer.  For example, when drawing
    /// a square, two triangles are needed.  Using only `Vertex`, one
    /// would need 6 separate vertices, 3 for each triangle. However, two of
    /// the vertices will be identical, wasting space for the duplicated
    /// attributes.  Instead, the `Mesh` can store 4 vertices and an
    /// `Index8` can be used instead.
    Index8(handle::Buffer<R, u8>, VertexCount),
    /// As `Index8` but with `u16` indices
    Index16(handle::Buffer<R, u16>, VertexCount),
    /// As `Index8` but with `u32` indices
    Index32(handle::Buffer<R, u32>, VertexCount),
}

/// A helper trait to build index slices from data.
pub trait ToIndexSlice<R: Resources> { //TODO: remove/refactor it
    /// Make an index slice.
    fn to_slice<F: Factory<R>>(self, factory: &mut F) -> Slice<R>;
}

macro_rules! impl_slice {
    ($ty:ty, $index:ident) => (
        impl<R: Resources> From<handle::Buffer<R, $ty>> for Slice<R> {
            fn from(buf: handle::Buffer<R, $ty>) -> Slice<R> {
                Slice {
                    start: 0,
                    end: buf.len() as VertexCount,
                    instances: None,
                    kind: SliceKind::$index(buf, 0)
                }
            }
        }
        impl<'a, R: Resources> ToIndexSlice<R> for &'a [$ty] {
            fn to_slice<F: Factory<R>>(self, factory: &mut F) -> Slice<R> {
                //debug_assert!(self.len() <= factory.get_capabilities().max_index_count);
                factory.create_buffer_const(self, BufferRole::Index, Bind::empty())
                       .unwrap().into()
            }
        }
    )
}

impl_slice!(u8, Index8);
impl_slice!(u16, Index16);
impl_slice!(u32, Index32);
<commit_msg>Updated Slice documentation<commit_after>// Copyright 2014 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Slices
//!
//! See `Slice`-structure documentation for more information on this module.

use gfx_core::handle;
use gfx_core::{Primitive, Resources, VertexCount};
use gfx_core::draw::InstanceOption;
use gfx_core::factory::{Bind, BufferRole, Factory};

/// A `Slice` dictates in which and in what order vertices get processed. It is required for
/// processing a PSO.
///
/// # Overview
/// A `Slice` object in essence dictates in what order the vertices in a `VertexBuffer` get
/// processed. To do this, it contains an internal index-buffer. This `Buffer` is a list of
/// indices into this `VertexBuffer` (vertex-index). A vertex-index of 0 represents the first
/// vertex in the `VertexBuffer`, a vertex-index of 1 represents the second, 2 represents the
/// third, and so on. The vertex-indices in the index-buffer are read in order; every vertex-index
/// tells the pipeline which vertex to process next.
///
/// Because the same index can re-appear multiple times, duplicate-vertices can be avoided. For
/// instance, if you want to draw a square, you need two triangles, and thus six vertices. Because
/// the same index can reappear multiple times, this means we can instead use 4 vertices, and 6
/// vertex-indices.
///
/// This index-buffer has a few variants. See the `SliceKind` documentation for a detailed
/// description.
///
/// The `start` and `end` properties say where in the index-buffer to start and stop reading.
/// Setting `start` to 0, and `end` to the length of the index-buffer, will cause the entire
/// index-buffer to be processed.
///
/// # Constuction & Handling
/// The `Slice` structure gets constructed automatically when creating a `VertexBuffer` using a
/// `Factory`.
///
/// A `Slice` buffer is required to process a PSO, as it contains the needed information on in what
/// order to draw which vertices. As such, every `draw` call on an `Encoder` requires a `Slice`.
#[derive(Clone, Debug, PartialEq)]
pub struct Slice<R: Resources> {
    /// The start index of the index-buffer. Processing will start at this location in the
    /// index-buffer.
    pub start: VertexCount,
    /// The end index in the index-buffer. Processing will stop at this location (exclusive) in
    /// the index buffer.
    pub end: VertexCount,
    /// Instancing configuration.
    pub instances: InstanceOption,
    /// Represents the type of index-buffer used.
    pub kind: SliceKind<R>,
}

impl<R: Resources> Slice<R> {
    /// Calculates the number of primitives of the specified type in this `Slice`.
    pub fn get_prim_count(&self, prim: Primitive) -> u32 {
        use gfx_core::Primitive::*;
        let nv = (self.end - self.start) as u32;
        match prim {
            PointList => nv,
            LineList => nv / 2,
            LineStrip => (nv-1),
            TriangleList => nv / 3,
            TriangleStrip => (nv-2) / 3,
        }
    }
}

/// Type of index-buffer used in a Slice.
///
/// The `Vertex` represents a hypothetical index-buffer from 0 to infinity. In other words, all
/// vertices get processed in order. Do note that the `Slice`' `start` and `end` restrictions still
/// apply for this variant. To render every vertex in the `VertexBuffer`, you would set `start` to
/// 0, and `end` to the `VertexBuffer`'s length.
///
/// The `Index*` variants represent an actual `Buffer` with a list of vertex-indices. The numeric
/// suffix specifies the amount of bits to use per index. Each of these also contains a
/// base-vertex. This is the index of the first vertex in the `VertexBuffer`. This value will be
/// added to every index in the index-buffer, effectively moving the start of the `VertexBuffer` to
/// this base-vertex.
#[derive(Clone, Debug, PartialEq)]
pub enum SliceKind<R: Resources> {
    /// Represents a hypothetical index-buffer from 0 to infinity. In other words, all vertices
    /// get processed in order.
    Vertex,
    /// An index-buffer with unsigned 8 bit indices.
    Index8(handle::Buffer<R, u8>, VertexCount),
    /// An index-buffer with unsigned 16 bit indices.
    Index16(handle::Buffer<R, u16>, VertexCount),
    /// An index-buffer with unsigned 32 bit indices.
    Index32(handle::Buffer<R, u32>, VertexCount),
}

/// A helper trait to build index slices from data.
pub trait ToIndexSlice<R: Resources> { //TODO: remove/refactor it
    /// Make an index slice.
    fn to_slice<F: Factory<R>>(self, factory: &mut F) -> Slice<R>;
}

macro_rules! impl_slice {
    ($ty:ty, $index:ident) => (
        impl<R: Resources> From<handle::Buffer<R, $ty>> for Slice<R> {
            fn from(buf: handle::Buffer<R, $ty>) -> Slice<R> {
                Slice {
                    start: 0,
                    end: buf.len() as VertexCount,
                    instances: None,
                    kind: SliceKind::$index(buf, 0)
                }
            }
        }
        impl<'a, R: Resources> ToIndexSlice<R> for &'a [$ty] {
            fn to_slice<F: Factory<R>>(self, factory: &mut F) -> Slice<R> {
                //debug_assert!(self.len() <= factory.get_capabilities().max_index_count);
                factory.create_buffer_const(self, BufferRole::Index, Bind::empty())
                       .unwrap().into()
            }
        }
    )
}

impl_slice!(u8, Index8);
impl_slice!(u16, Index16);
impl_slice!(u32, Index32);
<|endoftext|>


<commit_before>use std::result;
use std::fmt;

/// Stack trace record.
pub enum TraceEntry {
    /// Trace source file change that caused the error.
    SourceFile { target: String },
    /// Trace operator call that caused the error.
    Operator { target: String, extension: String },
    /// Trace position in last known source that cause the error.
    Position { from: Location },
}

/// Location record in source file.
pub struct Location {
    pub line: usize,
}

impl Location {
    pub fn new(line: usize) -> Location {
        Location { line: line }
    }
}

#[derive(Debug)]
pub enum ErrorMessage {
    InvalidArgumentCount { expected: usize, found: usize },
}

pub struct Error {
    pub line: Option<usize>,
    pub message: ErrorMessage,
    pub stack_trace: Vec<TraceEntry>,
}

impl Error {
    pub fn new(message: ErrorMessage) -> Error {
        Error {
            line: None,
            message: message,
            stack_trace: Vec::new(),
        }
    }

    pub fn new_at(message: ErrorMessage, line: usize) -> Error {
        Error {
            line: Some(line),
            message: message,
            stack_trace: Vec::new(),
        }
    }
}

impl fmt::Debug for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self.message)
    }
}

pub type Result<T> = result::Result<T, Error>;
<commit_msg>Runtime error docs.<commit_after>use std::result;
use std::fmt;

/// Stack trace record.
pub enum TraceEntry {
    /// Trace source file change that caused the error.
    SourceFile { target: String },
    /// Trace operator call that caused the error.
    Operator { target: String, extension: String },
    /// Trace position in last known source that cause the error.
    Position { from: Location },
}

/// Location record in source file.
pub struct Location {
    pub line: usize,
}

impl Location {
    pub fn new(line: usize) -> Location {
        Location { line: line }
    }
}

#[derive(Debug)]
/// Runtime error message.
pub enum ErrorMessage {
    /// Callable invoked with argument count that does not match defined count.
    InvalidArgumentCount { expected: usize, found: usize },
}

/// Runtime error with stack trace.
pub struct Error {
    pub message: ErrorMessage,
    pub stack_trace: Vec<TraceEntry>,
}

impl Error {
    pub fn new(message: ErrorMessage) -> Error {
        Error {
            message: message,
            stack_trace: Vec::new(),
        }
    }
}

impl fmt::Debug for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self.message)
    }
}

/// Runtime operation result.
pub type Result<T> = result::Result<T, Error>;
<|endoftext|>


<commit_before>extern crate libc;

use self::libc::{size_t, c_void};
use std::ptr;
use std::mem;

const CPUSTATES: usize = 5;

#[repr(C,packed)]
pub struct CPUInfo {
    pub state: [isize; CPUSTATES],
}

impl CPUInfo {
    fn new() -> CPUInfo {
        CPUInfo {
            state: [0, 0, 0, 0, 0],
        }
    }

    pub fn fetch() -> CPUInfo {
        let mut mib: [libc::c_int; 2] = [ libc::CTL_KERN, libc::KERN_CPTIME ];
        let mut info = CPUInfo::new();
        let buf: *mut c_void = info.state.as_mut_ptr() as *mut c_void;
        let mut size = mem::size_of::<CPUInfo>() as size_t;
        let outbuf: *mut c_void = ptr::null_mut() as *mut c_void;
        unsafe {
            libc::sysctl(&mut mib[0], 2, buf,
                         &mut size, outbuf, 0);
        }
        info
    }

    pub fn ncpus() -> u32 {
        unsafe {
            libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as u32
        }
    }

    pub fn get_busy(&self, old: &CPUInfo) -> u32 {
        let mut diff = self.state.clone();
        let mut sum = 0;
        for i in 0..CPUSTATES {
            diff[i] = self.state[i] - old.state[i];
            sum += diff[i];
        }
        if sum == 0 { sum += 1 }
        (((sum - diff[CPUSTATES - 1]) * 100) / sum) as u32
    }
}
<commit_msg>Retrieve cp_time mib on FreeBSD<commit_after>extern crate libc;

use self::libc::{size_t, c_void};
use std::ptr;
use std::mem;

const CPUSTATES: usize = 5;

#[repr(C,packed)]
pub struct CPUInfo {
    pub state: [isize; CPUSTATES],
}

impl CPUInfo {
    fn new() -> CPUInfo {
        CPUInfo {
            state: [0, 0, 0, 0, 0],
        }
    }

    pub fn fetch() -> CPUInfo {
        #[cfg(target_os = "openbsd")]
        let mut mib: [libc::c_int; 2] = [ libc::CTL_KERN, libc::KERN_CPTIME ];
        #[cfg(target_os = "freebsd")]
        let mut mib: [libc::c_int; 4] = CPUInfo::cp_time_mib();
        let mut info = CPUInfo::new();
        let buf: *mut c_void = info.state.as_mut_ptr() as *mut c_void;
        let mut size = mem::size_of::<CPUInfo>() as size_t;
        let outbuf: *mut c_void = ptr::null_mut() as *mut c_void;
        unsafe {
            libc::sysctl(&mut mib[0], mib.len() as u32, buf,
                         &mut size, outbuf, 0);
        }
        info
    }

    #[cfg(target_os = "freebsd")]
    fn cp_time_mib() -> [libc::c_int; 4] {
        let mut mib: [libc::c_int; 4] = [0, 0, 0, 0];
        unsafe {
            let mut size: usize = mib.len();
            let sctlname = "kern.cp_time";
            let name: *const i8 = sctlname.as_ptr() as *const i8;
            libc::sysctlnametomib(name, &mut mib[0], &mut size);
        }
        mib
    }

    pub fn ncpus() -> u32 {
        unsafe {
            libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as u32
        }
    }

    pub fn get_busy(&self, old: &CPUInfo) -> u32 {
        let mut diff = self.state.clone();
        let mut sum = 0;
        for i in 0..CPUSTATES {
            diff[i] = self.state[i] - old.state[i];
            sum += diff[i];
        }
        if sum == 0 { sum += 1 }
        (((sum - diff[CPUSTATES - 1]) * 100) / sum) as u32
    }
}
<|endoftext|>


<commit_before>use std::string::String;
use std::vec::Vec;

use byteorder::{BigEndian, WriteBytesExt};

use types::{BERT_LABEL, EXT_VERSION, BertTag};

// TODO: Error handling
pub struct Serializer;

pub struct Deserializer {
//    data: Vec<u8>
}

pub trait Serialize<T> {
    fn to_bert(&self, data: T) -> Vec<u8>;
}

trait Deserialize<T> {
    fn to_bert(&self, data: T) -> Vec<u8>;
}

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

    pub fn term_to_binary<T>(&self, data: T) -> Vec<u8> where Self: Serialize<T> {
        let mut binary = vec![EXT_VERSION];
        let serialized_data = self.to_bert(data);
        binary.extend(serialized_data.iter().clone());
        binary
    }

    pub fn generate_term(&self, tag: BertTag, data: Vec<u8>) -> Vec<u8> {
        let mut binary = vec![tag as u8];
        binary.extend(data.iter().clone());
        binary
    }

    pub fn convert_string_to_binary(&self, data: &str) -> Vec<u8> {
        let binary_string = data.as_bytes();
        let binary_length = binary_string.len() as u8;
        let mut binary = vec![0u8, binary_length];
        binary.extend(binary_string.iter().clone());
        binary
    }

    pub fn merge_terms(&self, term_1: Vec<u8>, term_2: Vec<u8>) -> Vec<u8> {
        let mut binary: Vec<u8> = term_1.clone();
        binary.extend(term_2.iter().clone());
        binary
    }

    pub fn get_atom(&self, name: Vec<u8>) -> Vec<u8> {
        self.generate_term(BertTag::Atom, name)
    }

    pub fn get_nil(&self) -> Vec<u8> {
        vec![BertTag::Nil as u8]
    }

    pub fn get_bert_nil(&self) -> Vec<u8> {
        let bert_atom = self.get_bert_atom();

        let binary_nil_string = self.convert_string_to_binary("nil");
        let nil_atom = self.get_atom(binary_nil_string);

        let mut binary: Vec<u8> = vec![];
        binary.extend(bert_atom.iter().clone());
        binary.extend(nil_atom.iter().clone());
        self.get_small_tuple(2, binary)
    }

    pub fn get_bert_atom(&self) -> Vec<u8> {
        let binary_string = self.convert_string_to_binary(BERT_LABEL);
        self.get_atom(binary_string)
    }

    fn get_small_tuple(&self, arity: u8, elements: Vec<u8>) -> Vec<u8> {
        let mut binary = vec![arity];
        binary.extend(elements.iter().clone());
        self.generate_term(BertTag::SmallTuple, binary)
    }

    fn get_large_tuple(&self, arity: i32, elements: Vec<u8>) -> Vec<u8> {
        let mut binary = vec![];
        binary.write_i32::<BigEndian>(arity).unwrap();
        binary.extend(elements.iter().clone());
        self.generate_term(BertTag::LargeTuple, binary)
    }
}

impl Serialize<u8> for Serializer {
    fn to_bert(&self, data: u8) -> Vec<u8> {
        self.generate_term(BertTag::SmallInteger, vec![data])
    }
}

impl Serialize<i32> for Serializer {
    fn to_bert(&self, data: i32) -> Vec<u8> {
        let mut binary = vec![];
        binary.write_i32::<BigEndian>(data).unwrap();
        self.generate_term(BertTag::Integer, binary)
    }
}

impl Serialize<f64> for Serializer {
    fn to_bert(&self, data: f64) -> Vec<u8> {
        let mut binary = vec![];
        binary.write_f64::<BigEndian>(data).unwrap();
        self.generate_term(BertTag::NewFloat, binary)
    }
}

impl Serialize<String> for Serializer {
    fn to_bert(&self, data: String) -> Vec<u8> {
        let binary_string = self.convert_string_to_binary(&data);
        self.generate_term(BertTag::String, binary_string)
    }
}

impl<'a> Serialize<&'a str> for Serializer {
    fn to_bert(&self, data: &'a str) -> Vec<u8> {
        let binary_string = self.convert_string_to_binary(data);
        self.generate_term(BertTag::String, binary_string)
    }
}

impl Serialize<bool> for Serializer {
    fn to_bert(&self, data: bool) -> Vec<u8> {
        let boolean_string = data.to_string();
        let binary_boolean = self.convert_string_to_binary(&boolean_string);

        let bert_atom = self.get_bert_atom();
        let boolean_atom = self.get_atom(binary_boolean);

        let binary = self.merge_terms(bert_atom, boolean_atom);
        self.get_small_tuple(2, binary)
    }
}

#[cfg(test)]
mod test_serializer {
    use super::{Serializer};

    #[test]
    fn test_serialize_u8() {
        let serializer = Serializer::new();

        assert_eq!(
            serializer.term_to_binary(1u8),
            vec![131u8, 97, 1]
        );

        assert_eq!(
            serializer.term_to_binary(255u8),
            vec![131u8, 97, 255]
        );
    }

    #[test]
    fn test_serialize_i32() {
        let serializer = Serializer::new();

        assert_eq!(
            serializer.term_to_binary(-2147483648),
            vec![131u8, 98, 128, 0, 0, 0]
        );

        assert_eq!(
            serializer.term_to_binary(-1i32),
            vec![131u8, 98, 255, 255, 255, 255]
        );

        assert_eq!(
            serializer.term_to_binary(512i32),
            vec![131u8, 98, 0, 0, 2, 0]
        );

        assert_eq!(
            serializer.term_to_binary(2147483647),
            vec![131u8, 98, 127, 255, 255, 255]
        );
    }

    #[test]
    fn test_serializer_f64() {
        let serializer = Serializer::new();

        assert_eq!(
            serializer.term_to_binary(-3.14f64),
            vec![131, 70, 192, 9, 30, 184, 81, 235, 133, 31]
        );

        assert_eq!(
            serializer.term_to_binary(0.0f64),
            vec![131, 70, 0, 0, 0, 0, 0, 0, 0, 0]
        );

        assert_eq!(
            serializer.term_to_binary(3.14f64),
            vec![131, 70, 64, 9, 30, 184, 81, 235, 133, 31]
        )

    }

    #[test]
    fn test_serialize_bool() {
        let serializer = Serializer::new();

        assert_eq!(
            serializer.term_to_binary(true),
            vec![
                131u8,
                104,                            // small tuple tag
                2,                              // tuple length
                100, 0, 4,  98, 101, 114, 116,  // "bert" as atom
                100, 0, 4, 116, 114, 117, 101   // "true" as atom
            ]
        );

        assert_eq!(
            serializer.term_to_binary(false),
            vec![
                131u8,
                104,                               // small tuple tag
                2,                                 // tuple length
                100, 0, 4, 98, 101, 114, 116,      // "bert" as atom
                100, 0, 5, 102, 97, 108, 115, 101  // "false" as atom
            ]
        );
    }

    #[test]
    fn test_serialize_string() {
        let serializer = Serializer::new();

        // string by value
        assert_eq!(
            serializer.term_to_binary(String::from("test")),
            vec![131u8, 107, 0, 4, 116, 101, 115, 116]
        );

        // string by reference
        assert_eq!(
            serializer.term_to_binary("test"),
            vec![131u8, 107, 0, 4, 116, 101, 115, 116]
        );
    }

    #[test]
    fn test_get_nil() {
        let serializer = Serializer::new();

        assert_eq!(
            serializer.get_nil(),
            vec![106]
        );
    }

    #[test]
    fn test_get_bert_nil() {
        let serializer = Serializer::new();

        assert_eq!(
            serializer.get_bert_nil(),
            vec![
                104,
                2,                              // tuple length
                100, 0, 4,  98, 101, 114, 116,  // "bert" as atom
                100, 0, 3, 110, 105, 108        // "nil" as atom
            ]
        )
    }
}
<commit_msg>Added tests for public functions of Serializer<commit_after>use std::string::String;
use std::vec::Vec;

use byteorder::{BigEndian, WriteBytesExt};

use types::{BERT_LABEL, EXT_VERSION, BertTag};

// TODO: Error handling
pub struct Serializer;

pub struct Deserializer {
//    data: Vec<u8>
}

pub trait Serialize<T> {
    fn to_bert(&self, data: T) -> Vec<u8>;
}

trait Deserialize<T> {
    fn to_bert(&self, data: T) -> Vec<u8>;
}

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

    pub fn term_to_binary<T>(&self, data: T) -> Vec<u8> where Self: Serialize<T> {
        let mut binary = vec![EXT_VERSION];
        let serialized_data = self.to_bert(data);
        binary.extend(serialized_data.iter().clone());
        binary
    }

    pub fn generate_term(&self, tag: BertTag, data: Vec<u8>) -> Vec<u8> {
        let mut binary = vec![tag as u8];
        binary.extend(data.iter().clone());
        binary
    }

    pub fn convert_string_to_binary(&self, data: &str) -> Vec<u8> {
        let binary_string = data.as_bytes();
        let binary_length = binary_string.len() as u8;
        let mut binary = vec![0u8, binary_length];
        binary.extend(binary_string.iter().clone());
        binary
    }

    pub fn merge_terms(&self, term_1: Vec<u8>, term_2: Vec<u8>) -> Vec<u8> {
        let mut binary: Vec<u8> = term_1.clone();
        binary.extend(term_2.iter().clone());
        binary
    }

    pub fn get_atom(&self, name: Vec<u8>) -> Vec<u8> {
        self.generate_term(BertTag::Atom, name)
    }

    pub fn get_nil(&self) -> Vec<u8> {
        vec![BertTag::Nil as u8]
    }

    pub fn get_bert_nil(&self) -> Vec<u8> {
        let bert_atom = self.get_bert_atom();

        let binary_nil_string = self.convert_string_to_binary("nil");
        let nil_atom = self.get_atom(binary_nil_string);

        let mut binary: Vec<u8> = vec![];
        binary.extend(bert_atom.iter().clone());
        binary.extend(nil_atom.iter().clone());
        self.get_small_tuple(2, binary)
    }

    pub fn get_bert_atom(&self) -> Vec<u8> {
        let binary_string = self.convert_string_to_binary(BERT_LABEL);
        self.get_atom(binary_string)
    }

    fn get_small_tuple(&self, arity: u8, elements: Vec<u8>) -> Vec<u8> {
        let mut binary = vec![arity];
        binary.extend(elements.iter().clone());
        self.generate_term(BertTag::SmallTuple, binary)
    }

    fn get_large_tuple(&self, arity: i32, elements: Vec<u8>) -> Vec<u8> {
        let mut binary = vec![];
        binary.write_i32::<BigEndian>(arity).unwrap();
        binary.extend(elements.iter().clone());
        self.generate_term(BertTag::LargeTuple, binary)
    }
}

impl Serialize<u8> for Serializer {
    fn to_bert(&self, data: u8) -> Vec<u8> {
        self.generate_term(BertTag::SmallInteger, vec![data])
    }
}

impl Serialize<i32> for Serializer {
    fn to_bert(&self, data: i32) -> Vec<u8> {
        let mut binary = vec![];
        binary.write_i32::<BigEndian>(data).unwrap();
        self.generate_term(BertTag::Integer, binary)
    }
}

impl Serialize<f64> for Serializer {
    fn to_bert(&self, data: f64) -> Vec<u8> {
        let mut binary = vec![];
        binary.write_f64::<BigEndian>(data).unwrap();
        self.generate_term(BertTag::NewFloat, binary)
    }
}

impl Serialize<String> for Serializer {
    fn to_bert(&self, data: String) -> Vec<u8> {
        let binary_string = self.convert_string_to_binary(&data);
        self.generate_term(BertTag::String, binary_string)
    }
}

impl<'a> Serialize<&'a str> for Serializer {
    fn to_bert(&self, data: &'a str) -> Vec<u8> {
        let binary_string = self.convert_string_to_binary(data);
        self.generate_term(BertTag::String, binary_string)
    }
}

impl Serialize<bool> for Serializer {
    fn to_bert(&self, data: bool) -> Vec<u8> {
        let boolean_string = data.to_string();
        let binary_boolean = self.convert_string_to_binary(&boolean_string);

        let bert_atom = self.get_bert_atom();
        let boolean_atom = self.get_atom(binary_boolean);

        let binary = self.merge_terms(bert_atom, boolean_atom);
        self.get_small_tuple(2, binary)
    }
}

#[cfg(test)]
mod test_serializer {
    use super::{Serializer};
    use types::{BertTag};

    #[test]
    fn test_serialize_u8() {
        let serializer = Serializer::new();

        assert_eq!(
            serializer.term_to_binary(1u8),
            vec![131u8, 97, 1]
        );

        assert_eq!(
            serializer.term_to_binary(255u8),
            vec![131u8, 97, 255]
        );
    }

    #[test]
    fn test_serialize_i32() {
        let serializer = Serializer::new();

        assert_eq!(
            serializer.term_to_binary(-2147483648),
            vec![131u8, 98, 128, 0, 0, 0]
        );

        assert_eq!(
            serializer.term_to_binary(-1i32),
            vec![131u8, 98, 255, 255, 255, 255]
        );

        assert_eq!(
            serializer.term_to_binary(512i32),
            vec![131u8, 98, 0, 0, 2, 0]
        );

        assert_eq!(
            serializer.term_to_binary(2147483647),
            vec![131u8, 98, 127, 255, 255, 255]
        );
    }

    #[test]
    fn test_serializer_f64() {
        let serializer = Serializer::new();

        assert_eq!(
            serializer.term_to_binary(-3.14f64),
            vec![131u8, 70, 192, 9, 30, 184, 81, 235, 133, 31]
        );

        assert_eq!(
            serializer.term_to_binary(0.0f64),
            vec![131u8, 70, 0, 0, 0, 0, 0, 0, 0, 0]
        );

        assert_eq!(
            serializer.term_to_binary(3.14f64),
            vec![131u8, 70, 64, 9, 30, 184, 81, 235, 133, 31]
        )

    }

    #[test]
    fn test_serialize_bool() {
        let serializer = Serializer::new();

        assert_eq!(
            serializer.term_to_binary(true),
            vec![
                131u8,
                104,                            // small tuple tag
                2,                              // tuple length
                100, 0, 4,  98, 101, 114, 116,  // "bert" as atom
                100, 0, 4, 116, 114, 117, 101   // "true" as atom
            ]
        );

        assert_eq!(
            serializer.term_to_binary(false),
            vec![
                131u8,
                104,                               // small tuple tag
                2,                                 // tuple length
                100, 0, 4, 98, 101, 114, 116,      // "bert" as atom
                100, 0, 5, 102, 97, 108, 115, 101  // "false" as atom
            ]
        );
    }

    #[test]
    fn test_serialize_string() {
        let serializer = Serializer::new();

        // string by value
        assert_eq!(
            serializer.term_to_binary(String::from("test")),
            vec![131u8, 107, 0, 4, 116, 101, 115, 116]
        );

        // string by reference
        assert_eq!(
            serializer.term_to_binary("test"),
            vec![131u8, 107, 0, 4, 116, 101, 115, 116]
        );
    }

    #[test]
    fn test_generate_term() {
        let serializer = Serializer::new();

        let data: Vec<u8> = vec![0, 4, 116, 101, 115, 116];  // bert as string
        assert_eq!(
            serializer.generate_term(BertTag::Atom, data),
            vec![100u8, 0, 4, 116, 101, 115, 116]
        );
    }

    #[test]
    fn test_merge_terms() {
        let serializer = Serializer::new();

        let term_1: Vec<u8> = vec![100, 0, 4,  98, 101, 114, 116];
        let term_2: Vec<u8> = vec![100, 0, 3, 110, 105, 108];
        assert_eq!(
            serializer.merge_terms(term_1, term_2),
            vec![
                100u8, 0, 4, 98, 101, 114, 116,  // "bert" as atom
                100,   0, 3, 110, 105, 108       // "nil" as atom
            ]
        );
    }

    #[test]
    fn test_convert_string_to_binary() {
        let serializer = Serializer::new();

        let data = "bert";
        assert_eq!(
            serializer.convert_string_to_binary(data),
            vec![0u8, 4, 98, 101, 114, 116]
        );
    }

    #[test]
    fn test_get_atom() {
        let serializer = Serializer::new();

        let data: Vec<u8> = vec![0, 4, 116, 101, 115, 116];  // bert as string
        assert_eq!(
            serializer.get_atom(data),
            vec![100u8, 0, 4, 116, 101, 115, 116]
        );
    }

    #[test]
    fn test_get_nil() {
        let serializer = Serializer::new();

        assert_eq!(
            serializer.get_nil(),
            vec![106u8]
        );
    }

    #[test]
    fn test_get_bert_nil() {
        let serializer = Serializer::new();

        assert_eq!(
            serializer.get_bert_nil(),
            vec![
                104u8,
                2,                              // tuple length
                100, 0, 4,  98, 101, 114, 116,  // "bert" as atom
                100, 0, 3, 110, 105, 108        // "nil" as atom
            ]
        )
    }
}
<|endoftext|>