<commit_before>//! A large binary allocation for writing and sharing.

use bytes::arc::Bytes;

/// A large binary allocation for writing and sharing.
///
/// A bytes slab wraps a `Bytes` and maintains a valid (written) length, and supports writing after
/// this valid length, and extracting `Bytes` up to this valid length. Extracted bytes are enqueued
/// and checked for uniqueness in order to recycle them (once all shared references are dropped).
pub struct BytesSlab {
    buffer:         Bytes,                      // current working buffer.
    in_progress:    Vec<Option<Bytes>>,         // buffers shared with workers.
    stash:          Vec<Bytes>,                 // reclaimed and resuable buffers.
    shift:          usize,                      // current buffer allocation size.
    valid:          usize,                      // buffer[..valid] are valid bytes.
}

impl BytesSlab {
    /// Allocates a new `BytesSlab` with an initial size determined by a shift.
    pub fn new(shift: usize) -> Self {
        BytesSlab {
            buffer: Bytes::from(vec![0u8; 1 << shift].into_boxed_slice()),
            in_progress: Vec::new(),
            stash: Vec::new(),
            shift,
            valid: 0,
        }
    }
    /// The empty region of the slab.
    pub fn empty(&mut self) -> &mut [u8] {
        &mut self.buffer[self.valid..]
    }
    /// The valid region of the slab.
    pub fn valid(&mut self) -> &mut [u8] {
        &mut self.buffer[..self.valid]
    }
    /// Marks the next `bytes` bytes as valid.
    pub fn make_valid(&mut self, bytes: usize) {
        self.valid += bytes;
    }
    /// Extracts the first `bytes` valid bytes.
    pub fn extract(&mut self, bytes: usize) -> Bytes {
        debug_assert!(bytes <= self.valid);
        self.valid -= bytes;
        self.buffer.extract_to(bytes)
    }

    /// Ensures that `self.empty().len()` is at least `capacity`.
    ///
    /// This method may retire the current buffer if it does not have enough space, in which case
    /// it will copy any remaining contents into a new buffer. If this would not create enough free
    /// space, the shift is increased until it is sufficient.
    pub fn ensure_capacity(&mut self, capacity: usize) {

        if self.empty().len() < capacity {

            // Increase allocation if copy would be insufficient.
            while self.valid + capacity > (1 << self.shift) {
                self.shift += 1;
                self.stash.clear();         // clear wrongly sized buffers.
                self.in_progress.clear();   // clear wrongly sized buffers.
            }

            // Attempt to reclaim shared slices.
            if self.stash.is_empty() {
                for shared in self.in_progress.iter_mut() {
                    if let Some(mut bytes) = shared.take() {
                        if bytes.try_regenerate::<Box<[u8]>>() {
                            self.stash.push(bytes);
                        }
                        else {
                            *shared = Some(bytes);
                        }
                    }
                }
                self.in_progress.retain(|x| x.is_some());
            }

            let new_buffer = self.stash.pop().unwrap_or_else(|| Bytes::from(vec![0; 1 << self.shift].into_boxed_slice()));
            let old_buffer = ::std::mem::replace(&mut self.buffer, new_buffer);

            self.buffer[.. self.valid].copy_from_slice(&old_buffer[.. self.valid]);
            self.in_progress.push(Some(old_buffer));
        }
    }
}<commit_msg>only track appropriate buffers<commit_after>//! A large binary allocation for writing and sharing.

use bytes::arc::Bytes;

/// A large binary allocation for writing and sharing.
///
/// A bytes slab wraps a `Bytes` and maintains a valid (written) length, and supports writing after
/// this valid length, and extracting `Bytes` up to this valid length. Extracted bytes are enqueued
/// and checked for uniqueness in order to recycle them (once all shared references are dropped).
pub struct BytesSlab {
    buffer:         Bytes,                      // current working buffer.
    in_progress:    Vec<Option<Bytes>>,         // buffers shared with workers.
    stash:          Vec<Bytes>,                 // reclaimed and resuable buffers.
    shift:          usize,                      // current buffer allocation size.
    valid:          usize,                      // buffer[..valid] are valid bytes.
}

impl BytesSlab {
    /// Allocates a new `BytesSlab` with an initial size determined by a shift.
    pub fn new(shift: usize) -> Self {
        BytesSlab {
            buffer: Bytes::from(vec![0u8; 1 << shift].into_boxed_slice()),
            in_progress: Vec::new(),
            stash: Vec::new(),
            shift,
            valid: 0,
        }
    }
    /// The empty region of the slab.
    pub fn empty(&mut self) -> &mut [u8] {
        &mut self.buffer[self.valid..]
    }
    /// The valid region of the slab.
    pub fn valid(&mut self) -> &mut [u8] {
        &mut self.buffer[..self.valid]
    }
    /// Marks the next `bytes` bytes as valid.
    pub fn make_valid(&mut self, bytes: usize) {
        self.valid += bytes;
    }
    /// Extracts the first `bytes` valid bytes.
    pub fn extract(&mut self, bytes: usize) -> Bytes {
        debug_assert!(bytes <= self.valid);
        self.valid -= bytes;
        self.buffer.extract_to(bytes)
    }

    /// Ensures that `self.empty().len()` is at least `capacity`.
    ///
    /// This method may retire the current buffer if it does not have enough space, in which case
    /// it will copy any remaining contents into a new buffer. If this would not create enough free
    /// space, the shift is increased until it is sufficient.
    pub fn ensure_capacity(&mut self, capacity: usize) {

        if self.empty().len() < capacity {

            let mut increased_shift = false;

            // Increase allocation if copy would be insufficient.
            while self.valid + capacity > (1 << self.shift) {
                self.shift += 1;
                self.stash.clear();         // clear wrongly sized buffers.
                self.in_progress.clear();   // clear wrongly sized buffers.
                increased_shift = true;
            }

            // Attempt to reclaim shared slices.
            if self.stash.is_empty() {
                for shared in self.in_progress.iter_mut() {
                    if let Some(mut bytes) = shared.take() {
                        if bytes.try_regenerate::<Box<[u8]>>() {
                            // NOTE: Test should be redundant, but better safe...
                            if bytes.len() == (1 << self.shift) {
                                self.stash.push(bytes);
                            }
                        }
                        else {
                            *shared = Some(bytes);
                        }
                    }
                }
                self.in_progress.retain(|x| x.is_some());
            }

            let new_buffer = self.stash.pop().unwrap_or_else(|| Bytes::from(vec![0; 1 << self.shift].into_boxed_slice()));
            let old_buffer = ::std::mem::replace(&mut self.buffer, new_buffer);

            self.buffer[.. self.valid].copy_from_slice(&old_buffer[.. self.valid]);
            if !increased_shift {
                self.in_progress.push(Some(old_buffer));
            }
        }
    }
}<|endoftext|>


<commit_before>extern crate gcc;
extern crate bindgen;

use std::env;
use std::path::PathBuf;
use std::fs::File;
use std::time::{SystemTime, Duration};
use std::cmp;

pub fn main() {

    #[cfg(target_os = "windows")]
    {
        println!("cargo:rustc-link-search=native=../c/windows");
        println!("cargo:rustc-link-lib=static=sodium-release");
    }

    gcc::Config::new()
        .file("../c/netcode.c")
        .include("../c")
        .include("../c/windows")
        .define("NETCODE_ENABLE_TESTS", Some("0"))
        .define("NDEBUG", Some("0"))
        .compile("libnetcode.a");

    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
    let pub_path = out_path.join("pub_bindings.rs");
    let private_path = out_path.join("private_bindings.rs");

    //Do some basic dependecy management
    let targets = vec!(&pub_path, &private_path);
    let source = vec!("build.rs", "../c/netcode.c", "../c/netcode.h").iter()
        .map(|v| PathBuf::from(v))
        .collect::<Vec<_>>();

    let newest_source = source.iter()
        .map(|v| {
            File::open(v)
                .and_then(|f| f.metadata())
                .and_then(|m| m.modified())
                .expect(format!("Source file {:?} not found", v).as_str())
        })
        .max()
        .unwrap();

    let oldest_target = targets.iter()
        .filter_map(|v| {
            File::open(v)
                .and_then(|f| f.metadata())
                .and_then(|m| m.modified())
                .ok()
        })
        .min()
        .unwrap_or(newest_source - Duration::from_secs(1));

    if newest_source > oldest_target {
        //Export symbols for netcode
        let pub_bindings = bindgen::Builder::default()
            .no_unstable_rust()
            .header("../c/netcode.h")
            .generate()
            .expect("Unable to generate bindings");

        pub_bindings.write_to_file(&pub_path)
            .expect("Couldn't write bindings!");

        let include = env::var("INCLUDE").unwrap_or("".to_string());
        let sodium_include = env::var("SODIUM_LIB_DIR")
                                 .unwrap_or("../c/windows/sodium".to_string());

        let private_bindings = bindgen::Builder::default()
            .no_unstable_rust()
            .header("../c/netcode.c")
            .clang_arg("-I../c")
            .clang_arg(format!("-I{}", include))
            .clang_arg(format!("-I{}", sodium_include))
            .whitelisted_function("netcode_write_packet")
            .whitelisted_function("netcode_read_packet")
            .whitelisted_function("netcode_read_connect_token")
            .whitelisted_function("netcode_decrypt_challenge_token")
            .whitelisted_function("netcode_read_challenge_token")
            .whitelisted_function("netcode_replay_protection_reset")
            .whitelisted_function("free")
            .whitelisted_var("NETCODE_CONNECTION_NUM_PACKETS")
            .generate()
            .expect("Unable to generate bindings");

        private_bindings.write_to_file(&private_path)
            .expect("Couldn't write bindings!");
    }
}
<commit_msg>Fixing a few warnings<commit_after>extern crate gcc;
extern crate bindgen;

use std::env;
use std::path::PathBuf;
use std::fs::File;
use std::time::{Duration};

pub fn main() {

    #[cfg(target_os = "windows")]
    {
        println!("cargo:rustc-link-search=native=../c/windows");
        println!("cargo:rustc-link-lib=static=sodium-release");
    }

    gcc::Config::new()
        .file("../c/netcode.c")
        .include("../c")
        .include("../c/windows")
        .define("NETCODE_ENABLE_TESTS", Some("0"))
        .define("NDEBUG", Some("0"))
        .compile("libnetcode.a");

    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
    let pub_path = out_path.join("pub_bindings.rs");
    let private_path = out_path.join("private_bindings.rs");

    //Do some basic dependecy management
    let targets = vec!(&pub_path, &private_path);
    let source = vec!("build.rs", "../c/netcode.c", "../c/netcode.h").iter()
        .map(|v| PathBuf::from(v))
        .collect::<Vec<_>>();

    let newest_source = source.iter()
        .map(|v| {
            File::open(v)
                .and_then(|f| f.metadata())
                .and_then(|m| m.modified())
                .expect(format!("Source file {:?} not found", v).as_str())
        })
        .max()
        .unwrap();

    let oldest_target = targets.iter()
        .filter_map(|v| {
            File::open(v)
                .and_then(|f| f.metadata())
                .and_then(|m| m.modified())
                .ok()
        })
        .min()
        .unwrap_or(newest_source - Duration::from_secs(1));

    if newest_source > oldest_target {
        //Export symbols for netcode
        let pub_bindings = bindgen::Builder::default()
            .no_unstable_rust()
            .header("../c/netcode.h")
            .generate()
            .expect("Unable to generate bindings");

        pub_bindings.write_to_file(&pub_path)
            .expect("Couldn't write bindings!");

        let include = env::var("INCLUDE").unwrap_or("".to_string());
        let sodium_include = env::var("SODIUM_LIB_DIR")
                                 .unwrap_or("../c/windows/sodium".to_string());

        let private_bindings = bindgen::Builder::default()
            .no_unstable_rust()
            .header("../c/netcode.c")
            .clang_arg("-I../c")
            .clang_arg(format!("-I{}", include))
            .clang_arg(format!("-I{}", sodium_include))
            .whitelisted_function("netcode_write_packet")
            .whitelisted_function("netcode_read_packet")
            .whitelisted_function("netcode_read_connect_token")
            .whitelisted_function("netcode_decrypt_challenge_token")
            .whitelisted_function("netcode_read_challenge_token")
            .whitelisted_function("netcode_replay_protection_reset")
            .whitelisted_function("free")
            .whitelisted_var("NETCODE_CONNECTION_NUM_PACKETS")
            .generate()
            .expect("Unable to generate bindings");

        private_bindings.write_to_file(&private_path)
            .expect("Couldn't write bindings!");
    }
}
<|endoftext|>


<commit_before>

use std::collections::{HashMap, HashSet};
use std::any::Any;

use num::rational::BigRational;

#[derive(Debug, Clone, PartialEq)]
pub enum Property {
    Int(i64),
    Decimal(BigRational),
    String(String),
    Map(HashMap<String, Property>),
}

pub enum PropertyError {
    NotFound,
    TypeError
}

#[derive(Debug, Clone)]
pub struct PropertyMap {
    props: HashMap<i8, Property>,
}

impl PropertyMap {
    // pub fn set(&mut self, key: String, value: Box<Any>) {
    //     self.props.insert(key, value);
    // }
    pub fn set(&mut self, key: i8, value: Property) -> Option<Property> {
        self.props.insert(key, value)
    }
    pub fn set_string(&mut self, key: i8, value: String) -> Option<Property> {
        self.set(key, Property::String(value))
    }
    pub fn set_int(&mut self, key: i8, value: i64) -> Option<Property> {
        self.set(key, Property::Int(value))
    }
    pub fn get(&self, key: i8) -> Option<&Property> {
        self.props.get(&key)
    }

    pub fn get_int(&self, key:i8) -> Result<i64, PropertyError> {
        let p = try!(self.get(key).ok_or(PropertyError::NotFound));
        match *p {
            Property::Int(v) => Ok(v),
            _ => Err(PropertyError::TypeError)
        }
    }

    // pub fn get<T:Any>(&self, key: String) -> Result<&T, &str> {
    //     let result = try!(self.props.get(&key).ok_or("not found"));
    //     let downcasted = result.downcast_ref::<T>().ok_or("type fail");
    //     downcasted
    // }
    //
    // pub fn get_mut<T:Any>(&mut self, key: String) -> Result<&mut T, &str> {
    //     let mut result = try!(self.props.get_mut(&key).ok_or("not found"));
    //     let downcasted = result.downcast_mut::<T>().ok_or("type fail");
    //     downcasted
    // }

    pub fn new() -> PropertyMap {
        PropertyMap{ props: HashMap::new() }
    }
}

// impl Clone for PropertyMap {
//     fn clone(&self) -> PropertyMap {
//         PropertyMap{ props: HashMap::new() }
//     }
//     fn clone_from(&mut self, source: &PropertyMap)  {
//
//     }
// }
<commit_msg>for now, only allowing strings in sets<commit_after>

use std::collections::{HashMap, HashSet};
use std::any::Any;

use num::rational::BigRational;

#[derive(Debug, Clone, PartialEq)]
pub enum Property {
    Int(i64),
    Decimal(BigRational),
    String(String),
    Map(HashMap<String, Property>),
    Set(HashSet<String>)
}

pub enum PropertyError {
    NotFound,
    TypeError
}

#[derive(Debug, Clone)]
pub struct PropertyMap {
    props: HashMap<i8, Property>,
}

impl PropertyMap {
    // pub fn set(&mut self, key: String, value: Box<Any>) {
    //     self.props.insert(key, value);
    // }
    pub fn set(&mut self, key: i8, value: Property) -> Option<Property> {
        self.props.insert(key, value)
    }
    pub fn set_string(&mut self, key: i8, value: String) -> Option<Property> {
        self.set(key, Property::String(value))
    }
    pub fn set_int(&mut self, key: i8, value: i64) -> Option<Property> {
        self.set(key, Property::Int(value))
    }
    pub fn get(&self, key: i8) -> Option<&Property> {
        self.props.get(&key)
    }

    pub fn get_int(&self, key:i8) -> Result<i64, PropertyError> {
        let p = try!(self.get(key).ok_or(PropertyError::NotFound));
        match *p {
            Property::Int(v) => Ok(v),
            _ => Err(PropertyError::TypeError)
        }
    }

    // pub fn get<T:Any>(&self, key: String) -> Result<&T, &str> {
    //     let result = try!(self.props.get(&key).ok_or("not found"));
    //     let downcasted = result.downcast_ref::<T>().ok_or("type fail");
    //     downcasted
    // }
    //
    // pub fn get_mut<T:Any>(&mut self, key: String) -> Result<&mut T, &str> {
    //     let mut result = try!(self.props.get_mut(&key).ok_or("not found"));
    //     let downcasted = result.downcast_mut::<T>().ok_or("type fail");
    //     downcasted
    // }

    pub fn new() -> PropertyMap {
        PropertyMap{ props: HashMap::new() }
    }
}

// impl Clone for PropertyMap {
//     fn clone(&self) -> PropertyMap {
//         PropertyMap{ props: HashMap::new() }
//     }
//     fn clone_from(&mut self, source: &PropertyMap)  {
//
//     }
// }
<|endoftext|>


<commit_before>use crate::arch::wasm32;
use crate::cell::UnsafeCell;
use crate::mem;
use crate::sync::atomic::{AtomicU32, AtomicUsize, Ordering::SeqCst};
use crate::sys::thread;

pub struct Mutex {
    locked: AtomicUsize,
}

pub type MovableMutex = Box<Mutex>;

// Mutexes have a pretty simple implementation where they contain an `i32`
// internally that is 0 when unlocked and 1 when the mutex is locked.
// Acquisition has a fast path where it attempts to cmpxchg the 0 to a 1, and
// if it fails it then waits for a notification. Releasing a lock is then done
// by swapping in 0 and then notifying any waiters, if present.

impl Mutex {
    pub const fn new() -> Mutex {
        Mutex { locked: AtomicUsize::new(0) }
    }

    #[inline]
    pub unsafe fn init(&mut self) {
        // nothing to do
    }

    pub unsafe fn lock(&self) {
        while !self.try_lock() {
            let val = wasm32::memory_atomic_wait32(
                self.ptr(),
                1,  // we expect our mutex is locked
                -1, // wait infinitely
            );
            // we should have either woke up (0) or got a not-equal due to a
            // race (1). We should never time out (2)
            debug_assert!(val == 0 || val == 1);
        }
    }

    pub unsafe fn unlock(&self) {
        let prev = self.locked.swap(0, SeqCst);
        debug_assert_eq!(prev, 1);
        wasm32::memory_atomic_notify(self.ptr(), 1); // wake up one waiter, if any
    }

    #[inline]
    pub unsafe fn try_lock(&self) -> bool {
        self.locked.compare_exchange(0, 1, SeqCst, SeqCst).is_ok()
    }

    #[inline]
    pub unsafe fn destroy(&self) {
        // nothing to do
    }

    #[inline]
    fn ptr(&self) -> *mut i32 {
        assert_eq!(mem::size_of::<usize>(), mem::size_of::<i32>());
        self.locked.as_mut_ptr() as *mut i32
    }
}

pub struct ReentrantMutex {
    owner: AtomicU32,
    recursions: UnsafeCell<u32>,
}

unsafe impl Send for ReentrantMutex {}
unsafe impl Sync for ReentrantMutex {}

// Reentrant mutexes are similarly implemented to mutexs above except that
// instead of "1" meaning unlocked we use the id of a thread to represent
// whether it has locked a mutex. That way we have an atomic counter which
// always holds the id of the thread that currently holds the lock (or 0 if the
// lock is unlocked).
//
// Once a thread acquires a lock recursively, which it detects by looking at
// the value that's already there, it will update a local `recursions` counter
// in a nonatomic fashion (as we hold the lock). The lock is then fully
// released when this recursion counter reaches 0.

impl ReentrantMutex {
    pub const unsafe fn uninitialized() -> ReentrantMutex {
        ReentrantMutex { owner: AtomicU32::new(0), recursions: UnsafeCell::new(0) }
    }

    pub unsafe fn init(&self) {
        // nothing to do...
    }

    pub unsafe fn lock(&self) {
        let me = thread::my_id();
        while let Err(owner) = self._try_lock(me) {
            let val = wasm32::memory_atomic_wait32(self.ptr(), owner as i32, -1);
            debug_assert!(val == 0 || val == 1);
        }
    }

    #[inline]
    pub unsafe fn try_lock(&self) -> bool {
        self._try_lock(thread::my_id()).is_ok()
    }

    #[inline]
    unsafe fn _try_lock(&self, id: u32) -> Result<(), u32> {
        let id = id.checked_add(1).unwrap(); // make sure `id` isn't 0
        match self.owner.compare_exchange(0, id, SeqCst, SeqCst) {
            // we transitioned from unlocked to locked
            Ok(_) => {
                debug_assert_eq!(*self.recursions.get(), 0);
                Ok(())
            }

            // we currently own this lock, so let's update our count and return
            // true.
            Err(n) if n == id => {
                *self.recursions.get() += 1;
                Ok(())
            }

            // Someone else owns the lock, let our caller take care of it
            Err(other) => Err(other),
        }
    }

    pub unsafe fn unlock(&self) {
        // If we didn't ever recursively lock the lock then we fully unlock the
        // mutex and wake up a waiter, if any. Otherwise we decrement our
        // recursive counter and let some one else take care of the zero.
        match *self.recursions.get() {
            0 => {
                self.owner.swap(0, SeqCst);
                wasm32::memory_atomic_notify(self.ptr() as *mut i32, 1); // wake up one waiter, if any
            }
            ref mut n => *n -= 1,
        }
    }

    pub unsafe fn destroy(&self) {
        // nothing to do...
    }

    #[inline]
    fn ptr(&self) -> *mut i32 {
        self.owner.as_mut_ptr() as *mut i32
    }
}
<commit_msg>No longer put wasm mutexes in a box.<commit_after>use crate::arch::wasm32;
use crate::cell::UnsafeCell;
use crate::mem;
use crate::sync::atomic::{AtomicU32, AtomicUsize, Ordering::SeqCst};
use crate::sys::thread;

pub struct Mutex {
    locked: AtomicUsize,
}

pub type MovableMutex = Mutex;

// Mutexes have a pretty simple implementation where they contain an `i32`
// internally that is 0 when unlocked and 1 when the mutex is locked.
// Acquisition has a fast path where it attempts to cmpxchg the 0 to a 1, and
// if it fails it then waits for a notification. Releasing a lock is then done
// by swapping in 0 and then notifying any waiters, if present.

impl Mutex {
    pub const fn new() -> Mutex {
        Mutex { locked: AtomicUsize::new(0) }
    }

    #[inline]
    pub unsafe fn init(&mut self) {
        // nothing to do
    }

    pub unsafe fn lock(&self) {
        while !self.try_lock() {
            let val = wasm32::memory_atomic_wait32(
                self.ptr(),
                1,  // we expect our mutex is locked
                -1, // wait infinitely
            );
            // we should have either woke up (0) or got a not-equal due to a
            // race (1). We should never time out (2)
            debug_assert!(val == 0 || val == 1);
        }
    }

    pub unsafe fn unlock(&self) {
        let prev = self.locked.swap(0, SeqCst);
        debug_assert_eq!(prev, 1);
        wasm32::memory_atomic_notify(self.ptr(), 1); // wake up one waiter, if any
    }

    #[inline]
    pub unsafe fn try_lock(&self) -> bool {
        self.locked.compare_exchange(0, 1, SeqCst, SeqCst).is_ok()
    }

    #[inline]
    pub unsafe fn destroy(&self) {
        // nothing to do
    }

    #[inline]
    fn ptr(&self) -> *mut i32 {
        assert_eq!(mem::size_of::<usize>(), mem::size_of::<i32>());
        self.locked.as_mut_ptr() as *mut i32
    }
}

pub struct ReentrantMutex {
    owner: AtomicU32,
    recursions: UnsafeCell<u32>,
}

unsafe impl Send for ReentrantMutex {}
unsafe impl Sync for ReentrantMutex {}

// Reentrant mutexes are similarly implemented to mutexs above except that
// instead of "1" meaning unlocked we use the id of a thread to represent
// whether it has locked a mutex. That way we have an atomic counter which
// always holds the id of the thread that currently holds the lock (or 0 if the
// lock is unlocked).
//
// Once a thread acquires a lock recursively, which it detects by looking at
// the value that's already there, it will update a local `recursions` counter
// in a nonatomic fashion (as we hold the lock). The lock is then fully
// released when this recursion counter reaches 0.

impl ReentrantMutex {
    pub const unsafe fn uninitialized() -> ReentrantMutex {
        ReentrantMutex { owner: AtomicU32::new(0), recursions: UnsafeCell::new(0) }
    }

    pub unsafe fn init(&self) {
        // nothing to do...
    }

    pub unsafe fn lock(&self) {
        let me = thread::my_id();
        while let Err(owner) = self._try_lock(me) {
            let val = wasm32::memory_atomic_wait32(self.ptr(), owner as i32, -1);
            debug_assert!(val == 0 || val == 1);
        }
    }

    #[inline]
    pub unsafe fn try_lock(&self) -> bool {
        self._try_lock(thread::my_id()).is_ok()
    }

    #[inline]
    unsafe fn _try_lock(&self, id: u32) -> Result<(), u32> {
        let id = id.checked_add(1).unwrap(); // make sure `id` isn't 0
        match self.owner.compare_exchange(0, id, SeqCst, SeqCst) {
            // we transitioned from unlocked to locked
            Ok(_) => {
                debug_assert_eq!(*self.recursions.get(), 0);
                Ok(())
            }

            // we currently own this lock, so let's update our count and return
            // true.
            Err(n) if n == id => {
                *self.recursions.get() += 1;
                Ok(())
            }

            // Someone else owns the lock, let our caller take care of it
            Err(other) => Err(other),
        }
    }

    pub unsafe fn unlock(&self) {
        // If we didn't ever recursively lock the lock then we fully unlock the
        // mutex and wake up a waiter, if any. Otherwise we decrement our
        // recursive counter and let some one else take care of the zero.
        match *self.recursions.get() {
            0 => {
                self.owner.swap(0, SeqCst);
                wasm32::memory_atomic_notify(self.ptr() as *mut i32, 1); // wake up one waiter, if any
            }
            ref mut n => *n -= 1,
        }
    }

    pub unsafe fn destroy(&self) {
        // nothing to do...
    }

    #[inline]
    fn ptr(&self) -> *mut i32 {
        self.owner.as_mut_ptr() as *mut i32
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)] // stack_guard isn't used right now on all platforms
#![allow(unused_unsafe)] // thread_local with `const {}` triggers this liny

use crate::cell::RefCell;
use crate::sys::thread::guard::Guard;
use crate::thread::Thread;

struct ThreadInfo {
    stack_guard: Option<Guard>,
    thread: Thread,
}

thread_local! { static THREAD_INFO: RefCell<Option<ThreadInfo>> = const { RefCell::new(None) } }

impl ThreadInfo {
    fn with<R, F>(f: F) -> Option<R>
    where
        F: FnOnce(&mut ThreadInfo) -> R,
    {
        THREAD_INFO
            .try_with(move |thread_info| {
                let mut thread_info = thread_info.borrow_mut();
                let thread_info = thread_info.get_or_insert_with(|| ThreadInfo {
                    stack_guard: None,
                    thread: Thread::new(None),
                });
                f(thread_info)
            })
            .ok()
    }
}

pub fn current_thread() -> Option<Thread> {
    ThreadInfo::with(|info| info.thread.clone())
}

pub fn stack_guard() -> Option<Guard> {
    ThreadInfo::with(|info| info.stack_guard.clone()).and_then(|o| o)
}

pub fn set(stack_guard: Option<Guard>, thread: Thread) {
    THREAD_INFO.with(|c| assert!(c.borrow().is_none()));
    THREAD_INFO.with(move |c| *c.borrow_mut() = Some(ThreadInfo { stack_guard, thread }));
}

pub fn reset_guard(stack_guard: Option<Guard>) {
    THREAD_INFO.with(move |c| c.borrow_mut().as_mut().unwrap().stack_guard = stack_guard);
}
<commit_msg>Remove unused function<commit_after>#![allow(dead_code)] // stack_guard isn't used right now on all platforms
#![allow(unused_unsafe)] // thread_local with `const {}` triggers this liny

use crate::cell::RefCell;
use crate::sys::thread::guard::Guard;
use crate::thread::Thread;

struct ThreadInfo {
    stack_guard: Option<Guard>,
    thread: Thread,
}

thread_local! { static THREAD_INFO: RefCell<Option<ThreadInfo>> = const { RefCell::new(None) } }

impl ThreadInfo {
    fn with<R, F>(f: F) -> Option<R>
    where
        F: FnOnce(&mut ThreadInfo) -> R,
    {
        THREAD_INFO
            .try_with(move |thread_info| {
                let mut thread_info = thread_info.borrow_mut();
                let thread_info = thread_info.get_or_insert_with(|| ThreadInfo {
                    stack_guard: None,
                    thread: Thread::new(None),
                });
                f(thread_info)
            })
            .ok()
    }
}

pub fn current_thread() -> Option<Thread> {
    ThreadInfo::with(|info| info.thread.clone())
}

pub fn stack_guard() -> Option<Guard> {
    ThreadInfo::with(|info| info.stack_guard.clone()).and_then(|o| o)
}

pub fn set(stack_guard: Option<Guard>, thread: Thread) {
    THREAD_INFO.with(|c| assert!(c.borrow().is_none()));
    THREAD_INFO.with(move |c| *c.borrow_mut() = Some(ThreadInfo { stack_guard, thread }));
}
<|endoftext|>


<commit_before>use into_string::*;
use parser::*;
use std::iter;

/// Options for rendering Textile markup language.
pub struct RenderOptions {
    pub compress: bool,
    pub indent: u8,
}

impl Default for RenderOptions {
    fn default() -> RenderOptions {
        RenderOptions {
            compress: false,
            indent: 2,
        }
    }
}

/// Renders Textile string into HTML string with default options.
/// Accepts `&str`, `String` or `Path` data type.
///
/// # Example
///
/// ```rust
/// let html = textile::render("h2. *Heading of level 2*");
/// assert_eq!(html, "<h2><strong>Heading of level 2</strong></h2>".to_string());
/// ```
pub fn render<S: IntoString>(text: S) -> String {
    render_blocks(&parse(text.into_string()), &RenderOptions::default())
}

/// Renders Textile string into HTML string with specified options.
/// Accepts `&str`, `String` or `Path` data type.
///
/// # Example
///
/// ```rust
/// let html = textile::render_with("h2. *Heading of level 2*", textile::RenderOptions::default());
/// assert_eq!(html, "<h2><strong>Heading of level 2</strong></h2>".to_string());
/// ```
pub fn render_with<S: IntoString>(text: S, options: RenderOptions) -> String {
    render_blocks(&parse(text.into_string()), &options)
}

fn render_attributes(attributes: &[Attribute], options: &RenderOptions) -> String {
    if !attributes.is_empty() {
        let mut res = Vec::new();

        for attribute in attributes {
            let attr = match *attribute {
                Attribute::Align(ref align) => format!("align=\"{}\"", align),
                Attribute::Class(ref list) => format!("class=\"{}\"", list.join(" ")),
                Attribute::Id(ref id) => format!("id=\"{}\"", id),
                Attribute::Language(ref lang) => format!("lang=\"{}\"", lang),
                Attribute::Style(ref props) => {
                    let mut res = Vec::new();

                    for (key, value) in props {
                        if !options.compress {
                            res.push(format!("{}: {}", key, value))
                        } else {
                            res.push(format!("{}:{}", key, value))
                        }
                    }

                    if !options.compress {
                        format!("style=\"{}\"", res.join(";"))
                    } else {
                        format!("style=\"{}\"", res.join("; "))
                    }
                }
            };
            res.push(attr);
        }
        format!(" {}", res.join(" "))
    } else {
        String::default()
    }
}

fn render_blocks(elements: &[Block], options: &RenderOptions) -> String {
    let mut res = String::new();

    for (idx, element) in elements.iter().enumerate() {
        if idx > 0 && idx < elements.len() && !options.compress {
            res.push_str("\n");
        }
        res.push_str(&*render_block(element, options));
    }
    res
}

fn render_block(element: &Block, options: &RenderOptions) -> String {
    match *element {
        Block::BlockQuotation { ref attributes, ref elements } => {
            if !options.compress {
                let mut res = String::new();
                let spaces: String = iter::repeat(" ").take(options.indent as usize).collect();

                for element in elements {
                    res.push_str(&*format!("\n{}{}", spaces, render_block(element, options)));
                }
                format!("
{}\n
",
                        render_attributes(attributes, options),
                        res)
            } else {
                format!("
{}
",
                        render_attributes(attributes, options),
                        render_blocks(elements, options))
            }
        }
        Block::CodeBlock { ref attributes, ref code } => {
            format!("
{}
",
                    render_attributes(attributes, options),
                    code)
        }
        Block::Heading { ref attributes, level, ref elements } => {
            format!("<h{0}{1}>{2}</h{0}>",
                    level,
                    render_attributes(attributes, options),
                    render_inline_elements(elements, options))
        }
        Block::NoTextileBlock(ref strings) => strings.join("\n"),
        Block::Paragraph { ref attributes, ref elements, .. } => {
            format!("
{}
",
                    render_attributes(attributes, options),
                    render_inline_elements(elements, options))
        }
        _ => "".to_string(),
    }
}

fn render_inline_elements(elements: &[Inline], options: &RenderOptions) -> String {
    let mut res = String::new();

    for element in elements {
        let html = match *element {
            Inline::Abbreviation { ref abbr, ref transcript } => {
                format!("<acronym title=\"{}\">{}</acronym>",
                        transcript,
                        abbr)
            }
            Inline::Bold { ref attributes, ref elements, ref tag_type } => {
                let tag = match *tag_type {
                    BoldTagType::Strong => "strong",
                    BoldTagType::Bold => "b",
                };
                format!("<{0}{1}>{2}</{0}>",
                        tag,
                        render_attributes(attributes, options),
                        render_inline_elements(elements, options))
            }
            Inline::Break => "
".to_string(),
            Inline::Citation { ref attributes, ref elements } => {
                format!("{}",
                        render_attributes(attributes, options),
                        render_inline_elements(elements, options))
            }
            Inline::Code(ref text) => format!("{}", text),
            Inline::Image { ref attributes, ref alt, ref url } => {
                if !alt.is_empty() {
                    format!("",
                            url,
                            alt,
                            render_attributes(attributes, options))
                } else {
                    format!("",
                            url,
                            render_attributes(attributes, options))
                }
            }
            Inline::Italic { ref attributes, ref elements, ref tag_type } => {
                let tag = match *tag_type {
                    ItalicTagType::Emphasis => "em",
                    ItalicTagType::Italic => "i",
                };
                format!("<{0}{1}>{2}</{0}>",
                        tag,
                        render_attributes(attributes, options),
                        render_inline_elements(elements, options))
            }
            Inline::Link { ref attributes, ref description, ref url } => {
                format!("{}",
                        url,
                        render_attributes(attributes, options),
                        render_inline_elements(description, options))
            }
            Inline::Span { ref attributes, ref elements } => {
                format!("{}",
                        render_attributes(attributes, options),
                        render_inline_elements(elements, options))
            }
            Inline::Strikethrough { ref attributes, ref elements } => {
                format!("{}",
                        render_attributes(attributes, options),
                        render_inline_elements(elements, options))
            }
            Inline::Subscript { ref attributes, ref elements } => {
                format!("{}",
                        render_attributes(attributes, options),
                        render_inline_elements(elements, options))
            }
            Inline::Superscript { ref attributes, ref elements } => {
                format!("{}",
                        render_attributes(attributes, options),
                        render_inline_elements(elements, options))
            }
            Inline::Text(ref text) => text.to_string(),
            Inline::Underlined { ref attributes, ref elements } => {
                format!("{}",
                        render_attributes(attributes, options),
                        render_inline_elements(elements, options))
            }
        };
        res.push_str(&html);
    }
    res
}
<commit_msg>Add rendering support for 'pre' block element<commit_after>use into_string::*;
use parser::*;
use std::iter;

/// Options for rendering Textile markup language.
pub struct RenderOptions {
    pub compress: bool,
    pub indent: u8,
}

impl Default for RenderOptions {
    fn default() -> RenderOptions {
        RenderOptions {
            compress: false,
            indent: 2,
        }
    }
}

/// Renders Textile string into HTML string with default options.
/// Accepts `&str`, `String` or `Path` data type.
///
/// # Example
///
/// ```rust
/// let html = textile::render("h2. *Heading of level 2*");
/// assert_eq!(html, "<h2><strong>Heading of level 2</strong></h2>".to_string());
/// ```
pub fn render<S: IntoString>(text: S) -> String {
    render_blocks(&parse(text.into_string()), &RenderOptions::default())
}

/// Renders Textile string into HTML string with specified options.
/// Accepts `&str`, `String` or `Path` data type.
///
/// # Example
///
/// ```rust
/// let html = textile::render_with("h2. *Heading of level 2*", textile::RenderOptions::default());
/// assert_eq!(html, "<h2><strong>Heading of level 2</strong></h2>".to_string());
/// ```
pub fn render_with<S: IntoString>(text: S, options: RenderOptions) -> String {
    render_blocks(&parse(text.into_string()), &options)
}

fn render_attributes(attributes: &[Attribute], options: &RenderOptions) -> String {
    if !attributes.is_empty() {
        let mut res = Vec::new();

        for attribute in attributes {
            let attr = match *attribute {
                Attribute::Align(ref align) => format!("align=\"{}\"", align),
                Attribute::Class(ref list) => format!("class=\"{}\"", list.join(" ")),
                Attribute::Id(ref id) => format!("id=\"{}\"", id),
                Attribute::Language(ref lang) => format!("lang=\"{}\"", lang),
                Attribute::Style(ref props) => {
                    let mut res = Vec::new();

                    for (key, value) in props {
                        if !options.compress {
                            res.push(format!("{}: {}", key, value))
                        } else {
                            res.push(format!("{}:{}", key, value))
                        }
                    }

                    if !options.compress {
                        format!("style=\"{}\"", res.join(";"))
                    } else {
                        format!("style=\"{}\"", res.join("; "))
                    }
                }
            };
            res.push(attr);
        }
        format!(" {}", res.join(" "))
    } else {
        String::default()
    }
}

fn render_blocks(elements: &[Block], options: &RenderOptions) -> String {
    let mut res = String::new();

    for (idx, element) in elements.iter().enumerate() {
        if idx > 0 && idx < elements.len() && !options.compress {
            res.push_str("\n");
        }
        res.push_str(&*render_block(element, options));
    }
    res
}

fn render_block(element: &Block, options: &RenderOptions) -> String {
    match *element {
        Block::BlockQuotation { ref attributes, ref elements } => {
            if !options.compress {
                let mut res = String::new();
                let spaces: String = iter::repeat(" ").take(options.indent as usize).collect();

                for element in elements {
                    res.push_str(&*format!("\n{}{}", spaces, render_block(element, options)));
                }
                format!("
{}\n
",
                        render_attributes(attributes, options),
                        res)
            } else {
                format!("
{}
",
                        render_attributes(attributes, options),
                        render_blocks(elements, options))
            }
        }
        Block::CodeBlock { ref attributes, ref code } => {
            format!("
{}
",
                    render_attributes(attributes, options),
                    code)
        }
        Block::Heading { ref attributes, level, ref elements } => {
            format!("<h{0}{1}>{2}</h{0}>",
                    level,
                    render_attributes(attributes, options),
                    render_inline_elements(elements, options))
        }
        Block::NoTextileBlock(ref strings) => strings.join("\n"),
        Block::Paragraph { ref attributes, ref elements, .. } => {
            format!("
{}
",
                    render_attributes(attributes, options),
                    render_inline_elements(elements, options))
        },
        Block::Pre {ref attributes, ref lines} => {
            format!("
{}
",
                    render_attributes(attributes, options),
                    lines.join("\n"))
        },
        _ => "".to_string(),
    }
}

fn render_inline_elements(elements: &[Inline], options: &RenderOptions) -> String {
    let mut res = String::new();

    for element in elements {
        let html = match *element {
            Inline::Abbreviation { ref abbr, ref transcript } => {
                format!("<acronym title=\"{}\">{}</acronym>",
                        transcript,
                        abbr)
            }
            Inline::Bold { ref attributes, ref elements, ref tag_type } => {
                let tag = match *tag_type {
                    BoldTagType::Strong => "strong",
                    BoldTagType::Bold => "b",
                };
                format!("<{0}{1}>{2}</{0}>",
                        tag,
                        render_attributes(attributes, options),
                        render_inline_elements(elements, options))
            }
            Inline::Break => "
".to_string(),
            Inline::Citation { ref attributes, ref elements } => {
                format!("{}",
                        render_attributes(attributes, options),
                        render_inline_elements(elements, options))
            }
            Inline::Code(ref text) => format!("{}", text),
            Inline::Image { ref attributes, ref alt, ref url } => {
                if !alt.is_empty() {
                    format!("",
                            url,
                            alt,
                            render_attributes(attributes, options))
                } else {
                    format!("",
                            url,
                            render_attributes(attributes, options))
                }
            }
            Inline::Italic { ref attributes, ref elements, ref tag_type } => {
                let tag = match *tag_type {
                    ItalicTagType::Emphasis => "em",
                    ItalicTagType::Italic => "i",
                };
                format!("<{0}{1}>{2}</{0}>",
                        tag,
                        render_attributes(attributes, options),
                        render_inline_elements(elements, options))
            }
            Inline::Link { ref attributes, ref description, ref url } => {
                format!("{}",
                        url,
                        render_attributes(attributes, options),
                        render_inline_elements(description, options))
            }
            Inline::Span { ref attributes, ref elements } => {
                format!("{}",
                        render_attributes(attributes, options),
                        render_inline_elements(elements, options))
            }
            Inline::Strikethrough { ref attributes, ref elements } => {
                format!("{}",
                        render_attributes(attributes, options),
                        render_inline_elements(elements, options))
            }
            Inline::Subscript { ref attributes, ref elements } => {
                format!("{}",
                        render_attributes(attributes, options),
                        render_inline_elements(elements, options))
            }
            Inline::Superscript { ref attributes, ref elements } => {
                format!("{}",
                        render_attributes(attributes, options),
                        render_inline_elements(elements, options))
            }
            Inline::Text(ref text) => text.to_string(),
            Inline::Underlined { ref attributes, ref elements } => {
                format!("{}",
                        render_attributes(attributes, options),
                        render_inline_elements(elements, options))
            }
        };
        res.push_str(&html);
    }
    res
}
<|endoftext|>


<commit_before>use std;
use std::io;
use std::io::Write;
use std::io::prelude::*;
use std::fs::File;
use std::num::ParseIntError;
use std::path::Path;

use assembler::program_parsers::program;
use assembler::Assembler;
use vm::VM;

/// Core structure for the REPL for the Assembler
pub struct REPL {
    command_buffer: Vec<String>,
    vm: VM,
    asm: Assembler,
}

impl REPL {
    /// Creates and returns a new assembly REPL
    pub fn new() -> REPL {
        REPL {
            vm: VM::new(),
            command_buffer: vec![],
            asm: Assembler::new()
        }
    }

    /// Run loop similar to the VM execution loop, but the instructions are taken from the user directly
    /// at the terminal and not from pre-compiled bytecode
    pub fn run(&mut self) {
        println!("Welcome to Iridium! Let's be productive!");
        loop {
            // This allocates a new String in which to store whatever the user types each iteration.
            // TODO: Figure out how allocate this outside of the loop and re-use it every iteration
            let mut buffer = String::new();

            // Blocking call until the user types in a command
            let stdin = io::stdin();

            // Annoyingly, `print!` does not automatically flush stdout like `println!` does, so we
            // have to do that there for the user to see our `>>> ` prompt.
            print!(">>> ");
            io::stdout().flush().expect("Unable to flush stdout");

            // Here we'll look at the string the user gave us.
            stdin
                .read_line(&mut buffer)
                .expect("Unable to read line from user");
            let buffer = buffer.trim();
            self.command_buffer.push(buffer.to_string());
            match buffer {
                ".quit" => {
                    println!("Farewell! Have a great day!");
                    std::process::exit(0);
                }
                ".history" => {
                    for command in &self.command_buffer {
                        println!("{}", command);
                    }
                }
                ".program" => {
                    println!("Listing instructions currently in VM's program vector:");
                    for instruction in &self.vm.program {
                        println!("{}", instruction);
                    }
                    println!("End of Program Listing");
                }
                ".clear_program" => {
                    println!("Removing all bytes from VM's program vector...");
                    self.vm.program.truncate(0);
                    println!("Done!");
                }
                ".clear_registers" => {
                    println!("Setting all registers to 0");
                    for i in 0..self.vm.registers.len() {
                        self.vm.registers[i] = 0;
                    }
                    println!("Done!");
                }
                ".registers" => {
                    println!("Listing registers and all contents:");
                    println!("{:#?}", self.vm.registers);
                    println!("End of Register Listing")
                }
                ".symbols" => {
                    println!("Listing symbols table:");
                    println!("{:#?}", self.asm.symbols);
                    println!("End of Symbols Listing");
                }
                ".load_file" => {
                    print!("Please enter the path to the file you wish to load: ");
                    io::stdout().flush().expect("Unable to flush stdout");
                    let mut tmp = String::new();
                    stdin.read_line(&mut tmp).expect("Unable to read line from user");
                    println!("Attempting to load program from file...");
                    let tmp = tmp.trim();
                    let filename = Path::new(&tmp);
                    let mut f = File::open(Path::new(&filename)).expect("File not found");
                    let mut contents = String::new();
                    f.read_to_string(&mut contents).expect("There was an error reading from the file");
                    match self.asm.assemble(&contents) {
                        Ok(mut assembled_program) => {
                            println!("Sending assembled program to VM");
                            self.vm.program.append(&mut assembled_program);
                            println!("{:#?}", self.vm.program);
                            self.vm.run();
                        },
                        Err(errors) => {
                            for error in errors {
                                println!("Unable to parse input: {}", error);
                            }
                            continue;
                        }
                    }
                }
                _ => {
                    let program = match program(buffer.into()) {
                        // Rusts pattern matching is pretty powerful an can even be nested
                        Ok((_remainder, program)) => {
                            program
                        },
                        Err(e) => {
                            println!("Unable to parse input: {:?}", e);
                            continue;
                        }
                    };

                    self.vm.program.append(&mut program.to_bytes(&self.asm.symbols));
                    self.vm.run_once();
                }
            }
        }
    }

    /// Accepts a hexadecimal string WITHOUT a leading `0x` and returns a Vec of u8
    /// Example for a LOAD command: 00 01 03 E8
    #[allow(dead_code)]
    fn parse_hex(&mut self, i: &str) -> Result<Vec<u8>, ParseIntError> {
        let split = i.split(' ').collect::<Vec<&str>>();
        let mut results: Vec<u8> = vec![];
        for hex_string in split {
            let byte = u8::from_str_radix(&hex_string, 16);
            match byte {
                Ok(result) => {
                    results.push(result);
                }
                Err(e) => {
                    return Err(e);
                }
            }
        }
        Ok(results)
    }
}

impl Default for REPL {
    fn default() -> Self {
        Self::new()
    }
}
<commit_msg>Fixes a panic on trying to load a non-existent file<commit_after>use std;
use std::io;
use std::io::Write;
use std::io::prelude::*;
use std::fs::File;
use std::num::ParseIntError;
use std::path::Path;

use assembler::program_parsers::program;
use assembler::Assembler;
use vm::VM;

/// Core structure for the REPL for the Assembler
pub struct REPL {
    command_buffer: Vec<String>,
    vm: VM,
    asm: Assembler,
}

impl REPL {
    /// Creates and returns a new assembly REPL
    pub fn new() -> REPL {
        REPL {
            vm: VM::new(),
            command_buffer: vec![],
            asm: Assembler::new()
        }
    }

    /// Run loop similar to the VM execution loop, but the instructions are taken from the user directly
    /// at the terminal and not from pre-compiled bytecode
    pub fn run(&mut self) {
        println!("Welcome to Iridium! Let's be productive!");
        loop {
            // This allocates a new String in which to store whatever the user types each iteration.
            // TODO: Figure out how allocate this outside of the loop and re-use it every iteration
            let mut buffer = String::new();

            // Blocking call until the user types in a command
            let stdin = io::stdin();

            // Annoyingly, `print!` does not automatically flush stdout like `println!` does, so we
            // have to do that there for the user to see our `>>> ` prompt.
            print!(">>> ");
            io::stdout().flush().expect("Unable to flush stdout");

            // Here we'll look at the string the user gave us.
            stdin
                .read_line(&mut buffer)
                .expect("Unable to read line from user");
            let buffer = buffer.trim();
            self.command_buffer.push(buffer.to_string());
            match buffer {
                ".quit" => {
                    println!("Farewell! Have a great day!");
                    std::process::exit(0);
                }
                ".history" => {
                    for command in &self.command_buffer {
                        println!("{}", command);
                    }
                }
                ".program" => {
                    println!("Listing instructions currently in VM's program vector:");
                    for instruction in &self.vm.program {
                        println!("{}", instruction);
                    }
                    println!("End of Program Listing");
                }
                ".clear_program" => {
                    println!("Removing all bytes from VM's program vector...");
                    self.vm.program.truncate(0);
                    println!("Done!");
                }
                ".clear_registers" => {
                    println!("Setting all registers to 0");
                    for i in 0..self.vm.registers.len() {
                        self.vm.registers[i] = 0;
                    }
                    println!("Done!");
                }
                ".registers" => {
                    println!("Listing registers and all contents:");
                    println!("{:#?}", self.vm.registers);
                    println!("End of Register Listing")
                }
                ".symbols" => {
                    println!("Listing symbols table:");
                    println!("{:#?}", self.asm.symbols);
                    println!("End of Symbols Listing");
                }
                ".load_file" => {
                    print!("Please enter the path to the file you wish to load: ");
                    io::stdout().flush().expect("Unable to flush stdout");
                    let mut tmp = String::new();
                    stdin.read_line(&mut tmp).expect("Unable to read line from user");
                    println!("Attempting to load program from file...");
                    let tmp = tmp.trim();
                    let filename = Path::new(&tmp);
                    let mut f = match File::open(&filename) {
                        Ok(f) => { f }
                        Err(e) => {
                            println!("There was an error opening that file: {:?}", e);
                            continue;
                        }
                    };
                    let mut contents = String::new();
                    f.read_to_string(&mut contents).expect("There was an error reading from the file");
                    match self.asm.assemble(&contents) {
                        Ok(mut assembled_program) => {
                            println!("Sending assembled program to VM");
                            self.vm.program.append(&mut assembled_program);
                            println!("{:#?}", self.vm.program);
                            self.vm.run();
                        },
                        Err(errors) => {
                            for error in errors {
                                println!("Unable to parse input: {}", error);
                            }
                            continue;
                        }
                    }
                }
                ".spawn" => {

                }
                _ => {
                    let program = match program(buffer.into()) {
                        // Rusts pattern matching is pretty powerful an can even be nested
                        Ok((_remainder, program)) => {
                            program
                        },
                        Err(e) => {
                            println!("Unable to parse input: {:?}", e);
                            continue;
                        }
                    };

                    self.vm.program.append(&mut program.to_bytes(&self.asm.symbols));
                    self.vm.run_once();
                }
            }
        }
    }

    /// Accepts a hexadecimal string WITHOUT a leading `0x` and returns a Vec of u8
    /// Example for a LOAD command: 00 01 03 E8
    #[allow(dead_code)]
    fn parse_hex(&mut self, i: &str) -> Result<Vec<u8>, ParseIntError> {
        let split = i.split(' ').collect::<Vec<&str>>();
        let mut results: Vec<u8> = vec![];
        for hex_string in split {
            let byte = u8::from_str_radix(&hex_string, 16);
            match byte {
                Ok(result) => {
                    results.push(result);
                }
                Err(e) => {
                    return Err(e);
                }
            }
        }
        Ok(results)
    }
}

impl Default for REPL {
    fn default() -> Self {
        Self::new()
    }
}
<|endoftext|>


<commit_before>use futures::sink::Send;
use futures::stream::Stream;
use futures::{Async, Future, Poll, Sink};
use futures_state_stream::{StateStream, StreamEvent};

use native_tls::TlsConnector;

use std::io;
use std::net::ToSocketAddrs;

use tokio::net::tcp::{ConnectFuture, TcpStream};
use tokio_codec::Decoder;
use tokio_tls::{self, Connect};

use imap_proto::builders::command::Command;
use imap_proto::{Request, RequestId, State};
use proto::{ImapCodec, ImapTls, ImapTransport, ResponseData};

pub mod builder {
    pub use imap_proto::builders::command::{
        CommandBuilder, FetchBuilderAttributes, FetchBuilderMessages, FetchBuilderModifiers,
        FetchCommand, FetchCommandAttributes, FetchCommandMessages,
    };
}

pub trait ImapClient {
    type Transport: ImapTransport;
    fn into_parts(self) -> (Self::Transport, ClientState);
    fn rebuild(transport: Self::Transport, state: ClientState) -> Self;

    fn call(self, cmd: Command) -> ResponseStream<Self>
    where
        Self: ImapClient + Sized,
    {
        let (transport, mut state) = self.into_parts();
        let request_id = state.request_ids.next().unwrap(); // safe: never returns Err
        let (cmd_bytes, next_state) = cmd.into_parts();
        let future = transport.send(Request(request_id.clone(), cmd_bytes));
        ResponseStream::new(future, state, request_id, next_state)
    }
}

pub struct TlsClient {
    transport: ImapTls,
    state: ClientState,
}

impl TlsClient {
    pub fn connect(server: &str) -> io::Result<ImapConnectFuture> {
        let addr = (server, 993).to_socket_addrs()?.next().ok_or_else(|| {
            io::Error::new(
                io::ErrorKind::Other,
                format!("no IP addresses found for {}", server),
            )
        })?;
        Ok(ImapConnectFuture::TcpConnecting(
            TcpStream::connect(&addr),
            server.to_string(),
        ))
    }
}

impl ImapClient for TlsClient {
    type Transport = ImapTls;

    fn into_parts(self) -> (ImapTls, ClientState) {
        let Self { transport, state } = self;
        (transport, state)
    }

    fn rebuild(transport: ImapTls, state: ClientState) -> TlsClient {
        TlsClient { transport, state }
    }
}

pub struct ResponseStream<E>
where
    E: ImapClient,
{
    future: Option<Send<E::Transport>>,
    transport: Option<E::Transport>,
    state: Option<ClientState>,
    request_id: RequestId,
    next_state: Option<State>,
    done: bool,
}

impl<E> ResponseStream<E>
where
    E: ImapClient,
{
    pub fn new(
        future: Send<E::Transport>,
        state: ClientState,
        request_id: RequestId,
        next_state: Option<State>,
    ) -> Self {
        Self {
            future: Some(future),
            transport: None,
            state: Some(state),
            request_id,
            next_state,
            done: false,
        }
    }
}

impl<E> StateStream for ResponseStream<E>
where
    E: ImapClient,
{
    type Item = ResponseData;
    type State = E;
    type Error = io::Error;
    fn poll(&mut self) -> Poll<StreamEvent<Self::Item, Self::State>, Self::Error> {
        if let Some(mut future) = self.future.take() {
            match future.poll() {
                Ok(Async::Ready(transport)) => {
                    self.transport = Some(transport);
                }
                Ok(Async::NotReady) => {
                    self.future = Some(future);
                    return Ok(Async::NotReady);
                }
                Err(e) => {
                    return Err(e);
                }
            }
        }
        let mut transport = match self.transport.take() {
            None => return Ok(Async::NotReady),
            Some(mut transport) => transport,
        };
        if self.done {
            let mut state = self.state.take().unwrap(); // safe: initialized from start
            if let Some(next_state) = self.next_state.take() {
                state.state = next_state;
            }
            return Ok(Async::Ready(StreamEvent::Done(E::rebuild(
                transport, state,
            ))));
        }
        match transport.poll() {
            Ok(Async::Ready(Some(rsp))) => {
                if let Some(req_id) = rsp.request_id() {
                    self.done = *req_id == self.request_id;
                };
                self.transport = Some(transport);
                return Ok(Async::Ready(StreamEvent::Next(rsp)));
            }
            Err(e) => {
                return Err(e);
            }
            _ => (),
        }
        self.transport = Some(transport);
        Ok(Async::NotReady)
    }
}

pub enum ImapConnectFuture {
    #[doc(hidden)]
    TcpConnecting(ConnectFuture, String),
    #[doc(hidden)]
    TlsHandshake(Connect<TcpStream>),
    #[doc(hidden)]
    ServerGreeting(Option<ImapTls>),
}

impl Future for ImapConnectFuture {
    type Item = (ResponseData, TlsClient);
    type Error = io::Error;
    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        let mut new = None;
        if let ImapConnectFuture::TcpConnecting(ref mut future, ref domain) = *self {
            let stream = try_ready!(future.poll());
            let ctx = TlsConnector::builder().build().unwrap();
            let ctx = tokio_tls::TlsConnector::from(ctx);
            new = Some(ImapConnectFuture::TlsHandshake(ctx.connect(domain, stream)));
        }
        if new.is_some() {
            *self = new.take().unwrap();
        }
        if let ImapConnectFuture::TlsHandshake(ref mut future) = *self {
            let transport = ImapCodec::default().framed(try_ready!(future
                .map_err(|e| io::Error::new(io::ErrorKind::Other, e))
                .poll()));
            new = Some(ImapConnectFuture::ServerGreeting(Some(transport)));
        }
        if new.is_some() {
            *self = new.take().unwrap();
        }
        if let ImapConnectFuture::ServerGreeting(ref mut wrapped) = *self {
            let msg = try_ready!(wrapped.as_mut().unwrap().poll()).unwrap();
            return Ok(Async::Ready((
                msg,
                TlsClient {
                    transport: wrapped.take().unwrap(),
                    state: ClientState::new(),
                },
            )));
        }
        Ok(Async::NotReady)
    }
}

pub struct ClientState {
    state: State,
    request_ids: IdGenerator,
}

impl ClientState {
    pub fn new() -> Self {
        Self {
            state: State::NotAuthenticated,
            request_ids: IdGenerator::new(),
        }
    }
}

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

pub struct IdGenerator {
    next: u64,
}

impl IdGenerator {
    pub fn new() -> Self {
        Self { next: 0 }
    }
}

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

impl Iterator for IdGenerator {
    type Item = RequestId;
    fn next(&mut self) -> Option<Self::Item> {
        self.next += 1;
        Some(RequestId(format!("A{:04}", self.next % 10_000)))
    }
}
<commit_msg>Remove unnecessary mut modifier<commit_after>use futures::sink::Send;
use futures::stream::Stream;
use futures::{Async, Future, Poll, Sink};
use futures_state_stream::{StateStream, StreamEvent};

use native_tls::TlsConnector;

use std::io;
use std::net::ToSocketAddrs;

use tokio::net::tcp::{ConnectFuture, TcpStream};
use tokio_codec::Decoder;
use tokio_tls::{self, Connect};

use imap_proto::builders::command::Command;
use imap_proto::{Request, RequestId, State};
use proto::{ImapCodec, ImapTls, ImapTransport, ResponseData};

pub mod builder {
    pub use imap_proto::builders::command::{
        CommandBuilder, FetchBuilderAttributes, FetchBuilderMessages, FetchBuilderModifiers,
        FetchCommand, FetchCommandAttributes, FetchCommandMessages,
    };
}

pub trait ImapClient {
    type Transport: ImapTransport;
    fn into_parts(self) -> (Self::Transport, ClientState);
    fn rebuild(transport: Self::Transport, state: ClientState) -> Self;

    fn call(self, cmd: Command) -> ResponseStream<Self>
    where
        Self: ImapClient + Sized,
    {
        let (transport, mut state) = self.into_parts();
        let request_id = state.request_ids.next().unwrap(); // safe: never returns Err
        let (cmd_bytes, next_state) = cmd.into_parts();
        let future = transport.send(Request(request_id.clone(), cmd_bytes));
        ResponseStream::new(future, state, request_id, next_state)
    }
}

pub struct TlsClient {
    transport: ImapTls,
    state: ClientState,
}

impl TlsClient {
    pub fn connect(server: &str) -> io::Result<ImapConnectFuture> {
        let addr = (server, 993).to_socket_addrs()?.next().ok_or_else(|| {
            io::Error::new(
                io::ErrorKind::Other,
                format!("no IP addresses found for {}", server),
            )
        })?;
        Ok(ImapConnectFuture::TcpConnecting(
            TcpStream::connect(&addr),
            server.to_string(),
        ))
    }
}

impl ImapClient for TlsClient {
    type Transport = ImapTls;

    fn into_parts(self) -> (ImapTls, ClientState) {
        let Self { transport, state } = self;
        (transport, state)
    }

    fn rebuild(transport: ImapTls, state: ClientState) -> TlsClient {
        TlsClient { transport, state }
    }
}

pub struct ResponseStream<E>
where
    E: ImapClient,
{
    future: Option<Send<E::Transport>>,
    transport: Option<E::Transport>,
    state: Option<ClientState>,
    request_id: RequestId,
    next_state: Option<State>,
    done: bool,
}

impl<E> ResponseStream<E>
where
    E: ImapClient,
{
    pub fn new(
        future: Send<E::Transport>,
        state: ClientState,
        request_id: RequestId,
        next_state: Option<State>,
    ) -> Self {
        Self {
            future: Some(future),
            transport: None,
            state: Some(state),
            request_id,
            next_state,
            done: false,
        }
    }
}

impl<E> StateStream for ResponseStream<E>
where
    E: ImapClient,
{
    type Item = ResponseData;
    type State = E;
    type Error = io::Error;
    fn poll(&mut self) -> Poll<StreamEvent<Self::Item, Self::State>, Self::Error> {
        if let Some(mut future) = self.future.take() {
            match future.poll() {
                Ok(Async::Ready(transport)) => {
                    self.transport = Some(transport);
                }
                Ok(Async::NotReady) => {
                    self.future = Some(future);
                    return Ok(Async::NotReady);
                }
                Err(e) => {
                    return Err(e);
                }
            }
        }
        let mut transport = match self.transport.take() {
            None => return Ok(Async::NotReady),
            Some(transport) => transport,
        };
        if self.done {
            let mut state = self.state.take().unwrap(); // safe: initialized from start
            if let Some(next_state) = self.next_state.take() {
                state.state = next_state;
            }
            return Ok(Async::Ready(StreamEvent::Done(E::rebuild(
                transport, state,
            ))));
        }
        match transport.poll() {
            Ok(Async::Ready(Some(rsp))) => {
                if let Some(req_id) = rsp.request_id() {
                    self.done = *req_id == self.request_id;
                };
                self.transport = Some(transport);
                return Ok(Async::Ready(StreamEvent::Next(rsp)));
            }
            Err(e) => {
                return Err(e);
            }
            _ => (),
        }
        self.transport = Some(transport);
        Ok(Async::NotReady)
    }
}

pub enum ImapConnectFuture {
    #[doc(hidden)]
    TcpConnecting(ConnectFuture, String),
    #[doc(hidden)]
    TlsHandshake(Connect<TcpStream>),
    #[doc(hidden)]
    ServerGreeting(Option<ImapTls>),
}

impl Future for ImapConnectFuture {
    type Item = (ResponseData, TlsClient);
    type Error = io::Error;
    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        let mut new = None;
        if let ImapConnectFuture::TcpConnecting(ref mut future, ref domain) = *self {
            let stream = try_ready!(future.poll());
            let ctx = TlsConnector::builder().build().unwrap();
            let ctx = tokio_tls::TlsConnector::from(ctx);
            new = Some(ImapConnectFuture::TlsHandshake(ctx.connect(domain, stream)));
        }
        if new.is_some() {
            *self = new.take().unwrap();
        }
        if let ImapConnectFuture::TlsHandshake(ref mut future) = *self {
            let transport = ImapCodec::default().framed(try_ready!(future
                .map_err(|e| io::Error::new(io::ErrorKind::Other, e))
                .poll()));
            new = Some(ImapConnectFuture::ServerGreeting(Some(transport)));
        }
        if new.is_some() {
            *self = new.take().unwrap();
        }
        if let ImapConnectFuture::ServerGreeting(ref mut wrapped) = *self {
            let msg = try_ready!(wrapped.as_mut().unwrap().poll()).unwrap();
            return Ok(Async::Ready((
                msg,
                TlsClient {
                    transport: wrapped.take().unwrap(),
                    state: ClientState::new(),
                },
            )));
        }
        Ok(Async::NotReady)
    }
}

pub struct ClientState {
    state: State,
    request_ids: IdGenerator,
}

impl ClientState {
    pub fn new() -> Self {
        Self {
            state: State::NotAuthenticated,
            request_ids: IdGenerator::new(),
        }
    }
}

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

pub struct IdGenerator {
    next: u64,
}

impl IdGenerator {
    pub fn new() -> Self {
        Self { next: 0 }
    }
}

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

impl Iterator for IdGenerator {
    type Item = RequestId;
    fn next(&mut self) -> Option<Self::Item> {
        self.next += 1;
        Some(RequestId(format!("A{:04}", self.next % 10_000)))
    }
}
<|endoftext|>


<commit_before>use hyper::header::{CookiePair as Cookie, ContentLength, ContentType, Header, Location, SetCookie};
use hyper::status::StatusCode as Status;

use hyper::{Control, Headers, Next};

use hyper::mime::{Mime, TopLevel, SubLevel, Attr, Value};

use handlebars::Handlebars;
use serde::ser::Serialize as ToJson;

pub use serde_json::value as value;

use std::any::Any;
use std::fmt::Debug;
use std::borrow::Cow;
use std::io::{ErrorKind, Read, Result, Write};
use std::marker::PhantomData;

use std::fs::{File, read_dir};
use std::path::Path;

use std::boxed::Box;
use std::sync::atomic::{AtomicBool, Ordering};

use buffer::Buffer;
use deque::{self, Stealer, Worker};

pub struct Resp {
    status: Status,
    headers: Headers,
    body: Buffer,
    worker: Option<Worker<Buffer>>,
    stealer: Option<Stealer<Buffer>>,

    ctrl: Control,
    ended_or_notify: AtomicBool
}

impl Resp {
    pub fn new(ctrl: Control) -> Resp {
        Resp {
            status: Status::Ok,
            headers: Headers::default(),
            body: Buffer::new(),
            worker: None,
            stealer: None,

            ctrl: ctrl,
            ended_or_notify: AtomicBool::new(false)
        }
    }

    /// called by handler to know whether we can write the response or not
    ///
    /// two possible cases:
    ///   - done before can_write: in synchronous style, done is called first,
    ///     sets ended_or_notify to true and does not notify the handler
    ///   - can_write before done: response not done yet, can_write is called first,
    ///     sets ended_or_notify to true so that when done is called, it will notify the handler
    fn can_write(&self) -> bool {
        if self.ended_or_notify.compare_and_swap(false, true, Ordering::AcqRel) {
            // if true, response already ended, we can write it
            true
        } else {
            // if false, response did not end yet
            // ended has been set to true to mean "need to notify handler"
            false
        }
    }

    /// mirror function of can_write, called by Response
    fn done(&self) {
        if self.ended_or_notify.compare_and_swap(false, true, Ordering::AcqRel) {
            // if true, means we need to notify, the flag is not updated
            self.notify();
        } else {
            // if previously false: no need to notify
            // ended has been set to true to mean "response ended"
        }
    }

    /// notify handler we have something to write
    /// called by done and append
    fn notify(&self) {
        self.ctrl.ready(Next::write()).unwrap();
    }

    fn is_streaming(&self) -> bool {
        self.worker.is_some()
    }

    fn status(&mut self, status: Status) {
        self.status = status;
    }

    fn has_header<H: Header>(&self) -> bool {
        self.headers.has::<H>()
    }

    fn header<H: Header>(&mut self, header: H) {
        self.headers.set(header);
    }

    fn header_raw<K: Into<Cow<'static, str>> + Debug>(&mut self, name: K, value: Vec<Vec<u8>>) {
        self.headers.set_raw(name, value);
    }

    fn push_cookie(&mut self, cookie: Cookie) {
        self.headers.get_mut::<SetCookie>().unwrap().push(cookie)
    }

    fn len(&self) -> usize {
        self.body.len()
    }

    fn append<D: AsRef<[u8]>>(&self, content: D) {
        self.worker.as_ref().unwrap().push(content.as_ref().into());
        self.notify();
    }

    fn send<D: Into<Vec<u8>>>(&mut self, content: D) {
        self.body.send(content);
    }

    fn init_deque(&mut self) {
        let (worker, stealer) = deque::new();
        self.worker = Some(worker);
        self.stealer = Some(stealer);
    }
}

/// This holds data for the response.
pub struct ResponseHolder {
    resp: Box<Resp>
}

impl ResponseHolder {

    pub fn new(control: Control) -> ResponseHolder {
        ResponseHolder {
            resp: Box::new(Resp::new(control))
        }
    }

    pub fn new_response(&mut self) -> Response {
        Response {
            resp: &mut *self.resp as *mut Resp,
            streaming: false,
            _marker: PhantomData
        }
    }

    pub fn get_status(&self) -> Status {
        self.resp.status
    }

    pub fn set_headers(&self, headers: &mut Headers) {
        *headers = self.resp.headers.clone();
    }

    pub fn is_streaming(&self) -> bool {
        self.resp.is_streaming()
    }

    pub fn body(&mut self) -> &mut Buffer {
        &mut self.resp.body
    }

    pub fn pop(&mut self) -> Option<Buffer> {
        match self.resp.stealer.as_ref().unwrap().steal() {
            deque::Data(buffer) => Some(buffer),
            deque::Empty => None,
            deque::Abort => panic!("abort")
        }
    }

    /// two possible cases:
    ///   - done before can_write: in synchronous style, done is called first,
    ///     sets ended_or_notify to true and does not notify the handler
    ///   - can_write before done: response not done yet, can_write is called first,
    ///     sets ended_or_notify to true so that when done is called, it will notify the handler
    pub fn can_write(&self) -> bool {
        self.resp.can_write()
    }
}

/// This represents the response that will be sent back to the application.
///
/// Includes a status code (default 200 OK), headers, and a body.
/// The response can be updated and sent back immediately in a synchronous way,
/// or deferred pending some computation (asynchronous mode).
///
/// The response is sent when it is dropped.
pub struct Response<W: Any = Fresh> {
    resp: *mut Resp,
    streaming: bool,
    _marker: PhantomData<W>
}

// no worries, the response is always modified by only one thread at a time
unsafe impl Send for Response {}

impl Drop for ResponseHolder {
    fn drop(&mut self) {
        println!("drop response holder");
    }
}

impl<T: Any> Drop for Response<T> {
    fn drop(&mut self) {
        println!("drop response (streaming? {})", self.streaming);
        if self.streaming {
            // append an empty buffer to indicate there is no more data left, and notify handler
            self.resp().append(&[]);
        } else {
            self.resp().done();
        }
    }
}

impl Drop for Resp {
    fn drop(&mut self) {
        println!("drop resp");
    }
}

pub enum Fresh {}
pub enum Streaming {}

impl<W: Any> Response<W> {
    fn resp(&self) -> &Resp {
        unsafe {
            &*self.resp
        }
    }

    fn resp_mut(&self) -> &mut Resp {
        unsafe {
            &mut *self.resp
        }
    }
}

impl Response<Fresh> {
    /// Sets the status code of this response.
    pub fn status(&mut self, status: Status) -> &mut Self {
        self.resp_mut().status(status);
        self
    }

    /// Sets the Content-Type header.
    pub fn content_type<S: Into<Vec<u8>>>(&mut self, mime: S) -> &mut Self {
        self.header_raw("Content-Type", mime)
    }

    /// Sets the Content-Length header.
    pub fn len(&mut self, len: u64) -> &mut Self {
        self.header(ContentLength(len))
    }

    /// Sets the given cookie.
    pub fn cookie(&mut self, cookie: Cookie) {
        let has_cookie_header = self.resp().has_header::<SetCookie>();
        if has_cookie_header {
            self.resp_mut().push_cookie(cookie)
        } else {
            self.resp_mut().header(SetCookie(vec![cookie]))
        }
    }

    /// Sets the given header.
    pub fn header<H: Header>(&mut self, header: H) -> &mut Self {
        self.resp_mut().header(header);
        self
    }

    /// Sets the given header with raw strings.
    pub fn header_raw<K: Into<Cow<'static, str>> + Debug, V: Into<Vec<u8>>>(&mut self, name: K, value: V) -> &mut Self {
        self.resp_mut().header_raw(name, vec![value.into()]);
        self
    }

    /// Sets the Location header.
    pub fn location<S: Into<String>>(&mut self, url: S) -> &mut Self {
        self.header(Location(url.into()))
    }

    /// Redirects to the given URL with the given status, or 302 Found if none is given.
    pub fn redirect(mut self, url: &str, status: Option<Status>) {
        self.location(url);
        self.end(status.unwrap_or(Status::Found))
    }

    /// Ends this response with the given status and an empty body
    pub fn end(mut self, status: Status) {
        self.status(status);
        self.len(0);
    }

    /// Renders the template at the given path using the given data.
    pub fn render<P: AsRef<Path>, T: ToJson>(self, path: P, data: T) {
        let mut handlebars = Handlebars::new();
        let path = path.as_ref();
        let name = path.file_stem().unwrap().to_str().unwrap();

        handlebars.register_template_file(name, path).unwrap();
        // ignore errors if partials folder does not exist
        let _ = register_partials(&mut handlebars);
        let result = handlebars.render(name, &data);
        self.send(result.unwrap())
    }

    /// Sends the given content and ends this response.
    /// Status defaults to 200 Ok, headers must have been set before this method is called.
    pub fn send<D: Into<Vec<u8>>>(mut self, content: D) {
        self.resp_mut().send(content);
        let length = self.resp().len();
        self.len(length as u64);
    }

    /// Sends the given file, setting the Content-Type based on the file's extension.
    /// Known extensions are htm, html, jpg, jpeg, png, js, css.
    /// If the file does not exist, this method sends a 404 Not Found response.
    pub fn send_file<P: AsRef<Path>>(mut self, path: P) {
        let need_content_type = !self.resp().has_header::<ContentType>();
        if need_content_type {
            let extension = path.as_ref().extension();
            if let Some(ext) = extension {
                let content_type = match ext.to_string_lossy().as_ref() {
                    "htm" | "html" => Some(ContentType::html()),
                    "jpg" | "jpeg" => Some(ContentType::jpeg()),
                    "png" => Some(ContentType::png()),
                    "js" => Some(ContentType(Mime(TopLevel::Text, SubLevel::Javascript, vec![(Attr::Charset, Value::Utf8)]))),
                    "css" => Some(ContentType(Mime(TopLevel::Text, SubLevel::Css, vec![(Attr::Charset, Value::Utf8)]))),
                    _ => None
                };

                if let Some(content_type) = content_type {
                    self.resp_mut().header(content_type);
                }
            }
        }

        // read the whole file at once and send it
        // probably not the best idea for big files, we should use stream instead in that case
        match File::open(path) {
            Ok(mut file) => {
                let mut buf = Vec::with_capacity(file.metadata().ok().map_or(1024, |meta| meta.len() as usize));
                if let Err(err) = file.read_to_end(&mut buf) {
                    self.status(Status::InternalServerError).content_type("text/plain");
                    self.send(format!("{}", err))
                } else {
                    self.send(buf)
                }
            },
            Err(ref err) if err.kind() == ErrorKind::NotFound => self.end(Status::NotFound),
            Err(ref err) => {
                self.status(Status::InternalServerError).content_type("text/plain");
                self.send(format!("{}", err))
            }
        }
    }

    /// Moves to streaming mode.
    pub fn stream(self) -> Response<Streaming> {
        self.resp_mut().init_deque();
        Response {
            resp: self.resp,
            streaming: true,
            _marker: PhantomData
        }
    }
}

impl Response<Streaming> {
    /// Appends the given content to this response's body.
    /// Will change to support asynchronous use case.
    pub fn append<D: AsRef<[u8]>>(&mut self, content: D) {
        println!("append {} bytes", content.as_ref().len());
        self.resp().append(content);
    }
}

fn register_partials(handlebars: &mut Handlebars) -> Result<()> {
    for it in try!(read_dir("views/partials")) {
        let entry = try!(it);
        let path = entry.path();
        if path.extension().is_some() && path.extension().unwrap() == "hbs" {
            let name = path.file_stem().unwrap().to_str().unwrap();
            handlebars.register_template_file(name, path.as_path()).unwrap();
        }
    }
    Ok(())
}
<commit_msg>improved doc, made render set content type if not set<commit_after>use hyper::header::{CookiePair as Cookie, ContentLength, ContentType, Header, Location, SetCookie};
use hyper::status::StatusCode as Status;

use hyper::{Control, Headers, Next};

use hyper::mime::{Mime, TopLevel, SubLevel, Attr, Value};

use handlebars::Handlebars;
use serde::ser::Serialize as ToJson;

pub use serde_json::value as value;

use std::any::Any;
use std::fmt::Debug;
use std::borrow::Cow;
use std::io::{ErrorKind, Read, Result, Write};
use std::marker::PhantomData;

use std::fs::{File, read_dir};
use std::path::Path;

use std::boxed::Box;
use std::sync::atomic::{AtomicBool, Ordering};

use buffer::Buffer;
use deque::{self, Stealer, Worker};

pub struct Resp {
    status: Status,
    headers: Headers,
    body: Buffer,
    worker: Option<Worker<Buffer>>,
    stealer: Option<Stealer<Buffer>>,

    ctrl: Control,
    ended_or_notify: AtomicBool
}

impl Resp {
    pub fn new(ctrl: Control) -> Resp {
        Resp {
            status: Status::Ok,
            headers: Headers::default(),
            body: Buffer::new(),
            worker: None,
            stealer: None,

            ctrl: ctrl,
            ended_or_notify: AtomicBool::new(false)
        }
    }

    /// called by handler to know whether we can write the response or not
    ///
    /// two possible cases:
    ///   - done before can_write: in synchronous style, done is called first,
    ///     sets ended_or_notify to true and does not notify the handler
    ///   - can_write before done: response not done yet, can_write is called first,
    ///     sets ended_or_notify to true so that when done is called, it will notify the handler
    fn can_write(&self) -> bool {
        if self.ended_or_notify.compare_and_swap(false, true, Ordering::AcqRel) {
            // if true, response already ended, we can write it
            true
        } else {
            // if false, response did not end yet
            // ended has been set to true to mean "need to notify handler"
            false
        }
    }

    /// mirror function of can_write, called by Response
    fn done(&self) {
        if self.ended_or_notify.compare_and_swap(false, true, Ordering::AcqRel) {
            // if true, means we need to notify, the flag is not updated
            self.notify();
        } else {
            // if previously false: no need to notify
            // ended has been set to true to mean "response ended"
        }
    }

    /// notify handler we have something to write
    /// called by done and append
    fn notify(&self) {
        self.ctrl.ready(Next::write()).unwrap();
    }

    fn is_streaming(&self) -> bool {
        self.worker.is_some()
    }

    fn status(&mut self, status: Status) {
        self.status = status;
    }

    fn has_header<H: Header>(&self) -> bool {
        self.headers.has::<H>()
    }

    fn header<H: Header>(&mut self, header: H) {
        self.headers.set(header);
    }

    fn header_raw<K: Into<Cow<'static, str>> + Debug>(&mut self, name: K, value: Vec<Vec<u8>>) {
        self.headers.set_raw(name, value);
    }

    fn push_cookie(&mut self, cookie: Cookie) {
        self.headers.get_mut::<SetCookie>().unwrap().push(cookie)
    }

    fn len(&self) -> usize {
        self.body.len()
    }

    fn append<D: AsRef<[u8]>>(&self, content: D) {
        self.worker.as_ref().unwrap().push(content.as_ref().into());
        self.notify();
    }

    fn send<D: Into<Vec<u8>>>(&mut self, content: D) {
        self.body.send(content);
    }

    fn init_deque(&mut self) {
        let (worker, stealer) = deque::new();
        self.worker = Some(worker);
        self.stealer = Some(stealer);
    }
}

/// This holds data for the response.
pub struct ResponseHolder {
    resp: Box<Resp>
}

impl ResponseHolder {

    pub fn new(control: Control) -> ResponseHolder {
        ResponseHolder {
            resp: Box::new(Resp::new(control))
        }
    }

    pub fn new_response(&mut self) -> Response {
        Response {
            resp: &mut *self.resp as *mut Resp,
            streaming: false,
            _marker: PhantomData
        }
    }

    pub fn get_status(&self) -> Status {
        self.resp.status
    }

    pub fn set_headers(&self, headers: &mut Headers) {
        *headers = self.resp.headers.clone();
    }

    pub fn is_streaming(&self) -> bool {
        self.resp.is_streaming()
    }

    pub fn body(&mut self) -> &mut Buffer {
        &mut self.resp.body
    }

    pub fn pop(&mut self) -> Option<Buffer> {
        match self.resp.stealer.as_ref().unwrap().steal() {
            deque::Data(buffer) => Some(buffer),
            deque::Empty => None,
            deque::Abort => panic!("abort")
        }
    }

    /// two possible cases:
    ///   - done before can_write: in synchronous style, done is called first,
    ///     sets ended_or_notify to true and does not notify the handler
    ///   - can_write before done: response not done yet, can_write is called first,
    ///     sets ended_or_notify to true so that when done is called, it will notify the handler
    pub fn can_write(&self) -> bool {
        self.resp.can_write()
    }
}

/// This represents the response that will be sent back to the application.
///
/// Includes a status code (default 200 OK), headers, and a body.
/// The response can be updated and sent back immediately in a synchronous way,
/// or deferred pending some computation (asynchronous mode).
///
/// The response is sent when it is dropped.
pub struct Response<W: Any = Fresh> {
    resp: *mut Resp,
    streaming: bool,
    _marker: PhantomData<W>
}

// no worries, the response is always modified by only one thread at a time
unsafe impl Send for Response {}

impl Drop for ResponseHolder {
    fn drop(&mut self) {
        println!("drop response holder");
    }
}

impl<T: Any> Drop for Response<T> {
    fn drop(&mut self) {
        println!("drop response (streaming? {})", self.streaming);
        if self.streaming {
            // append an empty buffer to indicate there is no more data left, and notify handler
            self.resp().append(&[]);
        } else {
            self.resp().done();
        }
    }
}

impl Drop for Resp {
    fn drop(&mut self) {
        println!("drop resp");
    }
}

pub enum Fresh {}
pub enum Streaming {}

impl<W: Any> Response<W> {
    fn resp(&self) -> &Resp {
        unsafe {
            &*self.resp
        }
    }

    fn resp_mut(&self) -> &mut Resp {
        unsafe {
            &mut *self.resp
        }
    }
}

impl Response<Fresh> {
    /// Sets the status code of this response.
    pub fn status(&mut self, status: Status) -> &mut Self {
        self.resp_mut().status(status);
        self
    }

    /// Sets the Content-Type header.
    pub fn content_type<S: Into<Vec<u8>>>(&mut self, mime: S) -> &mut Self {
        self.header_raw("Content-Type", mime)
    }

    /// Sets the Content-Length header.
    pub fn len(&mut self, len: u64) -> &mut Self {
        self.header(ContentLength(len))
    }

    /// Sets the given cookie.
    pub fn cookie(&mut self, cookie: Cookie) {
        let has_cookie_header = self.resp().has_header::<SetCookie>();
        if has_cookie_header {
            self.resp_mut().push_cookie(cookie)
        } else {
            self.resp_mut().header(SetCookie(vec![cookie]))
        }
    }

    /// Sets the given header.
    pub fn header<H: Header>(&mut self, header: H) -> &mut Self {
        self.resp_mut().header(header);
        self
    }

    /// Sets the given header with raw strings.
    pub fn header_raw<K: Into<Cow<'static, str>> + Debug, V: Into<Vec<u8>>>(&mut self, name: K, value: V) -> &mut Self {
        self.resp_mut().header_raw(name, vec![value.into()]);
        self
    }

    /// Sets the Location header.
    pub fn location<S: Into<String>>(&mut self, url: S) -> &mut Self {
        self.header(Location(url.into()))
    }

    /// Redirects to the given URL with the given status, or 302 Found if none is given.
    pub fn redirect(mut self, url: &str, status: Option<Status>) {
        self.location(url);
        self.end(status.unwrap_or(Status::Found))
    }

    /// Ends this response with the given status and an empty body
    pub fn end(mut self, status: Status) {
        self.status(status);
        self.len(0);
    }

    /// Renders the template at the given path using the given data.
    ///
    /// If no Content-Type header is set, the content type is set to `text/html`.
    pub fn render<P: AsRef<Path>, T: ToJson>(self, path: P, data: T) {
        let need_content_type = !self.resp().has_header::<ContentType>();
        if need_content_type {
            self.resp_mut().header(ContentType::html());
        }

        let mut handlebars = Handlebars::new();
        let path = path.as_ref();
        let name = path.file_stem().unwrap().to_str().unwrap();

        handlebars.register_template_file(name, path).unwrap();
        // ignore errors if partials folder does not exist
        let _ = register_partials(&mut handlebars);
        let result = handlebars.render(name, &data);
        self.send(result.unwrap())
    }

    /// Sends the given content and ends this response.
    ///
    /// Status defaults to 200 Ok, headers must have been set before this method is called.
    pub fn send<D: Into<Vec<u8>>>(mut self, content: D) {
        self.resp_mut().send(content);
        let length = self.resp().len();
        self.len(length as u64);
    }

    /// Sends the given file, setting the Content-Type based on the file's extension.
    ///
    /// Known extensions are htm, html, jpg, jpeg, png, js, css.
    /// If the file does not exist, this method sends a 404 Not Found response.
    pub fn send_file<P: AsRef<Path>>(mut self, path: P) {
        let need_content_type = !self.resp().has_header::<ContentType>();
        if need_content_type {
            let extension = path.as_ref().extension();
            if let Some(ext) = extension {
                let content_type = match ext.to_string_lossy().as_ref() {
                    "htm" | "html" => Some(ContentType::html()),
                    "jpg" | "jpeg" => Some(ContentType::jpeg()),
                    "png" => Some(ContentType::png()),
                    "js" => Some(ContentType(Mime(TopLevel::Text, SubLevel::Javascript, vec![(Attr::Charset, Value::Utf8)]))),
                    "css" => Some(ContentType(Mime(TopLevel::Text, SubLevel::Css, vec![(Attr::Charset, Value::Utf8)]))),
                    _ => None
                };

                if let Some(content_type) = content_type {
                    self.resp_mut().header(content_type);
                }
            }
        }

        // read the whole file at once and send it
        // probably not the best idea for big files, we should use stream instead in that case
        match File::open(path) {
            Ok(mut file) => {
                let mut buf = Vec::with_capacity(file.metadata().ok().map_or(1024, |meta| meta.len() as usize));
                if let Err(err) = file.read_to_end(&mut buf) {
                    self.status(Status::InternalServerError).content_type("text/plain");
                    self.send(format!("{}", err))
                } else {
                    self.send(buf)
                }
            },
            Err(ref err) if err.kind() == ErrorKind::NotFound => self.end(Status::NotFound),
            Err(ref err) => {
                self.status(Status::InternalServerError).content_type("text/plain");
                self.send(format!("{}", err))
            }
        }
    }

    /// Moves to streaming mode.
    pub fn stream(self) -> Response<Streaming> {
        self.resp_mut().init_deque();
        Response {
            resp: self.resp,
            streaming: true,
            _marker: PhantomData
        }
    }
}

impl Response<Streaming> {
    /// Appends the given content to this response's body.
    pub fn append<D: AsRef<[u8]>>(&mut self, content: D) {
        println!("append {} bytes", content.as_ref().len());
        self.resp().append(content);
    }
}

fn register_partials(handlebars: &mut Handlebars) -> Result<()> {
    for it in try!(read_dir("views/partials")) {
        let entry = try!(it);
        let path = entry.path();
        if path.extension().is_some() && path.extension().unwrap() == "hbs" {
            let name = path.file_stem().unwrap().to_str().unwrap();
            handlebars.register_template_file(name, path.as_path()).unwrap();
        }
    }
    Ok(())
}
<|endoftext|>