<commit_before>//! Tests and test infrastructure.
//!
//! Unless you're writing custom benchmarks, you don't need this.

use std::old_io::timer;
use std::time::Duration;
use std::sync::{Arc, Mutex, RwLock};
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::cell::UnsafeCell;
use std::thread::Thread;
use std::default::Default;
use std::any::Any;
use time::precise_time_ns;
use test::black_box;

use Seqloq;

#[doc(hidden)]
pub trait TestableMutex: Send + Sync {
    fn create() -> Self;
    fn check(&self, delay: Duration) -> usize;
    fn frob(&self, delay: Duration);
}

const ARRAY_LEN: usize = 4;

#[derive(Copy)]
pub struct TestArray(pub [u64; ARRAY_LEN]);

impl TestArray {
    pub fn new() -> TestArray {
        TestArray([0; ARRAY_LEN])
    }

    pub fn check(&self, delay: Duration) -> usize {
        let v = self.0[0];
        let n = self.0.iter().skip(1)
            .filter(|e| {
                timer::sleep(delay);
                **e != v
            }).count();

        // Make sure it won't short-circuit even if inlined
        black_box(n);
        n
    }

    pub fn frob(&mut self, delay: Duration) {
        for e in self.0.iter_mut() {
            *e += 1;
            timer::sleep(delay);
        }
    }
}

impl TestableMutex for Mutex<TestArray> {
    fn create() -> Mutex<TestArray> {
        Mutex::new(TestArray::new())
    }

    fn check(&self, delay: Duration) -> usize {
        self.lock().unwrap().check(delay)
    }

    fn frob(&self, delay: Duration) {
        self.lock().unwrap().frob(delay);
    }
}

impl TestableMutex for RwLock<TestArray> {
    fn create() -> RwLock<TestArray> {
        RwLock::new(TestArray::new())
    }

    fn check(&self, delay: Duration) -> usize {
        self.read().unwrap().check(delay)
    }

    fn frob(&self, delay: Duration) {
        self.write().unwrap().frob(delay);
    }
}

impl TestableMutex for Seqloq<TestArray> {
    fn create() -> Seqloq<TestArray> {
        Seqloq::new(TestArray::new())
    }

    fn check(&self, delay: Duration) -> usize {
        let x = self.read();
        x.check(delay)
    }

    fn frob(&self, delay: Duration) {
        self.lock().frob(delay);
    }
}

pub struct SeqloqPeek<T>(Seqloq<T>);

impl TestableMutex for SeqloqPeek<TestArray> {
    fn create() -> SeqloqPeek<TestArray> {
        SeqloqPeek(Seqloq::new(TestArray::new()))
    }

    fn check(&self, delay: Duration) -> usize {
        self.0.peek(|x| unsafe {
            (*x).check(delay)
        })
    }

    fn frob(&self, delay: Duration) {
        self.0.frob(delay);
    }
}

struct BogusMutex<T>(UnsafeCell<T>);

unsafe impl<T: 'static> Send for BogusMutex<T> { }
unsafe impl<T: 'static> Sync for BogusMutex<T> { }

impl TestableMutex for BogusMutex<TestArray> {
    fn create() -> BogusMutex<TestArray> {
        BogusMutex(UnsafeCell::new(TestArray::new()))
    }

    fn check(&self, delay: Duration) -> usize {
        unsafe {
            (*self.0.get()).check(delay)
        }
    }

    fn frob(&self, delay: Duration) {
        unsafe {
            (*self.0.get()).frob(delay);
        }
    }
}

#[derive(Copy)]
pub struct ThreadSpec {
    /// Number of threads to spawn.
    pub qty: u64,
    /// Number of times to operate in each thread.
    pub steps: u64,
    /// Delay on each step of the checking or incrementing operation, in microseconds
    pub delay: u64,
    /// Pause between operations, with the mutex unlocked, in microseconds
    pub pause: u64,
}

impl Default for ThreadSpec {
    fn default() -> ThreadSpec {
        ThreadSpec {
            qty: 100,
            steps: 100,
            delay: 2,
            pause: 2000,
        }
    }
}

impl ThreadSpec {
    fn pause(&self) {
        timer::sleep(Duration::microseconds(self.pause as i64));
    }
}

struct SharedData<M> {
    mutex: M,
    shutdown: AtomicBool,
    failed_checks: AtomicUsize,
}

#[derive(Copy, Show)]
pub enum BenchMode { Reader, Writer }

pub struct BenchRequest<'a> {
    pub mode: BenchMode,
    pub num_samples: u64,
    pub samples: &'a mut Vec<u64>,
}

pub fn reader_writer_test<M: TestableMutex>(
    readers: ThreadSpec,
    writers: ThreadSpec,
    bench: Option<BenchRequest>,
    should_fail: bool)
{
    // should be safe to put this on the stack, but screw it
    let shared = Arc::new(SharedData {
        mutex: <M as TestableMutex>::create(),
        shutdown: AtomicBool::new(false),
        failed_checks: AtomicUsize::new(0),
    });
    let mut guards = vec![];

    macro_rules! go {
        ($spec:ident, $is_writer:expr) => {
            for _ in 0..$spec.qty {
                let shared = shared.clone();
                guards.push(Thread::scoped(move || {
                    for _ in 0..$spec.steps {
                        let delay = Duration::microseconds($spec.delay as i64);
                        if $is_writer {
                            shared.mutex.frob(delay);
                        } else {
                            if 0 != shared.mutex.check(delay) {
                                shared.failed_checks.fetch_add(1, Ordering::SeqCst);
                            }
                        }

                        $spec.pause();
                        if shared.shutdown.load(Ordering::SeqCst) {
                            break;
                        }
                    }
                }));
            }
        }
    }

    go!(readers, false);
    go!(writers, true);

    if let Some(bench) = bench {
        for _ in 0..bench.num_samples {
            let t0;
            let t1;
            match bench.mode {
                BenchMode::Reader => {
                    t0 = precise_time_ns();
                    let res = shared.mutex.check(Duration::zero());
                    t1 = precise_time_ns();
                    assert_eq!(res, 0);
                    readers.pause();
                },

                BenchMode::Writer => {
                    t0 = precise_time_ns();
                    shared.mutex.frob(Duration::zero());
                    t1 = precise_time_ns();
                    writers.pause();
                },
            }
            bench.samples.push(t1 - t0);
        }

        shared.shutdown.store(true, Ordering::SeqCst);
    }

    for r in guards.into_iter() {
        if let Err(e) = r.join() {
            // can't print Box<Any + Send> :(
            panic!("thread panicked with {:?}", e.get_type_id());
        }
    }

    let failures = shared.failed_checks.load(Ordering::SeqCst);
    if should_fail {
        assert!(failures > 0);
    } else {
        assert_eq!(failures, 0);
    }
}

macro_rules! mk_test {
    ($name:ident, $mutex:ident) => {
        #[test]
        fn $name() {
            let spec = Default::default();
            reader_writer_test::<$mutex<TestArray>>(spec, spec, None, false);
        }
    }
}

mk_test!(test_mutex, Mutex);
mk_test!(test_rwlock, RwLock);
mk_test!(test_seqloq, Seqloq);
mk_test!(test_seqloq_peek, SeqloqPeek);

#[test]
fn test_bogus_mutex() {
    let spec = Default::default();
    reader_writer_test::<BogusMutex<TestArray>>(spec, spec, None, true);
}
<commit_msg>Fix warning<commit_after>//! Tests and test infrastructure.
//!
//! Unless you're writing custom benchmarks, you don't need this.

use std::old_io::timer;
use std::time::Duration;
use std::sync::{Arc, Mutex, RwLock};
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::cell::UnsafeCell;
use std::thread::Thread;
use std::default::Default;
use std::any::Any;
use time::precise_time_ns;
use test::black_box;

use Seqloq;

#[doc(hidden)]
pub trait TestableMutex: Send + Sync {
    fn create() -> Self;
    fn check(&self, delay: Duration) -> usize;
    fn frob(&self, delay: Duration);
}

const ARRAY_LEN: usize = 4;

#[derive(Copy)]
pub struct TestArray(pub [u64; ARRAY_LEN]);

impl TestArray {
    pub fn new() -> TestArray {
        TestArray([0; ARRAY_LEN])
    }

    pub fn check(&self, delay: Duration) -> usize {
        let v = self.0[0];
        let n = self.0.iter().skip(1)
            .filter(|e| {
                timer::sleep(delay);
                **e != v
            }).count();

        // Make sure it won't short-circuit even if inlined
        black_box(n);
        n
    }

    pub fn frob(&mut self, delay: Duration) {
        for e in self.0.iter_mut() {
            *e += 1;
            timer::sleep(delay);
        }
    }
}

impl TestableMutex for Mutex<TestArray> {
    fn create() -> Mutex<TestArray> {
        Mutex::new(TestArray::new())
    }

    fn check(&self, delay: Duration) -> usize {
        self.lock().unwrap().check(delay)
    }

    fn frob(&self, delay: Duration) {
        self.lock().unwrap().frob(delay);
    }
}

impl TestableMutex for RwLock<TestArray> {
    fn create() -> RwLock<TestArray> {
        RwLock::new(TestArray::new())
    }

    fn check(&self, delay: Duration) -> usize {
        self.read().unwrap().check(delay)
    }

    fn frob(&self, delay: Duration) {
        self.write().unwrap().frob(delay);
    }
}

impl TestableMutex for Seqloq<TestArray> {
    fn create() -> Seqloq<TestArray> {
        Seqloq::new(TestArray::new())
    }

    fn check(&self, delay: Duration) -> usize {
        let x = self.read();
        x.check(delay)
    }

    fn frob(&self, delay: Duration) {
        self.lock().frob(delay);
    }
}

pub struct SeqloqPeek<T>(Seqloq<T>);

impl TestableMutex for SeqloqPeek<TestArray> {
    fn create() -> SeqloqPeek<TestArray> {
        SeqloqPeek(Seqloq::new(TestArray::new()))
    }

    fn check(&self, delay: Duration) -> usize {
        self.0.peek(|x| unsafe {
            (*x).check(delay)
        })
    }

    fn frob(&self, delay: Duration) {
        self.0.frob(delay);
    }
}

struct BogusMutex<T>(UnsafeCell<T>);

unsafe impl<T: 'static> Send for BogusMutex<T> { }
unsafe impl<T: 'static> Sync for BogusMutex<T> { }

impl TestableMutex for BogusMutex<TestArray> {
    fn create() -> BogusMutex<TestArray> {
        BogusMutex(UnsafeCell::new(TestArray::new()))
    }

    fn check(&self, delay: Duration) -> usize {
        unsafe {
            (*self.0.get()).check(delay)
        }
    }

    fn frob(&self, delay: Duration) {
        unsafe {
            (*self.0.get()).frob(delay);
        }
    }
}

#[derive(Copy)]
pub struct ThreadSpec {
    /// Number of threads to spawn.
    pub qty: u64,
    /// Number of times to operate in each thread.
    pub steps: u64,
    /// Delay on each step of the checking or incrementing operation, in microseconds
    pub delay: u64,
    /// Pause between operations, with the mutex unlocked, in microseconds
    pub pause: u64,
}

impl Default for ThreadSpec {
    fn default() -> ThreadSpec {
        ThreadSpec {
            qty: 100,
            steps: 100,
            delay: 2,
            pause: 2000,
        }
    }
}

impl ThreadSpec {
    fn pause(&self) {
        timer::sleep(Duration::microseconds(self.pause as i64));
    }
}

struct SharedData<M> {
    mutex: M,
    shutdown: AtomicBool,
    failed_checks: AtomicUsize,
}

#[derive(Copy, Debug)]
pub enum BenchMode { Reader, Writer }

pub struct BenchRequest<'a> {
    pub mode: BenchMode,
    pub num_samples: u64,
    pub samples: &'a mut Vec<u64>,
}

pub fn reader_writer_test<M: TestableMutex>(
    readers: ThreadSpec,
    writers: ThreadSpec,
    bench: Option<BenchRequest>,
    should_fail: bool)
{
    // should be safe to put this on the stack, but screw it
    let shared = Arc::new(SharedData {
        mutex: <M as TestableMutex>::create(),
        shutdown: AtomicBool::new(false),
        failed_checks: AtomicUsize::new(0),
    });
    let mut guards = vec![];

    macro_rules! go {
        ($spec:ident, $is_writer:expr) => {
            for _ in 0..$spec.qty {
                let shared = shared.clone();
                guards.push(Thread::scoped(move || {
                    for _ in 0..$spec.steps {
                        let delay = Duration::microseconds($spec.delay as i64);
                        if $is_writer {
                            shared.mutex.frob(delay);
                        } else {
                            if 0 != shared.mutex.check(delay) {
                                shared.failed_checks.fetch_add(1, Ordering::SeqCst);
                            }
                        }

                        $spec.pause();
                        if shared.shutdown.load(Ordering::SeqCst) {
                            break;
                        }
                    }
                }));
            }
        }
    }

    go!(readers, false);
    go!(writers, true);

    if let Some(bench) = bench {
        for _ in 0..bench.num_samples {
            let t0;
            let t1;
            match bench.mode {
                BenchMode::Reader => {
                    t0 = precise_time_ns();
                    let res = shared.mutex.check(Duration::zero());
                    t1 = precise_time_ns();
                    assert_eq!(res, 0);
                    readers.pause();
                },

                BenchMode::Writer => {
                    t0 = precise_time_ns();
                    shared.mutex.frob(Duration::zero());
                    t1 = precise_time_ns();
                    writers.pause();
                },
            }
            bench.samples.push(t1 - t0);
        }

        shared.shutdown.store(true, Ordering::SeqCst);
    }

    for r in guards.into_iter() {
        if let Err(e) = r.join() {
            // can't print Box<Any + Send> :(
            panic!("thread panicked with {:?}", e.get_type_id());
        }
    }

    let failures = shared.failed_checks.load(Ordering::SeqCst);
    if should_fail {
        assert!(failures > 0);
    } else {
        assert_eq!(failures, 0);
    }
}

macro_rules! mk_test {
    ($name:ident, $mutex:ident) => {
        #[test]
        fn $name() {
            let spec = Default::default();
            reader_writer_test::<$mutex<TestArray>>(spec, spec, None, false);
        }
    }
}

mk_test!(test_mutex, Mutex);
mk_test!(test_rwlock, RwLock);
mk_test!(test_seqloq, Seqloq);
mk_test!(test_seqloq_peek, SeqloqPeek);

#[test]
fn test_bogus_mutex() {
    let spec = Default::default();
    reader_writer_test::<BogusMutex<TestArray>>(spec, spec, None, true);
}
<|endoftext|>


<commit_before>
#[cfg(test)]
mod tests {

use std::thread;
use std::sync::mpsc;
use std::time::Duration;
use std::collections::HashMap;

use Actor;
use MessageType;
use MessageVariant;
use Message;
use ActorAddress;
use spawn;

pub struct Echo;

const TEST : &'static str = ":test";

impl Actor for Echo {
    fn process_message(&mut self, message: Message, myself: &ActorAddress) {
        match *message.get_type() {
            MessageType::Init => {
                Message::init().with_sender(myself)
                               .with_datum(message.get_datum().clone())
                               .send_to(message.get_sender());
            },
            MessageType::Stop => {
                Message::stop().with_sender(myself)
                               .with_datum(message.get_datum().clone())
                               .send_to(message.get_sender());
            },
            MessageType::Custom(s) => {
                Message::custom(s).with_sender(myself)
                                  .with_datum(message.get_datum().clone())
                                  .send_to(message.get_sender());
            },
        }
    }
}

#[test]
fn basic_check() {
    let (tx, rx) = mpsc::channel();
    let fake_actor = ActorAddress { endpoint: tx };
    let worker = spawn(Echo);

     // Hopefully this is enough for the init message to get to the worker
    thread::sleep(Duration::from_millis(500));

    Message::custom(TEST).with_sender(&fake_actor).send_to(&worker);
    Message::custom(TEST).with_sender(&fake_actor).with_i64(-123).send_to(&worker);
    Message::custom(TEST).with_sender(&fake_actor).with_u64(456).send_to(&worker);
    Message::custom(TEST).with_sender(&fake_actor).with_f64(123.456).send_to(&worker);
    Message::custom(TEST).with_sender(&fake_actor).with_str("blah").send_to(&worker);
    Message::custom(TEST).with_sender(&fake_actor).with_map(HashMap::new()).send_to(&worker);
    Message::custom(TEST).with_sender(&fake_actor).with_act(&worker).send_to(&worker);
    Message::stop().with_sender(&fake_actor).send_to(&worker);

     // Hopefully this is enough for the stop message to get to the worker
    thread::sleep(Duration::from_millis(500));

    let mut m = rx.recv().unwrap();
    assert_eq!(*m.get_type(), MessageType::Custom(TEST));
    match *m.get_datum() {
        MessageVariant::Void => (), // ok
        _ => { assert!(false, "Unexpected message datum"); }
    }

    m = rx.recv().unwrap();
    assert_eq!(*m.get_type(), MessageType::Custom(TEST));
    match *m.get_datum() {
        MessageVariant::I64(-123) => (), // ok
        _ => { assert!(false, "Unexpected message datum"); }
    }

    m = rx.recv().unwrap();
    assert_eq!(*m.get_type(), MessageType::Custom(TEST));
    match *m.get_datum() {
        MessageVariant::U64(456) => (), // ok
        _ => { assert!(false, "Unexpected message datum"); }
    }

    m = rx.recv().unwrap();
    assert_eq!(*m.get_type(), MessageType::Custom(TEST));
    match *m.get_datum() {
        MessageVariant::F64(123.456) => (), // ok
        _ => { assert!(false, "Unexpected message datum"); }
    }

    m = rx.recv().unwrap();
    assert_eq!(*m.get_type(), MessageType::Custom(TEST));
    match *m.get_datum() {
        MessageVariant::Str(ref s) => { assert_eq!(s, "blah"); }, // ok
        _ => { assert!(false, "Unexpected message datum"); }
    }

    m = rx.recv().unwrap();
    assert_eq!(*m.get_type(), MessageType::Custom(TEST));
    match *m.get_datum() {
        MessageVariant::Map(ref m) => { assert!(m.is_empty()) }, // ok
        _ => { assert!(false, "Unexpected message datum"); }
    }

    m = rx.recv().unwrap();
    assert_eq!(*m.get_type(), MessageType::Custom(TEST));
    match *m.get_datum() {
        MessageVariant::Act(_) => (), // ok
        _ => { assert!(false, "Unexpected message datum"); }
    }
}

}

// The textbook tests are based on the book called "Seven Concurrency Models
// In Seven Weeks". Chapter 5 of the book is about the actor model. I am trying
// to replicate the examples within with the mecha library.

#[cfg(test)]
mod textbook_tests {

use std::thread;
use std::sync::mpsc;
use std::time::Duration;
use std::collections::HashMap;

use Actor;
use MessageType;
use MessageVariant;
use Message;
use ActorAddress;
use spawn;

struct Talker;

const GREET: &'static str = ":greet";
const PRAISE: &'static str = ":praise";
const CELEBRATE: &'static str = ":celebrate";

impl Actor for Talker {
    fn process_message(&mut self, message: Message, myself: &ActorAddress) {
        match *message.get_type() {
            MessageType::Custom(GREET) => {
                match *message.get_datum() {
                    MessageVariant::Str(ref s) => {
                        println!("Hello {}!", s);
                    },
                    _ => (),
                }
            },
            MessageType::Custom(PRAISE) => {
                match *message.get_datum() {
                    MessageVariant::Str(ref s) => {
                        println!("{}, you're amazing!", s);
                    },
                    _ => (),
                }
            },
            MessageType::Custom(CELEBRATE) => {
                match *message.get_datum() {
                    MessageVariant::Map(ref m) => {
                        let name = m.get("name").unwrap().clone().as_str().unwrap();
                        let age = m.get("age").unwrap().clone().as_u64().unwrap();
                        println!("Here's to another {} years, {}!", age, name);
                    },
                    _ => (),
                }
            },
            _ => (),
        }
    }
}

#[test]
fn test_talker() {
    let (tx, rx) = mpsc::channel();
    let fake_actor = ActorAddress { endpoint: tx };
    let worker = spawn(Talker);

    Message::custom(GREET).with_str("Hewey").send_to(&worker);
    Message::custom(PRAISE).with_str("Dewey").send_to(&worker);
    let mut m = HashMap::new();
    m.insert("name".to_string(), MessageVariant::from("Louie"));
    m.insert("age".to_string(), MessageVariant::from(16u64));
    Message::custom(CELEBRATE).with_map(m).send_to(&worker);

    Message::stop().send_to(&worker);

     // Hopefully this is enough for the stop message to get to the worker
    thread::sleep(Duration::from_millis(500));
}

}
<commit_msg>Fix warnings in tests<commit_after>
#[cfg(test)]
mod tests {

use std::thread;
use std::sync::mpsc;
use std::time::Duration;
use std::collections::HashMap;

use Actor;
use MessageType;
use MessageVariant;
use Message;
use ActorAddress;
use spawn;

pub struct Echo;

const TEST : &'static str = ":test";

impl Actor for Echo {
    fn process_message(&mut self, message: Message, myself: &ActorAddress) {
        match *message.get_type() {
            MessageType::Init => {
                Message::init().with_sender(myself)
                               .with_datum(message.get_datum().clone())
                               .send_to(message.get_sender());
            },
            MessageType::Stop => {
                Message::stop().with_sender(myself)
                               .with_datum(message.get_datum().clone())
                               .send_to(message.get_sender());
            },
            MessageType::Custom(s) => {
                Message::custom(s).with_sender(myself)
                                  .with_datum(message.get_datum().clone())
                                  .send_to(message.get_sender());
            },
        }
    }
}

#[test]
fn basic_check() {
    let (tx, rx) = mpsc::channel();
    let fake_actor = ActorAddress { endpoint: tx };
    let worker = spawn(Echo);

     // Hopefully this is enough for the init message to get to the worker
    thread::sleep(Duration::from_millis(500));

    Message::custom(TEST).with_sender(&fake_actor).send_to(&worker);
    Message::custom(TEST).with_sender(&fake_actor).with_i64(-123).send_to(&worker);
    Message::custom(TEST).with_sender(&fake_actor).with_u64(456).send_to(&worker);
    Message::custom(TEST).with_sender(&fake_actor).with_f64(123.456).send_to(&worker);
    Message::custom(TEST).with_sender(&fake_actor).with_str("blah").send_to(&worker);
    Message::custom(TEST).with_sender(&fake_actor).with_map(HashMap::new()).send_to(&worker);
    Message::custom(TEST).with_sender(&fake_actor).with_act(&worker).send_to(&worker);
    Message::stop().with_sender(&fake_actor).send_to(&worker);

     // Hopefully this is enough for the stop message to get to the worker
    thread::sleep(Duration::from_millis(500));

    let mut m = rx.recv().unwrap();
    assert_eq!(*m.get_type(), MessageType::Custom(TEST));
    match *m.get_datum() {
        MessageVariant::Void => (), // ok
        _ => { assert!(false, "Unexpected message datum"); }
    }

    m = rx.recv().unwrap();
    assert_eq!(*m.get_type(), MessageType::Custom(TEST));
    match *m.get_datum() {
        MessageVariant::I64(-123) => (), // ok
        _ => { assert!(false, "Unexpected message datum"); }
    }

    m = rx.recv().unwrap();
    assert_eq!(*m.get_type(), MessageType::Custom(TEST));
    match *m.get_datum() {
        MessageVariant::U64(456) => (), // ok
        _ => { assert!(false, "Unexpected message datum"); }
    }

    m = rx.recv().unwrap();
    assert_eq!(*m.get_type(), MessageType::Custom(TEST));
    match *m.get_datum() {
        MessageVariant::F64(123.456) => (), // ok
        _ => { assert!(false, "Unexpected message datum"); }
    }

    m = rx.recv().unwrap();
    assert_eq!(*m.get_type(), MessageType::Custom(TEST));
    match *m.get_datum() {
        MessageVariant::Str(ref s) => { assert_eq!(s, "blah"); }, // ok
        _ => { assert!(false, "Unexpected message datum"); }
    }

    m = rx.recv().unwrap();
    assert_eq!(*m.get_type(), MessageType::Custom(TEST));
    match *m.get_datum() {
        MessageVariant::Map(ref m) => { assert!(m.is_empty()) }, // ok
        _ => { assert!(false, "Unexpected message datum"); }
    }

    m = rx.recv().unwrap();
    assert_eq!(*m.get_type(), MessageType::Custom(TEST));
    match *m.get_datum() {
        MessageVariant::Act(_) => (), // ok
        _ => { assert!(false, "Unexpected message datum"); }
    }
}

}

// The textbook tests are based on the book called "Seven Concurrency Models
// In Seven Weeks". Chapter 5 of the book is about the actor model. I am trying
// to replicate the examples within with the mecha library.

#[cfg(test)]
mod textbook_tests {

use std::thread;
use std::time::Duration;
use std::collections::HashMap;

use Actor;
use MessageType;
use MessageVariant;
use Message;
use ActorAddress;
use spawn;

struct Talker;

const GREET: &'static str = ":greet";
const PRAISE: &'static str = ":praise";
const CELEBRATE: &'static str = ":celebrate";

impl Actor for Talker {
    fn process_message(&mut self, message: Message, _: &ActorAddress) {
        match *message.get_type() {
            MessageType::Custom(GREET) => {
                match *message.get_datum() {
                    MessageVariant::Str(ref s) => {
                        println!("Hello {}!", s);
                    },
                    _ => (),
                }
            },
            MessageType::Custom(PRAISE) => {
                match *message.get_datum() {
                    MessageVariant::Str(ref s) => {
                        println!("{}, you're amazing!", s);
                    },
                    _ => (),
                }
            },
            MessageType::Custom(CELEBRATE) => {
                match *message.get_datum() {
                    MessageVariant::Map(ref m) => {
                        let name = m.get("name").unwrap().clone().as_str().unwrap();
                        let age = m.get("age").unwrap().clone().as_u64().unwrap();
                        println!("Here's to another {} years, {}!", age, name);
                    },
                    _ => (),
                }
            },
            _ => (),
        }
    }
}

#[test]
fn test_talker() {
    let worker = spawn(Talker);

    Message::custom(GREET).with_str("Hewey").send_to(&worker);
    Message::custom(PRAISE).with_str("Dewey").send_to(&worker);
    let mut m = HashMap::new();
    m.insert("name".to_string(), MessageVariant::from("Louie"));
    m.insert("age".to_string(), MessageVariant::from(16u64));
    Message::custom(CELEBRATE).with_map(m).send_to(&worker);

    Message::stop().send_to(&worker);

     // Hopefully this is enough for the stop message to get to the worker
    thread::sleep(Duration::from_millis(500));
}

}
<|endoftext|>


<commit_before>pub struct Timer {
    div: u8,
    tima: u8,
    tma: u8,
    tac: u8
}

impl Timer {
    pub fn new() -> Timer {
        Timer {
            div: 0x00,
            tima: 0x00,
            tma: 0x00,
            tac: 0x00
        }
    }

    pub fn write_byte(&mut self, address: u16, value: u8) {
        match address {
            0xFF04 => { self.div = value; },
            0xFF05 => { self.tima = value; },
            0xFF06 => { self.tma = value; },
            0xFF07 => { self.tac = value; },
            _ => unreachable!()
        }
    }

    pub fn read_byte(&self, address: u16) -> u8 {
        match address {
            0xFF04 => self.div,
            0xFF05 => self.tima,
            0xFF06 => self.tma,
            0xFF07 => self.tac,
            _ => unreachable!()
        }
    }
}
<commit_msg>Add small changes to timer<commit_after>pub struct Timer {
    div: u8,
    tima: u8,
    tma: u8,
    tac: u8
}

static ENABLED_FLAG: u8 = 0b0000_0100;
static FREQUENCY_FLAG : u8 = 0b0000_0011;

impl Timer {
    pub fn new() -> Timer {
        Timer {
            div: 0x00,
            tima: 0x00,
            tma: 0x00,
            tac: 0x00
        }
    }

    pub fn step(&mut self, increment: u8) {
    }

    pub fn write_byte(&mut self, address: u16, value: u8) {
        match address {
            0xFF04 => { self.div = 0x00; },
            0xFF05 => { self.tima = value; },
            0xFF06 => { self.tma = value; },
            0xFF07 => { self.tac = value; },
            _ => unreachable!()
        }
    }

    pub fn read_byte(&self, address: u16) -> u8 {
        match address {
            0xFF04 => self.div,
            0xFF05 => self.tima,
            0xFF06 => self.tma,
            0xFF07 => self.tac,
            _ => unreachable!()
        }
    }

    fn is_enabled(&self) -> bool {
        (self.tac & ENABLED_FLAG) == ENABLED_FLAG
    }

    fn frequency(&self) -> bool {
        (self.tac & FREQUENCY_FLAG) == FREQUENCY_FLAG
    }
}
<|endoftext|>


<commit_before>#[derive(Debug, PartialEq, Copy, Clone)]
pub enum TokenError {
    // If a token not a valid number
    // For example "+0a" starts as a number, but contains invalid characters.
    InvalidNumber,
}

#[derive(Debug, PartialEq, Copy, Clone)]
pub enum Token<'a> {
    Error((&'a str, TokenError)),
    Whitespace(&'a str),

    Str(&'a str),
    QStr(&'a str),

    OpenBracket,
    CloseBracket,
    OpenBrace,
    CloseBrace,
    OpenCurly,
    CloseCurly,

    UInt(u64),
    SInt(i64),
    Float(f64),
}

#[inline]
fn scan<F: Fn(char) -> bool>(s: &str, cond: F) -> (&str, &str) {
    // split at the first non-"cond" character
    match s.find(|c: char| !cond(c)) {
        None => (s, ""),
        Some(pos) => s.split_at(pos),
    }
}

#[inline]
pub fn is_token_delim(c: char) -> bool {
    c.is_whitespace() || c == '(' || c == ')' || c == '[' || c == ']' || c == '{' || c == '}'
}

// TODO ; comment
fn next_token<'a>(s: &'a str) -> Option<(Token<'a>, &'a str)> {
    match s.slice_shift_char() {
        None => None,
        Some((c, s2)) => {
            match c {
                '(' => Some((Token::OpenBrace, s2)),
                ')' => Some((Token::CloseBrace, s2)),

                '[' => Some((Token::OpenBracket, s2)),
                ']' => Some((Token::CloseBracket, s2)),

                '{' => Some((Token::OpenCurly, s2)),
                '}' => Some((Token::CloseCurly, s2)),

                '"' => {
                    // TODO: QStr
                    None
                }

                c if char::is_whitespace(c) => {
                    let (ws, rest) = scan(s, char::is_whitespace);
                    Some((Token::Whitespace(ws), rest))
                }

                '+' | '-' => {
                    let (string, rest) = scan(s, |ch| !is_token_delim(ch));
                    assert!(string.len() > 0);

                    // parse +|- always as a signed integer first.
                    // this is the way to distinguish a positive signed
                    // integer from a positive unsigned (+1 == SInt, while 1 == UInt).

                    // if it is followed by a digit, this is should be a number.
                    match s2.slice_shift_char() {
                        Some((ch, _)) if char::is_digit(ch, 10) => {
                            // +|- followed by [0-9]. This must be a number!

                            if let Ok(i) = string.parse::<i64>() {
                                Some((Token::SInt(i), rest))
                            } else if let Ok(i) = string.parse::<f64>() {
                                Some((Token::Float(i), rest))
                            } else {
                                Some((Token::Error((string, TokenError::InvalidNumber)), rest))
                            }
                        }
                        _ => {
                            // If it is followed by any other character (or none) it is a valid
                            // string token.
                            // XXX: Check for invalid characters in string.
                            Some((Token::Str(string), rest))
                        }
                    }
                }

                '0'...'9' => {
                    // this should be either a unsigned integer of a floating point number. If not,
                    // it's invalid.
                    let (string, rest) = scan(s, |ch| !is_token_delim(ch));
                    assert!(string.len() > 0);

                    if let Ok(i) = string.parse::<u64>() {
                        Some((Token::UInt(i), rest))
                    } else if let Ok(i) = string.parse::<f64>() {
                        Some((Token::Float(i), rest))
                    } else {
                        Some((Token::Error((string, TokenError::InvalidNumber)), rest))
                    }
                }

                _ => {
                    // this neither starts with '+' or '-' or 'digit'. this is definitively a
                    // string.

                    let (string, rest) = scan(s, |ch| !is_token_delim(ch));
                    assert!(string.len() > 0);

                    // Str
                    Some((Token::Str(string), rest))
                }
            }
        }
    }
}

pub struct Tokenizer<'a> {
    current: &'a str,
    ignore_ws: bool,
}

impl<'a> Tokenizer<'a> {
    pub fn new(s: &'a str, ignore_ws: bool) -> Tokenizer<'a> {
        Tokenizer {
            current: s,
            ignore_ws: ignore_ws,
        }
    }
}

impl<'a> Iterator for Tokenizer<'a> {
    type Item = Token<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            match next_token(self.current) {
                Some((tok, rest)) => {
                    self.current = rest;
                    if self.ignore_ws {
                        if let Token::Whitespace(_) = tok {
                            continue;
                        }
                    }
                    return Some(tok);
                }
                None => {
                    return None;
                }
            }
        }
    }
}

#[test]
fn test_tokenizer_whitespace() {
    let t = Tokenizer::new(" (abc 123)", false);
    let tokens: Vec<_> = t.into_iter().collect();
    assert_eq!(vec![Token::Whitespace(" "),
                    Token::OpenBrace,
                    Token::Str("abc"),
                    Token::Whitespace(" "),
                    Token::UInt(123),
                    Token::CloseBrace],
               tokens);
}

#[test]
fn test_tokenizer_no_whitespace() {
    let t = Tokenizer::new(" (abc 123)", true);
    let tokens: Vec<_> = t.into_iter().collect();
    assert_eq!(vec![Token::OpenBrace, Token::Str("abc"), Token::UInt(123), Token::CloseBrace],
               tokens);
}

#[test]
fn test_token() {
    assert_eq!(Some((Token::Whitespace("  "), "abc")), next_token("  abc"));
    assert_eq!(Some((Token::Str("abc"), "")), next_token("abc"));
    assert_eq!(Some((Token::Str("abc"), "(")), next_token("abc("));

    assert_eq!(Some((Token::OpenBrace, ")")), next_token("()"));

    assert_eq!(Some((Token::UInt(12345), "")), next_token("12345"));
    assert_eq!(Some((Token::UInt(12345), " ")), next_token("12345 "));
    assert_eq!(Some((Token::SInt(12345), " ")), next_token("+12345 "));
    assert_eq!(Some((Token::SInt(-12345), " ")), next_token("-12345 "));
    assert_eq!(Some((Token::Str("-a"), " ")), next_token("-a "));
    assert_eq!(Some((Token::Str("+a"), " ")), next_token("+a "));
    assert_eq!(Some((Token::Str("+a"), "(")), next_token("+a("));

    assert_eq!(Some((Token::Error(("12345+", TokenError::InvalidNumber)), "")),
               next_token("12345+"));
    assert_eq!(Some((Token::UInt(12345), " +")), next_token("12345 +"));
    assert_eq!(Some((Token::Float(12345.123), "")), next_token("12345.123"));
    assert_eq!(Some((Token::Float(12345.123), "(")),
               next_token("12345.123("));
}
<commit_msg>Remove Copy trait from Token<commit_after>#[derive(Debug, PartialEq, Copy, Clone)]
pub enum TokenError {
    // If a token not a valid number
    // For example "+0a" starts as a number, but contains invalid characters.
    InvalidNumber,
}

#[derive(Debug, PartialEq, Clone)]
pub enum Token<'a> {
    Error((&'a str, TokenError)),
    Whitespace(&'a str),

    Str(&'a str),
    QStr(&'a str),

    OpenBracket,
    CloseBracket,
    OpenBrace,
    CloseBrace,
    OpenCurly,
    CloseCurly,

    UInt(u64),
    SInt(i64),
    Float(f64),
}

#[inline]
fn scan<F: Fn(char) -> bool>(s: &str, cond: F) -> (&str, &str) {
    // split at the first non-"cond" character
    match s.find(|c: char| !cond(c)) {
        None => (s, ""),
        Some(pos) => s.split_at(pos),
    }
}

#[inline]
pub fn is_token_delim(c: char) -> bool {
    c.is_whitespace() || c == '(' || c == ')' || c == '[' || c == ']' || c == '{' || c == '}'
}

// TODO ; comment
fn next_token<'a>(s: &'a str) -> Option<(Token<'a>, &'a str)> {
    match s.slice_shift_char() {
        None => None,
        Some((c, s2)) => {
            match c {
                '(' => Some((Token::OpenBrace, s2)),
                ')' => Some((Token::CloseBrace, s2)),

                '[' => Some((Token::OpenBracket, s2)),
                ']' => Some((Token::CloseBracket, s2)),

                '{' => Some((Token::OpenCurly, s2)),
                '}' => Some((Token::CloseCurly, s2)),

                '"' => {
                    // TODO: QStr
                    None
                }

                c if char::is_whitespace(c) => {
                    let (ws, rest) = scan(s, char::is_whitespace);
                    Some((Token::Whitespace(ws), rest))
                }

                '+' | '-' => {
                    let (string, rest) = scan(s, |ch| !is_token_delim(ch));
                    assert!(string.len() > 0);

                    // parse +|- always as a signed integer first.
                    // this is the way to distinguish a positive signed
                    // integer from a positive unsigned (+1 == SInt, while 1 == UInt).

                    // if it is followed by a digit, this is should be a number.
                    match s2.slice_shift_char() {
                        Some((ch, _)) if char::is_digit(ch, 10) => {
                            // +|- followed by [0-9]. This must be a number!

                            if let Ok(i) = string.parse::<i64>() {
                                Some((Token::SInt(i), rest))
                            } else if let Ok(i) = string.parse::<f64>() {
                                Some((Token::Float(i), rest))
                            } else {
                                Some((Token::Error((string, TokenError::InvalidNumber)), rest))
                            }
                        }
                        _ => {
                            // If it is followed by any other character (or none) it is a valid
                            // string token.
                            // XXX: Check for invalid characters in string.
                            Some((Token::Str(string), rest))
                        }
                    }
                }

                '0'...'9' => {
                    // this should be either a unsigned integer of a floating point number. If not,
                    // it's invalid.
                    let (string, rest) = scan(s, |ch| !is_token_delim(ch));
                    assert!(string.len() > 0);

                    if let Ok(i) = string.parse::<u64>() {
                        Some((Token::UInt(i), rest))
                    } else if let Ok(i) = string.parse::<f64>() {
                        Some((Token::Float(i), rest))
                    } else {
                        Some((Token::Error((string, TokenError::InvalidNumber)), rest))
                    }
                }

                _ => {
                    // this neither starts with '+' or '-' or 'digit'. this is definitively a
                    // string.

                    let (string, rest) = scan(s, |ch| !is_token_delim(ch));
                    assert!(string.len() > 0);

                    // Str
                    Some((Token::Str(string), rest))
                }
            }
        }
    }
}

pub struct Tokenizer<'a> {
    current: &'a str,
    ignore_ws: bool,
}

impl<'a> Tokenizer<'a> {
    pub fn new(s: &'a str, ignore_ws: bool) -> Tokenizer<'a> {
        Tokenizer {
            current: s,
            ignore_ws: ignore_ws,
        }
    }
}

impl<'a> Iterator for Tokenizer<'a> {
    type Item = Token<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            match next_token(self.current) {
                Some((tok, rest)) => {
                    self.current = rest;
                    if self.ignore_ws {
                        if let Token::Whitespace(_) = tok {
                            continue;
                        }
                    }
                    return Some(tok);
                }
                None => {
                    return None;
                }
            }
        }
    }
}

#[test]
fn test_tokenizer_whitespace() {
    let t = Tokenizer::new(" (abc 123)", false);
    let tokens: Vec<_> = t.into_iter().collect();
    assert_eq!(vec![Token::Whitespace(" "),
                    Token::OpenBrace,
                    Token::Str("abc"),
                    Token::Whitespace(" "),
                    Token::UInt(123),
                    Token::CloseBrace],
               tokens);
}

#[test]
fn test_tokenizer_no_whitespace() {
    let t = Tokenizer::new(" (abc 123)", true);
    let tokens: Vec<_> = t.into_iter().collect();
    assert_eq!(vec![Token::OpenBrace, Token::Str("abc"), Token::UInt(123), Token::CloseBrace],
               tokens);
}

#[test]
fn test_token() {
    assert_eq!(Some((Token::Whitespace("  "), "abc")), next_token("  abc"));
    assert_eq!(Some((Token::Str("abc"), "")), next_token("abc"));
    assert_eq!(Some((Token::Str("abc"), "(")), next_token("abc("));

    assert_eq!(Some((Token::OpenBrace, ")")), next_token("()"));

    assert_eq!(Some((Token::UInt(12345), "")), next_token("12345"));
    assert_eq!(Some((Token::UInt(12345), " ")), next_token("12345 "));
    assert_eq!(Some((Token::SInt(12345), " ")), next_token("+12345 "));
    assert_eq!(Some((Token::SInt(-12345), " ")), next_token("-12345 "));
    assert_eq!(Some((Token::Str("-a"), " ")), next_token("-a "));
    assert_eq!(Some((Token::Str("+a"), " ")), next_token("+a "));
    assert_eq!(Some((Token::Str("+a"), "(")), next_token("+a("));

    assert_eq!(Some((Token::Error(("12345+", TokenError::InvalidNumber)), "")),
               next_token("12345+"));
    assert_eq!(Some((Token::UInt(12345), " +")), next_token("12345 +"));
    assert_eq!(Some((Token::Float(12345.123), "")), next_token("12345.123"));
    assert_eq!(Some((Token::Float(12345.123), "(")),
               next_token("12345.123("));
}
<|endoftext|>


<commit_before>use std::fmt;
use std::mem::transmute;
use std::ops::Deref;

use llvm_sys::prelude::*;
use llvm_sys::core::*;
use llvm_sys::*;

use super::*;

/// Enumeration of all the base types of the LLVM type system.
#[allow(non_camel_case_types)]
#[derive(Debug)]
#[repr(C)]
pub enum Kind {
    Void = 0,
    Half,
    Float,
    Double,
    X86_FP80,
    FP128,
    PPC_FP128,
    Label,
    Integer,
    Function,
    Struct,
    Array,
    Pointer,
    Vector,
    Metadata,
    X86_MMX,
    Token,
}

/// Should always be used as `&Type`.
///
/// `Type`s are owned by `Context` instances such that only one instance of a
/// specific `Type` exists per `Context`, e.g. only 1 `Type` for `i64` exists
/// per context. `Type`s are also never mutated and never destroyed, living for
/// the lifetime of the `Context` that owns them.
// TODO: can this be made into an unsized type?
pub struct Type(LLVMType);

impl<'a> Into<&'a Type> for LLVMTypeRef {
    fn into(self) -> &'a Type {
        unsafe { transmute::<LLVMTypeRef, &Type>(self) }
    }
}

impl<'a> From<&'a Type> for LLVMTypeRef {
    fn from(ty: &'a Type) -> LLVMTypeRef {
        unsafe { transmute::<&Type, LLVMTypeRef>(ty) }
    }
}

impl Type {
    pub fn kind(&self) -> Kind {
        unsafe { transmute(LLVMGetTypeKind(self.into())) }
    }

    pub fn is_sized(&self) -> bool {
        unsafe { LLVMTypeIsSized(self.into()) == 1 }
    }
}

// This counts as the llvm::Type::print method from the C++ API, though the C++
// version has more options.
impl fmt::Display for Type {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        unsafe {
            let s_ptr = LLVMPrintTypeToString(self.into());
            let r = write!(f, "{}", c_str_to_str!(s_ptr));
            LLVMDisposeMessage(s_ptr);
            r
        }
    }
}

impl fmt::Debug for Type {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "llvm::Type({})", self)
    }
}

impl PartialEq for Type {
    fn eq(&self, other: &Self) -> bool {
        LLVMTypeRef::from(self) == LLVMTypeRef::from(other)
    }
}

impl Eq for Type {}

macro_rules! impl_type {
    ($t:ty) => {
        impl<'a> Into<&'a $t> for LLVMTypeRef {
            fn into(self) -> &'a $t {
                unsafe { transmute::<LLVMTypeRef, &$t>(self) }
            }
        }

        impl<'a> From<&'a $t> for LLVMTypeRef {
            fn from(ty: &'a $t) -> LLVMTypeRef {
                unsafe { transmute::<&$t, LLVMTypeRef>(ty) }
            }
        }

        impl Deref for $t {
            type Target = Type;

            fn deref(&self) -> &Self::Target {
                unsafe { transmute::<&Self, &Self::Target>(self) }
            }
        }
    }
}

// Base types:

pub struct Void(Type);
impl_type!(Void);

pub struct Half(Type);
impl_type!(Half);

pub struct Float(Type);
impl_type!(Float);

pub struct Double(Type);
impl_type!(Double);

#[allow(non_camel_case_types)]
pub struct X86_FP80(Type);
impl_type!(X86_FP80);

#[allow(non_camel_case_types)]
pub struct FP128(Type);
impl_type!(FP128);

#[allow(non_camel_case_types)]
pub struct PPC_FP128(Type);
impl_type!(PPC_FP128);

pub struct Label(Type);
impl_type!(Label);

pub struct Metadata(Type);
impl_type!(Metadata);

#[allow(non_camel_case_types)]
pub struct X86_MMX(Type);
impl_type!(X86_MMX);

pub struct Token(Type);
impl_type!(Token);

/// Integer types are constructed with a size. Construct them with the methods
/// that `Context` provides.
pub struct Integer(Type);
impl_type!(Integer);

impl Integer {
    pub fn width(&self) -> u32 {
        unsafe { LLVMGetIntTypeWidth(self.into()) }
    }
}

/// A function type is a tuple consisting of a return type and an array of
/// parameter types.
pub struct Function(Type);
impl_type!(Function);

impl Function {
    pub fn new<'a>(
        return_type: &'a Type,
        param_types: &[&'a Type],
        is_var_args: bool,
    ) -> &'a Function {
        unsafe {
            LLVMFunctionType(
                return_type.into(),
                transmute::<*const &Type, *mut LLVMTypeRef>(param_types.as_ptr()),
                param_types.len() as u32,
                is_var_args as LLVMBool,
            ).into()
        }
    }
}

pub struct Struct(Type);
impl_type!(Struct);

pub struct Array(Type);
impl_type!(Array);

pub struct Pointer(Type);
impl_type!(Pointer);

pub struct Vector(Type);
impl_type!(Vector);

/// Represents a LLVM Context Type
pub trait ContextType {
    fn get_type_in_context<'a>(context: &'a Context) -> &'a Type;
}

macro_rules! impl_context_type {
    ($t: ty, $to_type_in_context: ident) => {
        impl ContextType for $t {
            fn get_type_in_context<'a>(context: &'a Context) -> &'a Type {
                unsafe {
                    $to_type_in_context(context.ptr).into()
                }
            }
        }
    }
}

impl_context_type!(bool, LLVMInt1TypeInContext);
// This might actually not be true, Not sure
impl_context_type!(char, LLVMInt8TypeInContext);
impl_context_type!(u8, LLVMInt8TypeInContext);
impl_context_type!(u16, LLVMInt16TypeInContext);
impl_context_type!(u32, LLVMInt32TypeInContext);
impl_context_type!(u64, LLVMInt64TypeInContext);
impl_context_type!(i8, LLVMInt8TypeInContext);
impl_context_type!(i16, LLVMInt16TypeInContext);
impl_context_type!(i32, LLVMInt32TypeInContext);
impl_context_type!(i64, LLVMInt64TypeInContext);
impl_context_type!(f32, LLVMFloatTypeInContext);
impl_context_type!(f64, LLVMDoubleTypeInContext);
//TODO: Function Types
//TODO: Structure Types
//TODO: Sequential Types
//TODO: Other Types
<commit_msg>add note about this impl<commit_after>use std::fmt;
use std::mem::transmute;
use std::ops::Deref;

use llvm_sys::prelude::*;
use llvm_sys::core::*;
use llvm_sys::*;

use super::*;

/// Enumeration of all the base types of the LLVM type system.
#[allow(non_camel_case_types)]
#[derive(Debug)]
#[repr(C)]
pub enum Kind {
    Void = 0,
    Half,
    Float,
    Double,
    X86_FP80,
    FP128,
    PPC_FP128,
    Label,
    Integer,
    Function,
    Struct,
    Array,
    Pointer,
    Vector,
    Metadata,
    X86_MMX,
    Token,
}

/// Should always be used as `&Type`.
///
/// `Type`s are owned by `Context` instances such that only one instance of a
/// specific `Type` exists per `Context`, e.g. only 1 `Type` for `i64` exists
/// per context. `Type`s are also never mutated and never destroyed, living for
/// the lifetime of the `Context` that owns them.
// TODO: can this be made into an unsized type?
pub struct Type(LLVMType);

impl<'a> Into<&'a Type> for LLVMTypeRef {
    fn into(self) -> &'a Type {
        unsafe { transmute::<LLVMTypeRef, &Type>(self) }
    }
}

impl<'a> From<&'a Type> for LLVMTypeRef {
    fn from(ty: &'a Type) -> LLVMTypeRef {
        unsafe { transmute::<&Type, LLVMTypeRef>(ty) }
    }
}

impl Type {
    pub fn kind(&self) -> Kind {
        unsafe { transmute(LLVMGetTypeKind(self.into())) }
    }

    pub fn is_sized(&self) -> bool {
        unsafe { LLVMTypeIsSized(self.into()) == 1 }
    }
}

// This counts as the llvm::Type::print method from the C++ API, though the C++
// version has more options.
impl fmt::Display for Type {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        unsafe {
            let s_ptr = LLVMPrintTypeToString(self.into());
            let r = write!(f, "{}", c_str_to_str!(s_ptr));
            LLVMDisposeMessage(s_ptr);
            r
        }
    }
}

impl fmt::Debug for Type {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "llvm::Type({})", self)
    }
}

impl PartialEq for Type {
    fn eq(&self, other: &Self) -> bool {
        LLVMTypeRef::from(self) == LLVMTypeRef::from(other)
    }
}

impl Eq for Type {}

macro_rules! impl_type {
    ($t:ty) => {
        impl<'a> Into<&'a $t> for LLVMTypeRef {
            fn into(self) -> &'a $t {
                unsafe { transmute::<LLVMTypeRef, &$t>(self) }
            }
        }

        // This would not be needed if the compiler could infer that the
        // From<&Type> for LLVMTypeRef above worked on &SubType.
        impl<'a> From<&'a $t> for LLVMTypeRef {
            fn from(ty: &'a $t) -> LLVMTypeRef {
                unsafe { transmute::<&$t, LLVMTypeRef>(ty) }
            }
        }

        impl Deref for $t {
            type Target = Type;

            fn deref(&self) -> &Self::Target {
                unsafe { transmute::<&Self, &Self::Target>(self) }
            }
        }
    }
}

// Base types:

pub struct Void(Type);
impl_type!(Void);

pub struct Half(Type);
impl_type!(Half);

pub struct Float(Type);
impl_type!(Float);

pub struct Double(Type);
impl_type!(Double);

#[allow(non_camel_case_types)]
pub struct X86_FP80(Type);
impl_type!(X86_FP80);

#[allow(non_camel_case_types)]
pub struct FP128(Type);
impl_type!(FP128);

#[allow(non_camel_case_types)]
pub struct PPC_FP128(Type);
impl_type!(PPC_FP128);

pub struct Label(Type);
impl_type!(Label);

pub struct Metadata(Type);
impl_type!(Metadata);

#[allow(non_camel_case_types)]
pub struct X86_MMX(Type);
impl_type!(X86_MMX);

pub struct Token(Type);
impl_type!(Token);

/// Integer types are constructed with a size. Construct them with the methods
/// that `Context` provides.
pub struct Integer(Type);
impl_type!(Integer);

impl Integer {
    pub fn width(&self) -> u32 {
        unsafe { LLVMGetIntTypeWidth(self.into()) }
    }
}

/// A function type is a tuple consisting of a return type and an array of
/// parameter types.
pub struct Function(Type);
impl_type!(Function);

impl Function {
    pub fn new<'a>(
        return_type: &'a Type,
        param_types: &[&'a Type],
        is_var_args: bool,
    ) -> &'a Function {
        unsafe {
            LLVMFunctionType(
                return_type.into(),
                transmute::<*const &Type, *mut LLVMTypeRef>(param_types.as_ptr()),
                param_types.len() as u32,
                is_var_args as LLVMBool,
            ).into()
        }
    }
}

pub struct Struct(Type);
impl_type!(Struct);

pub struct Array(Type);
impl_type!(Array);

pub struct Pointer(Type);
impl_type!(Pointer);

pub struct Vector(Type);
impl_type!(Vector);

/// Represents a LLVM Context Type
pub trait ContextType {
    fn get_type_in_context<'a>(context: &'a Context) -> &'a Type;
}

macro_rules! impl_context_type {
    ($t: ty, $to_type_in_context: ident) => {
        impl ContextType for $t {
            fn get_type_in_context<'a>(context: &'a Context) -> &'a Type {
                unsafe {
                    $to_type_in_context(context.ptr).into()
                }
            }
        }
    }
}

impl_context_type!(bool, LLVMInt1TypeInContext);
// This might actually not be true, Not sure
impl_context_type!(char, LLVMInt8TypeInContext);
impl_context_type!(u8, LLVMInt8TypeInContext);
impl_context_type!(u16, LLVMInt16TypeInContext);
impl_context_type!(u32, LLVMInt32TypeInContext);
impl_context_type!(u64, LLVMInt64TypeInContext);
impl_context_type!(i8, LLVMInt8TypeInContext);
impl_context_type!(i16, LLVMInt16TypeInContext);
impl_context_type!(i32, LLVMInt32TypeInContext);
impl_context_type!(i64, LLVMInt64TypeInContext);
impl_context_type!(f32, LLVMFloatTypeInContext);
impl_context_type!(f64, LLVMDoubleTypeInContext);
//TODO: Function Types
//TODO: Structure Types
//TODO: Sequential Types
//TODO: Other Types
<|endoftext|>


<commit_before>//! Definition of a TOML value

use std::collections::{BTreeMap, HashMap};
use std::hash::Hash;
use std::mem::discriminant;
use std::ops;
use std::str::FromStr;

pub use crate::easy::datetime::*;
pub use crate::easy::map::Map;

/// Representation of a TOML value.
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
#[serde(untagged)]
pub enum Value {
    /// Represents a TOML integer
    Integer(i64),
    /// Represents a TOML float
    Float(f64),
    /// Represents a TOML boolean
    Boolean(bool),
    /// Represents a TOML datetime
    Datetime(Datetime),
    /// Represents a TOML string
    String(String),
    /// Represents a TOML array
    Array(Array),
    /// Represents a TOML table
    Table(Table),
}

/// Type representing a TOML array, payload of the `Value::Array` variant
pub type Array = Vec<Value>;

/// Type representing a TOML table, payload of the `Value::Table` variant.
/// By default it is backed by a BTreeMap, enable the `preserve_order` feature
/// to use a LinkedHashMap instead.
pub type Table = Map<String, Value>;

impl Value {
    /// Convert a `T` into `toml::Value` which is an enum that can represent
    /// any valid TOML data.
    ///
    /// This conversion can fail if `T`'s implementation of `Serialize` decides to
    /// fail, or if `T` contains a map with non-string keys.
    pub fn try_from<T>(value: T) -> Result<Value, crate::TomlError>
    where
        T: serde::ser::Serialize,
    {
        let doc = super::to_document(&value)?;
        let value = super::from_document(doc)?;
        Ok(value)
    }

    /// Interpret a `toml::Value` as an instance of type `T`.
    ///
    /// This conversion can fail if the structure of the `Value` does not match the
    /// structure expected by `T`, for example if `T` is a struct type but the
    /// `Value` contains something other than a TOML table. It can also fail if the
    /// structure is correct but `T`'s implementation of `Deserialize` decides that
    /// something is wrong with the data, for example required struct fields are
    /// missing from the TOML map or some number is too big to fit in the expected
    /// primitive type.
    pub fn try_into<T>(self) -> Result<T, crate::TomlError>
    where
        T: serde::de::Deserialize<'static>,
    {
        let doc = super::to_document(&self)?;
        let value = super::from_document(doc)?;
        Ok(value)
    }

    /// Index into a TOML array or map. A string index can be used to access a
    /// value in a map, and a usize index can be used to access an element of an
    /// array.
    ///
    /// Returns `None` if the type of `self` does not match the type of the
    /// index, for example if the index is a string and `self` is an array or a
    /// number. Also returns `None` if the given key does not exist in the map
    /// or the given index is not within the bounds of the array.
    pub fn get<I: Index>(&self, index: I) -> Option<&Value> {
        index.index(self)
    }

    /// Mutably index into a TOML array or map. A string index can be used to
    /// access a value in a map, and a usize index can be used to access an
    /// element of an array.
    ///
    /// Returns `None` if the type of `self` does not match the type of the
    /// index, for example if the index is a string and `self` is an array or a
    /// number. Also returns `None` if the given key does not exist in the map
    /// or the given index is not within the bounds of the array.
    pub fn get_mut<I: Index>(&mut self, index: I) -> Option<&mut Value> {
        index.index_mut(self)
    }

    /// Extracts the integer value if it is an integer.
    pub fn as_integer(&self) -> Option<i64> {
        match *self {
            Value::Integer(i) => Some(i),
            _ => None,
        }
    }

    /// Tests whether this value is an integer.
    pub fn is_integer(&self) -> bool {
        self.as_integer().is_some()
    }

    /// Extracts the float value if it is a float.
    pub fn as_float(&self) -> Option<f64> {
        match *self {
            Value::Float(f) => Some(f),
            _ => None,
        }
    }

    /// Tests whether this value is a float.
    pub fn is_float(&self) -> bool {
        self.as_float().is_some()
    }

    /// Extracts the boolean value if it is a boolean.
    pub fn as_bool(&self) -> Option<bool> {
        match *self {
            Value::Boolean(b) => Some(b),
            _ => None,
        }
    }

    /// Tests whether this value is a boolean.
    pub fn is_bool(&self) -> bool {
        self.as_bool().is_some()
    }

    /// Extracts the string of this value if it is a string.
    pub fn as_str(&self) -> Option<&str> {
        match *self {
            Value::String(ref s) => Some(&**s),
            _ => None,
        }
    }

    /// Tests if this value is a string.
    pub fn is_str(&self) -> bool {
        self.as_str().is_some()
    }

    /// Extracts the datetime value if it is a datetime.
    ///
    /// Note that a parsed TOML value will only contain ISO 8601 dates. An
    /// example date is:
    ///
    /// ```notrust
    /// 1979-05-27T07:32:00Z
    /// ```
    pub fn as_datetime(&self) -> Option<&Datetime> {
        match *self {
            Value::Datetime(ref s) => Some(s),
            _ => None,
        }
    }

    /// Tests whether this value is a datetime.
    pub fn is_datetime(&self) -> bool {
        self.as_datetime().is_some()
    }

    /// Extracts the array value if it is an array.
    pub fn as_array(&self) -> Option<&Vec<Value>> {
        match *self {
            Value::Array(ref s) => Some(s),
            _ => None,
        }
    }

    /// Extracts the array value if it is an array.
    pub fn as_array_mut(&mut self) -> Option<&mut Vec<Value>> {
        match *self {
            Value::Array(ref mut s) => Some(s),
            _ => None,
        }
    }

    /// Tests whether this value is an array.
    pub fn is_array(&self) -> bool {
        self.as_array().is_some()
    }

    /// Extracts the table value if it is a table.
    pub fn as_table(&self) -> Option<&Table> {
        match *self {
            Value::Table(ref s) => Some(s),
            _ => None,
        }
    }

    /// Extracts the table value if it is a table.
    pub fn as_table_mut(&mut self) -> Option<&mut Table> {
        match *self {
            Value::Table(ref mut s) => Some(s),
            _ => None,
        }
    }

    /// Tests whether this value is a table.
    pub fn is_table(&self) -> bool {
        self.as_table().is_some()
    }

    /// Tests whether this and another value have the same type.
    pub fn same_type(&self, other: &Value) -> bool {
        discriminant(self) == discriminant(other)
    }

    /// Returns a human-readable representation of the type of this value.
    pub fn type_str(&self) -> &'static str {
        match *self {
            Value::String(..) => "string",
            Value::Integer(..) => "integer",
            Value::Float(..) => "float",
            Value::Boolean(..) => "boolean",
            Value::Datetime(..) => "datetime",
            Value::Array(..) => "array",
            Value::Table(..) => "table",
        }
    }
}

impl std::fmt::Display for Value {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        super::to_string_pretty(self)
            .map_err(|_| std::fmt::Error)?
            .fmt(f)
    }
}

impl<I> ops::Index<I> for Value
where
    I: Index,
{
    type Output = Value;

    fn index(&self, index: I) -> &Value {
        self.get(index).expect("index not found")
    }
}

impl<I> ops::IndexMut<I> for Value
where
    I: Index,
{
    fn index_mut(&mut self, index: I) -> &mut Value {
        self.get_mut(index).expect("index not found")
    }
}

impl<'a> From<&'a str> for Value {
    #[inline]
    fn from(val: &'a str) -> Value {
        Value::String(val.to_string())
    }
}

impl<V: Into<Value>> From<Vec<V>> for Value {
    fn from(val: Vec<V>) -> Value {
        Value::Array(val.into_iter().map(|v| v.into()).collect())
    }
}

impl<S: Into<String>, V: Into<Value>> From<BTreeMap<S, V>> for Value {
    fn from(val: BTreeMap<S, V>) -> Value {
        let table = val.into_iter().map(|(s, v)| (s.into(), v.into())).collect();

        Value::Table(table)
    }
}

impl<S: Into<String> + Hash + Eq, V: Into<Value>> From<HashMap<S, V>> for Value {
    fn from(val: HashMap<S, V>) -> Value {
        let table = val.into_iter().map(|(s, v)| (s.into(), v.into())).collect();

        Value::Table(table)
    }
}

macro_rules! impl_into_value {
    ($variant:ident : $T:ty) => {
        impl From<$T> for Value {
            #[inline]
            fn from(val: $T) -> Value {
                Value::$variant(val.into())
            }
        }
    };
}

impl_into_value!(String: String);
impl_into_value!(Integer: i64);
impl_into_value!(Integer: i32);
impl_into_value!(Integer: i8);
impl_into_value!(Integer: u8);
impl_into_value!(Integer: u32);
impl_into_value!(Float: f64);
impl_into_value!(Float: f32);
impl_into_value!(Boolean: bool);
impl_into_value!(Datetime: Datetime);
impl_into_value!(Table: Table);

/// Types that can be used to index a `toml_edit::easy::Value`
///
/// Currently this is implemented for `usize` to index arrays and `str` to index
/// tables.
///
/// This trait is sealed and not intended for implementation outside of the
/// `toml` crate.
pub trait Index: crate::private::Sealed {
    #[doc(hidden)]
    fn index<'a>(&self, val: &'a Value) -> Option<&'a Value>;
    #[doc(hidden)]
    fn index_mut<'a>(&self, val: &'a mut Value) -> Option<&'a mut Value>;
}

impl Index for usize {
    fn index<'a>(&self, val: &'a Value) -> Option<&'a Value> {
        match *val {
            Value::Array(ref a) => a.get(*self),
            _ => None,
        }
    }

    fn index_mut<'a>(&self, val: &'a mut Value) -> Option<&'a mut Value> {
        match *val {
            Value::Array(ref mut a) => a.get_mut(*self),
            _ => None,
        }
    }
}

impl Index for str {
    fn index<'a>(&self, val: &'a Value) -> Option<&'a Value> {
        match *val {
            Value::Table(ref a) => a.get(self),
            _ => None,
        }
    }

    fn index_mut<'a>(&self, val: &'a mut Value) -> Option<&'a mut Value> {
        match *val {
            Value::Table(ref mut a) => a.get_mut(self),
            _ => None,
        }
    }
}

impl Index for String {
    fn index<'a>(&self, val: &'a Value) -> Option<&'a Value> {
        self[..].index(val)
    }

    fn index_mut<'a>(&self, val: &'a mut Value) -> Option<&'a mut Value> {
        self[..].index_mut(val)
    }
}

impl<'s, T: ?Sized> Index for &'s T
where
    T: Index,
{
    fn index<'a>(&self, val: &'a Value) -> Option<&'a Value> {
        (**self).index(val)
    }

    fn index_mut<'a>(&self, val: &'a mut Value) -> Option<&'a mut Value> {
        (**self).index_mut(val)
    }
}

impl FromStr for Value {
    type Err = crate::easy::de::Error;
    fn from_str(s: &str) -> Result<Value, Self::Err> {
        crate::easy::from_str(s)
    }
}
<commit_msg>perf(easy): Hand-optimize `easy::Value` serde support (#227)<commit_after>//! Definition of a TOML value

use std::collections::{BTreeMap, HashMap};
use std::hash::Hash;
use std::mem::discriminant;
use std::ops;
use std::str::FromStr;

pub use crate::easy::datetime::*;
use crate::easy::map::Entry;
pub use crate::easy::map::Map;

/// Representation of a TOML value.
#[derive(PartialEq, Clone, Debug, serde::Serialize)]
#[serde(untagged)]
pub enum Value {
    /// Represents a TOML integer
    Integer(i64),
    /// Represents a TOML float
    Float(f64),
    /// Represents a TOML boolean
    Boolean(bool),
    /// Represents a TOML datetime
    Datetime(Datetime),
    /// Represents a TOML string
    String(String),
    /// Represents a TOML array
    Array(Array),
    /// Represents a TOML table
    Table(Table),
}

/// Type representing a TOML array, payload of the `Value::Array` variant
pub type Array = Vec<Value>;

/// Type representing a TOML table, payload of the `Value::Table` variant.
/// By default it is backed by a BTreeMap, enable the `preserve_order` feature
/// to use a LinkedHashMap instead.
pub type Table = Map<String, Value>;

impl Value {
    /// Convert a `T` into `toml::Value` which is an enum that can represent
    /// any valid TOML data.
    ///
    /// This conversion can fail if `T`'s implementation of `Serialize` decides to
    /// fail, or if `T` contains a map with non-string keys.
    pub fn try_from<T>(value: T) -> Result<Value, crate::TomlError>
    where
        T: serde::ser::Serialize,
    {
        let doc = super::to_document(&value)?;
        let value = super::from_document(doc)?;
        Ok(value)
    }

    /// Interpret a `toml::Value` as an instance of type `T`.
    ///
    /// This conversion can fail if the structure of the `Value` does not match the
    /// structure expected by `T`, for example if `T` is a struct type but the
    /// `Value` contains something other than a TOML table. It can also fail if the
    /// structure is correct but `T`'s implementation of `Deserialize` decides that
    /// something is wrong with the data, for example required struct fields are
    /// missing from the TOML map or some number is too big to fit in the expected
    /// primitive type.
    pub fn try_into<T>(self) -> Result<T, crate::TomlError>
    where
        T: serde::de::Deserialize<'static>,
    {
        let doc = super::to_document(&self)?;
        let value = super::from_document(doc)?;
        Ok(value)
    }

    /// Index into a TOML array or map. A string index can be used to access a
    /// value in a map, and a usize index can be used to access an element of an
    /// array.
    ///
    /// Returns `None` if the type of `self` does not match the type of the
    /// index, for example if the index is a string and `self` is an array or a
    /// number. Also returns `None` if the given key does not exist in the map
    /// or the given index is not within the bounds of the array.
    pub fn get<I: Index>(&self, index: I) -> Option<&Value> {
        index.index(self)
    }

    /// Mutably index into a TOML array or map. A string index can be used to
    /// access a value in a map, and a usize index can be used to access an
    /// element of an array.
    ///
    /// Returns `None` if the type of `self` does not match the type of the
    /// index, for example if the index is a string and `self` is an array or a
    /// number. Also returns `None` if the given key does not exist in the map
    /// or the given index is not within the bounds of the array.
    pub fn get_mut<I: Index>(&mut self, index: I) -> Option<&mut Value> {
        index.index_mut(self)
    }

    /// Extracts the integer value if it is an integer.
    pub fn as_integer(&self) -> Option<i64> {
        match *self {
            Value::Integer(i) => Some(i),
            _ => None,
        }
    }

    /// Tests whether this value is an integer.
    pub fn is_integer(&self) -> bool {
        self.as_integer().is_some()
    }

    /// Extracts the float value if it is a float.
    pub fn as_float(&self) -> Option<f64> {
        match *self {
            Value::Float(f) => Some(f),
            _ => None,
        }
    }

    /// Tests whether this value is a float.
    pub fn is_float(&self) -> bool {
        self.as_float().is_some()
    }

    /// Extracts the boolean value if it is a boolean.
    pub fn as_bool(&self) -> Option<bool> {
        match *self {
            Value::Boolean(b) => Some(b),
            _ => None,
        }
    }

    /// Tests whether this value is a boolean.
    pub fn is_bool(&self) -> bool {
        self.as_bool().is_some()
    }

    /// Extracts the string of this value if it is a string.
    pub fn as_str(&self) -> Option<&str> {
        match *self {
            Value::String(ref s) => Some(&**s),
            _ => None,
        }
    }

    /// Tests if this value is a string.
    pub fn is_str(&self) -> bool {
        self.as_str().is_some()
    }

    /// Extracts the datetime value if it is a datetime.
    ///
    /// Note that a parsed TOML value will only contain ISO 8601 dates. An
    /// example date is:
    ///
    /// ```notrust
    /// 1979-05-27T07:32:00Z
    /// ```
    pub fn as_datetime(&self) -> Option<&Datetime> {
        match *self {
            Value::Datetime(ref s) => Some(s),
            _ => None,
        }
    }

    /// Tests whether this value is a datetime.
    pub fn is_datetime(&self) -> bool {
        self.as_datetime().is_some()
    }

    /// Extracts the array value if it is an array.
    pub fn as_array(&self) -> Option<&Vec<Value>> {
        match *self {
            Value::Array(ref s) => Some(s),
            _ => None,
        }
    }

    /// Extracts the array value if it is an array.
    pub fn as_array_mut(&mut self) -> Option<&mut Vec<Value>> {
        match *self {
            Value::Array(ref mut s) => Some(s),
            _ => None,
        }
    }

    /// Tests whether this value is an array.
    pub fn is_array(&self) -> bool {
        self.as_array().is_some()
    }

    /// Extracts the table value if it is a table.
    pub fn as_table(&self) -> Option<&Table> {
        match *self {
            Value::Table(ref s) => Some(s),
            _ => None,
        }
    }

    /// Extracts the table value if it is a table.
    pub fn as_table_mut(&mut self) -> Option<&mut Table> {
        match *self {
            Value::Table(ref mut s) => Some(s),
            _ => None,
        }
    }

    /// Tests whether this value is a table.
    pub fn is_table(&self) -> bool {
        self.as_table().is_some()
    }

    /// Tests whether this and another value have the same type.
    pub fn same_type(&self, other: &Value) -> bool {
        discriminant(self) == discriminant(other)
    }

    /// Returns a human-readable representation of the type of this value.
    pub fn type_str(&self) -> &'static str {
        match *self {
            Value::String(..) => "string",
            Value::Integer(..) => "integer",
            Value::Float(..) => "float",
            Value::Boolean(..) => "boolean",
            Value::Datetime(..) => "datetime",
            Value::Array(..) => "array",
            Value::Table(..) => "table",
        }
    }
}

impl std::fmt::Display for Value {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        super::to_string_pretty(self)
            .map_err(|_| std::fmt::Error)?
            .fmt(f)
    }
}

impl<I> ops::Index<I> for Value
where
    I: Index,
{
    type Output = Value;

    fn index(&self, index: I) -> &Value {
        self.get(index).expect("index not found")
    }
}

impl<I> ops::IndexMut<I> for Value
where
    I: Index,
{
    fn index_mut(&mut self, index: I) -> &mut Value {
        self.get_mut(index).expect("index not found")
    }
}

impl<'a> From<&'a str> for Value {
    #[inline]
    fn from(val: &'a str) -> Value {
        Value::String(val.to_string())
    }
}

impl<V: Into<Value>> From<Vec<V>> for Value {
    fn from(val: Vec<V>) -> Value {
        Value::Array(val.into_iter().map(|v| v.into()).collect())
    }
}

impl<S: Into<String>, V: Into<Value>> From<BTreeMap<S, V>> for Value {
    fn from(val: BTreeMap<S, V>) -> Value {
        let table = val.into_iter().map(|(s, v)| (s.into(), v.into())).collect();

        Value::Table(table)
    }
}

impl<S: Into<String> + Hash + Eq, V: Into<Value>> From<HashMap<S, V>> for Value {
    fn from(val: HashMap<S, V>) -> Value {
        let table = val.into_iter().map(|(s, v)| (s.into(), v.into())).collect();

        Value::Table(table)
    }
}

macro_rules! impl_into_value {
    ($variant:ident : $T:ty) => {
        impl From<$T> for Value {
            #[inline]
            fn from(val: $T) -> Value {
                Value::$variant(val.into())
            }
        }
    };
}

impl_into_value!(String: String);
impl_into_value!(Integer: i64);
impl_into_value!(Integer: i32);
impl_into_value!(Integer: i8);
impl_into_value!(Integer: u8);
impl_into_value!(Integer: u32);
impl_into_value!(Float: f64);
impl_into_value!(Float: f32);
impl_into_value!(Boolean: bool);
impl_into_value!(Datetime: Datetime);
impl_into_value!(Table: Table);

/// Types that can be used to index a `toml_edit::easy::Value`
///
/// Currently this is implemented for `usize` to index arrays and `str` to index
/// tables.
///
/// This trait is sealed and not intended for implementation outside of the
/// `toml` crate.
pub trait Index: crate::private::Sealed {
    #[doc(hidden)]
    fn index<'a>(&self, val: &'a Value) -> Option<&'a Value>;
    #[doc(hidden)]
    fn index_mut<'a>(&self, val: &'a mut Value) -> Option<&'a mut Value>;
}

impl Index for usize {
    fn index<'a>(&self, val: &'a Value) -> Option<&'a Value> {
        match *val {
            Value::Array(ref a) => a.get(*self),
            _ => None,
        }
    }

    fn index_mut<'a>(&self, val: &'a mut Value) -> Option<&'a mut Value> {
        match *val {
            Value::Array(ref mut a) => a.get_mut(*self),
            _ => None,
        }
    }
}

impl Index for str {
    fn index<'a>(&self, val: &'a Value) -> Option<&'a Value> {
        match *val {
            Value::Table(ref a) => a.get(self),
            _ => None,
        }
    }

    fn index_mut<'a>(&self, val: &'a mut Value) -> Option<&'a mut Value> {
        match *val {
            Value::Table(ref mut a) => a.get_mut(self),
            _ => None,
        }
    }
}

impl Index for String {
    fn index<'a>(&self, val: &'a Value) -> Option<&'a Value> {
        self[..].index(val)
    }

    fn index_mut<'a>(&self, val: &'a mut Value) -> Option<&'a mut Value> {
        self[..].index_mut(val)
    }
}

impl<'s, T: ?Sized> Index for &'s T
where
    T: Index,
{
    fn index<'a>(&self, val: &'a Value) -> Option<&'a Value> {
        (**self).index(val)
    }

    fn index_mut<'a>(&self, val: &'a mut Value) -> Option<&'a mut Value> {
        (**self).index_mut(val)
    }
}

impl FromStr for Value {
    type Err = crate::easy::de::Error;
    fn from_str(s: &str) -> Result<Value, Self::Err> {
        crate::easy::from_str(s)
    }
}

impl<'de> serde::de::Deserialize<'de> for Value {
    fn deserialize<D>(deserializer: D) -> Result<Value, D::Error>
    where
        D: serde::de::Deserializer<'de>,
    {
        struct ValueVisitor;

        impl<'de> serde::de::Visitor<'de> for ValueVisitor {
            type Value = Value;

            fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
                formatter.write_str("any valid TOML value")
            }

            fn visit_bool<E>(self, value: bool) -> Result<Value, E> {
                Ok(Value::Boolean(value))
            }

            fn visit_i64<E>(self, value: i64) -> Result<Value, E> {
                Ok(Value::Integer(value))
            }

            fn visit_u64<E: serde::de::Error>(self, value: u64) -> Result<Value, E> {
                if value <= i64::max_value() as u64 {
                    Ok(Value::Integer(value as i64))
                } else {
                    Err(serde::de::Error::custom("u64 value was too large"))
                }
            }

            fn visit_u32<E>(self, value: u32) -> Result<Value, E> {
                Ok(Value::Integer(value.into()))
            }

            fn visit_i32<E>(self, value: i32) -> Result<Value, E> {
                Ok(Value::Integer(value.into()))
            }

            fn visit_f64<E>(self, value: f64) -> Result<Value, E> {
                Ok(Value::Float(value))
            }

            fn visit_str<E>(self, value: &str) -> Result<Value, E> {
                Ok(Value::String(value.into()))
            }

            fn visit_string<E>(self, value: String) -> Result<Value, E> {
                Ok(Value::String(value))
            }

            fn visit_some<D>(self, deserializer: D) -> Result<Value, D::Error>
            where
                D: serde::de::Deserializer<'de>,
            {
                serde::de::Deserialize::deserialize(deserializer)
            }

            fn visit_seq<V>(self, mut visitor: V) -> Result<Value, V::Error>
            where
                V: serde::de::SeqAccess<'de>,
            {
                let mut vec = Vec::new();
                while let Some(elem) = visitor.next_element()? {
                    vec.push(elem);
                }
                Ok(Value::Array(vec))
            }

            fn visit_map<V>(self, mut visitor: V) -> Result<Value, V::Error>
            where
                V: serde::de::MapAccess<'de>,
            {
                let mut key = String::new();
                let datetime = visitor.next_key_seed(DatetimeOrTable { key: &mut key })?;
                match datetime {
                    Some(true) => {
                        let date: String = visitor.next_value()?;
                        let date = date.parse::<Datetime>().map_err(serde::de::Error::custom)?;
                        return Ok(Value::Datetime(date));
                    }
                    None => return Ok(Value::Table(Map::new())),
                    Some(false) => {}
                }
                let mut map = Map::new();
                map.insert(key, visitor.next_value()?);
                while let Some(key) = visitor.next_key::<String>()? {
                    if let Entry::Vacant(vacant) = map.entry(&key) {
                        vacant.insert(visitor.next_value()?);
                    } else {
                        let msg = format!("duplicate key: `{}`", key);
                        return Err(serde::de::Error::custom(msg));
                    }
                }
                Ok(Value::Table(map))
            }
        }

        deserializer.deserialize_any(ValueVisitor)
    }
}

struct DatetimeOrTable<'a> {
    key: &'a mut String,
}

impl<'a, 'de> serde::de::DeserializeSeed<'de> for DatetimeOrTable<'a> {
    type Value = bool;

    fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
    where
        D: serde::de::Deserializer<'de>,
    {
        deserializer.deserialize_any(self)
    }
}

impl<'a, 'de> serde::de::Visitor<'de> for DatetimeOrTable<'a> {
    type Value = bool;

    fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        formatter.write_str("a string key")
    }

    fn visit_str<E>(self, s: &str) -> Result<bool, E>
    where
        E: serde::de::Error,
    {
        if s == crate::datetime::dt_serde::FIELD {
            Ok(true)
        } else {
            self.key.push_str(s);
            Ok(false)
        }
    }

    fn visit_string<E>(self, s: String) -> Result<bool, E>
    where
        E: serde::de::Error,
    {
        if s == crate::datetime::dt_serde::FIELD {
            Ok(true)
        } else {
            *self.key = s;
            Ok(false)
        }
    }
}
<|endoftext|>


<commit_before>use std::fs::{File, remove_file};
use std::io::{ErrorKind, Read, Write};

use rusoto::{AwsResult, ChainProvider, Region};
use rusoto::kms::{
    DecryptRequest,
    DecryptResponse,
    EncryptRequest,
    EncryptResponse,
    KMSClient,
};

use error::{KawsError, KawsResult};

pub struct Encryptor<'a> {
    client: KMSClient<'a>,
    decrypted_files: Vec<String>,
    kms_master_key_id: &'a str,
}

impl<'a> Encryptor<'a> {
    pub fn new(
        provider: ChainProvider,
        region: &'a Region,
        kms_master_key_id: &'a str,
    ) -> Encryptor<'a> {
        Encryptor {
            client: KMSClient::new(provider, region),
            decrypted_files: vec![],
            kms_master_key_id: kms_master_key_id,
        }
    }

    pub fn decrypt<'b>(&mut self, encrypted_data: &'b str) -> AwsResult<DecryptResponse> {
        let request = DecryptRequest {
            encryption_context: None,
            grant_tokens: None,
            ciphertext_blob: encrypted_data.as_bytes().to_vec()
        };

        self.client.decrypt(&request)
    }

    pub fn decrypt_file<'b>(&mut self, source: &'b str, destination: &'b str) -> KawsResult {
        let mut src = try!(File::open(source));

        let mut encrypted_data = String::new();

        try!(src.read_to_string(&mut encrypted_data));

        let decrypted_data = try!(self.decrypt(&encrypted_data));

        let mut dst = try!(File::create(destination));

        match decrypted_data.plaintext {
            Some(ref plaintext) => try!(dst.write_all(plaintext)),
            None => return Err(KawsError::new("No plaintext was returned from KMS".to_owned())),
        }

        self.decrypted_files.push(destination.to_string());

        Ok(None)
    }

    pub fn encrypt<'b>(&mut self, decrypted_data: &'b str) -> AwsResult<EncryptResponse> {
        let request = EncryptRequest {
            plaintext: decrypted_data.as_bytes().to_vec(),
            encryption_context: None,
            key_id: self.kms_master_key_id.to_owned(),
            grant_tokens: None,
        };

        self.client.encrypt(&request)
    }

    pub fn encrypt_file<'b>(&mut self, source: &'b str, destination: &'b str) -> KawsResult {
        let mut src = try!(File::open(source));

        let mut contents = String::new();

        try!(src.read_to_string(&mut contents));

        let encrypted_data = try!(self.encrypt(&contents));

        let mut dst = try!(File::create(destination));

        match encrypted_data.ciphertext_blob {
            Some(ref ciphertext_blob) => try!(dst.write_all(ciphertext_blob)),
            None => return Err(KawsError::new("No ciphertext was returned from KMS".to_owned())),
        }

        Ok(None)
    }
}

impl<'a> Drop for Encryptor<'a> {
    fn drop(&mut self) {
        let mut failures = vec![];

        for file in self.decrypted_files.iter() {
            log_wrap!(&format!("Removing unencrypted file {:?}", file), {
                if let Err(error) = remove_file(file) {
                    match error.kind() {
                        ErrorKind::NotFound => {},
                        _ => failures.push(error),
                    }
                }
            });
        }

        if !failures.is_empty() {
            panic!(
                "Failed to remove one or more encrypted files! You should remove these files \
                manually if they are present: {:?}",
                failures,
            );
        }
    }
}
<commit_msg>Remove source files after encrypting.<commit_after>use std::fs::{File, remove_file};
use std::io::{ErrorKind, Read, Write};

use rusoto::{AwsResult, ChainProvider, Region};
use rusoto::kms::{
    DecryptRequest,
    DecryptResponse,
    EncryptRequest,
    EncryptResponse,
    KmsClient,
};

use error::{KawsError, KawsResult};

pub struct Encryptor<'a> {
    client: KmsClient<'a>,
    decrypted_files: Vec<String>,
    kms_master_key_id: &'a str,
}

impl<'a> Encryptor<'a> {
    pub fn new(
        provider: ChainProvider,
        region: &'a Region,
        kms_master_key_id: &'a str,
    ) -> Encryptor<'a> {
        Encryptor {
            client: KmsClient::new(provider, region),
            decrypted_files: vec![],
            kms_master_key_id: kms_master_key_id,
        }
    }

    pub fn decrypt<'b>(&mut self, encrypted_data: &'b str) -> AwsResult<DecryptResponse> {
        let request = DecryptRequest {
            encryption_context: None,
            grant_tokens: None,
            ciphertext_blob: encrypted_data.as_bytes().to_vec()
        };

        self.client.decrypt(&request)
    }

    pub fn decrypt_file<'b>(&mut self, source: &'b str, destination: &'b str) -> KawsResult {
        let mut src = try!(File::open(source));

        let mut encrypted_data = String::new();

        try!(src.read_to_string(&mut encrypted_data));

        let decrypted_data = try!(self.decrypt(&encrypted_data));

        let mut dst = try!(File::create(destination));

        match decrypted_data.plaintext {
            Some(ref plaintext) => try!(dst.write_all(plaintext)),
            None => return Err(KawsError::new("No plaintext was returned from KMS".to_owned())),
        }

        self.decrypted_files.push(destination.to_owned());

        Ok(None)
    }

    pub fn encrypt<'b>(&mut self, decrypted_data: &'b str) -> AwsResult<EncryptResponse> {
        let request = EncryptRequest {
            plaintext: decrypted_data.as_bytes().to_vec(),
            encryption_context: None,
            key_id: self.kms_master_key_id.to_owned(),
            grant_tokens: None,
        };

        self.client.encrypt(&request)
    }

    pub fn encrypt_file<'b>(&mut self, source: &'b str, destination: &'b str) -> KawsResult {
        let mut src = try!(File::open(source));

        let mut contents = String::new();

        try!(src.read_to_string(&mut contents));

        let encrypted_data = try!(self.encrypt(&contents));

        let mut dst = try!(File::create(destination));

        match encrypted_data.ciphertext_blob {
            Some(ref ciphertext_blob) => try!(dst.write_all(ciphertext_blob)),
            None => return Err(KawsError::new("No ciphertext was returned from KMS".to_owned())),
        }

        self.decrypted_files.push(source.to_owned());

        Ok(None)
    }
}

impl<'a> Drop for Encryptor<'a> {
    fn drop(&mut self) {
        let mut failures = vec![];

        for file in self.decrypted_files.iter() {
            log_wrap!(&format!("Removing unencrypted file {:?}", file), {
                if let Err(error) = remove_file(file) {
                    match error.kind() {
                        ErrorKind::NotFound => {},
                        _ => failures.push(error),
                    }
                }
            });
        }

        if !failures.is_empty() {
            panic!(
                "Failed to remove one or more encrypted files! You should remove these files \
                manually if they are present: {:?}",
                failures,
            );
        }
    }
}
<|endoftext|>