<commit_before>use common::slice::GetSlice;

use alloc::boxed::Box;

use arch::memory::Memory;

use collections::slice;
use collections::string::{String, ToString};
use collections::vec::Vec;

use common::debug;

use core::cmp;

use disk::Disk;
use disk::ide::Extent;

use fs::redoxfs::{FileSystem, Node, NodeData};

use fs::{KScheme, Resource, ResourceSeek, Url, VecResource};

use syscall::{O_CREAT, O_TRUNC, MODE_DIR, MODE_FILE, Stat};

use system::error::{Error, Result, ENOENT, EIO};

/// A file resource
pub struct FileResource {
    pub scheme: *mut FileScheme,
    pub node: Node,
    pub vec: Vec<u8>,
    pub seek: usize,
    pub dirty: bool,
}

impl Resource for FileResource {
    fn dup(&self) -> Result<Box<Resource>> {
        Ok(box FileResource {
            scheme: self.scheme,
            node: self.node.clone(),
            vec: self.vec.clone(),
            seek: self.seek,
            dirty: self.dirty,
        })
    }

    fn path(&self, buf: &mut [u8]) -> Result<usize> {
        let path_a = b"file:/";
        let path_b = self.node.name.as_bytes();
        for (b, p) in buf.iter_mut().zip(path_a.iter().chain(path_b.iter())) {
            *b = *p;
        }

        Ok(cmp::min(buf.len(), path_a.len() + path_b.len()))
    }

    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        let mut i = 0;
        while i < buf.len() && self.seek < self.vec.len() {
            match self.vec.get(self.seek) {
                Some(b) => buf[i] = *b,
                None => (),
            }
            self.seek += 1;
            i += 1;
        }
        Ok(i)
    }

    fn write(&mut self, buf: &[u8]) -> Result<usize> {
        let mut i = 0;
        while i < buf.len() && self.seek < self.vec.len() {
            self.vec[self.seek] = buf[i];
            self.seek += 1;
            i += 1;
        }
        while i < buf.len() {
            self.vec.push(buf[i]);
            self.seek += 1;
            i += 1;
        }
        if i > 0 {
            self.dirty = true;
        }
        Ok(i)
    }

    fn seek(&mut self, pos: ResourceSeek) -> Result<usize> {
        match pos {
            ResourceSeek::Start(offset) => self.seek = offset,
            ResourceSeek::Current(offset) =>
                self.seek = cmp::max(0, self.seek as isize + offset) as usize,
            ResourceSeek::End(offset) =>
                self.seek = cmp::max(0, self.vec.len() as isize + offset) as usize,
        }
        while self.vec.len() < self.seek {
            self.vec.push(0);
        }
        Ok(self.seek)
    }

    // TODO: Check to make sure proper amount of bytes written. See Disk::write
    fn sync(&mut self) -> Result<()> {
        if self.dirty {
            let mut node_dirty = false;
            let mut pos = 0;
            let mut remaining = self.vec.len() as isize;
            for ref mut extent in &mut self.node.extents {
                if remaining > 0 && extent.empty() {
                    debug::d("Reallocate file, extra: ");
                    debug::ds(remaining);
                    debug::dl();

                    unsafe {
                        let sectors = ((remaining + 511) / 512) as u64;
                        if (*self.scheme).fs.header.free_space.length >= sectors * 512 {
                            extent.block = (*self.scheme).fs.header.free_space.block;
                            extent.length = remaining as u64;
                            (*self.scheme).fs.header.free_space.block = (*self.scheme)
                                                                            .fs
                                                                            .header
                                                                            .free_space
                                                                            .block +
                                                                        sectors;
                            (*self.scheme).fs.header.free_space.length = (*self.scheme)
                                                                             .fs
                                                                             .header
                                                                             .free_space
                                                                             .length -
                                                                         sectors * 512;

                            node_dirty = true;
                        }
                    }
                }

                // Make sure it is a valid extent
                if !extent.empty() {
                    let current_sectors = (extent.length as usize + 511) / 512;
                    let max_size = current_sectors * 512;

                    let size = cmp::min(remaining as usize, max_size);

                    if size as u64 != extent.length {
                        extent.length = size as u64;
                        node_dirty = true;
                    }

                    while self.vec.len() < pos + max_size {
                        self.vec.push(0);
                    }

                    unsafe {
                        let _ = (*self.scheme).fs.disk.write(extent.block, &self.vec[pos .. pos + max_size]);
                    }

                    self.vec.truncate(pos + size);

                    pos += size;
                    remaining -= size as isize;
                }
            }

            if node_dirty {
                debug::d("Node dirty, rewrite\n");

                if self.node.block > 0 {
                    unsafe {
                        if let Some(mut node_data) = Memory::<NodeData>::new(1) {
                            node_data.write(0, self.node.data());

                            let mut buffer = slice::from_raw_parts(node_data.address() as *mut u8, 512);
                            let _ = (*self.scheme).fs.disk.write(self.node.block, &mut buffer);

                            debug::d("Renode\n");

                            for mut node in (*self.scheme).fs.nodes.iter_mut() {
                                if node.block == self.node.block {
                                    *node = self.node.clone();
                                }
                            }
                        }
                    }
                } else {
                    debug::d("Need to place Node block\n");
                }
            }

            self.dirty = false;

            if remaining > 0 {
                debug::d("Need to defragment file, extra: ");
                debug::ds(remaining);
                debug::dl();
                return Err(Error::new(EIO));
            }
        }
        Ok(())
    }

    fn truncate(&mut self, len: usize) -> Result<()> {
        while len > self.vec.len() {
            self.vec.push(0);
        }
        self.vec.truncate(len);
        self.seek = cmp::min(self.seek, self.vec.len());
        self.dirty = true;
        Ok(())
    }
}

impl Drop for FileResource {
    fn drop(&mut self) {
        let _ = self.sync();
    }
}

/// A file scheme (pci + fs)
pub struct FileScheme {
    fs: FileSystem,
}

impl FileScheme {
    /// Create a new file scheme from an array of Disks
    pub fn new(mut disks: Vec<Box<Disk>>) -> Option<Box<Self>> {
        while ! disks.is_empty() {
            let disk = disks.remove(0);
            let name = disk.name();
            match FileSystem::from_disk(disk) {
                Ok(fs) => return Some(box FileScheme { fs: fs }),
                Err(err) => debugln!("{}: {}", name, err)
            }
        }

        None
    }
}

impl KScheme for FileScheme {
    fn on_irq(&mut self, _irq: u8) {
        /*if irq == self.fs.disk.irq {
        }*/
    }

    fn scheme(&self) -> &str {
        "file"
    }

    fn open(&mut self, url: Url, flags: usize) -> Result<Box<Resource>> {
        let path = url.reference().trim_matches('/');

        let children = self.fs.list(path);
        if ! children.is_empty() {
            let mut list = String::new();
            let mut dirs: Vec<String> = Vec::new();

            for file in children.iter() {
                let mut line = String::new();
                match file.find('/') {
                    Some(index) => {
                        let dirname = file.get_slice(..index + 1).to_string();
                        let mut found = false;
                        for dir in dirs.iter() {
                            if dirname == *dir {
                                found = true;
                                break;
                            }
                        }
                        if found {
                            line.clear();
                        } else {
                            line = dirname.clone();
                            dirs.push(dirname);
                        }
                    }
                    None => line = file.clone(),
                }
                if !line.is_empty() {
                    if !list.is_empty() {
                        list = list + "\n" + &line;
                    } else {
                        list = line;
                    }
                }
            }

            if list.len() > 0 {
                Ok(box VecResource::new(url.to_string(), list.into_bytes()))
            } else {
                Err(Error::new(ENOENT))
            }
        } else {
            match self.fs.node(path) {
                Some(node) => {
                    let mut vec: Vec<u8> = Vec::new();
                    for extent in &node.extents {
                        if extent.block > 0 && extent.length > 0 {
                            let current_sectors = (extent.length as usize + 511) / 512;
                            let max_size = current_sectors * 512;

                            let size = cmp::min(extent.length as usize, max_size);

                            let pos = vec.len();

                            while vec.len() < pos + max_size {
                                vec.push(0);
                            }

                            let _ = self.fs.disk.read(extent.block, &mut vec[pos..pos + max_size]);

                            vec.truncate(pos + size);
                        }
                    }

                    let mut resource = box FileResource {
                        scheme: self,
                        node: node,
                        vec: vec,
                        seek: 0,
                        dirty: false,
                    };

                    if flags & O_TRUNC == O_TRUNC {
                        try!(resource.truncate(0));
                    }

                    Ok(resource)
                }
                None => {
                    if flags & O_CREAT == O_CREAT {
                        // TODO: Create file
                        let mut node = Node {
                            block: 0,
                            name: path.to_string(),
                            extents: [Extent {
                                block: 0,
                                length: 0,
                            }; 16],
                        };

                        if self.fs.header.free_space.length >= 512 {
                            node.block = self.fs.header.free_space.block;
                            self.fs.header.free_space.block = self.fs.header.free_space.block + 1;
                            self.fs.header.free_space.length = self.fs.header.free_space.length -
                                                               512;
                        }

                        self.fs.nodes.push(node.clone());

                        Ok(box FileResource {
                            scheme: self,
                            node: node,
                            vec: Vec::new(),
                            seek: 0,
                            dirty: false,
                        })
                    } else {
                        Err(Error::new(ENOENT))
                    }
                }
            }
        }
    }

    fn stat(&mut self, url: Url, stat: &mut Stat) -> Result<()> {
        let path = url.reference().trim_matches('/');

        let children = self.fs.list(path);
        if ! children.is_empty() {
            let mut list = String::new();
            let mut dirs: Vec<String> = Vec::new();

            for file in children.iter() {
                let mut line = String::new();
                match file.find('/') {
                    Some(index) => {
                        let dirname = file.get_slice(..index + 1).to_string();
                        let mut found = false;
                        for dir in dirs.iter() {
                            if dirname == *dir {
                                found = true;
                                break;
                            }
                        }
                        if found {
                            line.clear();
                        } else {
                            line = dirname.clone();
                            dirs.push(dirname);
                        }
                    }
                    None => line = file.clone(),
                }
                if !line.is_empty() {
                    if !list.is_empty() {
                        list = list + "\n" + &line;
                    } else {
                        list = line;
                    }
                }
            }

            if list.len() > 0 {
                stat.st_mode = MODE_DIR;
                stat.st_size = list.len() as u64;

                Ok(())
            } else {
                Err(Error::new(ENOENT))
            }
        } else {
            match self.fs.node(path) {
                Some(node) => {
                    stat.st_mode = MODE_FILE;
                    stat.st_size = 0;

                    for extent in &node.extents {
                        if extent.block > 0 && extent.length > 0 {
                            stat.st_size += extent.length;
                        }
                    }

                    Ok(())
                }
                None => Err(Error::new(ENOENT))
            }
        }
    }

    fn unlink(&mut self, url: Url) -> Result<()> {
        let mut ret = Err(Error::new(ENOENT));

        let path = url.reference().trim_matches('/');

        let mut i = 0;
        while i < self.fs.nodes.len() {
            let mut remove = false;

            if let Some(node) = self.fs.nodes.get(i) {
                remove = node.name == path;
            }

            if remove {
                self.fs.nodes.remove(i);
                ret = Ok(());
            } else {
                i += 1;
            }
        }

        ret
    }
}
<commit_msg>Comment out write messages<commit_after>use common::slice::GetSlice;

use alloc::boxed::Box;

use arch::memory::Memory;

use collections::slice;
use collections::string::{String, ToString};
use collections::vec::Vec;

use common::debug;

use core::cmp;

use disk::Disk;
use disk::ide::Extent;

use fs::redoxfs::{FileSystem, Node, NodeData};

use fs::{KScheme, Resource, ResourceSeek, Url, VecResource};

use syscall::{O_CREAT, O_TRUNC, MODE_DIR, MODE_FILE, Stat};

use system::error::{Error, Result, ENOENT, EIO};

/// A file resource
pub struct FileResource {
    pub scheme: *mut FileScheme,
    pub node: Node,
    pub vec: Vec<u8>,
    pub seek: usize,
    pub dirty: bool,
}

impl Resource for FileResource {
    fn dup(&self) -> Result<Box<Resource>> {
        Ok(box FileResource {
            scheme: self.scheme,
            node: self.node.clone(),
            vec: self.vec.clone(),
            seek: self.seek,
            dirty: self.dirty,
        })
    }

    fn path(&self, buf: &mut [u8]) -> Result<usize> {
        let path_a = b"file:/";
        let path_b = self.node.name.as_bytes();
        for (b, p) in buf.iter_mut().zip(path_a.iter().chain(path_b.iter())) {
            *b = *p;
        }

        Ok(cmp::min(buf.len(), path_a.len() + path_b.len()))
    }

    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        let mut i = 0;
        while i < buf.len() && self.seek < self.vec.len() {
            match self.vec.get(self.seek) {
                Some(b) => buf[i] = *b,
                None => (),
            }
            self.seek += 1;
            i += 1;
        }
        Ok(i)
    }

    fn write(&mut self, buf: &[u8]) -> Result<usize> {
        let mut i = 0;
        while i < buf.len() && self.seek < self.vec.len() {
            self.vec[self.seek] = buf[i];
            self.seek += 1;
            i += 1;
        }
        while i < buf.len() {
            self.vec.push(buf[i]);
            self.seek += 1;
            i += 1;
        }
        if i > 0 {
            self.dirty = true;
        }
        Ok(i)
    }

    fn seek(&mut self, pos: ResourceSeek) -> Result<usize> {
        match pos {
            ResourceSeek::Start(offset) => self.seek = offset,
            ResourceSeek::Current(offset) =>
                self.seek = cmp::max(0, self.seek as isize + offset) as usize,
            ResourceSeek::End(offset) =>
                self.seek = cmp::max(0, self.vec.len() as isize + offset) as usize,
        }
        while self.vec.len() < self.seek {
            self.vec.push(0);
        }
        Ok(self.seek)
    }

    // TODO: Check to make sure proper amount of bytes written. See Disk::write
    fn sync(&mut self) -> Result<()> {
        if self.dirty {
            let mut node_dirty = false;
            let mut pos = 0;
            let mut remaining = self.vec.len() as isize;
            for ref mut extent in &mut self.node.extents {
                if remaining > 0 && extent.empty() {
                    /*
                    debug::d("Reallocate file, extra: ");
                    debug::ds(remaining);
                    debug::dl();
                    */

                    unsafe {
                        let sectors = ((remaining + 511) / 512) as u64;
                        if (*self.scheme).fs.header.free_space.length >= sectors * 512 {
                            extent.block = (*self.scheme).fs.header.free_space.block;
                            extent.length = remaining as u64;
                            (*self.scheme).fs.header.free_space.block = (*self.scheme)
                                                                            .fs
                                                                            .header
                                                                            .free_space
                                                                            .block +
                                                                        sectors;
                            (*self.scheme).fs.header.free_space.length = (*self.scheme)
                                                                             .fs
                                                                             .header
                                                                             .free_space
                                                                             .length -
                                                                         sectors * 512;

                            node_dirty = true;
                        }
                    }
                }

                // Make sure it is a valid extent
                if !extent.empty() {
                    let current_sectors = (extent.length as usize + 511) / 512;
                    let max_size = current_sectors * 512;

                    let size = cmp::min(remaining as usize, max_size);

                    if size as u64 != extent.length {
                        extent.length = size as u64;
                        node_dirty = true;
                    }

                    while self.vec.len() < pos + max_size {
                        self.vec.push(0);
                    }

                    unsafe {
                        let _ = (*self.scheme).fs.disk.write(extent.block, &self.vec[pos .. pos + max_size]);
                    }

                    self.vec.truncate(pos + size);

                    pos += size;
                    remaining -= size as isize;
                }
            }

            if node_dirty {
                //debug::d("Node dirty, rewrite\n");

                if self.node.block > 0 {
                    unsafe {
                        if let Some(mut node_data) = Memory::<NodeData>::new(1) {
                            node_data.write(0, self.node.data());

                            let mut buffer = slice::from_raw_parts(node_data.address() as *mut u8, 512);
                            let _ = (*self.scheme).fs.disk.write(self.node.block, &mut buffer);

                            //debug::d("Renode\n");

                            for mut node in (*self.scheme).fs.nodes.iter_mut() {
                                if node.block == self.node.block {
                                    *node = self.node.clone();
                                }
                            }
                        }
                    }
                } else {
                    debug::d("Need to place Node block\n");
                }
            }

            self.dirty = false;

            if remaining > 0 {
                debug::d("Need to defragment file, extra: ");
                debug::ds(remaining);
                debug::dl();
                return Err(Error::new(EIO));
            }
        }
        Ok(())
    }

    fn truncate(&mut self, len: usize) -> Result<()> {
        while len > self.vec.len() {
            self.vec.push(0);
        }
        self.vec.truncate(len);
        self.seek = cmp::min(self.seek, self.vec.len());
        self.dirty = true;
        Ok(())
    }
}

impl Drop for FileResource {
    fn drop(&mut self) {
        let _ = self.sync();
    }
}

/// A file scheme (pci + fs)
pub struct FileScheme {
    fs: FileSystem,
}

impl FileScheme {
    /// Create a new file scheme from an array of Disks
    pub fn new(mut disks: Vec<Box<Disk>>) -> Option<Box<Self>> {
        while ! disks.is_empty() {
            let disk = disks.remove(0);
            let name = disk.name();
            match FileSystem::from_disk(disk) {
                Ok(fs) => return Some(box FileScheme { fs: fs }),
                Err(err) => debugln!("{}: {}", name, err)
            }
        }

        None
    }
}

impl KScheme for FileScheme {
    fn on_irq(&mut self, _irq: u8) {
        /*if irq == self.fs.disk.irq {
        }*/
    }

    fn scheme(&self) -> &str {
        "file"
    }

    fn open(&mut self, url: Url, flags: usize) -> Result<Box<Resource>> {
        let path = url.reference().trim_matches('/');

        let children = self.fs.list(path);
        if ! children.is_empty() {
            let mut list = String::new();
            let mut dirs: Vec<String> = Vec::new();

            for file in children.iter() {
                let mut line = String::new();
                match file.find('/') {
                    Some(index) => {
                        let dirname = file.get_slice(..index + 1).to_string();
                        let mut found = false;
                        for dir in dirs.iter() {
                            if dirname == *dir {
                                found = true;
                                break;
                            }
                        }
                        if found {
                            line.clear();
                        } else {
                            line = dirname.clone();
                            dirs.push(dirname);
                        }
                    }
                    None => line = file.clone(),
                }
                if !line.is_empty() {
                    if !list.is_empty() {
                        list = list + "\n" + &line;
                    } else {
                        list = line;
                    }
                }
            }

            if list.len() > 0 {
                Ok(box VecResource::new(url.to_string(), list.into_bytes()))
            } else {
                Err(Error::new(ENOENT))
            }
        } else {
            match self.fs.node(path) {
                Some(node) => {
                    let mut vec: Vec<u8> = Vec::new();
                    for extent in &node.extents {
                        if extent.block > 0 && extent.length > 0 {
                            let current_sectors = (extent.length as usize + 511) / 512;
                            let max_size = current_sectors * 512;

                            let size = cmp::min(extent.length as usize, max_size);

                            let pos = vec.len();

                            while vec.len() < pos + max_size {
                                vec.push(0);
                            }

                            let _ = self.fs.disk.read(extent.block, &mut vec[pos..pos + max_size]);

                            vec.truncate(pos + size);
                        }
                    }

                    let mut resource = box FileResource {
                        scheme: self,
                        node: node,
                        vec: vec,
                        seek: 0,
                        dirty: false,
                    };

                    if flags & O_TRUNC == O_TRUNC {
                        try!(resource.truncate(0));
                    }

                    Ok(resource)
                }
                None => {
                    if flags & O_CREAT == O_CREAT {
                        // TODO: Create file
                        let mut node = Node {
                            block: 0,
                            name: path.to_string(),
                            extents: [Extent {
                                block: 0,
                                length: 0,
                            }; 16],
                        };

                        if self.fs.header.free_space.length >= 512 {
                            node.block = self.fs.header.free_space.block;
                            self.fs.header.free_space.block = self.fs.header.free_space.block + 1;
                            self.fs.header.free_space.length = self.fs.header.free_space.length -
                                                               512;
                        }

                        self.fs.nodes.push(node.clone());

                        Ok(box FileResource {
                            scheme: self,
                            node: node,
                            vec: Vec::new(),
                            seek: 0,
                            dirty: false,
                        })
                    } else {
                        Err(Error::new(ENOENT))
                    }
                }
            }
        }
    }

    fn stat(&mut self, url: Url, stat: &mut Stat) -> Result<()> {
        let path = url.reference().trim_matches('/');

        let children = self.fs.list(path);
        if ! children.is_empty() {
            let mut list = String::new();
            let mut dirs: Vec<String> = Vec::new();

            for file in children.iter() {
                let mut line = String::new();
                match file.find('/') {
                    Some(index) => {
                        let dirname = file.get_slice(..index + 1).to_string();
                        let mut found = false;
                        for dir in dirs.iter() {
                            if dirname == *dir {
                                found = true;
                                break;
                            }
                        }
                        if found {
                            line.clear();
                        } else {
                            line = dirname.clone();
                            dirs.push(dirname);
                        }
                    }
                    None => line = file.clone(),
                }
                if !line.is_empty() {
                    if !list.is_empty() {
                        list = list + "\n" + &line;
                    } else {
                        list = line;
                    }
                }
            }

            if list.len() > 0 {
                stat.st_mode = MODE_DIR;
                stat.st_size = list.len() as u64;

                Ok(())
            } else {
                Err(Error::new(ENOENT))
            }
        } else {
            match self.fs.node(path) {
                Some(node) => {
                    stat.st_mode = MODE_FILE;
                    stat.st_size = 0;

                    for extent in &node.extents {
                        if extent.block > 0 && extent.length > 0 {
                            stat.st_size += extent.length;
                        }
                    }

                    Ok(())
                }
                None => Err(Error::new(ENOENT))
            }
        }
    }

    fn unlink(&mut self, url: Url) -> Result<()> {
        let mut ret = Err(Error::new(ENOENT));

        let path = url.reference().trim_matches('/');

        let mut i = 0;
        while i < self.fs.nodes.len() {
            let mut remove = false;

            if let Some(node) = self.fs.nodes.get(i) {
                remove = node.name == path;
            }

            if remove {
                self.fs.nodes.remove(i);
                ret = Ok(());
            } else {
                i += 1;
            }
        }

        ret
    }
}
<|endoftext|>


<commit_before><commit_msg>Add stub metal_triangle example<commit_after>extern crate metl;

use metl::Device;
use metl::extras::window::{WindowBuilder};

fn main() {
    let window = WindowBuilder::new().build().unwrap();
    let device = Device::system_default_device().unwrap();

    // todo(burtonageo): implement
}
<|endoftext|>


<commit_before>//! A simple crate for executing work on a thread pool, and getting back a
//! future.
//!
//! This crate provides a simple thread pool abstraction for running work
//! externally from the current thread that's running. An instance of `Future`
//! is handed back to represent that the work may be done later, and futher
//! computations can be chained along with it as well.
//!
//! ```rust
//! extern crate futures;
//! extern crate futures_cpupool;
//!
//! use std::sync::mpsc::channel;
//!
//! use futures::Future;
//! use futures_cpupool::CpuPool;
//!
//! # fn long_running_computation() -> u32 { 2 }
//! # fn long_running_computation2(a: u32) -> u32 { a }
//! # fn main() {
//!
//! // Create a worker thread pool with four threads
//! let pool = CpuPool::new(4);
//!
//! // Execute some work on the thread pool, optionally closing over data.
//! let a = pool.execute(long_running_computation);
//! let b = pool.execute(|| long_running_computation2(100));
//!
//! // Express some further computation once the work is completed on the thread
//! // pool.
//! let c = a.join(b).map(|(a, b)| a + b);
//!
//! // Block the current thread to get the result.
//! let (tx, rx) = channel();
//! c.then(move |res| {
//!     tx.send(res)
//! }).forget();
//! let res = rx.recv().unwrap();
//!
//! // Print out the result
//! println!("{:?}", res);
//! # }
//! ```

#![deny(missing_docs)]

extern crate crossbeam;
extern crate futures;
extern crate num_cpus;

use std::any::Any;
use std::panic::{self, AssertUnwindSafe};
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::thread;

use crossbeam::sync::MsQueue;
use futures::{Future, oneshot, Oneshot, Poll};

/// A thread pool intended to run CPU intensive work.
///
/// This thread pool will hand out futures representing the completed work
/// that happens on the thread pool itself, and the futures can then be later
/// composed with other work as part of an overall computation.
///
/// The worker threads associated with a thread pool are kept alive so long as
/// there is an open handle to the `CpuPool` or there is work running on them. Once
/// all work has been drained and all references have gone away the worker
/// threads will be shut down.
///
/// Currently `CpuPool` implements `Clone` which just clones a new reference to
/// the underlying thread pool.
pub struct CpuPool {
    inner: Arc<Inner>,
}

fn _assert() {
    fn _assert_send<T: Send>() {}
    fn _assert_sync<T: Sync>() {}
    _assert_send::<CpuPool>();
    _assert_sync::<CpuPool>();
}

struct Inner {
    queue: MsQueue<Message>,
    cnt: AtomicUsize,
    size: u32,
}

/// The type of future returned from the `CpuPool::execute` function.
///
/// This future will either resolve to `R`, the completed value, or
/// `Box<Any+Send>` if the computation panics (with the payload of the panic).
pub struct CpuFuture<R: Send + 'static> {
    inner: Oneshot<thread::Result<R>>,
}

trait Thunk: Send + 'static {
    fn call_box(self: Box<Self>);
}

impl<F: FnOnce() + Send + 'static> Thunk for F {
    fn call_box(self: Box<Self>) {
        (*self)()
    }
}

enum Message {
    Run(Box<Thunk>),
    Close,
}

impl CpuPool {
    /// Creates a new thread pool with `size` worker threads associated with it.
    ///
    /// The returned handle can use `execute` to run work on this thread pool,
    /// and clones can be made of it to get multiple references to the same
    /// thread pool.
    pub fn new(size: u32) -> CpuPool {
        let pool = CpuPool {
            inner: Arc::new(Inner {
                queue: MsQueue::new(),
                cnt: AtomicUsize::new(1),
                size: size,
            }),
        };

        for _ in 0..size {
            let pool = CpuPool { inner: pool.inner.clone() };
            thread::spawn(|| pool.work());
        }

        return pool
    }

    /// Creates a new thread pool with a number of workers equal to the number
    /// of CPUs on the host.
    pub fn new_num_cpus() -> CpuPool {
        CpuPool::new(num_cpus::get() as u32)
    }

    /// Execute some work on this thread pool, returning a future to the work
    /// that's running on the thread pool.
    ///
    /// This function will execute the closure `f` on the associated thread
    /// pool, and return a future representing the finished computation. The
    /// future will either resolve to `R` if the computation finishes
    /// successfully or to `Box<Any+Send>` if it panics.
    pub fn execute<F, R>(&self, f: F) -> CpuFuture<R>
        where F: FnOnce() -> R + Send + 'static,
              R: Send + 'static,
    {
        let (tx, rx) = oneshot();
        self.inner.queue.push(Message::Run(Box::new(|| {
            tx.complete(panic::catch_unwind(AssertUnwindSafe(f)));
        })));
        CpuFuture { inner: rx }
    }

    fn work(self) {
        let mut done = false;
        while !done {
            match self.inner.queue.pop() {
                Message::Close => done = true,
                Message::Run(r) => r.call_box(),
            }
        }
    }
}

impl Clone for CpuPool {
    fn clone(&self) -> CpuPool {
        self.inner.cnt.fetch_add(1, Ordering::Relaxed);
        CpuPool { inner: self.inner.clone() }
    }
}

impl Drop for CpuPool {
    fn drop(&mut self) {
        if self.inner.cnt.fetch_sub(1, Ordering::Relaxed) > 1 {
            return
        }
        for _ in 0..self.inner.size {
            self.inner.queue.push(Message::Close);
        }
    }
}

impl<R: Send + 'static> Future for CpuFuture<R> {
    type Item = R;
    type Error = Box<Any + Send>;

    fn poll(&mut self) -> Poll<R, Box<Any + Send>> {
        match self.inner.poll() {
            Poll::Ok(res) => res.into(),
            Poll::Err(_) => panic!("shouldn't be canceled"),
            Poll::NotReady => Poll::NotReady,
        }
    }
}
<commit_msg>Add a TODO in futures-cpupool to skip work<commit_after>//! A simple crate for executing work on a thread pool, and getting back a
//! future.
//!
//! This crate provides a simple thread pool abstraction for running work
//! externally from the current thread that's running. An instance of `Future`
//! is handed back to represent that the work may be done later, and futher
//! computations can be chained along with it as well.
//!
//! ```rust
//! extern crate futures;
//! extern crate futures_cpupool;
//!
//! use std::sync::mpsc::channel;
//!
//! use futures::Future;
//! use futures_cpupool::CpuPool;
//!
//! # fn long_running_computation() -> u32 { 2 }
//! # fn long_running_computation2(a: u32) -> u32 { a }
//! # fn main() {
//!
//! // Create a worker thread pool with four threads
//! let pool = CpuPool::new(4);
//!
//! // Execute some work on the thread pool, optionally closing over data.
//! let a = pool.execute(long_running_computation);
//! let b = pool.execute(|| long_running_computation2(100));
//!
//! // Express some further computation once the work is completed on the thread
//! // pool.
//! let c = a.join(b).map(|(a, b)| a + b);
//!
//! // Block the current thread to get the result.
//! let (tx, rx) = channel();
//! c.then(move |res| {
//!     tx.send(res)
//! }).forget();
//! let res = rx.recv().unwrap();
//!
//! // Print out the result
//! println!("{:?}", res);
//! # }
//! ```

#![deny(missing_docs)]

extern crate crossbeam;
extern crate futures;
extern crate num_cpus;

use std::any::Any;
use std::panic::{self, AssertUnwindSafe};
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::thread;

use crossbeam::sync::MsQueue;
use futures::{Future, oneshot, Oneshot, Poll};

/// A thread pool intended to run CPU intensive work.
///
/// This thread pool will hand out futures representing the completed work
/// that happens on the thread pool itself, and the futures can then be later
/// composed with other work as part of an overall computation.
///
/// The worker threads associated with a thread pool are kept alive so long as
/// there is an open handle to the `CpuPool` or there is work running on them. Once
/// all work has been drained and all references have gone away the worker
/// threads will be shut down.
///
/// Currently `CpuPool` implements `Clone` which just clones a new reference to
/// the underlying thread pool.
pub struct CpuPool {
    inner: Arc<Inner>,
}

fn _assert() {
    fn _assert_send<T: Send>() {}
    fn _assert_sync<T: Sync>() {}
    _assert_send::<CpuPool>();
    _assert_sync::<CpuPool>();
}

struct Inner {
    queue: MsQueue<Message>,
    cnt: AtomicUsize,
    size: u32,
}

/// The type of future returned from the `CpuPool::execute` function.
///
/// This future will either resolve to `R`, the completed value, or
/// `Box<Any+Send>` if the computation panics (with the payload of the panic).
pub struct CpuFuture<R: Send + 'static> {
    inner: Oneshot<thread::Result<R>>,
}

trait Thunk: Send + 'static {
    fn call_box(self: Box<Self>);
}

impl<F: FnOnce() + Send + 'static> Thunk for F {
    fn call_box(self: Box<Self>) {
        (*self)()
    }
}

enum Message {
    Run(Box<Thunk>),
    Close,
}

impl CpuPool {
    /// Creates a new thread pool with `size` worker threads associated with it.
    ///
    /// The returned handle can use `execute` to run work on this thread pool,
    /// and clones can be made of it to get multiple references to the same
    /// thread pool.
    pub fn new(size: u32) -> CpuPool {
        let pool = CpuPool {
            inner: Arc::new(Inner {
                queue: MsQueue::new(),
                cnt: AtomicUsize::new(1),
                size: size,
            }),
        };

        for _ in 0..size {
            let pool = CpuPool { inner: pool.inner.clone() };
            thread::spawn(|| pool.work());
        }

        return pool
    }

    /// Creates a new thread pool with a number of workers equal to the number
    /// of CPUs on the host.
    pub fn new_num_cpus() -> CpuPool {
        CpuPool::new(num_cpus::get() as u32)
    }

    /// Execute some work on this thread pool, returning a future to the work
    /// that's running on the thread pool.
    ///
    /// This function will execute the closure `f` on the associated thread
    /// pool, and return a future representing the finished computation. The
    /// future will either resolve to `R` if the computation finishes
    /// successfully or to `Box<Any+Send>` if it panics.
    pub fn execute<F, R>(&self, f: F) -> CpuFuture<R>
        where F: FnOnce() -> R + Send + 'static,
              R: Send + 'static,
    {
        let (tx, rx) = oneshot();
        self.inner.queue.push(Message::Run(Box::new(|| {
            // TODO: should check to see if `tx` is canceled by the time we're
            //       running, and if so we just skip the entire computation.
            tx.complete(panic::catch_unwind(AssertUnwindSafe(f)));
        })));
        CpuFuture { inner: rx }
    }

    fn work(self) {
        let mut done = false;
        while !done {
            match self.inner.queue.pop() {
                Message::Close => done = true,
                Message::Run(r) => r.call_box(),
            }
        }
    }
}

impl Clone for CpuPool {
    fn clone(&self) -> CpuPool {
        self.inner.cnt.fetch_add(1, Ordering::Relaxed);
        CpuPool { inner: self.inner.clone() }
    }
}

impl Drop for CpuPool {
    fn drop(&mut self) {
        if self.inner.cnt.fetch_sub(1, Ordering::Relaxed) > 1 {
            return
        }
        for _ in 0..self.inner.size {
            self.inner.queue.push(Message::Close);
        }
    }
}

impl<R: Send + 'static> Future for CpuFuture<R> {
    type Item = R;
    type Error = Box<Any + Send>;

    fn poll(&mut self) -> Poll<R, Box<Any + Send>> {
        match self.inner.poll() {
            Poll::Ok(res) => res.into(),
            Poll::Err(_) => panic!("shouldn't be canceled"),
            Poll::NotReady => Poll::NotReady,
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>a TableService example that lists all the tables<commit_after>use azure_sdk_storage_core::client::Client;
use azure_sdk_storage_table::table::TableService;
use futures::future::*;
use std::error::Error;
use tokio_core::reactor::Core;

fn main() {
    code().unwrap();
}

// We run a separate method to use the elegant quotation mark operator.
// A series of unwrap(), unwrap() would have achieved the same result.
fn code() -> Result<(), Box<dyn Error>> {
    // First we retrieve the account name and master key from environment variables.
    let account = std::env::var("STORAGE_ACCOUNT").expect("Set env variable STORAGE_ACCOUNT first!");
    let master_key = std::env::var("STORAGE_MASTER_KEY").expect("Set env variable STORAGE_MASTER_KEY first!");

    let mut core = Core::new()?;

    let client = Client::new(&account, &master_key)?;
    let table_service = TableService::new(client);

    let future = table_service.list_tables().and_then(move |tables| {
        println!("Account {} has {} tables(s)", account, tables.len());
        for ref table in tables {
            println!("{}", table);
        }
        Ok(())
    });

    core.run(future)?;
    Ok(())
}<|endoftext|>


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

#![allow(non_snake_case)]

register_long_diagnostics! {

E0510: r##"
`return_address` was used in an invalid context. Erroneous code example:

```
extern "rust-intrinsic" {
    fn return_address() -> *const u8;
}

pub unsafe fn by_value() -> i32 {
    let _ = return_address();
    // error: invalid use of `return_address` intrinsic: function does
    //        not use out pointer
    0
}
```

Returned values are stored in registers. In the case where the returned
type doesn't fit in a register, the function returns `()` and has an
additional input argument, this is a pointer where the result should
be written. Example:

```
extern "rust-intrinsic" {
    fn return_address() -> *const u8;
}

pub unsafe fn by_pointer() -> String {
    let _ = return_address();
    String::new() // ok!
}
```
"##,

E0512: r##"
A transmute was called on types with different sizes. Erroneous code example:

```
extern "rust-intrinsic" {
    pub fn ctpop8(x: u8) -> u8;
}

fn main() {
    unsafe { ctpop8(::std::mem::transmute(0u16)); }
    // error: transmute called on types with different sizes
}
```

Please use types with same size or use the awaited type directly. Example:

```
extern "rust-intrinsic" {
    pub fn ctpop8(x: u8) -> u8;
}

fn main() {
    unsafe { ctpop8(::std::mem::transmute(0i8)); } // ok!
    // or:
    unsafe { ctpop8(0u8); } // ok!
}
```
"##,

E0515: r##"
A constant index expression was out of bounds. Erroneous code example:

```
let x = &[0, 1, 2][7]; // error: const index-expr is out of bounds
```

Please specify a valid index (not inferior to 0 or superior to array length).
Example:

```
let x = &[0, 1, 2][2]; // ok
```
"##,

}

register_diagnostics! {
    E0511, // invalid monomorphization of `{}` intrinsic
}
<commit_msg>Add E0511 error explanation<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(non_snake_case)]

register_long_diagnostics! {

E0510: r##"
`return_address` was used in an invalid context. Erroneous code example:

```
extern "rust-intrinsic" {
    fn return_address() -> *const u8;
}

pub unsafe fn by_value() -> i32 {
    let _ = return_address();
    // error: invalid use of `return_address` intrinsic: function does
    //        not use out pointer
    0
}
```

Return values may be stored in a return register(s) or written into a so-called
out pointer. In case the returned value is too big (this is
target-ABI-dependent and generally not portable or future proof) to fit into
the return register(s), the compiler will return the value by writing it into
space allocated in the caller's stack frame. Example:

```
extern "rust-intrinsic" {
    fn return_address() -> *const u8;
}

pub unsafe fn by_pointer() -> String {
    let _ = return_address();
    String::new() // ok!
}
```
"##,

E0511: r##"
Invalid monomorphization of an intrinsic function was used. Erroneous code
example:

```
extern "platform-intrinsic" {
    fn simd_add<T>(a: T, b: T) -> T;
}

unsafe { simd_add(0, 1); }
// error: invalid monomorphization of `simd_add` intrinsic
```

The generic type has to be a SIMD type. Example:

```
#[repr(simd)]
#[derive(Copy, Clone)]
struct i32x1(i32);

extern "platform-intrinsic" {
    fn simd_add<T>(a: T, b: T) -> T;
}

unsafe { simd_add(i32x1(0), i32x1(1)); } // ok!
```
"##,

E0512: r##"
Transmute with two differently sized types was attempted. Erroneous code
example:

```
extern "rust-intrinsic" {
    pub fn ctpop8(x: u8) -> u8;
}

fn main() {
    unsafe { ctpop8(::std::mem::transmute(0u16)); }
    // error: transmute called with differently sized types
}
```

Please use types with same size or use the expected type directly. Example:

```
extern "rust-intrinsic" {
    pub fn ctpop8(x: u8) -> u8;
}

fn main() {
    unsafe { ctpop8(::std::mem::transmute(0i8)); } // ok!
    // or:
    unsafe { ctpop8(0u8); } // ok!
}
```
"##,

E0515: r##"
A constant index expression was out of bounds. Erroneous code example:

```
let x = &[0, 1, 2][7]; // error: const index-expr is out of bounds
```

Please specify a valid index (not inferior to 0 or superior to array length).
Example:

```
let x = &[0, 1, 2][2]; // ok
```
"##,

}
<|endoftext|>


<commit_before><commit_msg>Add new interrupt system, Rust rewrite<commit_after>use core::ptr;
use core::mem;

// These constants MUST have defined with same values as those in src/asm_routines/constants.asm
// They also MUST match the ones in plan.md
// If a constant defined here doesn't exists in that file, then it's also fine
const GDT_SELECTOR_CODE: u16 = 0x08;
const IDT_ADDRESS: usize = 0x0;
const IDTR_ADDRESS: usize = 0x1000;
const IDT_ENTRY_COUNT: usize = 0x100;

#[derive(Debug, Clone, Copy)]
#[repr(C, packed)]
struct IDTReference {
    limit: u16,
    offset: u64
}
impl IDTReference {
    pub fn new() -> IDTReference {
        IDTReference {
            limit: ((IDT_ENTRY_COUNT-1)*(mem::size_of::<IDTDescriptor>()))  as u16,
            offset: IDT_ADDRESS as u64
        }
    }
    pub fn write(&self) {
        unsafe {
            ptr::write(IDTR_ADDRESS as *mut Self, *self);
        }
    }
}

#[derive(Debug, Clone, Copy)]
#[repr(C, packed)]
pub struct IDTDescriptor {
    pointer_low: u16,
    gdt_selector: u16,
    zero: u8,
    options: u8,
    pointer_middle: u16,
    pointer_high: u32,
    reserved: u32
}

impl IDTDescriptor {
    pub fn new(present: bool, pointer: u64, ring: u8) -> IDTDescriptor {
        assert!(ring < 4);
        assert!(present || (pointer == 0 && ring == 0)); // pointer and ring must be 0 if not present
        // example options: present => 1, ring 0 => 00, interrupt gate => 0, interrupt gate => 1110,
        let options: u8 = 0b0_00_0_1110 | (ring << 5) | ((if present {1} else {0}) << 7);

        IDTDescriptor {
            pointer_low: (pointer & 0xffff) as u16,
            gdt_selector: GDT_SELECTOR_CODE,
            zero: 0,
            options: options,
            pointer_middle: ((pointer & 0xffff_0000) >> 16) as u16,
            pointer_high: ((pointer & 0xffff_ffff_0000_0000) >> 32) as u32,
            reserved: 0,
        }
    }
}

pub extern "C" fn exception_de() -> ! {
    panic!("Division by zero.");
}

pub extern "C" fn exception_df() -> ! {
    panic!("Double fault.");
}

pub extern "C" fn exception_gp() -> ! {
    unsafe {
        asm!("mov dword ptr [0xb8000], 0x4f654f31" ::: "memory" : "volatile", "intel");
    }
    panic!("General protection fault.");
}

pub fn init() {
    let mut exception_handlers: [Option<*const fn()>; IDT_ENTRY_COUNT] = [None; IDT_ENTRY_COUNT];

    exception_handlers[0x00] = Some(exception_de as *const fn());
    exception_handlers[0x08] = Some(exception_df as *const fn());
    exception_handlers[0x0d] = Some(exception_gp as *const fn());

    for index in 0...(IDT_ENTRY_COUNT-1) {
        let descriptor = match exception_handlers[index] {
            None            => {IDTDescriptor::new(false, 0, 0)},
            Some(pointer)   => {IDTDescriptor::new(true, pointer as u64, 0)} // TODO: currenly all are ring 0b00
        };
        unsafe {
            ptr::write_volatile((IDT_ADDRESS + index * mem::size_of::<IDTDescriptor>()) as *mut _, descriptor);
        }
    }

    IDTReference::new().write();

    unsafe {
        asm!("lidt [$0]" :: "r"(IDTR_ADDRESS) : "memory" : "volatile", "intel");
    }
}
<|endoftext|>


<commit_before><commit_msg>Tower of Hanoi in Rust<commit_after><|endoftext|>


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

//! SMTP client

use std::string::String;
use std::error::FromError;
use std::io::net::tcp::TcpStream;
use std::io::net::ip::{SocketAddr, ToSocketAddr};

use tools::get_first_word;
use common::{CRLF, MESSAGE_ENDING};
use response::Response;
use extension::Extension;
use command::Command;
use transaction::TransactionState;
use error::{SmtpResult, ErrorKind};
use client::connecter::Connecter;
use client::server_info::ServerInfo;
use client::stream::ClientStream;
use sendable_email::SendableEmail;

pub mod server_info;
pub mod connecter;
pub mod stream;

/// Structure that implements the SMTP client
pub struct Client<S = TcpStream> {
    /// TCP stream between client and server
    /// Value is None before connection
    stream: Option<S>,
    /// Socket we are connecting to
    server_addr: SocketAddr,
    /// Our hostname for HELO/EHLO commands
    my_hostname: String,
    /// Information about the server
    /// Value is None before HELO/EHLO
    server_info: Option<ServerInfo>,
    /// Transaction state, to check the sequence of commands
    state: TransactionState,
}

macro_rules! try_smtp (
    ($err: expr $client: ident) => ({
        match $err {
            Ok(val) => val,
            Err(err) => fail_with_err!(err $client),
        }
    })
)

macro_rules! fail_with_err (
    ($err: expr $client: ident) => ({
        $client.close_on_error();
        return Err(FromError::from_error($err))
    })
)

macro_rules! check_command_sequence (
    ($command: ident $client: ident) => ({
        if !$client.state.is_allowed(&$command) {
            fail_with_err!(
                Response{code: 503, message: Some("Bad sequence of commands".to_string())} $client
            );
        }
    })
)

impl<S = TcpStream> Client<S> {
    /// Creates a new SMTP client
    ///
    /// It does not connects to the server, but only create the `Client`
    pub fn new<A: ToSocketAddr>(addr: A, my_hostname: Option<&str>) -> Client<S> {
        Client{
            stream: None,
            server_addr: addr.to_socket_addr().unwrap(),
            my_hostname: my_hostname.unwrap_or("localhost").to_string(),
            server_info: None,
            state: TransactionState::new(),
        }
    }

    /// Creates a new local SMTP client to port 25
    ///
    /// It does not connects to the server, but only create the `Client`
    pub fn localhost() -> Client<S> {
        Client::new("localhost", Some("localhost"))
    }
}

impl<S: Connecter + ClientStream + Clone = TcpStream> Client<S> {
    /// Closes the SMTP transaction if possible, and then closes the TCP session
    fn close_on_error(&mut self) {
        if self.is_connected() {
            let _ = self.quit();
        }
        self.close();
    }

    /// Sends an email
    pub fn send_email<T: SendableEmail>(&mut self, email: T) -> SmtpResult {

        let from_address = email.from_address();
        let to_addresses = email.to_addresses();
        let message = email.message();

        // Connect to the server
        if !self.is_connected() {
            try!(self.connect());
        }

        // Extended Hello or Hello
        if let Err(error) = self.ehlo() {
            match error.kind {
                ErrorKind::PermanentError(Response{code: 550, message: _}) => {
                    try_smtp!(self.helo() self);
                },
                _ => {
                    try_smtp!(Err(error) self)
                },
            };
        }

        // Print server information
        debug!("server {}", self.server_info.as_ref().unwrap());

        // Mail
        try_smtp!(self.mail(from_address.as_slice()) self);

        // Log the mail command
        info!("from=<{}>, size={}, nrcpt={}", from_address, message.len(), to_addresses.len());

        // Recipient
        // TODO Return rejected addresses
        // TODO Manage the number of recipients
        for to_address in to_addresses.iter() {
            try_smtp!(self.rcpt(to_address.as_slice()) self);
        }

        // Data
        try_smtp!(self.data() self);

        // Message content
        let sent = try_smtp!(self.message(message.as_slice()) self);

        // Log the rcpt command
        info!("to=<{}>, status=sent ({})",
            to_addresses.connect(">, to=<"), sent);

        // Quit
        //try_smtp!(self.quit() self);

        return Ok(sent);
    }

    /// Connects to the configured server
    pub fn connect(&mut self) -> SmtpResult {
        let command = Command::Connect;
        check_command_sequence!(command self);

        // Connect should not be called when the client is already connected
        if !self.stream.is_none() {
            fail_with_err!("The connection is already established" self);
        }

        // Try to connect
        self.stream = Some(try!(Connecter::connect(self.server_addr)));

        // Log the connection
        info!("connection established to {}",
              self.stream.as_mut().unwrap().peer_name().unwrap());

        let result = try!(self.stream.as_mut().unwrap().get_reply());

        let checked_result = try!(command.test_success(result));
        self.state = self.state.next_state(&command).unwrap();
        Ok(checked_result)
    }

    /// Sends an SMTP command
    pub fn send_command(&mut self, command: Command) -> SmtpResult {
        // for now we do not support SMTPUTF8
        if !command.is_ascii() {
            fail_with_err!("Non-ASCII string" self);
        }
        self.send_server(command, None)
    }

    /// Sends the email content
    fn send_message(&mut self, message: &str) -> SmtpResult {
        self.send_server(Command::Message, Some(message))
    }

    /// Sends content to the server, after checking the command sequence, and then
    /// updates the transaction state
    ///
    /// * If `message` is `None`, the given command will be formatted and sent to the server
    /// * If `message` is `Some(str)`, the `str` string will be sent to the server
    fn send_server(&mut self, command: Command, message: Option<&str>) -> SmtpResult {
        check_command_sequence!(command self);

        let result = try!(match message {
            Some(message) => self.stream.as_mut().unwrap().send_and_get_response(
                                message, MESSAGE_ENDING
                             ),
            None          => self.stream.as_mut().unwrap().send_and_get_response(
                                command.to_string().as_slice(), CRLF
                             ),
        });

        let checked_result = try!(command.test_success(result));
        self.state = self.state.next_state(&command).unwrap();
        Ok(checked_result)
    }

    /// Checks if the server is connected using the NOOP SMTP command
    pub fn is_connected(&mut self) -> bool {
        self.noop().is_ok()
    }

    /// Closes the TCP stream
    pub fn close(&mut self) {
        // Close the TCP connection
        drop(self.stream.as_mut().unwrap());
        // Reset client state
        self.stream = None;
        self.state = TransactionState::new();
        self.server_info = None;
    }

    /// Send a HELO command and fills `server_info`
    pub fn helo(&mut self) -> SmtpResult {
        let hostname = self.my_hostname.clone();
        let result = try!(self.send_command(Command::Hello(hostname)));
        self.server_info = Some(
            ServerInfo{
                name: get_first_word(result.message.as_ref().unwrap().as_slice()).to_string(),
                esmtp_features: None,
            }
        );
        Ok(result)
    }

    /// Sends a EHLO command and fills `server_info`
    pub fn ehlo(&mut self) -> SmtpResult {
        let hostname = self.my_hostname.clone();
        let result = try!(self.send_command(Command::ExtendedHello(hostname)));
        self.server_info = Some(
            ServerInfo{
                name: get_first_word(result.message.as_ref().unwrap().as_slice()).to_string(),
                esmtp_features: Extension::parse_esmtp_response(
                                    result.message.as_ref().unwrap().as_slice()
                                ),
            }
        );
        Ok(result)
    }

    /// Sends a MAIL command
    pub fn mail(&mut self, from_address: &str) -> SmtpResult {

        let server_info = match self.server_info.clone() {
            Some(info) => info,
            None       => fail_with_err!(Response{
                                    code: 503,
                                    message: Some("Bad sequence of commands".to_string()),
                          } self),
        };

        // Checks message encoding according to the server's capability
        // TODO : Add an encoding check.
        let options = match server_info.supports_feature(Extension::EightBitMime) {
            Some(extension) => Some(vec![extension.client_mail_option().unwrap().to_string()]),
            None => None,
        };

        self.send_command(
            Command::Mail(from_address.to_string(), options)
        )
    }

    /// Sends a RCPT command
    pub fn rcpt(&mut self, to_address: &str) -> SmtpResult {
        self.send_command(
            Command::Recipient(to_address.to_string(), None)
        )
    }

    /// Sends a DATA command
    pub fn data(&mut self) -> SmtpResult {
        self.send_command(Command::Data)
    }

    /// Sends the message content
    pub fn message(&mut self, message_content: &str) -> SmtpResult {

        let server_info = match self.server_info.clone() {
            Some(info) => info,
            None       => fail_with_err!(Response{
                                    code: 503,
                                    message: Some("Bad sequence of commands".to_string()),
                          } self)
        };

        // Check message encoding
        if !server_info.supports_feature(Extension::EightBitMime).is_some() {
            if !message_content.is_ascii() {
                fail_with_err!("Server does not accepts UTF-8 strings" self);
            }
        }

        // Get maximum message size if defined and compare to the message size
        if let Some(Extension::Size(max)) = server_info.supports_feature(Extension::Size(0)) {
            if message_content.len() > max {
                fail_with_err!(Response{
                    code: 552,
                    message: Some("Message exceeds fixed maximum message size".to_string()),
                } self);
            }
        }

        self.send_message(message_content)
    }

    /// Sends a QUIT command
    pub fn quit(&mut self) -> SmtpResult {
        self.send_command(Command::Quit)
    }

    /// Sends a RSET command
    pub fn rset(&mut self) -> SmtpResult {
        self.send_command(Command::Reset)
    }

    /// Sends a NOOP command
    pub fn noop(&mut self) -> SmtpResult {
        self.send_command(Command::Noop)
    }

    /// Sends a VRFY command
    pub fn vrfy(&mut self, to_address: &str) -> SmtpResult {
        self.send_command(Command::Verify(to_address.to_string()))
    }

    /// Sends a EXPN command
    pub fn expn(&mut self, list: &str) -> SmtpResult {
        self.send_command(Command::Expand(list.to_string()))
    }

}
<commit_msg>Fix client closing<commit_after>// Copyright 2014 Alexis Mousset. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! SMTP client

use std::string::String;
use std::error::FromError;
use std::io::net::tcp::TcpStream;
use std::io::net::ip::{SocketAddr, ToSocketAddr};

use tools::get_first_word;
use common::{CRLF, MESSAGE_ENDING, SMTP_PORT};
use response::Response;
use extension::Extension;
use command::Command;
use transaction::TransactionState;
use error::{SmtpResult, ErrorKind};
use client::connecter::Connecter;
use client::server_info::ServerInfo;
use client::stream::ClientStream;
use sendable_email::SendableEmail;

pub mod server_info;
pub mod connecter;
pub mod stream;

/// Structure that implements the SMTP client
pub struct Client<S = TcpStream> {
    /// TCP stream between client and server
    /// Value is None before connection
    stream: Option<S>,
    /// Socket we are connecting to
    server_addr: SocketAddr,
    /// Our hostname for HELO/EHLO commands
    my_hostname: String,
    /// Information about the server
    /// Value is None before HELO/EHLO
    server_info: Option<ServerInfo>,
    /// Transaction state, to check the sequence of commands
    state: TransactionState,
}

macro_rules! try_smtp (
    ($err: expr $client: ident) => ({
        match $err {
            Ok(val) => val,
            Err(err) => fail_with_err!(err $client),
        }
    })
)

macro_rules! fail_with_err (
    ($err: expr $client: ident) => ({
        $client.close();
        return Err(FromError::from_error($err))
    })
)

macro_rules! check_command_sequence (
    ($command: ident $client: ident) => ({
        if !$client.state.is_allowed(&$command) {
            fail_with_err!(
                Response{code: 503, message: Some("Bad sequence of commands".to_string())} $client
            );
        }
    })
)

impl<S = TcpStream> Client<S> {
    /// Creates a new SMTP client
    ///
    /// It does not connects to the server, but only create the `Client`
    pub fn new<A: ToSocketAddr>(addr: A, my_hostname: Option<&str>) -> Client<S> {
        Client{
            stream: None,
            server_addr: addr.to_socket_addr().unwrap(),
            my_hostname: my_hostname.unwrap_or("localhost").to_string(),
            server_info: None,
            state: TransactionState::new(),
        }
    }

    /// Creates a new local SMTP client to port 25
    ///
    /// It does not connects to the server, but only create the `Client`
    pub fn localhost() -> Client<S> {
        Client::new(("localhost", SMTP_PORT), Some("localhost"))
    }
}

impl<S: Connecter + ClientStream + Clone = TcpStream> Client<S> {
    /// Closes the TCP stream
    pub fn close(&mut self) {
        if self.stream.is_some() {
            if self.is_connected() {
                let _ = self.quit();
            }
            // Close the TCP connection
            drop(self.stream.as_mut().unwrap());
        }

        // Reset client state
        self.stream = None;
        self.state = TransactionState::new();
        self.server_info = None;
    }

    /// Sends an email
    ///
    /// This methods logs all steps of the message sending.
    pub fn send_email<T: SendableEmail>(&mut self, email: T) -> SmtpResult {

        let from_address = email.from_address();
        let to_addresses = email.to_addresses();
        let message = email.message();

        // Connect to the server
        if self.noop().is_err() {
            try!(self.connect());
        }

        // Extended Hello or Hello
        if let Err(error) = self.ehlo() {
            match error.kind {
                ErrorKind::PermanentError(Response{code: 550, message: _}) => {
                    try_smtp!(self.helo() self);
                },
                _ => {
                    try_smtp!(Err(error) self)
                },
            };
        }

        // Print server information
        debug!("server {}", self.server_info.as_ref().unwrap());

        // Mail
        try_smtp!(self.mail(from_address.as_slice()) self);

        // Log the mail command
        info!("from=<{}>, size={}, nrcpt={}", from_address, message.len(), to_addresses.len());

        // Recipient
        // TODO Return rejected addresses
        // TODO Manage the number of recipients
        for to_address in to_addresses.iter() {
            try_smtp!(self.rcpt(to_address.as_slice()) self);
        }

        // Data
        try_smtp!(self.data() self);

        // Message content
        let sent = try_smtp!(self.message(message.as_slice()) self);

        // Log the rcpt command
        info!("to=<{}>, status=sent ({})",
            to_addresses.connect(">, to=<"), sent);

        return Ok(sent);
    }

    /// Connects to the configured server
    pub fn connect(&mut self) -> SmtpResult {
        let command = Command::Connect;

        check_command_sequence!(command self);

        // Connect should not be called when the client is already connected
        if !self.stream.is_none() {
            fail_with_err!("The connection is already established" self);
        }

        // Try to connect
        self.stream = Some(try!(Connecter::connect(self.server_addr)));

        // Log the connection
        info!("connection established to {}",
              self.stream.as_mut().unwrap().peer_name().unwrap());

        let result = try!(self.stream.as_mut().unwrap().get_reply());

        let checked_result = try!(command.test_success(result));
        self.state = self.state.next_state(&command).unwrap();
        Ok(checked_result)
    }

    /// Sends an SMTP command
    pub fn send_command(&mut self, command: Command) -> SmtpResult {
        // for now we do not support SMTPUTF8
        if !command.is_ascii() {
            fail_with_err!("Non-ASCII string" self);
        }

        self.send_server(command, None)
    }

    /// Sends the email content
    fn send_message(&mut self, message: &str) -> SmtpResult {
        self.send_server(Command::Message, Some(message))
    }

    /// Sends content to the server, after checking the command sequence, and then
    /// updates the transaction state
    ///
    /// * If `message` is `None`, the given command will be formatted and sent to the server
    /// * If `message` is `Some(str)`, the `str` string will be sent to the server
    fn send_server(&mut self, command: Command, message: Option<&str>) -> SmtpResult {
        check_command_sequence!(command self);

        let result = try!(match message {
            Some(message) => self.stream.as_mut().unwrap().send_and_get_response(
                                message, MESSAGE_ENDING
                             ),
            None          => self.stream.as_mut().unwrap().send_and_get_response(
                                command.to_string().as_slice(), CRLF
                             ),
        });

        let checked_result = try!(command.test_success(result));
        self.state = self.state.next_state(&command).unwrap();
        Ok(checked_result)
    }

    /// Checks if the server is connected using the NOOP SMTP command
    pub fn is_connected(&mut self) -> bool {
        self.noop().is_ok()
    }

    /// Send a HELO command and fills `server_info`
    pub fn helo(&mut self) -> SmtpResult {
        let hostname = self.my_hostname.clone();
        let result = try!(self.send_command(Command::Hello(hostname)));
        self.server_info = Some(
            ServerInfo{
                name: get_first_word(result.message.as_ref().unwrap().as_slice()).to_string(),
                esmtp_features: None,
            }
        );
        Ok(result)
    }

    /// Sends a EHLO command and fills `server_info`
    pub fn ehlo(&mut self) -> SmtpResult {
        let hostname = self.my_hostname.clone();
        let result = try!(self.send_command(Command::ExtendedHello(hostname)));
        self.server_info = Some(
            ServerInfo{
                name: get_first_word(result.message.as_ref().unwrap().as_slice()).to_string(),
                esmtp_features: Extension::parse_esmtp_response(
                                    result.message.as_ref().unwrap().as_slice()
                                ),
            }
        );
        Ok(result)
    }

    /// Sends a MAIL command
    pub fn mail(&mut self, from_address: &str) -> SmtpResult {

        let server_info = match self.server_info.clone() {
            Some(info) => info,
            None       => fail_with_err!(Response{
                                    code: 503,
                                    message: Some("Bad sequence of commands".to_string()),
                          } self),
        };

        // Checks message encoding according to the server's capability
        // TODO : Add an encoding check.
        let options = match server_info.supports_feature(Extension::EightBitMime) {
            Some(extension) => Some(vec![extension.client_mail_option().unwrap().to_string()]),
            None => None,
        };

        self.send_command(
            Command::Mail(from_address.to_string(), options)
        )
    }

    /// Sends a RCPT command
    pub fn rcpt(&mut self, to_address: &str) -> SmtpResult {
        self.send_command(
            Command::Recipient(to_address.to_string(), None)
        )
    }

    /// Sends a DATA command
    pub fn data(&mut self) -> SmtpResult {
        self.send_command(Command::Data)
    }

    /// Sends the message content
    pub fn message(&mut self, message_content: &str) -> SmtpResult {

        let server_info = match self.server_info.clone() {
            Some(info) => info,
            None       => fail_with_err!(Response{
                                    code: 503,
                                    message: Some("Bad sequence of commands".to_string()),
                          } self)
        };

        // Check message encoding
        if !server_info.supports_feature(Extension::EightBitMime).is_some() {
            if !message_content.is_ascii() {
                fail_with_err!("Server does not accepts UTF-8 strings" self);
            }
        }

        // Get maximum message size if defined and compare to the message size
        if let Some(Extension::Size(max)) = server_info.supports_feature(Extension::Size(0)) {
            if message_content.len() > max {
                fail_with_err!(Response{
                    code: 552,
                    message: Some("Message exceeds fixed maximum message size".to_string()),
                } self);
            }
        }

        self.send_message(message_content)
    }

    /// Sends a QUIT command
    pub fn quit(&mut self) -> SmtpResult {
        self.send_command(Command::Quit)
    }

    /// Sends a RSET command
    pub fn rset(&mut self) -> SmtpResult {
        self.send_command(Command::Reset)
    }

    /// Sends a NOOP command
    pub fn noop(&mut self) -> SmtpResult {
        self.send_command(Command::Noop)
    }

    /// Sends a VRFY command
    pub fn vrfy(&mut self, to_address: &str) -> SmtpResult {
        self.send_command(Command::Verify(to_address.to_string()))
    }

    /// Sends a EXPN command
    pub fn expn(&mut self, list: &str) -> SmtpResult {
        self.send_command(Command::Expand(list.to_string()))
    }

}
<|endoftext|>


<commit_before><commit_msg>docs(core): add more docs to stack<commit_after><|endoftext|>


<commit_before>use std;
use std::io::{IoResult, IoError};

pub struct BufReader<R> {
    reader: R,
    buffer: [u8, ..4096],
    start: uint,
    end: uint,  // exclusive
}

pub mod Bytes {
    pub trait Select {
        fn select<'a>(&'a mut self, bytes: uint) -> Selected<'a>;
    }

    pub enum Selected<'a> {
        NewlineFound(&'a [u8]),
        Complete(&'a [u8]),
        Partial(&'a [u8]),
        EndOfFile,
    }
}

impl<R: Reader> BufReader<R> {
    pub fn new(reader: R) -> BufReader<R> {
        let empty_buffer = unsafe {
            std::mem::uninitialized::<[u8, ..4096]>()
        };

        BufReader {
            reader: reader,
            buffer: empty_buffer,
            start: 0,
            end: 0,
        }
    }

    #[inline]
    fn read(&mut self) -> IoResult<uint> {
        let buffer_fill = self.buffer.mut_slice_from(self.end);

        match self.reader.read(buffer_fill) {
            Ok(nread) => {
                self.end += nread;
                Ok(nread)
            }
            error => error
        }
    }

    #[inline]
    fn maybe_fill_buf(&mut self) -> IoResult<uint> {
        if self.end == self.start {
            self.start = 0;
            self.end = 0;

            self.read()
        } else {
            Ok(0)
        }
    }

    pub fn consume_line(&mut self) -> uint {
        let mut bytes_consumed = 0;

        loop {
            match self.maybe_fill_buf() {
                Err(IoError { kind: std::io::EndOfFile, .. }) => (),
                Err(err) => fail!("read error: {}", err.desc),
                _ => ()
            }

            let buffer_used = self.end - self.start;

            if buffer_used == 0 { return bytes_consumed; }

            for idx in range(self.start, self.end) {
                // the indices are always correct, use unsafe for speed
                if unsafe { *self.buffer.unsafe_ref(idx) } == b'\n' {
                    self.start = idx + 1;
                    return bytes_consumed + idx + 1;
                }
            }

            bytes_consumed += buffer_used;

            self.start = 0;
            self.end = 0;
        }
    }
}

impl<R: Reader> Bytes::Select for BufReader<R> {
    fn select<'a>(&'a mut self, bytes: uint) -> Bytes::Selected<'a> {
        match self.maybe_fill_buf() {
            Err(IoError { kind: std::io::EndOfFile, .. }) => (),
            Err(err) => fail!("read error: {}", err.desc),
            _ => ()
        }

        let buffer_used = self.end - self.start;

        if buffer_used == 0 { return Bytes::EndOfFile; }

        let (complete, max_segment_len) = {
            if bytes < buffer_used {
                (true, bytes + 1)
            } else {
                (false, buffer_used)
            }
        };

        for idx in range(self.start, self.start + max_segment_len) {
            // the indices are always correct, use unsafe for speed
            if unsafe { *self.buffer.unsafe_ref(idx) } == b'\n' {
                let segment = self.buffer.slice(self.start, idx + 1);

                self.start = idx + 1;

                return Bytes::NewlineFound(segment);
            }
        }

        if complete {
            let segment = self.buffer.slice(self.start,
                                            self.start + bytes);

            self.start += bytes;
            Bytes::Complete(segment)
        } else {
            let segment = self.buffer.slice(self.start, self.end);

            self.start = 0;
            self.end = 0;
            Bytes::Partial(segment)
        }
    }
}
<commit_msg>Get rid of unsafe indexing<commit_after>use std;
use std::io::{IoResult, IoError};

pub struct BufReader<R> {
    reader: R,
    buffer: [u8, ..4096],
    start: uint,
    end: uint,  // exclusive
}

pub mod Bytes {
    pub trait Select {
        fn select<'a>(&'a mut self, bytes: uint) -> Selected<'a>;
    }

    pub enum Selected<'a> {
        NewlineFound(&'a [u8]),
        Complete(&'a [u8]),
        Partial(&'a [u8]),
        EndOfFile,
    }
}

impl<R: Reader> BufReader<R> {
    pub fn new(reader: R) -> BufReader<R> {
        let empty_buffer = unsafe {
            std::mem::uninitialized::<[u8, ..4096]>()
        };

        BufReader {
            reader: reader,
            buffer: empty_buffer,
            start: 0,
            end: 0,
        }
    }

    #[inline]
    fn read(&mut self) -> IoResult<uint> {
        let buffer_fill = self.buffer.mut_slice_from(self.end);

        match self.reader.read(buffer_fill) {
            Ok(nread) => {
                self.end += nread;
                Ok(nread)
            }
            error => error
        }
    }

    #[inline]
    fn maybe_fill_buf(&mut self) -> IoResult<uint> {
        if self.end == self.start {
            self.start = 0;
            self.end = 0;

            self.read()
        } else {
            Ok(0)
        }
    }

    pub fn consume_line(&mut self) -> uint {
        let mut bytes_consumed = 0;

        loop {
            match self.maybe_fill_buf() {
                Ok(0) | Err(IoError { kind: std::io::EndOfFile, .. })
                    if self.start == self.end => return bytes_consumed,
                Err(err) => fail!("read error: {}", err.desc),
                _ => ()
            }

            let filled_buf = self.buffer.slice(self.start, self.end);

            match filled_buf.position_elem(&b'\n') {
                Some(idx) => {
                    self.start += idx + 1;
                    return bytes_consumed + idx + 1;
                }
                _ => ()
            }

            bytes_consumed += filled_buf.len();

            self.start = 0;
            self.end = 0;
        }
    }
}

impl<R: Reader> Bytes::Select for BufReader<R> {
    fn select<'a>(&'a mut self, bytes: uint) -> Bytes::Selected<'a> {
        match self.maybe_fill_buf() {
            Err(IoError { kind: std::io::EndOfFile, .. }) => (),
            Err(err) => fail!("read error: {}", err.desc),
            _ => ()
        }

        let newline_idx = match self.end - self.start {
            0 => return Bytes::EndOfFile,
            buf_used if bytes < buf_used => {
                // because the output delimiter should only be placed between
                // segments check if the byte after bytes is a newline
                let buf_slice = self.buffer.slice(self.start,
                                                  self.start + bytes + 1);

                match buf_slice.position_elem(&b'\n') {
                    Some(idx) => idx,
                    None => {
                        let segment = self.buffer.slice(self.start,
                                                        self.start + bytes);

                        self.start += bytes;

                        return Bytes::Complete(segment);
                    }
                }
            }
            _ => {
                let buf_filled = self.buffer.slice(self.start, self.end);

                match buf_filled.position_elem(&b'\n') {
                    Some(idx) => idx,
                    None => {
                        let segment = self.buffer.slice(self.start, self.end);

                        self.start = 0;
                        self.end = 0;

                        return Bytes::Partial(segment);
                    }
                }
            }
        };

        let new_start = self.start + newline_idx + 1;
        let segment = self.buffer.slice(self.start, new_start);

        self.start = new_start;
        Bytes::NewlineFound(segment)
    }
}
<|endoftext|>


<commit_before><commit_msg>Add EntryHeader type for store<commit_after>use toml::Table;

pub struct EntryHeader {
    toml: Table,
}

impl EntryHeader {

    pub fn new(toml: Table) -> EntryHeader {
        EntryHeader {
            toml: toml,
        }
    }

    pub fn toml(&self) -> &Table {
        &self.toml
    }

}
<|endoftext|>


<commit_before><commit_msg>test for munge-ing a struct<commit_after>extern crate crucible;
use crucible::*;
use crucible::cryptol::munge;

#[derive(Clone)]
struct Point{
    x: u32,
    y: u32,
}

fn reflect(p: Point) -> Point {
    Point{x: p.y, y: p.x}
}

#[crux_test]
fn munge_struct_equiv_test() {
    let (x, y) = <(u32, u32)>::symbolic("p");
    let p2 = reflect(munge(Point{x, y}));
    crucible_assert!(p2.x == y);
}
<|endoftext|>


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

use std::old_io::{Command, IoError, OtherIoError};
use target::TargetOptions;

use self::Arch::*;

#[allow(non_camel_case_types)]
#[derive(Copy)]
pub enum Arch {
    Armv7,
    Armv7s,
    Arm64,
    I386,
    X86_64
}

impl Arch {
    pub fn to_string(&self) -> &'static str {
        match self {
            &Armv7 => "armv7",
            &Armv7s => "armv7s",
            &Arm64 => "arm64",
            &I386 => "i386",
            &X86_64 => "x86_64"
        }
    }
}

pub fn get_sdk_root(sdk_name: &str) -> String {
    let res = Command::new("xcrun")
                      .arg("--show-sdk-path")
                      .arg("-sdk")
                      .arg(sdk_name)
                      .spawn()
                      .and_then(|c| c.wait_with_output())
                      .and_then(|output| {
                          if output.status.success() {
                              Ok(String::from_utf8(output.output).unwrap())
                          } else {
                              Err(IoError {
                                  kind: OtherIoError,
                                  desc: "process exit with error",
                                  detail: String::from_utf8(output.error).ok()})
                          }
                      });

    match res {
        Ok(output) => output.trim().to_string(),
        Err(e) => panic!("failed to get {} SDK path: {}", sdk_name, e)
    }
}

fn pre_link_args(arch: Arch) -> Vec<String> {
    let sdk_name = match arch {
        Armv7 | Armv7s | Arm64 => "iphoneos",
        I386 | X86_64 => "iphonesimulator"
    };

    let arch_name = arch.to_string();

    vec!["-arch".to_string(), arch_name.to_string(),
         "-Wl,-syslibroot".to_string(), get_sdk_root(sdk_name)]
}

fn target_cpu(arch: Arch) -> String {
    match arch {
        X86_64 => "x86-64",
        _ => "generic",
    }.to_string()
}

pub fn opts(arch: Arch) -> TargetOptions {
    TargetOptions {
        cpu: target_cpu(arch),
        dynamic_linking: false,
        executables: true,
        // Although there is an experimental implementation of LLVM which
        // supports SS on armv7 it wasn't approved by Apple, see:
        // http://lists.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon-20140505/216350.html
        // It looks like it might be never accepted to upstream LLVM.
        //
        // SS might be also enabled on Arm64 as it has builtin support in LLVM
        // but I haven't tested it through yet
        morestack: false,
        pre_link_args: pre_link_args(arch),
        .. super::apple_base::opts()
    }
}
<commit_msg>Adjusting default CPUs for iOS<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::old_io::{Command, IoError, OtherIoError};
use target::TargetOptions;

use self::Arch::*;

#[allow(non_camel_case_types)]
#[derive(Copy)]
pub enum Arch {
    Armv7,
    Armv7s,
    Arm64,
    I386,
    X86_64
}

impl Arch {
    pub fn to_string(&self) -> &'static str {
        match self {
            &Armv7 => "armv7",
            &Armv7s => "armv7s",
            &Arm64 => "arm64",
            &I386 => "i386",
            &X86_64 => "x86_64"
        }
    }
}

pub fn get_sdk_root(sdk_name: &str) -> String {
    let res = Command::new("xcrun")
                      .arg("--show-sdk-path")
                      .arg("-sdk")
                      .arg(sdk_name)
                      .spawn()
                      .and_then(|c| c.wait_with_output())
                      .and_then(|output| {
                          if output.status.success() {
                              Ok(String::from_utf8(output.output).unwrap())
                          } else {
                              Err(IoError {
                                  kind: OtherIoError,
                                  desc: "process exit with error",
                                  detail: String::from_utf8(output.error).ok()})
                          }
                      });

    match res {
        Ok(output) => output.trim().to_string(),
        Err(e) => panic!("failed to get {} SDK path: {}", sdk_name, e)
    }
}

fn pre_link_args(arch: Arch) -> Vec<String> {
    let sdk_name = match arch {
        Armv7 | Armv7s | Arm64 => "iphoneos",
        I386 | X86_64 => "iphonesimulator"
    };

    let arch_name = arch.to_string();

    vec!["-arch".to_string(), arch_name.to_string(),
         "-Wl,-syslibroot".to_string(), get_sdk_root(sdk_name)]
}

fn target_cpu(arch: Arch) -> String {
    match arch {
        Armv7 => "cortex-a8", // iOS7 is supported on iPhone 4 and higher
        Armv7s => "cortex-a9",
        Arm64 => "cyclone",
        I386 => "generic",
        X86_64 => "x86-64",
    }.to_string()
}

pub fn opts(arch: Arch) -> TargetOptions {
    TargetOptions {
        cpu: target_cpu(arch),
        dynamic_linking: false,
        executables: true,
        // Although there is an experimental implementation of LLVM which
        // supports SS on armv7 it wasn't approved by Apple, see:
        // http://lists.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon-20140505/216350.html
        // It looks like it might be never accepted to upstream LLVM.
        //
        // SS might be also enabled on Arm64 as it has builtin support in LLVM
        // but I haven't tested it through yet
        morestack: false,
        pre_link_args: pre_link_args(arch),
        .. super::apple_base::opts()
    }
}
<|endoftext|>