<commit_before>use std::collections::HashMap;
use graph_match::graph::Graph;
use graph_parser;

pub fn frame_index() -> HashMap<String, (usize, Graph)> {
    let mut index: HashMap<String, (usize, Graph)> = HashMap::new();
    let frames = vec![
        np_v_np()
    ];

    for frame in frames {
        index.insert(frame.0, (frame.1, frame.2));
    }
    return index;
}

fn np_v_np() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:obj\n\
                        type:edge identifier:subj source:1 target:0 label:nsubj\n\
                        type:edge identifier:obj source:1 target:2 label:dobj";
    return (String::from("NP VERB NP"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}
<commit_msg>Convert a number of Cypher frames<commit_after>use std::collections::HashMap;
use graph_match::graph::Graph;
us graph_parser;

pub fn frame_index() -> HashMap<String, (usize, Graph)> {
    let mut index: HashMap<String, (usize, Graph)> = HashMap::new();
    let frames = vec![
        np_v(),
        np_v_np(),
        np_v_adj(),
        np_v_adv(),
        np_v_adv_lex(),
        np_v_adv_prep_np(),
        lex_v_np_prep_np(),
        lex_v_prep_np_np(),
    ];

    for frame in frames {
        index.insert(frame.0, (frame.1, frame.2));
    }
    return index;
}

fn np_v_np() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:obj\n\
                        type:edge identifier:subj source:1 target:0 label:nsubj\n\
                        type:edge identifier:obj source:1 target:2 label:dobj";
    return (String::from("NP VERB NP"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

fn np_v() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:edge identifier:obj source:1 target:0 label:nsubj";
    return (String::from("NP VERB"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

fn np_v_adv() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:adv\n\
                        type:edge identifier:subj source:1 target:0 label:nsubj\n\
                        type:edge identifier:advmod source:1 target:2 label:advmod";
    return (String::from("NP VERB ADV"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

fn np_v_adv_prep_np() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:adv\n\
                        type:node identifier:nmod\n\
                        type:node identifier:prep\n\
                        type:edge identifier:subj source:1 target:0 label:nsubj\n\
                        type:edge identifier:advmod source:1 target:2 label:advmod\n\
                        type:edge identifier:nmod source:1 target:3 label:nmod\n\
                        type:edge identifier:case source:3 target:4 label:case";
    return (String::from("NP VERB ADV PREP NP"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

// lex should be before avd
fn np_v_adv_lex() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:dobj\n\
                        type:node identifier:adv\n\
                        type:node identifier:lex\n\
                        type:edge identifier:subj source:1 target:0 label:nsubj\n\
                        type:edge identifier:obj source:1 target:2 label:dobj\n\
                        type:edge identifier:adv source:1 target:3 label:advmod\n\
                        type:edge identifier:lex source:1 target:4 label:advmod";
    return (String::from("NP VERB ADV LEX"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

fn lex_v_np_prep_np() -> (String, usize, Graph) {
    let query_string = "type:node identifier:lex\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:obj\n\
                        type:node identifier:prep\n\
                        type:node identifier:nmod\n\
                        type:edge identifier:expl source:1 target:0 label:expl\n\
                        type:edge identifier:dobj source:1 target:2 label:dobj\n\
                        type:edge identifier:nmod source:1 target:3 label:nmod\n\
                        type:edge identifier:case source:3 target:4 label:case";
    return (String::from("LEX VERB NP PREP NP"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

// uses generic dependency, this should not expand.
fn lex_v_prep_np_np() -> (String, usize, Graph) {
    let query_string = "type:node identifier:lex\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:nmod\n\
                        type:node identifier:prep\n\
                        type:node identifier:dep\n\
                        type:edge identifier:expl source:1 target:0 label:expl\n\
                        type:edge identifier:nmod source:1 target:2 label:nmod\n\
                        type:edge identifier:case source:2 target:3 label:case\n\
                        type:edge identifier:dep source:2 target:4 label:dep";
    return (String::from("LEX VERB PREP NP NP"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

// copula frames
fn copula_np_v_adj() -> (String, usize, Graph) {
    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:adj\n\
                        type:edge identifier:subj source:1 target:0 label:nsubj\n\
                        type:edge identifier:xcomp source:1 target:2 label:xcomp";
    return (String::from("copula:NP VERB ADJ"), 1, graph_parser::parse(&query_string.to_string()).unwrap());
}

<|endoftext|>


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

use rayon::prelude::*;
use rayon;
use anymap;

#[derive(Clone, Default, Debug)]
pub struct Component {
    data: i32,
}

// #[derive(Clone, Default)]
// pub struct VecResource<T> {
//     data: Vec<T>,
// }

#[derive(Clone, Default, Debug)]
pub struct VecResource<T>
    where T: Debug
{
    data: Vec<T>,
}

impl<T> VecResource<T>
    where T: Debug
{
    pub fn new() -> Self {
        VecResource { data: Vec::new() }
    }
}

pub struct Entity((u32, u32));

pub struct World {
    entities: Vec<Entity>,
    components: anymap::AnyMap,
}

impl World {
    pub fn new() -> Self {
        World {
            entities: Vec::new(),
            components: anymap::AnyMap::new(),
        }
    }

    fn register<T>(&mut self)
        where T: Default + 'static
    {
        self.components.insert(T::default());
    }

    fn run<F, T, Eoutput, Einput>(&mut self, inputs: Vec<Einput>, f: F) -> Vec<Eoutput>
        where F: Fn((&T, &Einput)) -> Eoutput + Sync,
              T: Debug + Send + Sync + 'static,
              Eoutput: Send + Sync,
              Einput: Send + Sync
    {
        if let Some(resource) = self.components.get::<VecResource<T>>() {
            let d: &[T] = &resource.data;
            let mut v = Vec::new();
            d.par_iter().zip(&inputs).map(f).collect_into(&mut v);
            v
        } else {
            panic!("Tried to run a system on an unknown component type");
        }
    }

    fn create_entity(&mut self) {
        self.entities.push(Entity((0, 0)));
        let vr: &mut VecResource<u32> = self.components.entry().or_insert_with(VecResource::new);
        vr.data.push(self.entities.len() as u32);
    }
}

#[cfg(test)]
mod tests {

    use super::*;

    #[test]
    fn test_world_thingy() {
        let entity_count = 10;
        let mut w = World::new();
        for i in 0..entity_count {
            w.create_entity();
        }
        println!("Bar");
        let mut inputs = Vec::new();
        inputs.resize(entity_count, 1u32);
        let results = w.run(inputs, |(x1, x2): (&u32, &u32)| {
            println!("Xs are is {:?} {:?}", x1, x1);
            x1 + x2
        });
        println!("Results are {:?}", results);
        assert!(false);
    }
}
<commit_msg>making ecs tests better<commit_after>use std::fmt::Debug;

use rayon::prelude::*;
use rayon;
use anymap;

#[derive(Clone, Default, Debug)]
pub struct Component {
    data: i32,
}

// #[derive(Clone, Default)]
// pub struct VecResource<T> {
//     data: Vec<T>,
// }

#[derive(Clone, Default, Debug)]
pub struct VecResource<T>
    where T: Debug
{
    data: Vec<T>,
}

impl<T> VecResource<T>
    where T: Debug
{
    pub fn new() -> Self {
        VecResource { data: Vec::new() }
    }
}

pub struct Entity((u32, u32));

pub struct World {
    entities: Vec<Entity>,
    components: anymap::AnyMap,
}

impl World {
    pub fn new() -> Self {
        World {
            entities: Vec::new(),
            components: anymap::AnyMap::new(),
        }
    }

    fn register<T>(&mut self)
        where T: Default + 'static
    {
        self.components.insert(T::default());
    }

    fn run<F, T, Eoutput, Einput>(&mut self, inputs: Vec<Einput>, f: F) -> Vec<Eoutput>
        where F: Fn((&T, &Einput)) -> Eoutput + Sync,
              T: Debug + Send + Sync + 'static,
              Eoutput: Send + Sync,
              Einput: Send + Sync
    {
        if let Some(resource) = self.components.get::<VecResource<T>>() {
            let d: &[T] = &resource.data;
            let mut v = Vec::new();
            d.par_iter().zip(&inputs).map(f).collect_into(&mut v);
            v
        } else {
            panic!("Tried to run a system on an unknown component type");
        }
    }

    fn create_entity(&mut self) {
        self.entities.push(Entity((0, 0)));
        let vr: &mut VecResource<u32> = self.components.entry().or_insert_with(VecResource::new);
        vr.data.push(self.entities.len() as u32);
    }
}

#[cfg(test)]
mod tests {

    use super::*;

    #[test]
    fn test_world_thingy() {
        let entity_count = 10;
        let mut w = World::new();
        for i in 0..entity_count {
            w.create_entity();
        }
        println!("Bar");
        let mut inputs = Vec::new();
        inputs.resize(entity_count, 1u32);
        // Event input just being a vector is tricksy because it may not
        // be the same length as the entities vector.  It needs to be a particular
        // per-entity mapping of one kind or another.
        // Making it efficient so we don't need to always re-allocate a new vector
        // for returning new events will be a little wacky too.
        let results = w.run(inputs, |(x1, x2): (&u32, &u32)| {
            println!("Xs are is {:?} {:?}", x1, x2);
            x1 + x2
        });
        println!("Results are {:?}", results);
        let mut desired_results: Vec<u32> = Vec::new();
        desired_results.extend(&[2, 3, 4, 5, 6, 7, 8, 9, 10, 11][..]);
        assert_eq!(results, desired_results);
    }
}
<|endoftext|>


<commit_before>use ::{ NifEnv, NifTerm };
use wrapper::copy_term;
use wrapper::nif_interface::{ self, NIF_ENV, NIF_TERM };
pub use wrapper::nif_interface::ErlNifPid;
use std::mem;
use std::sync::{Arc, Weak};

impl<'a> NifEnv<'a> {
    /// Return the calling process's pid.
    ///
    /// # Panics
    ///
    /// Panics if this environment is process-independent.  (The only way to get such an
    /// environment is to use `OwnedEnv`.  The `NifEnv` that Rustler passes to NIFs when they're
    /// called is always associated with the calling Erlang process.)
    pub fn pid(self) -> ErlNifPid {
        let mut pid: ErlNifPid = unsafe { mem::uninitialized() };
        if unsafe { nif_interface::enif_self(self.as_c_arg(), &mut pid) }.is_null() {
            panic!("environment is process-independent");
        }
        pid
    }
}

// Helper function used by save() and load().
unsafe fn nif_term_into_env<'a>(term: NIF_TERM, src_env: NIF_ENV, dest_env: NIF_ENV) -> NIF_TERM {
    if src_env == dest_env {
        term
    } else {
        copy_term(dest_env, term)
    }
}

/// A process-independent environment.
///
/// An owned environment is a place where Erlang terms can be created outside of a NIF call. Rust
/// code can use an owned environment to build a message and send it to an Erlang process.
///
///     use rustler::env::{OwnedEnv, ErlNifPid};
///     use rustler::NifEncoder;
///
///     fn send_string_to_pid(data: &str, pid: ErlNifPid) {
///         let mut msg_env = OwnedEnv::new();
///         msg_env.send(pid, |env| data.encode(env));
///     }
///
/// There's no way to run Erlang code in an owned environment. It's not a process. It's just a
/// workspace for building terms.
pub struct OwnedEnv {
    env: Arc<NIF_ENV>
}

unsafe impl Send for OwnedEnv {}

impl OwnedEnv {
    /// Allocates a new process-independent environment.
    pub fn new() -> OwnedEnv {
        OwnedEnv {
            env: Arc::new(unsafe { nif_interface::enif_alloc_env() })
        }
    }

    /// Run some code in this environment.
    pub fn run<F, R>(&self, closure: F) -> R
        where F: for<'a> FnOnce(NifEnv<'a>) -> R
    {
        let env_lifetime = ();
        let env = unsafe { NifEnv::new(&env_lifetime, *self.env) };
        closure(env)
    }

    /// Run a closure that produces a term, then send the term to another process.
    ///
    /// After the closure runs and the message is sent, the environment is cleared as though by
    /// calling the `.clear()` method.
    pub fn send<F>(&mut self, recipient: ErlNifPid, closure: F)
        where F: for<'a> FnOnce(NifEnv<'a>) -> NifTerm<'a>
    {
        let env_lifetime = ();
        let c_env = *self.env;
        let env = unsafe { NifEnv::new(&env_lifetime, c_env) };
        let message = closure(env);

        self.env = Arc::new(c_env);
        unsafe {
            nif_interface::enif_send(*self.env, &recipient, *self.env, message.as_c_arg());
        }
    }

    /// Free all terms in this environment and clear it for reuse.
    ///
    /// This invalidates `SavedTerm`s that were saved in this environment;
    /// if you later try to `.load()` one, you'll get a panic.
    ///
    /// Unless you call this method after a call to `run()`, all terms created within the
    /// environment hang around in memory until the `OwnedEnv` is dropped: garbage collection does
    /// not continually happen as needed in a NIF environment.
    pub fn clear(&mut self) {
        let c_env = *self.env;
        self.env = Arc::new(c_env);
        unsafe { nif_interface::enif_clear_env(c_env); }
    }

    /// Save a term for use in a later call to `.run()` or `.send()`.
    ///
    /// For your safety, Rust doesn't let you save `NifTerm` values from one `.run()` call to a
    /// later `.run()` call. If you try, it'll complain about lifetimes.
    ///
    /// `.save()` offers a way to do this. For example, maybe you'd like to copy a term from the
    /// caller into an `OwnedEnv`, then use that term on another thread.
    ///
    ///     # use rustler::{ NifEnv, NifTerm };
    ///     use rustler::env::OwnedEnv;
    ///     use std::thread;
    ///
    ///     fn thread_example<'a>(env: NifEnv<'a>, term: NifTerm<'a>) {
    ///         // Copy `term` into a new OwnedEnv, for use on another thread.
    ///         let mut thread_env = OwnedEnv::new();
    ///         let saved_term = thread_env.save(term);
    ///
    ///         thread::spawn(move || {
    ///             // Now run some code on the thread, using the saved term.
    ///             thread_env.run(|env| {
    ///                 let term = saved_term.load(env);
    ///                 //... do stuff with term ...
    ///             });
    ///         });
    ///     }
    ///
    /// **Note: There is no way to save terms across `OwnedEnv::send()` or `clear()`.**
    /// If you try, the `.load()` call will panic.
    pub fn save<'a>(&self, term: NifTerm<'a>) -> SavedTerm {
        SavedTerm {
            term: unsafe { nif_term_into_env(term.as_c_arg(), term.get_env().as_c_arg(), *self.env) },
            env_generation: Arc::downgrade(&self.env),
        }
    }
}

impl Drop for OwnedEnv {
    fn drop(&mut self) {
        unsafe { nif_interface::enif_free_env(*self.env); }
    }
}

/// A term that was created in an `OwnedEnv` and saved for later use.
///
/// These are created by calling `OwnedEnv::save()`. See that method's documentation for an
/// example.
#[derive(Clone)]
pub struct SavedTerm {
    env_generation: Weak<NIF_ENV>,
    term: NIF_TERM,
}

unsafe impl Send for SavedTerm {}

impl SavedTerm {
    /// Load this saved term into any `NifEnv`.
    ///
    /// If `env` isn't in the same `OwnedEnv` where this term was saved, the term will be copied.
    ///
    /// # Panics
    /// Panics if the `OwnedEnv` where this term was saved has been cleared or dropped.
    pub fn load<'a>(&self, env: NifEnv<'a>) -> NifTerm<'a> {
        // Check that the saved term is still valid.
        match self.env_generation.upgrade() {
            None =>
                panic!("term is from a cleared or dropped OwnedEnv"),
            Some(env_arc) =>
                unsafe { NifTerm::new(env, nif_term_into_env(self.term, *env_arc, env.as_c_arg())) }
        }
    }
}
<commit_msg>Fix race condition in `SavedTerm::load(env)`.<commit_after>use ::{ NifEnv, NifTerm };
use wrapper::copy_term;
use wrapper::nif_interface::{ self, NIF_ENV, NIF_TERM };
pub use wrapper::nif_interface::ErlNifPid;
use std::mem;
use std::sync::{Arc, Weak};

impl<'a> NifEnv<'a> {
    /// Return the calling process's pid.
    ///
    /// # Panics
    ///
    /// Panics if this environment is process-independent.  (The only way to get such an
    /// environment is to use `OwnedEnv`.  The `NifEnv` that Rustler passes to NIFs when they're
    /// called is always associated with the calling Erlang process.)
    pub fn pid(self) -> ErlNifPid {
        let mut pid: ErlNifPid = unsafe { mem::uninitialized() };
        if unsafe { nif_interface::enif_self(self.as_c_arg(), &mut pid) }.is_null() {
            panic!("environment is process-independent");
        }
        pid
    }
}

// Helper function used by save() and load().
unsafe fn nif_term_into_env<'a>(term: NIF_TERM, src_env: NIF_ENV, dest_env: NIF_ENV) -> NIF_TERM {
    if src_env == dest_env {
        term
    } else {
        copy_term(dest_env, term)
    }
}

/// A process-independent environment.
///
/// An owned environment is a place where Erlang terms can be created outside of a NIF call. Rust
/// code can use an owned environment to build a message and send it to an Erlang process.
///
///     use rustler::env::{OwnedEnv, ErlNifPid};
///     use rustler::NifEncoder;
///
///     fn send_string_to_pid(data: &str, pid: ErlNifPid) {
///         let mut msg_env = OwnedEnv::new();
///         msg_env.send(pid, |env| data.encode(env));
///     }
///
/// There's no way to run Erlang code in an owned environment. It's not a process. It's just a
/// workspace for building terms.
pub struct OwnedEnv {
    env: Arc<NIF_ENV>
}

unsafe impl Send for OwnedEnv {}

impl OwnedEnv {
    /// Allocates a new process-independent environment.
    pub fn new() -> OwnedEnv {
        OwnedEnv {
            env: Arc::new(unsafe { nif_interface::enif_alloc_env() })
        }
    }

    /// Run some code in this environment.
    pub fn run<F, R>(&self, closure: F) -> R
        where F: for<'a> FnOnce(NifEnv<'a>) -> R
    {
        let env_lifetime = ();
        let env = unsafe { NifEnv::new(&env_lifetime, *self.env) };
        closure(env)
    }

    /// Run a closure that produces a term, then send the term to another process.
    ///
    /// After the closure runs and the message is sent, the environment is cleared as though by
    /// calling the `.clear()` method.
    pub fn send<F>(&mut self, recipient: ErlNifPid, closure: F)
        where F: for<'a> FnOnce(NifEnv<'a>) -> NifTerm<'a>
    {
        let env_lifetime = ();
        let c_env = *self.env;
        let env = unsafe { NifEnv::new(&env_lifetime, c_env) };
        let message = closure(env);

        self.env = Arc::new(c_env);
        unsafe {
            nif_interface::enif_send(*self.env, &recipient, *self.env, message.as_c_arg());
        }
    }

    /// Free all terms in this environment and clear it for reuse.
    ///
    /// This invalidates `SavedTerm`s that were saved in this environment;
    /// if you later try to `.load()` one, you'll get a panic.
    ///
    /// Unless you call this method after a call to `run()`, all terms created within the
    /// environment hang around in memory until the `OwnedEnv` is dropped: garbage collection does
    /// not continually happen as needed in a NIF environment.
    pub fn clear(&mut self) {
        let c_env = *self.env;
        self.env = Arc::new(c_env);
        unsafe { nif_interface::enif_clear_env(c_env); }
    }

    /// Save a term for use in a later call to `.run()` or `.send()`.
    ///
    /// For your safety, Rust doesn't let you save `NifTerm` values from one `.run()` call to a
    /// later `.run()` call. If you try, it'll complain about lifetimes.
    ///
    /// `.save()` offers a way to do this. For example, maybe you'd like to copy a term from the
    /// caller into an `OwnedEnv`, then use that term on another thread.
    ///
    ///     # use rustler::{ NifEnv, NifTerm };
    ///     use rustler::env::OwnedEnv;
    ///     use std::thread;
    ///
    ///     fn thread_example<'a>(env: NifEnv<'a>, term: NifTerm<'a>) {
    ///         // Copy `term` into a new OwnedEnv, for use on another thread.
    ///         let mut thread_env = OwnedEnv::new();
    ///         let saved_term = thread_env.save(term);
    ///
    ///         thread::spawn(move || {
    ///             // Now run some code on the thread, using the saved term.
    ///             thread_env.run(|env| {
    ///                 let term = saved_term.load(env);
    ///                 //... do stuff with term ...
    ///             });
    ///         });
    ///     }
    ///
    /// **Note: There is no way to save terms across `OwnedEnv::send()` or `clear()`.**
    /// If you try, the `.load()` call will panic.
    pub fn save<'a>(&self, term: NifTerm<'a>) -> SavedTerm {
        SavedTerm {
            term: unsafe { nif_term_into_env(term.as_c_arg(), term.get_env().as_c_arg(), *self.env) },
            env_generation: Arc::downgrade(&self.env),
        }
    }
}

impl Drop for OwnedEnv {
    fn drop(&mut self) {
        unsafe { nif_interface::enif_free_env(*self.env); }
    }
}

/// A term that was created in an `OwnedEnv` and saved for later use.
///
/// These are created by calling `OwnedEnv::save()`. See that method's documentation for an
/// example.
#[derive(Clone)]
pub struct SavedTerm {
    env_generation: Weak<NIF_ENV>,
    term: NIF_TERM,
}

unsafe impl Send for SavedTerm {}

impl SavedTerm {
    /// Load this saved term back into its environment.
    ///
    /// # Panics
    ///
    /// `env` must be the `NifEnv` of a `.run()` or `.send()` call on the
    /// `OwnedEnv` where this term was saved, and the `OwnedEnv` must not have
    /// been cleared or dropped since then. Otherwise this method will panic.
    pub fn load<'a>(&self, env: NifEnv<'a>) -> NifTerm<'a> {
        // Check that the saved term is still valid.
        match self.env_generation.upgrade() {
            None =>
                panic!("term is from a cleared or dropped OwnedEnv"),
            Some(ref env_arc) if **env_arc == env.as_c_arg() =>
                unsafe { NifTerm::new(env, self.term) },
            _ =>
                panic!("can't load SavedTerm into a different environment"),
        }
    }
}
<|endoftext|>


<commit_before>#![allow(non_camel_case_types)]

pub use libc::{c_char, c_double, c_int, c_void, int64_t, uint64_t, malloc, size_t};

// misc types

#[repr(C)]
#[derive(Clone, Copy)]
pub struct C_msgpack_sbuffer {
    pub size: size_t,
    pub data: *const c_char,
    pub alloc: size_t
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct C_KeyValuePair {
    pub key: C_String,
    pub value: C_Object
}

// object container types

#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
#[allow(dead_code)]
pub enum ObjectType {
    BufferType,
    WindowType,
    TabpageType,
    NilType,
    BooleanType,
    IntegerType,
    FloatType,
    StringType,
    ArrayType,
    DictionaryType
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct C_Object {
    pub object_type: ObjectType,
    pub data: C_Array
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct C_Object_Buffer {
    pub object_type: ObjectType,
    pub data: C_Buffer
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct C_Object_Window {
    pub object_type: ObjectType,
    pub data: C_Window
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct C_Object_Tabpage {
    pub object_type: ObjectType,
    pub data: C_Tabpage
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct C_Object_Boolean {
    pub object_type: ObjectType,
    pub data: C_Boolean
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct C_Object_Integer {
    pub object_type: ObjectType,
    pub data: C_Integer
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct C_Object_Float {
    pub object_type: ObjectType,
    pub data: C_Float
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct C_Object_String {
    pub object_type: ObjectType,
    pub data: C_String
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct C_Object_Array {
    pub object_type: ObjectType,
    pub data: C_Array
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct C_Object_Dictionary {
    pub object_type: ObjectType,
    pub data: C_Dictionary
}

// object types

pub type C_Buffer = uint64_t;
pub type C_Window = uint64_t;
pub type C_Tabpage = uint64_t;
pub type C_Boolean = bool;
pub type C_Integer = int64_t;
pub type C_Float = c_double;

#[repr(C)]
#[derive(Clone, Copy)]
pub struct C_String {
    pub data: *const c_char,
    pub size: size_t
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct C_Array {
    pub items: *mut C_Object,
    pub size: size_t,
    pub capacity: size_t
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct C_Dictionary {
    pub items: *mut C_KeyValuePair,
    pub size: size_t,
    pub capacity: size_t
}

// functions

extern "C" {
    pub fn channel_from_fds (read_fd: c_int, write_fd: c_int) -> uint64_t;
    pub fn nvim_main_setup (argc: c_int, argv: *const *const c_char) -> c_int;
    pub fn nvim_main_loop () -> c_int;
    pub fn api_free_array (arr: C_Array);
    pub fn vim_array_add_nil (arr: *mut C_Array);
    pub fn vim_array_add_boolean (val: C_Boolean, arr: *mut C_Array);
    pub fn vim_array_add_integer (val: C_Integer, arr: *mut C_Array);
    pub fn vim_array_add_float (val: C_Float, arr: *mut C_Array);
    pub fn vim_array_add_string (val: C_String, arr: *mut C_Array);
    pub fn vim_array_add_array (val: C_Array, arr: *mut C_Array);
    pub fn vim_array_add_dictionary (val: C_Dictionary, arr: *mut C_Array);
    pub fn vim_msgpack_new () -> *mut C_msgpack_sbuffer;
    pub fn vim_msgpack_free (buf: *mut C_msgpack_sbuffer);
    pub fn vim_msgpack_parse (message: C_String, arr: *mut C_Array);
    pub fn vim_serialize_request (request_id: uint64_t,
                                  method: C_String,
                                  args: C_Array,
                                  buf: *mut C_msgpack_sbuffer);
}
<commit_msg>Fix order of object types<commit_after>#![allow(non_camel_case_types)]

pub use libc::{c_char, c_double, c_int, c_void, int64_t, uint64_t, malloc, size_t};

// misc types

#[repr(C)]
#[derive(Clone, Copy)]
pub struct C_msgpack_sbuffer {
    pub size: size_t,
    pub data: *const c_char,
    pub alloc: size_t
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct C_KeyValuePair {
    pub key: C_String,
    pub value: C_Object
}

// object container types

#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
#[allow(dead_code)]
pub enum ObjectType {
    NilType,
    BooleanType,
    IntegerType,
    FloatType,
    StringType,
    ArrayType,
    DictionaryType,
    BufferType,
    WindowType,
    TabpageType
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct C_Object {
    pub object_type: ObjectType,
    pub data: C_Array
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct C_Object_Buffer {
    pub object_type: ObjectType,
    pub data: C_Buffer
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct C_Object_Window {
    pub object_type: ObjectType,
    pub data: C_Window
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct C_Object_Tabpage {
    pub object_type: ObjectType,
    pub data: C_Tabpage
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct C_Object_Boolean {
    pub object_type: ObjectType,
    pub data: C_Boolean
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct C_Object_Integer {
    pub object_type: ObjectType,
    pub data: C_Integer
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct C_Object_Float {
    pub object_type: ObjectType,
    pub data: C_Float
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct C_Object_String {
    pub object_type: ObjectType,
    pub data: C_String
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct C_Object_Array {
    pub object_type: ObjectType,
    pub data: C_Array
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct C_Object_Dictionary {
    pub object_type: ObjectType,
    pub data: C_Dictionary
}

// object types

pub type C_Buffer = uint64_t;
pub type C_Window = uint64_t;
pub type C_Tabpage = uint64_t;
pub type C_Boolean = bool;
pub type C_Integer = int64_t;
pub type C_Float = c_double;

#[repr(C)]
#[derive(Clone, Copy)]
pub struct C_String {
    pub data: *const c_char,
    pub size: size_t
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct C_Array {
    pub items: *mut C_Object,
    pub size: size_t,
    pub capacity: size_t
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct C_Dictionary {
    pub items: *mut C_KeyValuePair,
    pub size: size_t,
    pub capacity: size_t
}

// functions

extern "C" {
    pub fn channel_from_fds (read_fd: c_int, write_fd: c_int) -> uint64_t;
    pub fn nvim_main_setup (argc: c_int, argv: *const *const c_char) -> c_int;
    pub fn nvim_main_loop () -> c_int;
    pub fn api_free_array (arr: C_Array);
    pub fn vim_array_add_nil (arr: *mut C_Array);
    pub fn vim_array_add_boolean (val: C_Boolean, arr: *mut C_Array);
    pub fn vim_array_add_integer (val: C_Integer, arr: *mut C_Array);
    pub fn vim_array_add_float (val: C_Float, arr: *mut C_Array);
    pub fn vim_array_add_string (val: C_String, arr: *mut C_Array);
    pub fn vim_array_add_array (val: C_Array, arr: *mut C_Array);
    pub fn vim_array_add_dictionary (val: C_Dictionary, arr: *mut C_Array);
    pub fn vim_msgpack_new () -> *mut C_msgpack_sbuffer;
    pub fn vim_msgpack_free (buf: *mut C_msgpack_sbuffer);
    pub fn vim_msgpack_parse (message: C_String, arr: *mut C_Array);
    pub fn vim_serialize_request (request_id: uint64_t,
                                  method: C_String,
                                  args: C_Array,
                                  buf: *mut C_msgpack_sbuffer);
}
<|endoftext|>


<commit_before>use libc::{c_void, c_int, c_long, size_t, c_float, c_double, c_char};

// There's a lot of leakage from libvorbis into libvorbisfile.
// TODO expose both libvorbis and libvorbisfile APIs.

pub static OV_FALSE: c_int = -1;
pub static OV_HOLE: c_int = -3;
pub static OV_EREAD: c_int = -128;
pub static OV_EFAULT: c_int = -129;
pub static OV_EIMPL: c_int = -130;
pub static OV_EINVAL: c_int = -131;
pub static OV_ENOTVORBIS: c_int = -132;
pub static OV_EBADHEADER: c_int = -133;
pub static OV_EVERSION: c_int = -134;
pub static OV_ENOTAUDIO: c_int = -135;
pub static OV_EBADPACKET: c_int = -136;
pub static OV_EBADLINK: c_int = -137;
pub static OV_ENOSEEK: c_int = -138;

#[repr(C)]
pub struct OggVorbis_File {
    pub datasource: *mut c_void,
    seekable: c_int,
    offset: i64,
    end: i64,
    oy: ogg_sync_state,

    links: int,
    offsets: *mut i64,
    dataoffsets: *mut i64,
    serialnos: *mut c_long,
    pcmlengths: *mut i64,
    vi: *mut vorbis_info,
    vc: *mut vorbis_comment,

    pcm_offset: i64,
    ready_state: c_int,
    current_serialno: c_long,
    current_link: c_int,

    bittrack: c_double,
    samptrack: c_double,

    os: ogg_stream_state,
    vd: vorbis_dsp_state,
    vb: vorbis_block,

    callbacks: ov_callbacks,
}

#[repr(C)]
pub struct ov_callbacks {
    pub read: extern "C" fn(ptr: *mut c_void, size: size_t, nmemb: size_t, datasource: *mut c_void) -> size_t,
    pub seek: extern "C" fn(datasource: *mut c_void, offset: i64, whence: c_int) -> c_int,
    pub close: extern "C" fn(datasource: *mut c_void) -> c_int,
    pub tell: extern "C" fn(datasource: *mut c_void) -> c_long,
}

#[repr(C)]
pub struct vorbis_block {
    pcm: *mut *mut c_float,
    opb: oggpack_buffer,

    lW: c_long,
    W: c_long,
    nW: c_long,
    pcmend: c_int,
    mode: c_int,

    eofflag: c_int,
    granulepos: i64,
    sequence: i64,
    vd: *const vorbis_dsp_state,

    localstore: *mut c_void,
    localtop: c_long,
    localalloc: c_long,
    totaluse: c_long,
    read: *mut alloc_chain,

    glue_bits: c_long,
    time_bits: c_long,
    floor_bits: c_long,
    res_bits: c_long,

    internal: *mut c_void,
}

#[repr(C)]
pub struct alloc_chain {
    ptr: *mut c_void,
    next: *mut alloc_chain,
}

#[repr(C)]
pub struct vorbis_comment {
    pub user_comments: *mut *mut c_char,
    pub comment_lengths: *mut c_int,
    pub comments: c_int,
    pub vendor: *mut c_char,
}

#[repr(C)]
pub struct ogg_sync_state {
    data: *mut c_char,
    storage: c_int,
    fill: c_int,
    returned: c_int,

    unsynced: c_int,
    headerbytes: c_int,
    bodybytes: c_int,
}

#[repr(C)]
pub struct ogg_stream_state {
    body_data: *mut c_char,
    body_storage: c_long,
    body_fill: c_long,
    body_returned: c_long,

    lacing_vals: *mut c_int,
    granule_vals: *mut i64,

    lacing_storage: c_long,
    lacing_fill: c_long,
    lacing_packet: c_long,
    lacing_returned: c_long,

    header: [c_char, ..282],
    header_fill: c_int,

    e_o_s: c_int,
    b_o_s: c_int,

    serialno: c_long,
    pageno: c_long,
    packetno: i64,
    granulepos: i64,
}

#[repr(C)]
pub struct oggpack_buffer {
    endbyte: c_long,
    endbit: c_int,

    buffer: *mut c_char,
    ptr: *mut c_char,
    storage: c_long,
}

#[repr(C)]
pub struct vorbis_info {
    pub version: c_int,
    pub channels: c_int,
    pub rate: c_long,

    pub bitrate_upper: c_long,
    pub bitrate_nominal: c_long,
    pub bitrate_lower: c_long,
    pub bitrate_window: c_long,

    codec_setup: *mut c_void,
}

#[repr(C)]
pub struct vorbis_dsp_state {
    analysisp: c_int,
    vi: *mut vorbis_info,

    pcm: *mut *mut c_float,
    pcmret: *mut *mut c_float,
    pcm_storage: c_int,
    pcm_currenet: c_int,
    pcm_returned: c_int,

    preextrapolate: c_int,
    eofflag: c_int,

    lW: c_long,
    W: c_long,
    nW: c_long,
    centerW: c_long,

    granulepos: i64,
    sequence: i64,

    glue_bits: i64,
    time_bits: i64,
    floor_bits: i64,
    res_bits: i64,

    backend_state: *mut c_void,
}

#[link(name="vorbisfile")]
extern "C" {
    pub fn ov_open_callbacks(datasource: *mut c_void, vf: *mut OggVorbis_File,
                         initial: *mut c_char, ibytes: c_long,
                         callbacks: ov_callbacks) -> c_int;

    pub fn ov_read_float(vf: *mut OggVorbis_File, pcm_channels: *mut *mut *mut c_float,
                         samples: c_int, bitstream: *mut c_int) -> c_long;

    pub fn ov_info(vf: *mut OggVorbis_File, link: c_int) -> *const vorbis_info;

    pub fn ov_clear(vf: *mut OggVorbis_File) -> c_int;

    pub fn ov_comment(vf: *mut OggVorbis_File, link: c_int) -> *const vorbis_comment;
}

<commit_msg>ffi: static -> const, per RFC 246.<commit_after>use libc::{c_void, c_int, c_long, size_t, c_float, c_double, c_char};

// There's a lot of leakage from libvorbis into libvorbisfile.
// TODO expose both libvorbis and libvorbisfile APIs.

pub const OV_FALSE: c_int = -1;
pub const OV_HOLE: c_int = -3;
pub const OV_EREAD: c_int = -128;
pub const OV_EFAULT: c_int = -129;
pub const OV_EIMPL: c_int = -130;
pub const OV_EINVAL: c_int = -131;
pub const OV_ENOTVORBIS: c_int = -132;
pub const OV_EBADHEADER: c_int = -133;
pub const OV_EVERSION: c_int = -134;
pub const OV_ENOTAUDIO: c_int = -135;
pub const OV_EBADPACKET: c_int = -136;
pub const OV_EBADLINK: c_int = -137;
pub const OV_ENOSEEK: c_int = -138;

#[repr(C)]
pub struct OggVorbis_File {
    pub datasource: *mut c_void,
    seekable: c_int,
    offset: i64,
    end: i64,
    oy: ogg_sync_state,

    links: int,
    offsets: *mut i64,
    dataoffsets: *mut i64,
    serialnos: *mut c_long,
    pcmlengths: *mut i64,
    vi: *mut vorbis_info,
    vc: *mut vorbis_comment,

    pcm_offset: i64,
    ready_state: c_int,
    current_serialno: c_long,
    current_link: c_int,

    bittrack: c_double,
    samptrack: c_double,

    os: ogg_stream_state,
    vd: vorbis_dsp_state,
    vb: vorbis_block,

    callbacks: ov_callbacks,
}

#[repr(C)]
pub struct ov_callbacks {
    pub read: extern "C" fn(ptr: *mut c_void, size: size_t, nmemb: size_t, datasource: *mut c_void) -> size_t,
    pub seek: extern "C" fn(datasource: *mut c_void, offset: i64, whence: c_int) -> c_int,
    pub close: extern "C" fn(datasource: *mut c_void) -> c_int,
    pub tell: extern "C" fn(datasource: *mut c_void) -> c_long,
}

#[repr(C)]
pub struct vorbis_block {
    pcm: *mut *mut c_float,
    opb: oggpack_buffer,

    lW: c_long,
    W: c_long,
    nW: c_long,
    pcmend: c_int,
    mode: c_int,

    eofflag: c_int,
    granulepos: i64,
    sequence: i64,
    vd: *const vorbis_dsp_state,

    localstore: *mut c_void,
    localtop: c_long,
    localalloc: c_long,
    totaluse: c_long,
    read: *mut alloc_chain,

    glue_bits: c_long,
    time_bits: c_long,
    floor_bits: c_long,
    res_bits: c_long,

    internal: *mut c_void,
}

#[repr(C)]
pub struct alloc_chain {
    ptr: *mut c_void,
    next: *mut alloc_chain,
}

#[repr(C)]
pub struct vorbis_comment {
    pub user_comments: *mut *mut c_char,
    pub comment_lengths: *mut c_int,
    pub comments: c_int,
    pub vendor: *mut c_char,
}

#[repr(C)]
pub struct ogg_sync_state {
    data: *mut c_char,
    storage: c_int,
    fill: c_int,
    returned: c_int,

    unsynced: c_int,
    headerbytes: c_int,
    bodybytes: c_int,
}

#[repr(C)]
pub struct ogg_stream_state {
    body_data: *mut c_char,
    body_storage: c_long,
    body_fill: c_long,
    body_returned: c_long,

    lacing_vals: *mut c_int,
    granule_vals: *mut i64,

    lacing_storage: c_long,
    lacing_fill: c_long,
    lacing_packet: c_long,
    lacing_returned: c_long,

    header: [c_char, ..282],
    header_fill: c_int,

    e_o_s: c_int,
    b_o_s: c_int,

    serialno: c_long,
    pageno: c_long,
    packetno: i64,
    granulepos: i64,
}

#[repr(C)]
pub struct oggpack_buffer {
    endbyte: c_long,
    endbit: c_int,

    buffer: *mut c_char,
    ptr: *mut c_char,
    storage: c_long,
}

#[repr(C)]
pub struct vorbis_info {
    pub version: c_int,
    pub channels: c_int,
    pub rate: c_long,

    pub bitrate_upper: c_long,
    pub bitrate_nominal: c_long,
    pub bitrate_lower: c_long,
    pub bitrate_window: c_long,

    codec_setup: *mut c_void,
}

#[repr(C)]
pub struct vorbis_dsp_state {
    analysisp: c_int,
    vi: *mut vorbis_info,

    pcm: *mut *mut c_float,
    pcmret: *mut *mut c_float,
    pcm_storage: c_int,
    pcm_currenet: c_int,
    pcm_returned: c_int,

    preextrapolate: c_int,
    eofflag: c_int,

    lW: c_long,
    W: c_long,
    nW: c_long,
    centerW: c_long,

    granulepos: i64,
    sequence: i64,

    glue_bits: i64,
    time_bits: i64,
    floor_bits: i64,
    res_bits: i64,

    backend_state: *mut c_void,
}

#[link(name="vorbisfile")]
extern "C" {
    pub fn ov_open_callbacks(datasource: *mut c_void, vf: *mut OggVorbis_File,
                         initial: *mut c_char, ibytes: c_long,
                         callbacks: ov_callbacks) -> c_int;

    pub fn ov_read_float(vf: *mut OggVorbis_File, pcm_channels: *mut *mut *mut c_float,
                         samples: c_int, bitstream: *mut c_int) -> c_long;

    pub fn ov_info(vf: *mut OggVorbis_File, link: c_int) -> *const vorbis_info;

    pub fn ov_clear(vf: *mut OggVorbis_File) -> c_int;

    pub fn ov_comment(vf: *mut OggVorbis_File, link: c_int) -> *const vorbis_comment;
}

<|endoftext|>


<commit_before>use core::mem::size_of;
use core::prelude::*;

use io;
use vga;

extern {
    fn idt_load(pointer: *const IDT);
    static isr_handlers: [u32, ..IDT_SIZE];
}

const IDT_SIZE: uint = 256;

const IDT_ALWAYS14: u8 = 14;
const IDT_PRESENT: u8 = 1 << 7;
const IDT_: u8 = IDT_PRESENT | IDT_ALWAYS14;

const INTERRUPT_GATE: u8 = 0xE;

type IDTTable = [IDTDescriptor, ..IDT_SIZE];
type ISRHandler = fn(registers: Registers);

static mut ISR_HANDLERS: [ISRHandler, ..IDT_SIZE] = [default_handler, ..IDT_SIZE];

static mut IDT_TABLE: IDTTable = [
    IDTDescriptor {
        base_lo: 0,
        sel: 0,
        always0: 0,
        flags: 0,
        base_hi: 0,
    }, ..IDT_SIZE
];

#[repr(packed)]
struct IDTDescriptor {
    base_lo: u16,  // the lower 16 bits of the address to jump to when this interrupt fires
    sel: u16,  // kernel segment selector
    always0: u8,  // this must always be zero
    flags: u8,  // more flags, see documentation
    base_hi: u16,  // the upper 16 bits of the address to jump to
}

impl IDTDescriptor {

    pub fn new(base: u32, sel: u16, flags: u8) -> IDTDescriptor {
        IDTDescriptor {
            base_lo: (base & 0xFFFF) as u16,
            base_hi: (base >> 16 & 0xFFFF) as u16,
            sel: sel,
            always0: 0u8,
            flags: flags,
        }
    }
}

#[repr(packed)]
struct IDT {
    limit: u16,
    base: *const IDTTable,
}

impl IDT {

    pub fn new() -> IDT {

        unsafe {

            for i in range(0, isr_handlers.len()) {
                IDT_TABLE[i] = IDTDescriptor::new(isr_handlers[i], 0x08, 0x8E);
            }

            IDT {
                limit: (size_of::<IDTDescriptor>() * IDT_TABLE.len() - 1) as u16,
                base: &IDT_TABLE as *const IDTTable,
            }
        }
    }

    pub fn load(&self) {
        unsafe {
            idt_load(self as *const IDT);
        }
    }
}

pub fn init() {
    IDT::new().load();
}

fn register_handler(no: uint, func: ISRHandler) {
    unsafe {
        IDT_TABLE[no] = IDTDescriptor::new(isr_handlers[no], 0x08, 0x8E);
        ISR_HANDLERS[no] = func;
    }
}

fn default_handler(registers: Registers) {
    let mut vga = vga::VGA::new();
    vga.clear();
    vga.puts("Unhandled interrupt!");
}

pub fn handle(registers: Registers) {
    let isr = registers.interrupt;

    if isr > 255 {
        return
    }

    if 31 < isr && isr < 48 {  // IRQ
        let irq = isr - 32;

        if irq < 8 {
            io::port::write(0x20, 0x20);  // master
        }

        io::port::write(0xA0, 0x20);  // slave
    }

    unsafe {
        ISR_HANDLERS[isr as uint](registers);
    }
}

#[repr(C)]
pub struct Registers {
    edi: u32,
    esi: u32,
    ebp: u32,
    esp: u32,
    ebx: u32,
    edx: u32,
    ecx: u32,
    eax: u32,
    gs: u32,
    fs: u32,
    es: u32,
    ds: u32,
    interrupt: u32,
    error: u32,
    eip: u32,
    cs: u32,
    eflags: u32,
    useresp: u32,
    ss: u32
}
<commit_msg>Fix Registers structure<commit_after>use core::mem::size_of;
use core::prelude::*;

use io;
use vga;

extern {
    fn idt_load(pointer: *const IDT);
    static isr_handlers: [u32, ..IDT_SIZE];
}

const IDT_SIZE: uint = 256;

const IDT_ALWAYS14: u8 = 14;
const IDT_PRESENT: u8 = 1 << 7;
const IDT_: u8 = IDT_PRESENT | IDT_ALWAYS14;

const INTERRUPT_GATE: u8 = 0xE;

type IDTTable = [IDTDescriptor, ..IDT_SIZE];
type ISRHandler = fn(registers: Registers);

static mut ISR_HANDLERS: [ISRHandler, ..IDT_SIZE] = [default_handler, ..IDT_SIZE];

static mut IDT_TABLE: IDTTable = [
    IDTDescriptor {
        base_lo: 0,
        sel: 0,
        always0: 0,
        flags: 0,
        base_hi: 0,
    }, ..IDT_SIZE
];

#[repr(packed)]
struct IDTDescriptor {
    base_lo: u16,  // the lower 16 bits of the address to jump to when this interrupt fires
    sel: u16,  // kernel segment selector
    always0: u8,  // this must always be zero
    flags: u8,  // more flags, see documentation
    base_hi: u16,  // the upper 16 bits of the address to jump to
}

impl IDTDescriptor {

    pub fn new(base: u32, sel: u16, flags: u8) -> IDTDescriptor {
        IDTDescriptor {
            base_lo: (base & 0xFFFF) as u16,
            base_hi: (base >> 16 & 0xFFFF) as u16,
            sel: sel,
            always0: 0u8,
            flags: flags,
        }
    }
}

#[repr(packed)]
struct IDT {
    limit: u16,
    base: *const IDTTable,
}

impl IDT {

    pub fn new() -> IDT {

        unsafe {

            for i in range(0, isr_handlers.len()) {
                IDT_TABLE[i] = IDTDescriptor::new(isr_handlers[i], 0x08, 0x8E);
            }

            IDT {
                limit: (size_of::<IDTDescriptor>() * IDT_TABLE.len() - 1) as u16,
                base: &IDT_TABLE as *const IDTTable,
            }
        }
    }

    pub fn load(&self) {
        unsafe {
            idt_load(self as *const IDT);
        }
    }
}

pub fn init() {
    IDT::new().load();
}

fn register_handler(no: uint, func: ISRHandler) {
    unsafe {
        IDT_TABLE[no] = IDTDescriptor::new(isr_handlers[no], 0x08, 0x8E);
        ISR_HANDLERS[no] = func;
    }
}

fn default_handler(registers: Registers) {
    let mut vga = vga::VGA::new();
    vga.clear();
    vga.puts("Unhandled interrupt!");
}

pub fn handle(registers: Registers) {
    let isr = registers.interrupt;

    if isr > 255 {
        return
    }

    if 31 < isr && isr < 48 {  // IRQ
        let irq = isr - 32;

        if irq < 8 {
            io::port::write(0x20, 0x20);  // master
        }

        io::port::write(0xA0, 0x20);  // slave
    }

    unsafe {
        ISR_HANDLERS[isr as uint](registers);
    }
}

#[repr(C)]
pub struct Registers {
    ds: u32,
    edi: u32,
    esi: u32,
    ebp: u32,
    esp: u32,
    ebx: u32,
    edx: u32,
    ecx: u32,
    eax: u32,
    pub interrupt: u32,
    error: u32,
    eip: u32,
    cs: u32,
    eflags: u32,
    useresp: u32,
    ss: u32,
}
<|endoftext|>


<commit_before>#![feature(slicing_syntax, unsafe_destructor)]
#![feature(old_orphan_check)]

extern crate libc;
extern crate time;
extern crate "rustc-serialize" as rustc_serialize;

pub mod client;
mod utils;
pub mod error;
pub mod queue;
pub mod status;
pub mod stats;
pub mod outputs;
pub mod songs;
pub mod playlists;
//pub mod idle;

<commit_msg>allow unstable<commit_after>#![feature(slicing_syntax, unsafe_destructor)]
#![feature(old_orphan_check)]
#![allow(unstable)]

extern crate libc;
extern crate time;
extern crate "rustc-serialize" as rustc_serialize;

pub mod client;
mod utils;
pub mod error;
pub mod queue;
pub mod status;
pub mod stats;
pub mod outputs;
pub mod songs;
pub mod playlists;
//pub mod idle;

<|endoftext|>


<commit_before>#![feature(optin_builtin_traits)]
#![feature(unsafe_destructor)]
#![feature(core)]
#![feature(std_misc)]
extern crate time;

use std::cell::UnsafeCell;
pub use std::sync::{
    TryLockError,
    LockResult,
    TryLockResult,
    PoisonError,
};
use std::thread;
use std::ops::{Deref, DerefMut};

use std::sync::atomic::{Ordering, AtomicUsize};

// Panic guards, taken from std::sync

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

struct Flag { failed: UnsafeCell<bool> }
unsafe impl Send for Flag {}
unsafe impl Sync for Flag {}

impl Flag {
    #[inline]
    fn new() -> Flag {
        Flag { failed : UnsafeCell { value : false }}
    }

    #[inline]
    fn borrow(&self) -> LockResult<Guard> {
        let ret = Guard { panicking: thread::panicking() };
        if unsafe { *self.failed.get() } {
            Err(PoisonError::new(ret))
        } else {
            Ok(ret)
        }
    }

    #[inline]
    fn done(&self, guard: &Guard) {
        if !guard.panicking && thread::panicking() {
            unsafe { *self.failed.get() = true; }
        }
    }

    #[inline]
    fn get(&self) -> bool {
        unsafe { *self.failed.get() }
    }
}

struct Guard {
    panicking: bool,
}

fn map_result<T, U, F>(result: LockResult<T>, f: F)
                           -> LockResult<U>
                           where F: FnOnce(T) -> U {
    match result {
        Ok(t) => Ok(f(t)),
        Err(err) => Err(PoisonError::new(f(err.into_inner())))
    }
}

// SpinLock implementation
//
const SHARED : usize = 0x80000000;
const EXCLWAIT : usize = 0x00100000;
const MAXWAIT : u64 = 2_000_000_000;
const SPIN_COUNT : u32 = 0xFF;

pub struct SpinLock<T> {
    count : AtomicUsize,
    data : UnsafeCell<T>,
    poison : Flag,
}

unsafe impl<T: Send + Sync> Send for SpinLock<T> {}
unsafe impl<T: Send + Sync> Sync for SpinLock<T> {}

impl<T : Send + Sync> SpinLock<T> {
    pub fn new(data : T) -> SpinLock<T> {
        SpinLock {
            count : AtomicUsize::new(0),
            data : UnsafeCell::new(data),
            poison : Flag::new(),
        }
    }

    #[inline]
    pub fn write(&self) -> LockResult<SpinLockWriteGuard<T>> {
        if self.count.fetch_add(1, Ordering::AcqRel) != 0 {
            return self.write_contested()
        }
        SpinLockWriteGuard::new(self, &self.data)
    }

    pub fn write_contested(&self) -> LockResult<SpinLockWriteGuard<T>> {
        let mut base_time : u64 = 0;
        let mut time : u64;
        let mut i = 0u32;

        self.count.fetch_add(EXCLWAIT - 1, Ordering::AcqRel);
        self.count.fetch_and(! SHARED, Ordering::AcqRel);
        loop {
            let count = self.count.load(Ordering::Acquire);
            if count & (EXCLWAIT - 1) == 0 &&
                self.count.compare_and_swap(count, (count & !EXCLWAIT) | 1, Ordering::AcqRel) == count {
                    break;
                }

            if i >= SPIN_COUNT  {
                time = time::precise_time_ns();
                if base_time == 0 {
                    base_time = time;
                } else if time - base_time > MAXWAIT {
                    // FIXME : not 100% sure about what happens if there are multiple EXCL requests pending
                    self.count.fetch_and(! EXCLWAIT, Ordering::AcqRel);
                    panic!("Spinning on a spin lock for too long")
                }
                thread::yield_now();
            } else {
                i += 1;
            }
        }
        SpinLockWriteGuard::new(self, &self.data)
    }

    #[inline]
    pub fn read(&self) -> LockResult<SpinLockReadGuard<T>> {
        if self.count.compare_and_swap(0, SHARED | 1, Ordering::AcqRel) == 0 {
            return self.read_contested()
        }
        SpinLockReadGuard::new(self, &self.data)
    }

    pub fn read_contested(&self) -> LockResult<SpinLockReadGuard<T>> {
        let mut i = 0u32;
        let mut base_time : u64 = 0;
        let mut time : u64;
        loop {
            let count = self.count.load(Ordering::Acquire);
            if count == 0 {
                if self.count.compare_and_swap(0, SHARED | 1, Ordering::AcqRel) == 0 {
                    break
                }
            } else if count & SHARED == SHARED {
                if self.count.compare_and_swap(count, count + 1, Ordering::AcqRel) == count {
                    break
                }
            }
            if i >= SPIN_COUNT  {
                time = time::precise_time_ns();
                if base_time == 0 {
                    base_time = time;
                } else if time - base_time > MAXWAIT {
                    panic!("Spinning on a spin lock for too long")
                }
                thread::yield_now();
            } else {
                i+=1;
            }
        }
        SpinLockReadGuard::new(self, &self.data)
    }

    #[inline]
    pub fn try_read(&self) -> TryLockResult<SpinLockReadGuard<T>> {
        if self.count.compare_and_swap(0, 1 | SHARED, Ordering::AcqRel) == 0 {
            return Ok(try!(SpinLockReadGuard::new(self, &self.data)))
        } else {
            let count = self.count.load(Ordering::Acquire);
            if count & SHARED == SHARED &&
                self.count.compare_and_swap(count, count + 1, Ordering::AcqRel) == count {
                return Ok(try!(SpinLockReadGuard::new(self, &self.data)))
            }
            return Err(TryLockError::WouldBlock)
        }
    }

    pub fn try_write(&self) -> TryLockResult<SpinLockWriteGuard<T>> {
        if self.count.compare_and_swap(0, 1, Ordering::AcqRel) == 0 {
            Ok(try!(SpinLockWriteGuard::new(self, &self.data)))
        } else {
            Err(TryLockError::WouldBlock)
        }
    }

    #[inline]
    pub fn is_poisonned(&self) -> bool {
        self.poison.get()
    }

}

impl<T> SpinLock<T> {

    #[inline]
    fn read_unlock(&self) {
        self.count.fetch_sub(1, Ordering::AcqRel);

        while self.count.load(Ordering::Acquire) == SHARED {
            if self.count.compare_and_swap(SHARED, 0, Ordering::AcqRel) == SHARED {
                break
            }
        }
    }

    fn write_unlock(&self) {
        self.count.fetch_sub(1, Ordering::AcqRel);
    }
}

#[must_use]
pub struct SpinLockReadGuard<'a, T : 'a> {
    lock : &'a SpinLock<T>,
    data : &'a UnsafeCell<T>,
}

impl<'a, T> !Send for SpinLockReadGuard<'a, T> {}

impl<'a, T> SpinLockReadGuard<'a, T> {
    fn new(lock : &'a SpinLock<T>, data : &'a UnsafeCell<T>) -> LockResult<SpinLockReadGuard<'a, T>> {
        map_result(lock.poison.borrow(), |_| {
            SpinLockReadGuard {
                lock : lock,
                data : data,
            }
        })
    }
}

impl<'a, T> Deref for SpinLockReadGuard<'a, T> {
    type Target = T;

    fn deref(&self) -> &T { unsafe { &*self.data.get() } }
}

#[unsafe_destructor]
impl<'a, T> Drop for SpinLockReadGuard<'a, T> {
    fn drop(&mut self) {
        self.lock.read_unlock();
    }
}

#[must_use]
pub struct SpinLockWriteGuard<'a, T : 'a> {
    lock : &'a SpinLock<T>,
    data : &'a UnsafeCell<T>,
    poison :  Guard,
}

impl<'a, T> !Send for SpinLockWriteGuard<'a, T> {}

impl<'a, T> SpinLockWriteGuard<'a, T> {
    fn new(lock : &'a SpinLock<T>, data : &'a UnsafeCell<T>) -> LockResult<SpinLockWriteGuard<'a, T>> {
        map_result(lock.poison.borrow(), |guard| {
            SpinLockWriteGuard {
                lock : lock,
                data : data,
                poison : guard,
            }
        })
    }
}

impl<'a, T> Deref for SpinLockWriteGuard<'a, T> {
    type Target = T;

    fn deref(&self) -> &T { unsafe { &*self.data.get() } }
}

impl<'a, T> DerefMut for SpinLockWriteGuard<'a, T> {
    fn deref_mut(&mut self) -> &mut T { unsafe { &mut *self.data.get() } }
}

#[unsafe_destructor]
impl<'a, T> Drop for SpinLockWriteGuard<'a, T> {
    fn drop(&mut self) {
        self.lock.poison.done(&self.poison);
        self.lock.write_unlock();
    }
}

#[cfg(test)]
mod tests;
<commit_msg>Relax memory barriers constraints a bit<commit_after>#![feature(optin_builtin_traits)]
#![feature(unsafe_destructor)]
#![feature(core)]
#![feature(std_misc)]
#![feature(test)]
extern crate time;

use std::cell::UnsafeCell;
pub use std::sync::{
    TryLockError,
    LockResult,
    TryLockResult,
    PoisonError,
};
use std::thread;
use std::ops::{Deref, DerefMut};

use std::sync::atomic::{Ordering, AtomicUsize};

// Panic guards, taken from std::sync

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

struct Flag { failed: UnsafeCell<bool> }
unsafe impl Send for Flag {}
unsafe impl Sync for Flag {}

impl Flag {
    #[inline]
    fn new() -> Flag {
        Flag { failed : UnsafeCell { value : false }}
    }

    #[inline]
    fn borrow(&self) -> LockResult<Guard> {
        let ret = Guard { panicking: thread::panicking() };
        if unsafe { *self.failed.get() } {
            Err(PoisonError::new(ret))
        } else {
            Ok(ret)
        }
    }

    #[inline]
    fn done(&self, guard: &Guard) {
        if !guard.panicking && thread::panicking() {
            unsafe { *self.failed.get() = true; }
        }
    }

    #[inline]
    fn get(&self) -> bool {
        unsafe { *self.failed.get() }
    }
}

struct Guard {
    panicking: bool,
}

fn map_result<T, U, F>(result: LockResult<T>, f: F)
                           -> LockResult<U>
                           where F: FnOnce(T) -> U {
    match result {
        Ok(t) => Ok(f(t)),
        Err(err) => Err(PoisonError::new(f(err.into_inner())))
    }
}

// SpinLock implementation
//
const SHARED : usize = 0x80000000;
const EXCLWAIT : usize = 0x00100000;
const MAXWAIT : u64 = 2_000_000_000;
const SPIN_COUNT : u32 = 0xFF;

pub struct SpinLock<T> {
    count : AtomicUsize,
    data : UnsafeCell<T>,
    poison : Flag,
}

unsafe impl<T: Send + Sync> Send for SpinLock<T> {}
unsafe impl<T: Send + Sync> Sync for SpinLock<T> {}

impl<T : Send + Sync> SpinLock<T> {
    pub fn new(data : T) -> SpinLock<T> {
        SpinLock {
            count : AtomicUsize::new(0),
            data : UnsafeCell::new(data),
            poison : Flag::new(),
        }
    }

    #[inline]
    pub fn write(&self) -> LockResult<SpinLockWriteGuard<T>> {
        if self.count.fetch_add(1, Ordering::Acquire) != 0 {
            return self.write_contested()
        }
        SpinLockWriteGuard::new(self, &self.data)
    }

    pub fn write_contested(&self) -> LockResult<SpinLockWriteGuard<T>> {
        let mut base_time : u64 = 0;
        let mut time : u64;
        let mut i = 0u32;

        self.count.fetch_add(EXCLWAIT - 1, Ordering::Relaxed);
        self.count.fetch_and(! SHARED, Ordering::Relaxed);
        loop {
            // Use relaxed ordering to avoid trashing the cache coherency handling for free
            let count = self.count.load(Ordering::Relaxed);
            if count & (EXCLWAIT - 1) == 0 &&
                self.count.compare_and_swap(count, count - EXCLWAIT + 1, Ordering::Acquire) == count {
                    break;
                }

            if i >= SPIN_COUNT  {
                time = time::precise_time_ns();
                if base_time == 0 {
                    base_time = time;
                } else if time - base_time > MAXWAIT {
                    // XXX we converted the SHARED locks to exclusive ones, i'm not sure how bad
                    // actually is
                    self.count.fetch_sub(EXCLWAIT, Ordering::Relaxed);
                    panic!("Spinning on a spin lock for too long")
                }
                thread::yield_now();
            } else {
                i += 1;
            }
        }
        SpinLockWriteGuard::new(self, &self.data)
    }

    #[inline]
    pub fn read(&self) -> LockResult<SpinLockReadGuard<T>> {
        if self.count.compare_and_swap(0, SHARED | 1, Ordering::Acquire) != 0 {
            return self.read_contested()
        }
        SpinLockReadGuard::new(self, &self.data)
    }

    pub fn read_contested(&self) -> LockResult<SpinLockReadGuard<T>> {
        let mut i = 0u32;
        let mut base_time : u64 = 0;
        let mut time : u64;
        loop {
            let count = self.count.load(Ordering::Relaxed);
            if count == 0 {
                if self.count.compare_and_swap(0, SHARED | 1, Ordering::Acquire) == 0 {
                    break
                }
            } else if count & SHARED == SHARED {
                if self.count.compare_and_swap(count, count + 1, Ordering::Acquire) == count {
                    break
                }
            }
            if i >= SPIN_COUNT  {
                time = time::precise_time_ns();
                if base_time == 0 {
                    base_time = time;
                } else if time - base_time > MAXWAIT {
                    panic!("Spinning on a spin lock for too long")
                }
                thread::yield_now();
            } else {
                i+=1;
            }
        }
        SpinLockReadGuard::new(self, &self.data)
    }

    #[inline]
    pub fn try_read(&self) -> TryLockResult<SpinLockReadGuard<T>> {
        if self.count.compare_and_swap(0, 1 | SHARED, Ordering::Acquire) == 0 {
            return Ok(try!(SpinLockReadGuard::new(self, &self.data)))
        } else {
            let count = self.count.load(Ordering::Relaxed);
            if count & SHARED == SHARED &&
                self.count.compare_and_swap(count, count + 1, Ordering::Acquire) == count {
                return Ok(try!(SpinLockReadGuard::new(self, &self.data)))
            }
            return Err(TryLockError::WouldBlock)
        }
    }

    pub fn try_write(&self) -> TryLockResult<SpinLockWriteGuard<T>> {
        if self.count.compare_and_swap(0, 1, Ordering::Acquire) == 0 {
            Ok(try!(SpinLockWriteGuard::new(self, &self.data)))
        } else {
            Err(TryLockError::WouldBlock)
        }
    }

    #[inline]
    pub fn is_poisonned(&self) -> bool {
        self.poison.get()
    }

}

impl<T> SpinLock<T> {

    #[inline]
    fn read_unlock(&self) {
        self.count.fetch_sub(1, Ordering::Release);

        while self.count.load(Ordering::Relaxed) == SHARED {
            if self.count.compare_and_swap(SHARED, 0, Ordering::Relaxed) == SHARED {
                break
            }
        }
    }

    fn write_unlock(&self) {
        self.count.fetch_sub(1, Ordering::Release);
    }
}

#[must_use]
pub struct SpinLockReadGuard<'a, T : 'a> {
    lock : &'a SpinLock<T>,
    data : &'a UnsafeCell<T>,
}

impl<'a, T> !Send for SpinLockReadGuard<'a, T> {}

impl<'a, T> SpinLockReadGuard<'a, T> {
    fn new(lock : &'a SpinLock<T>, data : &'a UnsafeCell<T>) -> LockResult<SpinLockReadGuard<'a, T>> {
        map_result(lock.poison.borrow(), |_| {
            SpinLockReadGuard {
                lock : lock,
                data : data,
            }
        })
    }
}

impl<'a, T> Deref for SpinLockReadGuard<'a, T> {
    type Target = T;

    fn deref(&self) -> &T { unsafe { &*self.data.get() } }
}

#[unsafe_destructor]
impl<'a, T> Drop for SpinLockReadGuard<'a, T> {
    fn drop(&mut self) {
        self.lock.read_unlock();
    }
}

#[must_use]
pub struct SpinLockWriteGuard<'a, T : 'a> {
    lock : &'a SpinLock<T>,
    data : &'a UnsafeCell<T>,
    poison :  Guard,
}

impl<'a, T> !Send for SpinLockWriteGuard<'a, T> {}

impl<'a, T> SpinLockWriteGuard<'a, T> {
    fn new(lock : &'a SpinLock<T>, data : &'a UnsafeCell<T>) -> LockResult<SpinLockWriteGuard<'a, T>> {
        map_result(lock.poison.borrow(), |guard| {
            SpinLockWriteGuard {
                lock : lock,
                data : data,
                poison : guard,
            }
        })
    }
}

impl<'a, T> Deref for SpinLockWriteGuard<'a, T> {
    type Target = T;

    fn deref(&self) -> &T { unsafe { &*self.data.get() } }
}

impl<'a, T> DerefMut for SpinLockWriteGuard<'a, T> {
    fn deref_mut(&mut self) -> &mut T { unsafe { &mut *self.data.get() } }
}

#[unsafe_destructor]
impl<'a, T> Drop for SpinLockWriteGuard<'a, T> {
    fn drop(&mut self) {
        self.lock.poison.done(&self.poison);
        self.lock.write_unlock();
    }
}

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


<commit_before>//! Derive Getters
//! ===
//!
//! Macro for autogenerating getters. Can only be used on named structs. Will generate
//! getters that will reside in a new trait so as not to pollute the struct namespace.
//!
//! # Usage
//! Add to your project Cargo.toml;
//! ```toml
//! [dependencies]
//! derive-getters = "0.0.4"
//! ```
//!
//! In lib.rs or main.rs;
//! ```
//! #[macro_use]
//! extern crate derive_getters;
//! #
//! # fn main() { }
//! ```
//!
//! # Example
//! ```
//! #[macro_use]
//! extern crate derive_getters;
//!
//! #[derive(Getters)]
//! struct Number {
//!    num: u64,
//! }
//!
//! fn main() {
//!    let number = Number { num: 655 };
//!    assert!(number.get_num() == &655);
//! }
//! ```
//!
//! A new trait, `NumberGetters` will have been generated and implemented for the `Numbers`
//! struct which contains the `get_num` method. To use the trait in other modules one must
//! define a `use` for it from the same location the struct resides.

#[macro_use] extern crate quote;
extern crate proc_macro;
extern crate syn;

use std::convert::From;

use proc_macro::TokenStream;

use syn::{Data, Type, Ident, Fields, Field, token::Comma};
use syn::punctuated::Punctuated;

static INVALID_STRUCT: &str = "Struct must be a named struct. Not unnamed or unit.";
static INVALID_VARIANT: &str = "Variant must be a struct. Not an enum or union.";
static GETTER_PREFIX: &str = "get_";

type TraitSlots = Vec<TraitSlot>;
type TraitName = Ident;
type StructName = Ident;

/// Derive getters into a seperate trait for the named struct.
#[proc_macro_derive(Getters)]
pub fn getters(input: TokenStream) -> TokenStream {
    let ast = syn::parse(input).unwrap();
    let (trait_tokens, struct_name, trait_name, trait_slots) = setup_getters_trait(&ast);
    let impl_tokens = setup_trait_impl(struct_name, trait_name, trait_slots);

    let mut tokens = quote::Tokens::new();
    tokens.append_all(trait_tokens.into_iter());
    tokens.append_all(impl_tokens.into_iter());

    //println!("Tokens: {}", &tokens);
    tokens.into()
}

// For building a list of methods that need to be in the trait.
struct TraitSlot {
    label: Ident,
    name: Ident,
    ty: Type,
}

impl TraitSlot {
    fn new(label: Ident, name: Ident, ty: Type) -> TraitSlot {
        TraitSlot {
            label: label,
            name: name,
            ty: ty,
        }
    }
}

fn field_to_trait_slot(field: &Field) -> TraitSlot {
    let name = field.ident.as_ref().unwrap().clone();
    let label = Ident::from(format!("{}{}", GETTER_PREFIX, &name).as_str());
    TraitSlot::new(label, name, field.ty.clone())
}

// Fetch the slots (aka fields) in a structure. If the passed in ast is not a `struct`, it
// return `None`.
fn get_slots<'a>(
    data: &'a syn::Data
) -> Result<&'a Punctuated<Field, Comma>, &'static str> {
    match data {
        &Data::Struct(ref body) => {
            match &body.fields {
                &Fields::Named(ref named) => Ok(&named.named),
                _ => Err(INVALID_STRUCT),
            }
        },
        _ => Err(INVALID_VARIANT),
    }
}

fn setup_getters_trait<'a>(
    ast: &'a syn::DeriveInput
) -> (quote::Tokens, StructName, TraitName, TraitSlots)  {
    let slots: Vec<TraitSlot> = get_slots(&ast.data)
        .unwrap_or_else(|e| panic!("Couldn't autogenerate: {}", e))
        .iter()
        .map(field_to_trait_slot)
        .collect();

    let trait_methods: Vec<quote::Tokens> = slots
        .iter()
        .map(|slot| {
            let label = slot.label.clone();
            let ty = slot.ty.clone();
            quote! {
                fn #label(&self) -> &#ty;
            }
        })
        .collect();

    let struct_name = ast.ident.clone();
    let trait_name = Ident::from(format!("{}Getters", &struct_name).as_str());

    let tokens = quote! {
        pub trait #trait_name {
            #(#trait_methods)*
        }
    };

    (tokens, struct_name, trait_name, slots)
}

fn setup_trait_impl(
    struct_name: StructName, trait_name: TraitName, slots: TraitSlots
) -> quote::Tokens {
    let trait_methods: Vec<quote::Tokens> = slots
        .into_iter()
        .map(|slot| {
            let label = slot.label.clone();
            let name = slot.name.clone();
            let ty = slot.ty.clone();
            quote! {
                fn #label(&self) -> &#ty {
                    &self.#name
                }
            }
        })
        .collect();

    quote! {
        impl #trait_name for #struct_name {
            #(#trait_methods)*
        }
    }
}
<commit_msg>WIP: Preliminary. Copying code and altering for struct impl instead of trait impl.<commit_after>//! Derive Getters
//! ===
//!
//! Macro for autogenerating getters. Can only be used on named structs. Will generate
//! getters that will reside in a new trait so as not to pollute the struct namespace.
//!
//! # Usage
//! Add to your project Cargo.toml;
//! ```toml
//! [dependencies]
//! derive-getters = "0.0.4"
//! ```
//!
//! In lib.rs or main.rs;
//! ```
//! #[macro_use]
//! extern crate derive_getters;
//! #
//! # fn main() { }
//! ```
//!
//! # Example
//! ```
//! #[macro_use]
//! extern crate derive_getters;
//!
//! #[derive(Getters)]
//! struct Number {
//!    num: u64,
//! }
//!
//! fn main() {
//!    let number = Number { num: 655 };
//!    assert!(number.get_num() == &655);
//! }
//! ```
//!
//! A new trait, `NumberGetters` will have been generated and implemented for the `Numbers`
//! struct which contains the `get_num` method. To use the trait in other modules one must
//! define a `use` for it from the same location the struct resides.

#[macro_use] extern crate quote;
extern crate proc_macro;
extern crate syn;

use std::convert::From;

use proc_macro::TokenStream;

use syn::{Data, Type, Ident, Fields, Field, token::Comma};
use syn::punctuated::Punctuated;

static INVALID_STRUCT: &str = "Struct must be a named struct. Not unnamed or unit.";
static INVALID_VARIANT: &str = "Variant must be a struct. Not an enum or union.";
//static GETTER_PREFIX: &str = "get_";
static GETTER_PREFIX: &str = "";

type TraitSlots = Vec<TraitSlot>;
type StructSlots = Vec<StructSlot>;
type TraitName = Ident;
type StructName = Ident;

/// Derive getters into a seperate trait for the named struct.
#[proc_macro_derive(Getters)]
pub fn getters(input: TokenStream) -> TokenStream {
    let ast = syn::parse(input).unwrap();
    let (trait_tokens, struct_name, trait_name, trait_slots) = setup_getters_trait(&ast);
    let impl_tokens = setup_trait_impl(struct_name, trait_name, trait_slots);

    let mut tokens = quote::Tokens::new();
    tokens.append_all(trait_tokens.into_iter());
    tokens.append_all(impl_tokens.into_iter());

    //println!("Tokens: {}", &tokens);
    tokens.into()
}

// For building a list of methods that need to be in the struct.
struct StructSlot {
    label: Ident,
    name: Ident,
    ty: Type,
}

impl StructSlot {
    fn new(label: Ident, name: Ident, ty: Type) -> StructSlot {
        StructSlot {
            label: label,
            name: name,
            ty: ty,
        }
    }
}

fn field_to_struct_slot(field: &Field) -> StructSlot {
    let name = field.ident.as_ref().unwrap().clone();
    let label = Ident::from(format!("{}{}", GETTER_PREFIX, &name).as_str());
    StructSlot::new(label, name, field.ty.clone())
}

// For building a list of methods that need to be in the trait.
struct TraitSlot {
    label: Ident,
    name: Ident,
    ty: Type,
}

impl TraitSlot {
    fn new(label: Ident, name: Ident, ty: Type) -> TraitSlot {
        TraitSlot {
            label: label,
            name: name,
            ty: ty,
        }
    }
}

fn field_to_trait_slot(field: &Field) -> TraitSlot {
    let name = field.ident.as_ref().unwrap().clone();
    let label = Ident::from(format!("{}{}", GETTER_PREFIX, &name).as_str());
    TraitSlot::new(label, name, field.ty.clone())
}

// Fetch the slots (aka fields) in a structure. If the passed in ast is not a `struct`, it
// return `None`.
fn get_slots<'a>(
    data: &'a syn::Data
) -> Result<&'a Punctuated<Field, Comma>, &'static str> {
    match data {
        &Data::Struct(ref body) => {
            match &body.fields {
                &Fields::Named(ref named) => Ok(&named.named),
                _ => Err(INVALID_STRUCT),
            }
        },
        _ => Err(INVALID_VARIANT),
    }
}

fn setup_getters_impl<'a>(
    ast: &'a syn::DeriveInput
) -> (quote::Tokens, StructName, StructSlots)  {
    let slots: Vec<StructSlot> = get_slots(&ast.data)
        .unwrap_or_else(|e| panic!("Couldn't autogenerate: {}", e))
        .iter()
        .map(field_to_struct_slot)
        .collect();

    let struct_methods: Vec<quote::Tokens> = slots
        .iter()
        .map(|slot| {
            let label = slot.label.clone();
            let ty = slot.ty.clone();
            quote! {
                fn #label(&self) -> &#ty;
            }
        })
        .collect();

    let struct_name = ast.ident.clone();
    //let trait_name = Ident::from(format!("{}Getters", &struct_name).as_str());

    let tokens = quote! {
        pub trait #struct_name {
            #(#struct_methods)*
        }
    };

    (tokens, struct_name, slots)
}

fn setup_getters_trait<'a>(
    ast: &'a syn::DeriveInput
) -> (quote::Tokens, StructName, TraitName, TraitSlots)  {
    let slots: Vec<TraitSlot> = get_slots(&ast.data)
        .unwrap_or_else(|e| panic!("Couldn't autogenerate: {}", e))
        .iter()
        .map(field_to_trait_slot)
        .collect();

    let trait_methods: Vec<quote::Tokens> = slots
        .iter()
        .map(|slot| {
            let label = slot.label.clone();
            let ty = slot.ty.clone();
            quote! {
                fn #label(&self) -> &#ty;
            }
        })
        .collect();

    let struct_name = ast.ident.clone();
    let trait_name = Ident::from(format!("{}Getters", &struct_name).as_str());

    let tokens = quote! {
        pub trait #trait_name {
            #(#trait_methods)*
        }
    };

    (tokens, struct_name, trait_name, slots)
}

fn setup_trait_impl(
    struct_name: StructName, trait_name: TraitName, slots: TraitSlots
) -> quote::Tokens {
    let trait_methods: Vec<quote::Tokens> = slots
        .into_iter()
        .map(|slot| {
            let label = slot.label.clone();
            let name = slot.name.clone();
            let ty = slot.ty.clone();
            quote! {
                fn #label(&self) -> &#ty {
                    &self.#name
                }
            }
        })
        .collect();

    quote! {
        impl #trait_name for #struct_name {
            #(#trait_methods)*
        }
    }
}
<|endoftext|>