<commit_before>use std::str;
use ast::Expression;

fn bytes_to_expression(bytes: &[u8]) -> Expression {
    // TODO: Remove this unwrap
    match str::from_utf8(bytes).unwrap() {
        "true" => Expression::Boolean(true),
        "false" => Expression::Boolean(false),

        // TODO: Add this error the error stack
        _ => panic!("Something has gone wrong with parsing boolean"),
    }
}

named!(pub boolean_literal<Expression>,
    map!(
        alt!(tag!("true") | tag!("false")),
        bytes_to_expression
    )
);
<commit_msg>Boolean parser now uses value!<commit_after>use ast::Expression;

named!(pub boolean_literal<Expression>,
    alt!(
        value!(Expression::Boolean(true), tag!("true")) |
        value!(Expression::Boolean(false), tag!("false"))
    )
);
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::collections::hash_map::Entry;

pub struct School {
    grades: HashMap<u32, Vec<String>>
}

impl School {
    pub fn new() -> School {
        School { grades: HashMap::new() }
    }

    pub fn add(&mut self, grade: u32, student: &str) {
        match self.grades.entry(grade) {
            Entry::Vacant(view) => { view.insert(vec![student.to_string()]); }
            Entry::Occupied(mut view) => {
                let l = view.get_mut();
                l.push(student.to_string());
                l.sort();
            },
        };
    }

    pub fn grades(&self) -> Vec<u32> {
        let mut s = self.grades.keys().map(|k| k.clone()).collect::<Vec<u32>>();
        s.sort();
        s
    }

    pub fn grade(&self, grade: u32) -> Option<&Vec<String>> {
        self.grades.get(&grade)
    }
}
<commit_msg>grade-school: Use `Entry#or_insert` in `add`<commit_after>use std::collections::HashMap;

pub struct School {
    grades: HashMap<u32, Vec<String>>
}

impl School {
    pub fn new() -> School {
        School { grades: HashMap::new() }
    }

    pub fn add(&mut self, grade: u32, student: &str) {
        let mut entry = self.grades.entry(grade).or_insert(Vec::new());
        entry.push(student.to_string());
        entry.sort();
    }

    pub fn grades(&self) -> Vec<u32> {
        let mut s = self.grades.keys().map(|k| k.clone()).collect::<Vec<u32>>();
        s.sort();
        s
    }

    pub fn grade(&self, grade: u32) -> Option<&Vec<String>> {
        self.grades.get(&grade)
    }
}
<|endoftext|>


<commit_before>use std::io::{self, Write};
use std::fs::File;
use std::sync::mpsc::{sync_channel, SyncSender, Receiver};

use time::{get_time, now_utc};
use irc::parse::IrcMsg;

use command_mapper::{Replier, RustBotPlugin};

fn logger_loop(rx: Receiver<IrcMsg>) -> Result<(), io::Error> {
    let logfile = format!("logs/{}.irclog", now_utc().rfc3339());
    let mut log = try!(File::create(&logfile));
    for msg in rx.iter() {
        let timespec = get_time();
        let timefmt = format!("{}:{} ", timespec.sec, timespec.nsec);
        try!(log.write_all(timefmt.as_bytes()));
        try!(log.write_all(msg.as_bytes()));
        try!(log.write_all(b"\r\n"));
    }
    Ok(())
}

pub struct LoggerPlugin {
    sender: Option<SyncSender<IrcMsg>>
}

impl LoggerPlugin {
    pub fn new() -> LoggerPlugin {
        LoggerPlugin { sender: None }
    }

    pub fn get_plugin_name() -> &'static str {
        "logger"
    }
}

impl RustBotPlugin for LoggerPlugin {
    fn start(&mut self) {
        let (tx, rx) = sync_channel(10);
        let _ = ::std::thread::Builder::new().name("plugin-logger".to_string()).spawn(move || {
            if let Err(err) = logger_loop(rx) {
                info!("Error in logger loop: {:?}", err);
            }
        });
        self.sender = Some(tx);
    }

    fn on_message(&mut self, replier: &mut Replier, msg: &IrcMsg) {
        let mut disable_self = false;
        if let Some(ref sender) = self.sender {
            if let Err(err) = replier.reply(msg.clone()) {
                info!("Logger service gone: {:?}", err);
                disable_self = true;
            }
        }
        if disable_self {
            self.sender = None;
        }
    }
}
<commit_msg>Fix logger: need to send message to log, not server.<commit_after>use std::io::{self, Write};
use std::fs::File;
use std::sync::mpsc::{sync_channel, SyncSender, Receiver};

use time::{get_time, now_utc};
use irc::parse::IrcMsg;

use command_mapper::{Replier, RustBotPlugin};

fn logger_loop(rx: Receiver<IrcMsg>) -> Result<(), io::Error> {
    let logfile = format!("logs/{}.irclog", now_utc().rfc3339());
    let mut log = try!(File::create(&logfile));
    for msg in rx.iter() {
        let timespec = get_time();
        let timefmt = format!("{}:{} ", timespec.sec, timespec.nsec);
        try!(log.write_all(timefmt.as_bytes()));
        try!(log.write_all(msg.as_bytes()));
        try!(log.write_all(b"\r\n"));
    }
    Ok(())
}

pub struct LoggerPlugin {
    sender: Option<SyncSender<IrcMsg>>
}

impl LoggerPlugin {
    pub fn new() -> LoggerPlugin {
        LoggerPlugin { sender: None }
    }

    pub fn get_plugin_name() -> &'static str {
        "logger"
    }
}

impl RustBotPlugin for LoggerPlugin {
    fn start(&mut self) {
        let (tx, rx) = sync_channel(10);
        let _ = ::std::thread::Builder::new().name("plugin-logger".to_string()).spawn(move || {
            if let Err(err) = logger_loop(rx) {
                info!("Error in logger loop: {:?}", err);
            }
        });
        self.sender = Some(tx);
    }

    fn on_message(&mut self, _: &mut Replier, msg: &IrcMsg) {
        let mut disable_self = false;
        if let Some(ref sender) = self.sender {
            if let Err(err) = sender.send(msg.clone()) {
                info!("Logger service gone: {:?}", err);
                disable_self = true;
            }
        }
        if disable_self {
            self.sender = None;
        }
    }
}
<|endoftext|>


<commit_before>use bifrost::utils::fut_exec::wait;
use client::AsyncClient;
use dovahkiin::types::custom_types::bytes::SmallBytes;
use dovahkiin::types::custom_types::id::Id;
use dovahkiin::types::custom_types::map::Map;
use dovahkiin::types::type_id_of;
use dovahkiin::types::value::ToValue;
use index::btree::Ordering;
use index::id_from_key;
use index::EntryKey;
use index::Slice;
use itertools::Itertools;
use parking_lot::Mutex;
use parking_lot::RwLock;
use ram::cell::Cell;
use ram::types::*;
use std::cell::RefCell;
use std::collections::btree_map::Range;
use std::collections::hash_map::DefaultHasher;
use std::collections::{BTreeMap, BTreeSet, LinkedList};
use std::fmt::Debug;
use std::marker::PhantomData;
use std::mem;
use std::sync::Arc;
use utils::lru_cache::LRUCache;

// LevelTree items cannot been added or removed individually
// Items must been merged from higher level in bulk
// Deletion will be performed when merging to or from higher level tree
// Because tree update will not to be performed in parallel. Unlike memtable, a single r/w lock
// should be sufficient. Thus concurrency control will be simple and efficient.

type Tombstones = BTreeSet<EntryKey>;
type PageCache<S> = Arc<Mutex<LRUCache<Id, Arc<SSPage<S>>>>>;

const PAGE_SCHEMA: &'static str = "NEB_SSTABLE_PAGE";

lazy_static! {
    static ref PAGE_SCHEMA_HASH: u32 = key_hash(PAGE_SCHEMA) as u32;
}

pub struct LevelTree<S>
where
    S: Slice<Item = EntryKey> + SortableEntrySlice,
{
    neb_client: Arc<AsyncClient>,
    index: BTreeMap<EntryKey, Id>,
    tombstones: Tombstones,
    pages: PageCache<S>,
    marker: PhantomData<S>,
}
struct SSPage<S>
where
    S: Slice<Item = EntryKey> + SortableEntrySlice,
{
    id: Id,
    slice: S,
}

impl<S> SSPage<S>
where
    S: Slice<Item = EntryKey> + SortableEntrySlice,
{
    pub fn from_cell(cell: Cell) -> Self {
        let mut slice = S::init();
        let slice_len = slice.as_slice().len();
        let cell_id = cell.id();
        let keys = cell.data;
        let keys_len = keys.len().unwrap();
        debug_assert!(slice_len == keys_len);
        let keys_array = if let Value::PrimArray(PrimitiveArray::SmallBytes(ref array)) = keys {
            array
        } else {
            panic!()
        };
        for (i, val) in keys_array.iter().enumerate() {
            slice.as_slice()[i] = EntryKey::from(val.as_slice());
        }
        Self {
            id: cell_id,
            slice,
        }
    }
}

pub fn page_slice_to_cell<S>(slice: S, id: &Id) -> Cell
where
    S: Slice<Item = EntryKey>,
{
    let value = slice
        .as_slice_immute()
        .iter()
        .map(|key| SmallBytes::from_vec(key.as_slice().to_vec()))
        .collect_vec()
        .value();
    Cell::new_with_id(*PAGE_SCHEMA_HASH, id, value)
}

impl<S> LevelTree<S>
where
    S: Slice<Item = EntryKey> + SortableEntrySlice,
{
    pub fn new(neb_client: &Arc<AsyncClient>) -> Self {
        let client = neb_client.clone();
        Self {
            neb_client: neb_client.clone(),
            index: BTreeMap::new(),
            tombstones: Tombstones::new(),
            // TODO: carefully set the capacity
            pages: Arc::new(Mutex::new(LRUCache::new(
                100,
                move |id| {
                    wait(client.read_cell(*id))
                        .unwrap()
                        .map(|cell| Arc::new(SSPage::from_cell(cell)))
                        .ok()
                },
                |_, _| {
                    // will do nothing on evict for pages will be write to back storage once updated
                },
            ))),
            marker: PhantomData {},
        }
    }

    pub fn seek(&self, key: &EntryKey, ordering: Ordering) -> RTCursor<S> {
        let mut range = match ordering {
            Ordering::Forward => self.index.range::<EntryKey, _>(key..),
            Ordering::Backward => self.index.range::<EntryKey, _>(..=key),
        };
        let first = match ordering {
            Ordering::Forward => range.next(),
            Ordering::Backward => range.next_back(),
        }
        .map(|(_, page_id)| self.pages.lock().get_or_fetch(page_id).unwrap().clone());

        let (pos, page_len) = if let Some(ref page) = first {
            (
                page.slice
                    .as_slice_immute()
                    .binary_search(key)
                    .unwrap_or_else(|i| i),
                page.slice.as_slice_immute().len(),
            )
        } else {
            (0, 0)
        };
        let mut cursor = RTCursor {
            ordering,
            range,
            page_len,
            current: first,
            index: pos,
            cache: self.pages.clone(),
        };

        if cursor.current.is_some() {
            match ordering {
                Ordering::Forward => {
                    if pos >= page_len {
                        cursor.next();
                    }
                }
                Ordering::Backward => {}
            }
        }

        cursor
    }

    pub fn merge(&mut self, mut source: Vec<EntryKey>, tombstones: &mut Tombstones) {
        let mut pages_cache = self.pages.lock();
        let (keys_to_removed, mut merged, mut ids_to_reuse) = {
            let (target_keys, target_pages): (Vec<_>, Vec<_>) = {
                let first = source.first().unwrap();
                let last = source.last().unwrap();
                self.index
                    .range::<EntryKey, _>(first..=last)
                    .map(|(k, id)| (k, pages_cache.get_or_fetch(id).unwrap().clone()))
                    .unzip()
            };
            let page_size = target_pages.first().unwrap().slice.len();
            let target_page_ids = target_pages.iter().map(|p| p.id).collect::<LinkedList<_>>();
            let mut target = target_pages
                .iter()
                .map(|page| page.slice.as_slice_immute())
                .flat_map(|x| x)
                .map(|x| (*x).clone())
                .collect_vec();

            let mut merged: Vec<S> = vec![S::init()];
            let src_len = source.len();
            let tgt_len = target.len();
            let mut srci = 0;
            let mut tgti = 0;

            let mut merging_slice_i = 0;

            while srci < src_len || tgti < tgt_len {
                let mut from_source = false;
                let mut lowest: &mut EntryKey = if srci >= src_len {
                    // source overflowed
                    tgti += 1;
                    &mut target[tgti - 1]
                } else if tgti >= tgt_len {
                    // target overflowed
                    srci += 1;
                    from_source = true;
                    &mut source[srci - 1]
                } else {
                    // normal case, compare
                    let t = &mut target[tgti];
                    let s = &mut source[srci];
                    if t <= s {
                        tgti += 1;
                        t
                    } else {
                        srci += 1;
                        from_source = true;
                        s
                    }
                };
                if from_source {
                    if tombstones.remove(lowest) {
                        continue;
                    }
                } else {
                    if self.tombstones.remove(lowest) {
                        continue;
                    }
                }
                mem::swap(
                    &mut merged.last_mut().unwrap().as_slice()[merging_slice_i],
                    lowest,
                );
                merging_slice_i += 1;
                if merging_slice_i >= page_size {
                    merging_slice_i = 0;
                    merged.push(S::init());
                }
            }
            if merging_slice_i == 0 {
                let merged_len = merged.len();
                merged.remove(merged_len - 1);
            }
            (
                target_keys.into_iter().map(|x| x.clone()).collect_vec(),
                merged,
                target_page_ids
            )
        };

        for k in keys_to_removed {
            self.index.remove(&k).unwrap();
        }

        for id in &ids_to_reuse {
            pages_cache.remove(id);
        }

        for mut page in merged {
            let index_key = page.as_slice()[0].clone();
            let reuse_id = ids_to_reuse.pop_back();
            let id = reuse_id.unwrap_or_else(|| Id::rand());
            let cell = page_slice_to_cell(page, &id);
            if reuse_id.is_some() {
                wait(self.neb_client.update_cell(cell)).unwrap();
            } else {
                wait(self.neb_client.write_cell(cell)).unwrap();
            }
            self.index.insert(index_key, id);
        }
    }
}

pub trait SortableEntrySlice: Sized + Slice<Item = EntryKey> {}

pub struct RTCursor<'a, S>
where
    S: Slice<Item = EntryKey> + SortableEntrySlice,
{
    index: usize,
    ordering: Ordering,
    page_len: usize,
    range: Range<'a, EntryKey, Id>,
    current: Option<Arc<SSPage<S>>>,
    cache: PageCache<S>,
}

impl<'a, S> RTCursor<'a, S>
where
    S: Slice<Item = EntryKey> + SortableEntrySlice,
{
    pub fn next(&mut self) -> bool {
        if self.current.is_some() {
            match self.ordering {
                Ordering::Forward => {
                    if self.index + 1 >= self.page_len {
                        if let Some((_, page_id)) = self.range.next() {
                            let next_page = self.get_page(page_id);
                            self.current = Some(next_page);
                            self.index = 0;
                        } else {
                            self.current = None;
                            return false;
                        }
                    } else {
                        self.index += 1;
                    }
                }
                Ordering::Backward => {
                    if self.index == 0 {
                        if let Some((_, page_id)) = self.range.next_back() {
                            let next_page = self.get_page(page_id);
                            self.current = Some(next_page);
                            self.index = self.page_len - 1;
                        } else {
                            self.current = None;
                            return false;
                        }
                    } else {
                        self.index -= 1;
                    }
                }
            }
            true
        } else {
            false
        }
    }

    pub fn current(&self) -> Option<&EntryKey> {
        if self.index <= 0 || self.index >= self.page_len {
            return None;
        }
        if let Some(ref page) = self.current {
            Some(&page.slice.as_slice_immute()[self.index])
        } else {
            None
        }
    }

    fn get_page(&self, id: &Id) -> Arc<SSPage<S>> {
        self.cache.lock().get_or_fetch(id).unwrap().clone()
    }
}

#[cfg(test)]
mod test {}
<commit_msg>sspage schema<commit_after>use bifrost::utils::fut_exec::wait;
use client::AsyncClient;
use dovahkiin::types::custom_types::bytes::SmallBytes;
use dovahkiin::types::custom_types::id::Id;
use dovahkiin::types::custom_types::map::Map;
use dovahkiin::types::type_id_of;
use dovahkiin::types::value::ToValue;
use index::btree::Ordering;
use index::id_from_key;
use index::EntryKey;
use index::Slice;
use itertools::Itertools;
use parking_lot::Mutex;
use parking_lot::RwLock;
use ram::cell::Cell;
use ram::types::*;
use std::cell::RefCell;
use std::collections::btree_map::Range;
use std::collections::hash_map::DefaultHasher;
use std::collections::{BTreeMap, BTreeSet, LinkedList};
use std::fmt::Debug;
use std::marker::PhantomData;
use std::mem;
use std::sync::Arc;
use utils::lru_cache::LRUCache;
use ram::schema::Schema;
use ram::schema::Field;

// LevelTree items cannot been added or removed individually
// Items must been merged from higher level in bulk
// Deletion will be performed when merging to or from higher level tree
// Because tree update will not to be performed in parallel. Unlike memtable, a single r/w lock
// should be sufficient. Thus concurrency control will be simple and efficient.

type Tombstones = BTreeSet<EntryKey>;
type PageCache<S> = Arc<Mutex<LRUCache<Id, Arc<SSPage<S>>>>>;

const PAGE_SCHEMA: &'static str = "NEB_SSTABLE_PAGE";

lazy_static! {
    static ref PAGE_SCHEMA_ID: u32 = key_hash(PAGE_SCHEMA) as u32;
}

pub struct LevelTree<S>
where
    S: Slice<Item = EntryKey> + SortableEntrySlice,
{
    neb_client: Arc<AsyncClient>,
    index: BTreeMap<EntryKey, Id>,
    tombstones: Tombstones,
    pages: PageCache<S>,
    marker: PhantomData<S>,
}
struct SSPage<S>
where
    S: Slice<Item = EntryKey> + SortableEntrySlice,
{
    id: Id,
    slice: S,
}

impl<S> SSPage<S>
where
    S: Slice<Item = EntryKey> + SortableEntrySlice,
{
    pub fn from_cell(cell: Cell) -> Self {
        let mut slice = S::init();
        let slice_len = slice.as_slice().len();
        let cell_id = cell.id();
        let keys = cell.data;
        let keys_len = keys.len().unwrap();
        debug_assert!(slice_len == keys_len);
        let keys_array = if let Value::PrimArray(PrimitiveArray::SmallBytes(ref array)) = keys {
            array
        } else {
            panic!()
        };
        for (i, val) in keys_array.iter().enumerate() {
            slice.as_slice()[i] = EntryKey::from(val.as_slice());
        }
        Self {
            id: cell_id,
            slice,
        }
    }
}

pub fn page_slice_to_cell<S>(slice: S, id: &Id) -> Cell
where
    S: Slice<Item = EntryKey>,
{
    let value = slice
        .as_slice_immute()
        .iter()
        .map(|key| SmallBytes::from_vec(key.as_slice().to_vec()))
        .collect_vec()
        .value();
    Cell::new_with_id(*PAGE_SCHEMA_ID, id, value)
}

impl<S> LevelTree<S>
where
    S: Slice<Item = EntryKey> + SortableEntrySlice,
{
    pub fn new(neb_client: &Arc<AsyncClient>) -> Self {
        let client = neb_client.clone();
        Self {
            neb_client: neb_client.clone(),
            index: BTreeMap::new(),
            tombstones: Tombstones::new(),
            // TODO: carefully set the capacity
            pages: Arc::new(Mutex::new(LRUCache::new(
                100,
                move |id| {
                    wait(client.read_cell(*id))
                        .unwrap()
                        .map(|cell| Arc::new(SSPage::from_cell(cell)))
                        .ok()
                },
                |_, _| {
                    // will do nothing on evict for pages will be write to back storage once updated
                },
            ))),
            marker: PhantomData {},
        }
    }

    pub fn seek(&self, key: &EntryKey, ordering: Ordering) -> RTCursor<S> {
        let mut range = match ordering {
            Ordering::Forward => self.index.range::<EntryKey, _>(key..),
            Ordering::Backward => self.index.range::<EntryKey, _>(..=key),
        };
        let first = match ordering {
            Ordering::Forward => range.next(),
            Ordering::Backward => range.next_back(),
        }
        .map(|(_, page_id)| self.pages.lock().get_or_fetch(page_id).unwrap().clone());

        let (pos, page_len) = if let Some(ref page) = first {
            (
                page.slice
                    .as_slice_immute()
                    .binary_search(key)
                    .unwrap_or_else(|i| i),
                page.slice.as_slice_immute().len(),
            )
        } else {
            (0, 0)
        };
        let mut cursor = RTCursor {
            ordering,
            range,
            page_len,
            current: first,
            index: pos,
            cache: self.pages.clone(),
        };

        if cursor.current.is_some() {
            match ordering {
                Ordering::Forward => {
                    if pos >= page_len {
                        cursor.next();
                    }
                }
                Ordering::Backward => {}
            }
        }

        cursor
    }

    pub fn merge(&mut self, mut source: Vec<EntryKey>, tombstones: &mut Tombstones) {
        let mut pages_cache = self.pages.lock();
        let (keys_to_removed, mut merged, mut ids_to_reuse) = {
            let (target_keys, target_pages): (Vec<_>, Vec<_>) = {
                let first = source.first().unwrap();
                let last = source.last().unwrap();
                self.index
                    .range::<EntryKey, _>(first..=last)
                    .map(|(k, id)| (k, pages_cache.get_or_fetch(id).unwrap().clone()))
                    .unzip()
            };
            let page_size = target_pages.first().unwrap().slice.len();
            let target_page_ids = target_pages.iter().map(|p| p.id).collect::<LinkedList<_>>();
            let mut target = target_pages
                .iter()
                .map(|page| page.slice.as_slice_immute())
                .flat_map(|x| x)
                .map(|x| (*x).clone())
                .collect_vec();

            let mut merged: Vec<S> = vec![S::init()];
            let src_len = source.len();
            let tgt_len = target.len();
            let mut srci = 0;
            let mut tgti = 0;

            let mut merging_slice_i = 0;

            while srci < src_len || tgti < tgt_len {
                let mut from_source = false;
                let mut lowest: &mut EntryKey = if srci >= src_len {
                    // source overflowed
                    tgti += 1;
                    &mut target[tgti - 1]
                } else if tgti >= tgt_len {
                    // target overflowed
                    srci += 1;
                    from_source = true;
                    &mut source[srci - 1]
                } else {
                    // normal case, compare
                    let t = &mut target[tgti];
                    let s = &mut source[srci];
                    if t <= s {
                        tgti += 1;
                        t
                    } else {
                        srci += 1;
                        from_source = true;
                        s
                    }
                };
                if from_source {
                    if tombstones.remove(lowest) {
                        continue;
                    }
                } else {
                    if self.tombstones.remove(lowest) {
                        continue;
                    }
                }
                mem::swap(
                    &mut merged.last_mut().unwrap().as_slice()[merging_slice_i],
                    lowest,
                );
                merging_slice_i += 1;
                if merging_slice_i >= page_size {
                    merging_slice_i = 0;
                    merged.push(S::init());
                }
            }
            if merging_slice_i == 0 {
                let merged_len = merged.len();
                merged.remove(merged_len - 1);
            }
            (
                target_keys.into_iter().map(|x| x.clone()).collect_vec(),
                merged,
                target_page_ids
            )
        };

        for k in keys_to_removed {
            self.index.remove(&k).unwrap();
        }

        for id in &ids_to_reuse {
            pages_cache.remove(id);
        }

        for mut page in merged {
            let index_key = page.as_slice()[0].clone();
            let reuse_id = ids_to_reuse.pop_back();
            let id = reuse_id.unwrap_or_else(|| Id::rand());
            let cell = page_slice_to_cell(page, &id);
            if reuse_id.is_some() {
                wait(self.neb_client.update_cell(cell)).unwrap();
            } else {
                wait(self.neb_client.write_cell(cell)).unwrap();
            }
            self.index.insert(index_key, id);
        }
    }
}

pub trait SortableEntrySlice: Sized + Slice<Item = EntryKey> {}

pub struct RTCursor<'a, S>
where
    S: Slice<Item = EntryKey> + SortableEntrySlice,
{
    index: usize,
    ordering: Ordering,
    page_len: usize,
    range: Range<'a, EntryKey, Id>,
    current: Option<Arc<SSPage<S>>>,
    cache: PageCache<S>,
}

impl<'a, S> RTCursor<'a, S>
where
    S: Slice<Item = EntryKey> + SortableEntrySlice,
{
    pub fn next(&mut self) -> bool {
        if self.current.is_some() {
            match self.ordering {
                Ordering::Forward => {
                    if self.index + 1 >= self.page_len {
                        if let Some((_, page_id)) = self.range.next() {
                            let next_page = self.get_page(page_id);
                            self.current = Some(next_page);
                            self.index = 0;
                        } else {
                            self.current = None;
                            return false;
                        }
                    } else {
                        self.index += 1;
                    }
                }
                Ordering::Backward => {
                    if self.index == 0 {
                        if let Some((_, page_id)) = self.range.next_back() {
                            let next_page = self.get_page(page_id);
                            self.current = Some(next_page);
                            self.index = self.page_len - 1;
                        } else {
                            self.current = None;
                            return false;
                        }
                    } else {
                        self.index -= 1;
                    }
                }
            }
            true
        } else {
            false
        }
    }

    pub fn current(&self) -> Option<&EntryKey> {
        if self.index <= 0 || self.index >= self.page_len {
            return None;
        }
        if let Some(ref page) = self.current {
            Some(&page.slice.as_slice_immute()[self.index])
        } else {
            None
        }
    }

    fn get_page(&self, id: &Id) -> Arc<SSPage<S>> {
        self.cache.lock().get_or_fetch(id).unwrap().clone()
    }
}

pub fn get_schema() -> Schema {
    Schema {
        id: *PAGE_SCHEMA_ID,
        name: String::from(PAGE_SCHEMA),
        key_field: None,
        str_key_field: None,
        is_dynamic: false,
        fields: Field::new(
            "*",
            type_id_of(Type::SmallBytes),
            false,
            true,
            None
        )
    }
}

#[cfg(test)]
mod test {

}
<|endoftext|>


<commit_before>use wlroots_sys::{wl_shm_format, wlr_texture, wlr_texture_get_matrix, wlr_texture_upload_pixels};

/// Wrapper around wl_shm_format, to make it easier and nicer to type.
#[repr(u32)]
pub enum TextureFormat {
    ARGB8888 = wl_shm_format::WL_SHM_FORMAT_ARGB8888 as u32,
    XRGB8888 = wl_shm_format::WL_SHM_FORMAT_XRGB8888 as u32,
    C8 = wl_shm_format::WL_SHM_FORMAT_C8 as u32,
    RGB332 = wl_shm_format::WL_SHM_FORMAT_RGB332 as u32,
    BGR233 = wl_shm_format::WL_SHM_FORMAT_BGR233 as u32,
    XRGB4444 = wl_shm_format::WL_SHM_FORMAT_XRGB4444 as u32,
    XBGR4444 = wl_shm_format::WL_SHM_FORMAT_XBGR4444 as u32,
    RGBX4444 = wl_shm_format::WL_SHM_FORMAT_RGBX4444 as u32,
    BGRX4444 = wl_shm_format::WL_SHM_FORMAT_BGRX4444 as u32,
    ARGB4444 = wl_shm_format::WL_SHM_FORMAT_ARGB4444 as u32,
    ABGR4444 = wl_shm_format::WL_SHM_FORMAT_ABGR4444 as u32,
    RGBA4444 = wl_shm_format::WL_SHM_FORMAT_RGBA4444 as u32,
    BGRA4444 = wl_shm_format::WL_SHM_FORMAT_BGRA4444 as u32,
    XRGB1555 = wl_shm_format::WL_SHM_FORMAT_XRGB1555 as u32,
    XBGR1555 = wl_shm_format::WL_SHM_FORMAT_XBGR1555 as u32,
    RGBX5551 = wl_shm_format::WL_SHM_FORMAT_RGBX5551 as u32,
    BGRX5551 = wl_shm_format::WL_SHM_FORMAT_BGRX5551 as u32,
    ARGB1555 = wl_shm_format::WL_SHM_FORMAT_ARGB1555 as u32,
    ABGR1555 = wl_shm_format::WL_SHM_FORMAT_ABGR1555 as u32,
    RGBA5551 = wl_shm_format::WL_SHM_FORMAT_RGBA5551 as u32,
    BGRA5551 = wl_shm_format::WL_SHM_FORMAT_BGRA5551 as u32,
    RGB565 = wl_shm_format::WL_SHM_FORMAT_RGB565 as u32,
    BGR565 = wl_shm_format::WL_SHM_FORMAT_BGR565 as u32,
    RGB888 = wl_shm_format::WL_SHM_FORMAT_RGB888 as u32,
    BGR888 = wl_shm_format::WL_SHM_FORMAT_BGR888 as u32,
    XBGR8888 = wl_shm_format::WL_SHM_FORMAT_XBGR8888 as u32,
    RGBX8888 = wl_shm_format::WL_SHM_FORMAT_RGBX8888 as u32,
    BGRX8888 = wl_shm_format::WL_SHM_FORMAT_BGRX8888 as u32,
    ABGR8888 = wl_shm_format::WL_SHM_FORMAT_ABGR8888 as u32,
    RGBA8888 = wl_shm_format::WL_SHM_FORMAT_RGBA8888 as u32,
    BGRA8888 = wl_shm_format::WL_SHM_FORMAT_BGRA8888 as u32,
    XRGB2101010 = wl_shm_format::WL_SHM_FORMAT_XRGB2101010 as u32,
    XBGR2101010 = wl_shm_format::WL_SHM_FORMAT_XBGR2101010 as u32,
    RGBX1010102 = wl_shm_format::WL_SHM_FORMAT_RGBX1010102 as u32,
    BGRX1010102 = wl_shm_format::WL_SHM_FORMAT_BGRX1010102 as u32,
    ARGB2101010 = wl_shm_format::WL_SHM_FORMAT_ARGB2101010 as u32,
    ABGR2101010 = wl_shm_format::WL_SHM_FORMAT_ABGR2101010 as u32,
    RGBA1010102 = wl_shm_format::WL_SHM_FORMAT_RGBA1010102 as u32,
    BGRA1010102 = wl_shm_format::WL_SHM_FORMAT_BGRA1010102 as u32,
    YUYV = wl_shm_format::WL_SHM_FORMAT_YUYV as u32,
    YVYU = wl_shm_format::WL_SHM_FORMAT_YVYU as u32,
    UYVY = wl_shm_format::WL_SHM_FORMAT_UYVY as u32,
    VYUY = wl_shm_format::WL_SHM_FORMAT_VYUY as u32,
    AYUV = wl_shm_format::WL_SHM_FORMAT_AYUV as u32,
    NV12 = wl_shm_format::WL_SHM_FORMAT_NV12 as u32,
    NV21 = wl_shm_format::WL_SHM_FORMAT_NV21 as u32,
    NV16 = wl_shm_format::WL_SHM_FORMAT_NV16 as u32,
    NV61 = wl_shm_format::WL_SHM_FORMAT_NV61 as u32,
    YUV410 = wl_shm_format::WL_SHM_FORMAT_YUV410 as u32,
    YVU410 = wl_shm_format::WL_SHM_FORMAT_YVU410 as u32,
    YUV411 = wl_shm_format::WL_SHM_FORMAT_YUV411 as u32,
    YVU411 = wl_shm_format::WL_SHM_FORMAT_YVU411 as u32,
    YUV420 = wl_shm_format::WL_SHM_FORMAT_YUV420 as u32,
    YVU420 = wl_shm_format::WL_SHM_FORMAT_YVU420 as u32,
    YUV422 = wl_shm_format::WL_SHM_FORMAT_YUV422 as u32,
    YVU422 = wl_shm_format::WL_SHM_FORMAT_YVU422 as u32,
    YUV444 = wl_shm_format::WL_SHM_FORMAT_YUV444 as u32,
    YVU444 = wl_shm_format::WL_SHM_FORMAT_YVU444 as u32
}

impl Into<wl_shm_format> for TextureFormat {
    fn into(self) -> wl_shm_format {
        // NOTE Rationale for transmute:
        // * Easiest way to convert to the value type
        // * Is safe because of the definitions above linking them together.
        unsafe { ::std::mem::transmute(self as u32) }
    }
}

#[derive(Debug)]
pub struct Texture {
    texture: *mut wlr_texture
}

impl Texture {
    pub(crate) unsafe fn from_ptr(texture: *mut wlr_texture) -> Self {
        Texture { texture }
    }

    pub(crate) unsafe fn as_ptr(&self) -> *mut wlr_texture {
        self.texture
    }

    pub fn upload_pixels(&mut self,
                         texture_format: TextureFormat,
                         stride: i32,
                         width: i32,
                         height: i32,
                         bytes: &[u8])
                         -> bool {
        unsafe {
            wlr_texture_upload_pixels(self.texture,
                                      texture_format.into(),
                                      stride,
                                      width,
                                      height,
                                      bytes.as_ptr())
        }
    }

    pub fn get_matrix(&self, projection: &[f32; 16], x: i32, y: i32) -> [f32; 16] {
        unsafe {
            let mut matrix: [f32; 16] = [0.0; 16];
            wlr_texture_get_matrix(self.texture, &mut matrix, projection, x, y);
            matrix
        }
    }
}
<commit_msg>Added Texture::size<commit_after>use libc::c_int;
use wlroots_sys::{wl_shm_format, wlr_texture, wlr_texture_get_matrix, wlr_texture_upload_pixels};

/// Wrapper around wl_shm_format, to make it easier and nicer to type.
#[repr(u32)]
pub enum TextureFormat {
    ARGB8888 = wl_shm_format::WL_SHM_FORMAT_ARGB8888 as u32,
    XRGB8888 = wl_shm_format::WL_SHM_FORMAT_XRGB8888 as u32,
    C8 = wl_shm_format::WL_SHM_FORMAT_C8 as u32,
    RGB332 = wl_shm_format::WL_SHM_FORMAT_RGB332 as u32,
    BGR233 = wl_shm_format::WL_SHM_FORMAT_BGR233 as u32,
    XRGB4444 = wl_shm_format::WL_SHM_FORMAT_XRGB4444 as u32,
    XBGR4444 = wl_shm_format::WL_SHM_FORMAT_XBGR4444 as u32,
    RGBX4444 = wl_shm_format::WL_SHM_FORMAT_RGBX4444 as u32,
    BGRX4444 = wl_shm_format::WL_SHM_FORMAT_BGRX4444 as u32,
    ARGB4444 = wl_shm_format::WL_SHM_FORMAT_ARGB4444 as u32,
    ABGR4444 = wl_shm_format::WL_SHM_FORMAT_ABGR4444 as u32,
    RGBA4444 = wl_shm_format::WL_SHM_FORMAT_RGBA4444 as u32,
    BGRA4444 = wl_shm_format::WL_SHM_FORMAT_BGRA4444 as u32,
    XRGB1555 = wl_shm_format::WL_SHM_FORMAT_XRGB1555 as u32,
    XBGR1555 = wl_shm_format::WL_SHM_FORMAT_XBGR1555 as u32,
    RGBX5551 = wl_shm_format::WL_SHM_FORMAT_RGBX5551 as u32,
    BGRX5551 = wl_shm_format::WL_SHM_FORMAT_BGRX5551 as u32,
    ARGB1555 = wl_shm_format::WL_SHM_FORMAT_ARGB1555 as u32,
    ABGR1555 = wl_shm_format::WL_SHM_FORMAT_ABGR1555 as u32,
    RGBA5551 = wl_shm_format::WL_SHM_FORMAT_RGBA5551 as u32,
    BGRA5551 = wl_shm_format::WL_SHM_FORMAT_BGRA5551 as u32,
    RGB565 = wl_shm_format::WL_SHM_FORMAT_RGB565 as u32,
    BGR565 = wl_shm_format::WL_SHM_FORMAT_BGR565 as u32,
    RGB888 = wl_shm_format::WL_SHM_FORMAT_RGB888 as u32,
    BGR888 = wl_shm_format::WL_SHM_FORMAT_BGR888 as u32,
    XBGR8888 = wl_shm_format::WL_SHM_FORMAT_XBGR8888 as u32,
    RGBX8888 = wl_shm_format::WL_SHM_FORMAT_RGBX8888 as u32,
    BGRX8888 = wl_shm_format::WL_SHM_FORMAT_BGRX8888 as u32,
    ABGR8888 = wl_shm_format::WL_SHM_FORMAT_ABGR8888 as u32,
    RGBA8888 = wl_shm_format::WL_SHM_FORMAT_RGBA8888 as u32,
    BGRA8888 = wl_shm_format::WL_SHM_FORMAT_BGRA8888 as u32,
    XRGB2101010 = wl_shm_format::WL_SHM_FORMAT_XRGB2101010 as u32,
    XBGR2101010 = wl_shm_format::WL_SHM_FORMAT_XBGR2101010 as u32,
    RGBX1010102 = wl_shm_format::WL_SHM_FORMAT_RGBX1010102 as u32,
    BGRX1010102 = wl_shm_format::WL_SHM_FORMAT_BGRX1010102 as u32,
    ARGB2101010 = wl_shm_format::WL_SHM_FORMAT_ARGB2101010 as u32,
    ABGR2101010 = wl_shm_format::WL_SHM_FORMAT_ABGR2101010 as u32,
    RGBA1010102 = wl_shm_format::WL_SHM_FORMAT_RGBA1010102 as u32,
    BGRA1010102 = wl_shm_format::WL_SHM_FORMAT_BGRA1010102 as u32,
    YUYV = wl_shm_format::WL_SHM_FORMAT_YUYV as u32,
    YVYU = wl_shm_format::WL_SHM_FORMAT_YVYU as u32,
    UYVY = wl_shm_format::WL_SHM_FORMAT_UYVY as u32,
    VYUY = wl_shm_format::WL_SHM_FORMAT_VYUY as u32,
    AYUV = wl_shm_format::WL_SHM_FORMAT_AYUV as u32,
    NV12 = wl_shm_format::WL_SHM_FORMAT_NV12 as u32,
    NV21 = wl_shm_format::WL_SHM_FORMAT_NV21 as u32,
    NV16 = wl_shm_format::WL_SHM_FORMAT_NV16 as u32,
    NV61 = wl_shm_format::WL_SHM_FORMAT_NV61 as u32,
    YUV410 = wl_shm_format::WL_SHM_FORMAT_YUV410 as u32,
    YVU410 = wl_shm_format::WL_SHM_FORMAT_YVU410 as u32,
    YUV411 = wl_shm_format::WL_SHM_FORMAT_YUV411 as u32,
    YVU411 = wl_shm_format::WL_SHM_FORMAT_YVU411 as u32,
    YUV420 = wl_shm_format::WL_SHM_FORMAT_YUV420 as u32,
    YVU420 = wl_shm_format::WL_SHM_FORMAT_YVU420 as u32,
    YUV422 = wl_shm_format::WL_SHM_FORMAT_YUV422 as u32,
    YVU422 = wl_shm_format::WL_SHM_FORMAT_YVU422 as u32,
    YUV444 = wl_shm_format::WL_SHM_FORMAT_YUV444 as u32,
    YVU444 = wl_shm_format::WL_SHM_FORMAT_YVU444 as u32
}

impl Into<wl_shm_format> for TextureFormat {
    fn into(self) -> wl_shm_format {
        // NOTE Rationale for transmute:
        // * Easiest way to convert to the value type
        // * Is safe because of the definitions above linking them together.
        unsafe { ::std::mem::transmute(self as u32) }
    }
}

#[derive(Debug)]
pub struct Texture {
    texture: *mut wlr_texture
}

impl Texture {
    pub(crate) unsafe fn from_ptr(texture: *mut wlr_texture) -> Self {
        Texture { texture }
    }

    pub(crate) unsafe fn as_ptr(&self) -> *mut wlr_texture {
        self.texture
    }

    /// Gets the size of the texture.
    ///
    /// Return value is in (width, height) format.
    pub fn size(&self) -> (c_int, c_int) {
        unsafe { ((*self.texture).width, (*self.texture).height) }
    }

    pub fn upload_pixels(&mut self,
                         texture_format: TextureFormat,
                         stride: i32,
                         width: i32,
                         height: i32,
                         bytes: &[u8])
                         -> bool {
        unsafe {
            wlr_texture_upload_pixels(self.texture,
                                      texture_format.into(),
                                      stride,
                                      width,
                                      height,
                                      bytes.as_ptr())
        }
    }

    pub fn get_matrix(&self, projection: &[f32; 16], x: i32, y: i32) -> [f32; 16] {
        unsafe {
            let mut matrix: [f32; 16] = [0.0; 16];
            wlr_texture_get_matrix(self.texture, &mut matrix, projection, x, y);
            matrix
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 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.

#![unstable(feature = "futures_api",
            reason = "futures in libcore are unstable",
            issue = "50547")]

use {fmt, mem};
use marker::Unpin;
use ptr::NonNull;

/// A `Waker` is a handle for waking up a task by notifying its executor that it
/// is ready to be run.
///
/// This handle contains a trait object pointing to an instance of the `UnsafeWake`
/// trait, allowing notifications to get routed through it.
#[repr(transparent)]
pub struct Waker {
    inner: NonNull<dyn UnsafeWake>,
}

impl Unpin for Waker {}
unsafe impl Send for Waker {}
unsafe impl Sync for Waker {}

impl Waker {
    /// Constructs a new `Waker` directly.
    ///
    /// Note that most code will not need to call this. Implementers of the
    /// `UnsafeWake` trait will typically provide a wrapper that calls this
    /// but you otherwise shouldn't call it directly.
    ///
    /// If you're working with the standard library then it's recommended to
    /// use the `Waker::from` function instead which works with the safe
    /// `Arc` type and the safe `Wake` trait.
    #[inline]
    pub unsafe fn new(inner: NonNull<dyn UnsafeWake>) -> Self {
        Waker { inner }
    }

    /// Wake up the task associated with this `Waker`.
    #[inline]
    pub fn wake(&self) {
        unsafe { self.inner.as_ref().wake() }
    }

    /// Returns whether or not this `Waker` and `other` awaken the same task.
    ///
    /// This function works on a best-effort basis, and may return false even
    /// when the `Waker`s would awaken the same task. However, if this function
    /// returns true, it is guaranteed that the `Waker`s will awaken the same
    /// task.
    ///
    /// This function is primarily used for optimization purposes.
    #[inline]
    pub fn will_wake(&self, other: &Waker) -> bool {
        self.inner == other.inner
    }
}

impl Clone for Waker {
    #[inline]
    fn clone(&self) -> Self {
        unsafe {
            self.inner.as_ref().clone_raw()
        }
    }
}

impl fmt::Debug for Waker {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Waker")
            .finish()
    }
}

impl Drop for Waker {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            self.inner.as_ref().drop_raw()
        }
    }
}

/// A `LocalWaker` is a handle for waking up a task by notifying its executor that it
/// is ready to be run.
///
/// This is similar to the `Waker` type, but cannot be sent across threads.
/// Task executors can use this type to implement more optimized singlethreaded wakeup
/// behavior.
#[repr(transparent)]
pub struct LocalWaker {
    inner: NonNull<dyn UnsafeWake>,
}

impl Unpin for LocalWaker {}
impl !Send for LocalWaker {}
impl !Sync for LocalWaker {}

impl LocalWaker {
    /// Constructs a new `LocalWaker` directly.
    ///
    /// Note that most code will not need to call this. Implementers of the
    /// `UnsafeWake` trait will typically provide a wrapper that calls this
    /// but you otherwise shouldn't call it directly.
    ///
    /// If you're working with the standard library then it's recommended to
    /// use the `local_waker_from_nonlocal` or `local_waker` to convert a `Waker`
    /// into a `LocalWaker`.
    ///
    /// For this function to be used safely, it must be sound to call `inner.wake_local()`
    /// on the current thread.
    #[inline]
    pub unsafe fn new(inner: NonNull<dyn UnsafeWake>) -> Self {
        LocalWaker { inner }
    }

    /// Converts this `LocalWaker` into a `Waker`.
    ///
    /// `Waker` is nearly identical to `LocalWaker`, but is threadsafe
    /// (implements `Send` and `Sync`).
    #[inline]
    pub fn into_waker(self) -> Waker {
        self.into()
    }

    /// Wake up the task associated with this `LocalWaker`.
    #[inline]
    pub fn wake(&self) {
        unsafe { self.inner.as_ref().wake_local() }
    }

    /// Returns whether or not this `LocalWaker` and `other` `LocalWaker` awaken the same task.
    ///
    /// This function works on a best-effort basis, and may return false even
    /// when the `LocalWaker`s would awaken the same task. However, if this function
    /// returns true, it is guaranteed that the `LocalWaker`s will awaken the same
    /// task.
    ///
    /// This function is primarily used for optimization purposes.
    #[inline]
    pub fn will_wake(&self, other: &LocalWaker) -> bool {
        self.inner == other.inner
    }

    /// Returns whether or not this `LocalWaker` and `other` `Waker` awaken the same task.
    ///
    /// This function works on a best-effort basis, and may return false even
    /// when the `Waker`s would awaken the same task. However, if this function
    /// returns true, it is guaranteed that the `LocalWaker`s will awaken the same
    /// task.
    ///
    /// This function is primarily used for optimization purposes.
    #[inline]
    pub fn will_wake_nonlocal(&self, other: &Waker) -> bool {
        self.inner == other.inner
    }
}

impl From<LocalWaker> for Waker {
    #[inline]
    fn from(local_waker: LocalWaker) -> Self {
        let inner = local_waker.inner;
        mem::forget(local_waker);
        Waker { inner }
    }
}

impl Clone for LocalWaker {
    #[inline]
    fn clone(&self) -> Self {
        let waker = unsafe { self.inner.as_ref().clone_raw() };
        let inner = waker.inner;
        mem::forget(waker);
        LocalWaker { inner }
    }
}

impl fmt::Debug for LocalWaker {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Waker")
            .finish()
    }
}

impl Drop for LocalWaker {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            self.inner.as_ref().drop_raw()
        }
    }
}

/// An unsafe trait for implementing custom memory management for a `Waker` or `LocalWaker`.
///
/// A `Waker` conceptually is a cloneable trait object for `Wake`, and is
/// most often essentially just `Arc<dyn Wake>`. However, in some contexts
/// (particularly `no_std`), it's desirable to avoid `Arc` in favor of some
/// custom memory management strategy. This trait is designed to allow for such
/// customization.
///
/// When using `std`, a default implementation of the `UnsafeWake` trait is provided for
/// `Arc<T>` where `T: Wake`.
pub unsafe trait UnsafeWake: Send + Sync {
    /// Creates a clone of this `UnsafeWake` and stores it behind a `Waker`.
    ///
    /// This function will create a new uniquely owned handle that under the
    /// hood references the same notification instance. In other words calls
    /// to `wake` on the returned handle should be equivalent to calls to
    /// `wake` on this handle.
    ///
    /// # Unsafety
    ///
    /// This function is unsafe to call because it's asserting the `UnsafeWake`
    /// value is in a consistent state, i.e. hasn't been dropped.
    unsafe fn clone_raw(&self) -> Waker;

    /// Drops this instance of `UnsafeWake`, deallocating resources
    /// associated with it.
    ///
    /// FIXME(cramertj)
    /// This method is intended to have a signature such as:
    ///
    /// ```ignore (not-a-doctest)
    /// fn drop_raw(self: *mut Self);
    /// ```
    ///
    /// Unfortunately in Rust today that signature is not object safe.
    /// Nevertheless it's recommended to implement this function *as if* that
    /// were its signature. As such it is not safe to call on an invalid
    /// pointer, nor is the validity of the pointer guaranteed after this
    /// function returns.
    ///
    /// # Unsafety
    ///
    /// This function is unsafe to call because it's asserting the `UnsafeWake`
    /// value is in a consistent state, i.e. hasn't been dropped.
    unsafe fn drop_raw(&self);

    /// Indicates that the associated task is ready to make progress and should
    /// be `poll`ed.
    ///
    /// Executors generally maintain a queue of "ready" tasks; `wake` should place
    /// the associated task onto this queue.
    ///
    /// # Panics
    ///
    /// Implementations should avoid panicking, but clients should also be prepared
    /// for panics.
    ///
    /// # Unsafety
    ///
    /// This function is unsafe to call because it's asserting the `UnsafeWake`
    /// value is in a consistent state, i.e. hasn't been dropped.
    unsafe fn wake(&self);

    /// Indicates that the associated task is ready to make progress and should
    /// be `poll`ed. This function is the same as `wake`, but can only be called
    /// from the thread that this `UnsafeWake` is "local" to. This allows for
    /// implementors to provide specialized wakeup behavior specific to the current
    /// thread. This function is called by `LocalWaker::wake`.
    ///
    /// Executors generally maintain a queue of "ready" tasks; `wake_local` should place
    /// the associated task onto this queue.
    ///
    /// # Panics
    ///
    /// Implementations should avoid panicking, but clients should also be prepared
    /// for panics.
    ///
    /// # Unsafety
    ///
    /// This function is unsafe to call because it's asserting the `UnsafeWake`
    /// value is in a consistent state, i.e. hasn't been dropped, and that the
    /// `UnsafeWake` hasn't moved from the thread on which it was created.
    unsafe fn wake_local(&self) {
        self.wake()
    }
}
<commit_msg>Auto merge of #54732 - cramertj:waker, r=aturon<commit_after>// Copyright 2018 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.

#![unstable(feature = "futures_api",
            reason = "futures in libcore are unstable",
            issue = "50547")]

use fmt;
use marker::Unpin;
use ptr::NonNull;

/// A `Waker` is a handle for waking up a task by notifying its executor that it
/// is ready to be run.
///
/// This handle contains a trait object pointing to an instance of the `UnsafeWake`
/// trait, allowing notifications to get routed through it.
#[repr(transparent)]
pub struct Waker {
    inner: NonNull<dyn UnsafeWake>,
}

impl Unpin for Waker {}
unsafe impl Send for Waker {}
unsafe impl Sync for Waker {}

impl Waker {
    /// Constructs a new `Waker` directly.
    ///
    /// Note that most code will not need to call this. Implementers of the
    /// `UnsafeWake` trait will typically provide a wrapper that calls this
    /// but you otherwise shouldn't call it directly.
    ///
    /// If you're working with the standard library then it's recommended to
    /// use the `Waker::from` function instead which works with the safe
    /// `Arc` type and the safe `Wake` trait.
    #[inline]
    pub unsafe fn new(inner: NonNull<dyn UnsafeWake>) -> Self {
        Waker { inner }
    }

    /// Wake up the task associated with this `Waker`.
    #[inline]
    pub fn wake(&self) {
        unsafe { self.inner.as_ref().wake() }
    }

    /// Returns whether or not this `Waker` and `other` awaken the same task.
    ///
    /// This function works on a best-effort basis, and may return false even
    /// when the `Waker`s would awaken the same task. However, if this function
    /// returns true, it is guaranteed that the `Waker`s will awaken the same
    /// task.
    ///
    /// This function is primarily used for optimization purposes.
    #[inline]
    pub fn will_wake(&self, other: &Waker) -> bool {
        self.inner == other.inner
    }

    /// Returns whether or not this `Waker` and `other` `LocalWaker` awaken
    /// the same task.
    ///
    /// This function works on a best-effort basis, and may return false even
    /// when the `Waker`s would awaken the same task. However, if this function
    /// returns true, it is guaranteed that the `Waker`s will awaken the same
    /// task.
    ///
    /// This function is primarily used for optimization purposes.
    #[inline]
    pub fn will_wake_local(&self, other: &LocalWaker) -> bool {
        self.will_wake(&other.0)
    }
}

impl Clone for Waker {
    #[inline]
    fn clone(&self) -> Self {
        unsafe {
            self.inner.as_ref().clone_raw()
        }
    }
}

impl fmt::Debug for Waker {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Waker")
            .finish()
    }
}

impl Drop for Waker {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            self.inner.as_ref().drop_raw()
        }
    }
}

/// A `LocalWaker` is a handle for waking up a task by notifying its executor that it
/// is ready to be run.
///
/// This is similar to the `Waker` type, but cannot be sent across threads.
/// Task executors can use this type to implement more optimized singlethreaded wakeup
/// behavior.
#[repr(transparent)]
#[derive(Clone)]
pub struct LocalWaker(Waker);

impl Unpin for LocalWaker {}
impl !Send for LocalWaker {}
impl !Sync for LocalWaker {}

impl LocalWaker {
    /// Constructs a new `LocalWaker` directly.
    ///
    /// Note that most code will not need to call this. Implementers of the
    /// `UnsafeWake` trait will typically provide a wrapper that calls this
    /// but you otherwise shouldn't call it directly.
    ///
    /// If you're working with the standard library then it's recommended to
    /// use the `local_waker_from_nonlocal` or `local_waker` to convert a `Waker`
    /// into a `LocalWaker`.
    ///
    /// For this function to be used safely, it must be sound to call `inner.wake_local()`
    /// on the current thread.
    #[inline]
    pub unsafe fn new(inner: NonNull<dyn UnsafeWake>) -> Self {
        LocalWaker(Waker::new(inner))
    }

    /// Borrows this `LocalWaker` as a `Waker`.
    ///
    /// `Waker` is nearly identical to `LocalWaker`, but is threadsafe
    /// (implements `Send` and `Sync`).
    #[inline]
    pub fn as_waker(&self) -> &Waker {
        &self.0
    }

    /// Converts this `LocalWaker` into a `Waker`.
    ///
    /// `Waker` is nearly identical to `LocalWaker`, but is threadsafe
    /// (implements `Send` and `Sync`).
    #[inline]
    pub fn into_waker(self) -> Waker {
        self.0
    }

    /// Wake up the task associated with this `LocalWaker`.
    #[inline]
    pub fn wake(&self) {
        unsafe { self.0.inner.as_ref().wake_local() }
    }

    /// Returns whether or not this `LocalWaker` and `other` `LocalWaker` awaken the same task.
    ///
    /// This function works on a best-effort basis, and may return false even
    /// when the `LocalWaker`s would awaken the same task. However, if this function
    /// returns true, it is guaranteed that the `LocalWaker`s will awaken the same
    /// task.
    ///
    /// This function is primarily used for optimization purposes.
    #[inline]
    pub fn will_wake(&self, other: &LocalWaker) -> bool {
        self.0.will_wake(&other.0)
    }

    /// Returns whether or not this `LocalWaker` and `other` `Waker` awaken the same task.
    ///
    /// This function works on a best-effort basis, and may return false even
    /// when the `Waker`s would awaken the same task. However, if this function
    /// returns true, it is guaranteed that the `LocalWaker`s will awaken the same
    /// task.
    ///
    /// This function is primarily used for optimization purposes.
    #[inline]
    pub fn will_wake_nonlocal(&self, other: &Waker) -> bool {
        self.0.will_wake(other)
    }
}

impl From<LocalWaker> for Waker {
    #[inline]
    fn from(local_waker: LocalWaker) -> Self {
        local_waker.0
    }
}

impl fmt::Debug for LocalWaker {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("LocalWaker")
            .finish()
    }
}

/// An unsafe trait for implementing custom memory management for a `Waker` or `LocalWaker`.
///
/// A `Waker` conceptually is a cloneable trait object for `Wake`, and is
/// most often essentially just `Arc<dyn Wake>`. However, in some contexts
/// (particularly `no_std`), it's desirable to avoid `Arc` in favor of some
/// custom memory management strategy. This trait is designed to allow for such
/// customization.
///
/// When using `std`, a default implementation of the `UnsafeWake` trait is provided for
/// `Arc<T>` where `T: Wake`.
pub unsafe trait UnsafeWake: Send + Sync {
    /// Creates a clone of this `UnsafeWake` and stores it behind a `Waker`.
    ///
    /// This function will create a new uniquely owned handle that under the
    /// hood references the same notification instance. In other words calls
    /// to `wake` on the returned handle should be equivalent to calls to
    /// `wake` on this handle.
    ///
    /// # Unsafety
    ///
    /// This function is unsafe to call because it's asserting the `UnsafeWake`
    /// value is in a consistent state, i.e. hasn't been dropped.
    unsafe fn clone_raw(&self) -> Waker;

    /// Drops this instance of `UnsafeWake`, deallocating resources
    /// associated with it.
    ///
    /// FIXME(cramertj)
    /// This method is intended to have a signature such as:
    ///
    /// ```ignore (not-a-doctest)
    /// fn drop_raw(self: *mut Self);
    /// ```
    ///
    /// Unfortunately in Rust today that signature is not object safe.
    /// Nevertheless it's recommended to implement this function *as if* that
    /// were its signature. As such it is not safe to call on an invalid
    /// pointer, nor is the validity of the pointer guaranteed after this
    /// function returns.
    ///
    /// # Unsafety
    ///
    /// This function is unsafe to call because it's asserting the `UnsafeWake`
    /// value is in a consistent state, i.e. hasn't been dropped.
    unsafe fn drop_raw(&self);

    /// Indicates that the associated task is ready to make progress and should
    /// be `poll`ed.
    ///
    /// Executors generally maintain a queue of "ready" tasks; `wake` should place
    /// the associated task onto this queue.
    ///
    /// # Panics
    ///
    /// Implementations should avoid panicking, but clients should also be prepared
    /// for panics.
    ///
    /// # Unsafety
    ///
    /// This function is unsafe to call because it's asserting the `UnsafeWake`
    /// value is in a consistent state, i.e. hasn't been dropped.
    unsafe fn wake(&self);

    /// Indicates that the associated task is ready to make progress and should
    /// be `poll`ed. This function is the same as `wake`, but can only be called
    /// from the thread that this `UnsafeWake` is "local" to. This allows for
    /// implementors to provide specialized wakeup behavior specific to the current
    /// thread. This function is called by `LocalWaker::wake`.
    ///
    /// Executors generally maintain a queue of "ready" tasks; `wake_local` should place
    /// the associated task onto this queue.
    ///
    /// # Panics
    ///
    /// Implementations should avoid panicking, but clients should also be prepared
    /// for panics.
    ///
    /// # Unsafety
    ///
    /// This function is unsafe to call because it's asserting the `UnsafeWake`
    /// value is in a consistent state, i.e. hasn't been dropped, and that the
    /// `UnsafeWake` hasn't moved from the thread on which it was created.
    unsafe fn wake_local(&self) {
        self.wake()
    }
}
<|endoftext|>


<commit_before>// FIXME: stolen from cargo. Should be extracted into a common crate.

//! Job management (mostly for windows)
//!
//! Most of the time when you're running cargo you expect Ctrl-C to actually
//! terminate the entire tree of processes in play, not just the one at the top
//! (cago). This currently works "by default" on Unix platforms because Ctrl-C
//! actually sends a signal to the *process group* rather than the parent
//! process, so everything will get torn down. On Windows, however, this does
//! not happen and Ctrl-C just kills cargo.
//!
//! To achieve the same semantics on Windows we use Job Objects to ensure that
//! all processes die at the same time. Job objects have a mode of operation
//! where when all handles to the object are closed it causes all child
//! processes associated with the object to be terminated immediately.
//! Conveniently whenever a process in the job object spawns a new process the
//! child will be associated with the job object as well. This means if we add
//! ourselves to the job object we create then everything will get torn down!

pub use self::imp::Setup;

pub fn setup() -> Option<Setup> {
    unsafe { imp::setup() }
}

#[cfg(unix)]
mod imp {
    use std::env;
    use libc;

    pub type Setup = ();

    pub unsafe fn setup() -> Option<()> {
        Some(())
    }
}

#[cfg(windows)]
mod imp {
    extern crate winapi;

    use std::io;
    use std::mem;
    use std::ptr;

    use self::winapi::shared::minwindef::*;
    use self::winapi::um::handleapi::*;
    use self::winapi::um::jobapi2::*;
    use self::winapi::um::processthreadsapi::*;
    use self::winapi::um::winnt::*;
    use self::winapi::um::winnt::HANDLE;

    pub struct Setup {
        job: Handle,
    }

    pub struct Handle {
        inner: HANDLE,
    }

    fn last_err() -> io::Error {
        io::Error::last_os_error()
    }

    pub unsafe fn setup() -> Option<Setup> {
        // Creates a new job object for us to use and then adds ourselves to it.
        // Note that all errors are basically ignored in this function,
        // intentionally. Job objects are "relatively new" in Windows,
        // particularly the ability to support nested job objects. Older
        // Windows installs don't support this ability. We probably don't want
        // to force Cargo to abort in this situation or force others to *not*
        // use job objects, so we instead just ignore errors and assume that
        // we're otherwise part of someone else's job object in this case.

        let job = CreateJobObjectW(ptr::null_mut(), ptr::null());
        if job.is_null() {
            return None;
        }
        let job = Handle { inner: job };

        // Indicate that when all handles to the job object are gone that all
        // process in the object should be killed. Note that this includes our
        // entire process tree by default because we've added ourselves and
        // our children will reside in the job once we spawn a process.
        let mut info: JOBOBJECT_EXTENDED_LIMIT_INFORMATION;
        info = mem::zeroed();
        info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
        let r = SetInformationJobObject(
            job.inner,
            JobObjectExtendedLimitInformation,
            &mut info as *mut _ as LPVOID,
            mem::size_of_val(&info) as DWORD,
        );
        if r == 0 {
            return None;
        }

        // Assign our process to this job object, meaning that our children will
        // now live or die based on our existence.
        let me = GetCurrentProcess();
        let r = AssignProcessToJobObject(job.inner, me);
        if r == 0 {
            return None;
        }

        Some(Setup { job })
    }

    impl Drop for Setup {
        fn drop(&mut self) {
            // On normal exits (not ctrl-c), we don't want to kill any child
            // processes. The destructor here configures our job object to
            // *not* kill everything on close, then closes the job object.
            unsafe {
                let mut info: JOBOBJECT_EXTENDED_LIMIT_INFORMATION;
                info = mem::zeroed();
                let r = SetInformationJobObject(
                    self.job.inner,
                    JobObjectExtendedLimitInformation,
                    &mut info as *mut _ as LPVOID,
                    mem::size_of_val(&info) as DWORD,
                );
                if r == 0 {
                    info!("failed to configure job object to defaults: {}", last_err());
                }
            }
        }
    }

    impl Drop for Handle {
        fn drop(&mut self) {
            unsafe {
                CloseHandle(self.inner);
            }
        }
    }
}
<commit_msg>Remove used imports<commit_after>// FIXME: stolen from cargo. Should be extracted into a common crate.

//! Job management (mostly for windows)
//!
//! Most of the time when you're running cargo you expect Ctrl-C to actually
//! terminate the entire tree of processes in play, not just the one at the top
//! (cago). This currently works "by default" on Unix platforms because Ctrl-C
//! actually sends a signal to the *process group* rather than the parent
//! process, so everything will get torn down. On Windows, however, this does
//! not happen and Ctrl-C just kills cargo.
//!
//! To achieve the same semantics on Windows we use Job Objects to ensure that
//! all processes die at the same time. Job objects have a mode of operation
//! where when all handles to the object are closed it causes all child
//! processes associated with the object to be terminated immediately.
//! Conveniently whenever a process in the job object spawns a new process the
//! child will be associated with the job object as well. This means if we add
//! ourselves to the job object we create then everything will get torn down!

pub use self::imp::Setup;

pub fn setup() -> Option<Setup> {
    unsafe { imp::setup() }
}

#[cfg(unix)]
mod imp {
    pub type Setup = ();

    pub unsafe fn setup() -> Option<()> {
        Some(())
    }
}

#[cfg(windows)]
mod imp {
    extern crate winapi;

    use std::io;
    use std::mem;
    use std::ptr;

    use self::winapi::shared::minwindef::*;
    use self::winapi::um::handleapi::*;
    use self::winapi::um::jobapi2::*;
    use self::winapi::um::processthreadsapi::*;
    use self::winapi::um::winnt::*;
    use self::winapi::um::winnt::HANDLE;

    pub struct Setup {
        job: Handle,
    }

    pub struct Handle {
        inner: HANDLE,
    }

    fn last_err() -> io::Error {
        io::Error::last_os_error()
    }

    pub unsafe fn setup() -> Option<Setup> {
        // Creates a new job object for us to use and then adds ourselves to it.
        // Note that all errors are basically ignored in this function,
        // intentionally. Job objects are "relatively new" in Windows,
        // particularly the ability to support nested job objects. Older
        // Windows installs don't support this ability. We probably don't want
        // to force Cargo to abort in this situation or force others to *not*
        // use job objects, so we instead just ignore errors and assume that
        // we're otherwise part of someone else's job object in this case.

        let job = CreateJobObjectW(ptr::null_mut(), ptr::null());
        if job.is_null() {
            return None;
        }
        let job = Handle { inner: job };

        // Indicate that when all handles to the job object are gone that all
        // process in the object should be killed. Note that this includes our
        // entire process tree by default because we've added ourselves and
        // our children will reside in the job once we spawn a process.
        let mut info: JOBOBJECT_EXTENDED_LIMIT_INFORMATION;
        info = mem::zeroed();
        info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
        let r = SetInformationJobObject(
            job.inner,
            JobObjectExtendedLimitInformation,
            &mut info as *mut _ as LPVOID,
            mem::size_of_val(&info) as DWORD,
        );
        if r == 0 {
            return None;
        }

        // Assign our process to this job object, meaning that our children will
        // now live or die based on our existence.
        let me = GetCurrentProcess();
        let r = AssignProcessToJobObject(job.inner, me);
        if r == 0 {
            return None;
        }

        Some(Setup { job })
    }

    impl Drop for Setup {
        fn drop(&mut self) {
            // On normal exits (not ctrl-c), we don't want to kill any child
            // processes. The destructor here configures our job object to
            // *not* kill everything on close, then closes the job object.
            unsafe {
                let mut info: JOBOBJECT_EXTENDED_LIMIT_INFORMATION;
                info = mem::zeroed();
                let r = SetInformationJobObject(
                    self.job.inner,
                    JobObjectExtendedLimitInformation,
                    &mut info as *mut _ as LPVOID,
                    mem::size_of_val(&info) as DWORD,
                );
                if r == 0 {
                    info!("failed to configure job object to defaults: {}", last_err());
                }
            }
        }
    }

    impl Drop for Handle {
        fn drop(&mut self) {
            unsafe {
                CloseHandle(self.inner);
            }
        }
    }
}
<|endoftext|>


<commit_before>//
// gash.rs
//
// Starting code for PS2
// Running on Rust 0.9
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu, David Evans
// Version 0.4
//

extern mod extra;

use std::{io, run, os, str};
use std::io::buffered::BufferedReader;
use std::path::posix::Path;
use std::io::fs::File;
use std::io::stdin;
use std::io::signal::{Listener, Interrupt};
use extra::getopts;
use std::libc::types::os::arch::posix88::{pid_t};
use std::libc::{c_int};

static exit_code : i32 = -999;
static nop_code : i32 = -1;

struct Shell {
    cmd_prompt : ~str,
    cmd_history : ~[~str],
}

impl Shell {

    fn new(prompt_str: &str) -> Shell {
        Shell {
            cmd_prompt: prompt_str.to_owned(),
            cmd_history: ~[],
        }
    }

    fn run(&mut self) {
        #[nolink]
        extern { fn setpgid(pid : pid_t, pgid: pid_t) -> c_int; }
        unsafe { println!("setting pgid... {:d}", setpgid(0, 0)); }

        let mut stdin = BufferedReader::new(stdin());

        // let (port_interrupt, chan_interrupt) : (Port<~str>, Chan<~str>) = Chan::new();
        let (port_PID, chan_PID) : (Port<i32>, Chan<i32>) = Chan::new();
        let (port_status, chan_status) : (Port<i32>, Chan<i32>) = Chan::new();
            // -1 is "continue" signal
        chan_status.send(nop_code); // Initial "go" signal, could be any number...
            // -2 is "exit" signal.
        spawn(proc() {
            let mut listener = Listener::new();
            listener.register(Interrupt);

            let mut last_pid : i32 = 1;
            loop {
                match port_PID.try_recv() {
                    Some(status) if status == exit_code => {
                        listener.unregister(Interrupt);
                        // println!("Matched exit code");
                        return;
                        // MAKE IT EXIT RIGHT HERE!
                    }
                    Some(pid) if pid == nop_code => {
                        // println!("Matched nop code");
                        chan_status.send(nop_code);    // To complete process
                    }
                    Some(pid) => {
                        // println!("Matched PID")
                        let mut my_pid : i32;
                        unsafe { my_pid = std::libc::getpid(); }
                        if (pid != my_pid) {
                            last_pid = pid;
                            // println!("Changed PID to {:d}", last_pid);
                        }
                            chan_status.send(nop_code);   // To complete process
                    }
                    None    => {}
                }

                // match listener.port.try_recv() {
                //     Some(Interrupt) => {
                //         println!("Killing {:d}", last_pid);
                //         // unsafe {
                //         //     let result : i32 = std::libc::funcs::posix88::signal::kill(last_pid, 0);
                //         // }
                //     }
                //     _ => {}
                // }
            }
        });

        loop {
            let status : i32 = port_status.recv();   // Wait for op to finish.
            print(self.cmd_prompt); // Prints "gash >"
            io::stdio::flush();

            let mut line : ~str = stdin.read_line().unwrap().to_owned();
            let mut cmd_line: ~str = line.trim().to_owned();
            let mut background: bool = false;
            let mut i : uint = 0;

            // This block handles if there are no spaces around pipe.
            let lineClone = line.clone();
            for character in lineClone.chars() {
                if character == '<' {
                    line = line.slice(0, i).to_owned() + " < " + line.slice(i+1, line.char_len()).to_owned();
                    i = i + 2;
                } else if character == '>' {
                    line = line.slice(0, i).to_owned() + " > " + line.slice(i+1, line.char_len()).to_owned();
                    i = i + 2;
                } else if character == '|' {
                    line = line.slice(0, i).to_owned() + " | " + line.slice(i+1, line.char_len()).to_owned();
                    i = i + 2;
                }
                i = i + 1;
            }

            if cmd_line.char_len() > 0 {
                background = cmd_line.char_at(cmd_line.char_len() - 1) == '&';
                if background {
                    cmd_line = cmd_line.slice(0, cmd_line.char_len() - 1).trim().to_owned();
                }
            }

            let params = cmd_line.clone().to_owned();
            let program = cmd_line.splitn(' ', 1).nth(0).expect("no program");

            match program {
                ""          =>  { chan_PID.send(nop_code);
                                  continue; }
                "exit"      =>  { chan_PID.send(exit_code);
                                  return; }  // Exit
                "cd"        =>  { Shell::run_check_mode(background, Shell::run_cd(params), &chan_PID); }
                "history"   =>  { Shell::run_check_mode(background, Shell::run_history(params, self.cmd_history), &chan_PID); }
                _           =>  { Shell::run_check_mode(background, Shell::run_cmdline(params), &chan_PID); }
            }

            self.cmd_history.push(program.to_owned());
        }
    }

    fn run_check_mode(background: bool, f: proc(), chan_PID : &Chan<i32>) {
        let (port_temp, chan_temp) : (Port<i32>, Chan<i32>) = Chan::new();
        if background {
            spawn(proc() {
                #[nolink]
                extern { fn setpgid(pid : pid_t, pgid: pid_t) -> c_int; }
                unsafe { println!("Setting pgid... {:d}", setpgid(std::libc::getpid(), 0)); }

                f();
            });
            chan_PID.send(nop_code);  // Don't send PID.
        } else {
            spawn(proc() {
                f();
                unsafe {
                    println!("Sending new PID of {:d}", std::libc::getpid());
                    chan_temp.send(std::libc::getpid());
                }
            });
            chan_PID.send(port_temp.recv());
        }
    }

    fn run_cmdline_single(cmd_line: &str) {
        (Shell::run_cmdline(cmd_line))();
    }

    fn run_cmdline(cmd_line: &str) -> proc() {
        let params = cmd_line.to_owned();
        return proc() {
            if params.trim() != "" {
                let output = Shell::handle_pipes(params, false);
                // write output to file (if necessary and exists)
                match output {
                    Some(outString) => {
                        match Shell::get_output_file(params) {
                            Some(fileName) => {
                                let mut f = File::create(&Path::new(fileName));
                                f.write(outString.into_bytes());
                            }
                            None => { /* Shouldn't happen... */ }
                        }
                    }
                    None => { /*Do nothing*/ }
                }
            }
        };
    }

    fn handle_pipes(cmd_line: &str, out_pipe: bool) -> Option<~str> {
        let pipeSplit = Shell::split_on_last_pipe(cmd_line);
        let mut argv = Shell::get_args_no_redirects(pipeSplit[0]);
        let program = argv.remove(0);
        let hasOutRedirect = match Shell::get_output_file(cmd_line) {
            Some(_) => { true }
            None => {
                if out_pipe {
                    true
                } else {
                    false
                }
            }
        };

        if pipeSplit.len() == 2 {
            return Shell::run_cmd(program, argv, Shell::handle_pipes(pipeSplit[1], true), hasOutRedirect);
        } else {
            return Shell::run_cmd(program, argv, Shell::get_input_file_contents(cmd_line), hasOutRedirect);
        }
    }

    fn run_cmd(program: &str, argv: &[~str], inputStr: Option<~str>, hasOutRedirect: bool) -> Option<~str> {
        if Shell::cmd_exists(program) {
            let mut options = run::ProcessOptions::new();
            options.in_fd = match inputStr {
                Some(_) => { None }
                None => { Some(0) }
            };

            options.out_fd = if hasOutRedirect {
                None
            } else {
                Some(1)
            };

            let mut process = run::Process::new(program, argv, options).unwrap();
            match inputStr {
                Some(string) => {
                    let buf = string.into_bytes();
                    process.input().write(buf);
                }
                None => {}
            }

            process.close_input();

            if hasOutRedirect {
                let processOutput = process.finish_with_output();
                return Some(str::from_utf8(processOutput.output).to_owned());
            } else {
                process.finish();
                return None;
            };
        } else {
            println!("{:s}: command not found", program);
            return None;
        }
    }

    fn cmd_exists(cmd_path: &str) -> bool {
        let ret = run::process_output("which", [cmd_path.to_owned()]);
        return ret.expect("exit code error.").status.success();
    }

    fn run_cd(cmd_line: &str) -> proc() {
        let params = cmd_line.to_owned();
        return proc() {
            let argv: ~[~str] = Shell::get_args(params);
            let pathOpt: Option<Path> = match argv.len() {
                1   =>  { os::homedir() }
                0   =>  { os::homedir() }
                _   =>  { Some(Path::new(argv[1])) }
            };

            match pathOpt {
                Some(path)   =>  {
                    if path.is_dir() {
                        os::change_dir(&path);
                    } else {
                        println!("Error: {:s} is not a directory", path.as_str().unwrap());
                    }
                }
                None        =>  {
                    println!("Error: Invalid path");
                }
            };
        };
    }

    fn run_history(cmd_line: &str, cmd_history: &[~str]) -> proc() {
        let history = cmd_history.to_owned();
        let params = cmd_line.to_owned();
        return proc() {
            let argv: ~[~str] = Shell::get_args(params);
            if (argv.len() > 1) {
                println!("Error: history does not take options (sadly).");
            }
            else {
                let mut i = 1;
                for entry in history.iter() {
                    println!("{:d} \t{:s}", i, entry.to_owned());
                    i = i + 1;
                }
            }
        };
    }

    fn split_on_last_pipe(cmd_line: &str) -> ~[~str] {
        return cmd_line.rsplitn('|', 1).filter_map(|x| Some(x.trim().to_owned())).to_owned_vec();
    }

    fn get_input_file_contents(cmd_line: &str) -> Option<~str> {
        return match cmd_line.splitn('<', 1).nth(1) {
            Some(inputFileCandidate) => {
                match inputFileCandidate.trim().splitn(' ', 1).nth(0) {
                    Some(inputFile) => {
                        match File::open(&Path::new(inputFile)) {
                            Some(mut file) => {
                                Some(file.read_to_str())
                            }
                            None => {
                                println!("File {:s} does not exist", inputFile);
                                None
                            }
                        }
                    }
                    None => { None }
                }
            }
            None => { None }
        };
    }

    fn get_output_file(cmd_line: &str) -> Option<~str> {
        return match cmd_line.splitn('>', 1).nth(1) {
            Some(inputFileCandidate) => {
                match inputFileCandidate.trim().splitn(' ', 1).nth(0) {
                    Some(inputFile) => { Some(inputFile.to_owned()) }
                    None => { None }
                }
            }
            None => { None }
        };
    }

    fn get_args_no_redirects(cmd_line: &str) -> ~[~str] {
        let mut activeRedirect = false;
        return cmd_line.split(' ').filter_map(|x| if x == ">" || x == "<" {
            activeRedirect = true;
            None
        } else if x == "" {
            None
        } else if activeRedirect {
            activeRedirect = false;
            None
        } else {
            Some(x.to_owned())
        }).to_owned_vec();
    }

    fn get_args(cmd_line: &str) -> ~[~str] {
        return cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();
    }
}

fn get_cmdline_from_args() -> Option<~str> {
    /* Begin processing program arguments and initiate the parameters. */
    let args = os::args();

    let opts = ~[
        getopts::optopt("c")
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_err_msg()) }
    };

    if matches.opt_present("c") {
        let cmd_str = match matches.opt_str("c") {
                                                Some(cmd_str) => {cmd_str.to_owned()},
                                                None => {~""}
                                              };
        return Some(cmd_str);
    } else {
        return None;
    }
}

fn main() {
    let opt_cmd_line = get_cmdline_from_args();

    match opt_cmd_line {
        Some(cmd_line) => Shell::run_cmdline_single(cmd_line),
        None           => Shell::new("gash > ").run()
    }
}
<commit_msg>Cleaned up some code, commented out unecessary parts.<commit_after>//
// gash.rs
//
// Starting code for PS2
// Running on Rust 0.9
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu, David Evans
// Version 0.4
//

extern mod extra;

use std::{io, run, os, str};
use std::io::buffered::BufferedReader;
use std::path::posix::Path;
use std::io::fs::File;
use std::io::stdin;
use std::io::signal::{Listener, Interrupt};
use extra::getopts;
// use std::libc::types::os::arch::posix88::{pid_t};
// use std::libc::{c_int};

static exit_code : i32 = -999;
static nop_code : i32 = -1;

struct Shell {
    cmd_prompt : ~str,
    cmd_history : ~[~str],
}

impl Shell {

    fn new(prompt_str: &str) -> Shell {
        Shell {
            cmd_prompt: prompt_str.to_owned(),
            cmd_history: ~[],
        }
    }

    fn run(&mut self) {
        // I thought this would declare a new process group that I can use
        // to put background processes in later so they didn't get sent the
        // SIGINT signal. Needless to say it doesn't work...
        // #[nolink]
        // extern { fn setpgid(pid : pid_t, pgid: pid_t) -> c_int; }
        // unsafe { println!("setting pgid... {:d}", setpgid(0, 0)); }

        let mut stdin = BufferedReader::new(stdin());

        let (port_PID, chan_PID) : (Port<i32>, Chan<i32>) = Chan::new();
        let (port_status, chan_status) : (Port<i32>, Chan<i32>) = Chan::new();
        chan_status.send(nop_code);
        spawn(proc() {
            let mut listener = Listener::new();
            listener.register(Interrupt);

            let mut last_pid : i32 = 1;
            loop {
                match port_PID.try_recv() {
                    Some(status) if status == exit_code => {
                        listener.unregister(Interrupt);
                        // println!("Matched exit code");
                        return;
                    }
                    // These two would work if the SIGINT signal didn't get sent
                    // to everything... They're not necessary right now but I don't
                    // want to take them out in case we end up using the PID later.
                    Some(pid) if pid == nop_code => {
                        // println!("Matched nop code");
                        chan_status.send(nop_code);    // To complete process
                    }
                    Some(pid) => {
                        // println!("Matched PID")
                        let mut my_pid : i32;
                        unsafe { my_pid = std::libc::getpid(); }
                        if (pid != my_pid) {
                            last_pid = pid;
                            // println!("Changed PID to {:d}", last_pid);
                        }
                            chan_status.send(nop_code);   // To complete process
                    }
                    None    => {}
                }

                // This MIGHT kill the process if it wasn't already killed along with everything else...
                // match listener.port.try_recv() {
                //     Some(Interrupt) => {
                //         println!("Killing {:d}", last_pid);
                //         unsafe {
                //             let result : i32 = std::libc::funcs::posix88::signal::kill(last_pid, 0);
                //         }
                //     }
                //     _ => {}
                // }
            }
        });

        loop {
            port_status.recv();   // Wait for op to finish.
            print(self.cmd_prompt); // Prints "gash >"
            io::stdio::flush();

            let mut line : ~str = stdin.read_line().unwrap().to_owned();
            let mut cmd_line: ~str = line.trim().to_owned();
            let mut background: bool = false;
            let mut i : uint = 0;

            // This block handles if there are no spaces around pipe.
            let lineClone = line.clone();
            for character in lineClone.chars() {
                if character == '<' {
                    line = line.slice(0, i).to_owned() + " < " + line.slice(i+1, line.char_len()).to_owned();
                    i = i + 2;
                } else if character == '>' {
                    line = line.slice(0, i).to_owned() + " > " + line.slice(i+1, line.char_len()).to_owned();
                    i = i + 2;
                } else if character == '|' {
                    line = line.slice(0, i).to_owned() + " | " + line.slice(i+1, line.char_len()).to_owned();
                    i = i + 2;
                }
                i = i + 1;
            }

            if cmd_line.char_len() > 0 {
                background = cmd_line.char_at(cmd_line.char_len() - 1) == '&';
                if background {
                    cmd_line = cmd_line.slice(0, cmd_line.char_len() - 1).trim().to_owned();
                }
            }

            let params = cmd_line.clone().to_owned();
            let program = cmd_line.splitn(' ', 1).nth(0).expect("no program");

            match program {
                ""          =>  { chan_PID.send(nop_code);
                                  continue; }
                "exit"      =>  { chan_PID.send(exit_code);
                                  return; }  // Exit
                "cd"        =>  { Shell::run_check_mode(background, Shell::run_cd(params), &chan_PID); }
                "history"   =>  { Shell::run_check_mode(background, Shell::run_history(params, self.cmd_history), &chan_PID); }
                _           =>  { Shell::run_check_mode(background, Shell::run_cmdline(params), &chan_PID); }
            }

            self.cmd_history.push(program.to_owned());
        }
    }

    fn run_check_mode(background: bool, f: proc(), chan_PID : &Chan<i32>) {
        let (port_temp, chan_temp) : (Port<i32>, Chan<i32>) = Chan::new();
        if background {
            spawn(proc() {
                // This should have moved the process into a new process group.
                // It didn't work though. Still got SIGINT from the interrupt.
                // #[nolink]
                // extern { fn setpgid(pid : pid_t, pgid: pid_t) -> c_int; }
                // unsafe { println!("Setting pgid... {:d}", setpgid(std::libc::getpid(), 0)); }

                f();
            });
            chan_PID.send(nop_code);  // Don't send PID.
        } else {
            spawn(proc() {
                f();
                unsafe {
                    // println!("Sending new PID of {:d}", std::libc::getpid());
                    chan_temp.send(std::libc::getpid());
                }
            });
            chan_PID.send(port_temp.recv());
        }
    }

    fn run_cmdline_single(cmd_line: &str) {
        (Shell::run_cmdline(cmd_line))();
    }

    fn run_cmdline(cmd_line: &str) -> proc() {
        let params = cmd_line.to_owned();
        return proc() {
            if params.trim() != "" {
                let output = Shell::handle_pipes(params, false);
                // write output to file (if necessary and exists)
                match output {
                    Some(outString) => {
                        match Shell::get_output_file(params) {
                            Some(fileName) => {
                                let mut f = File::create(&Path::new(fileName));
                                f.write(outString.into_bytes());
                            }
                            None => { /* Shouldn't happen... */ }
                        }
                    }
                    None => { /*Do nothing*/ }
                }
            }
        };
    }

    fn handle_pipes(cmd_line: &str, out_pipe: bool) -> Option<~str> {
        let pipeSplit = Shell::split_on_last_pipe(cmd_line);
        let mut argv = Shell::get_args_no_redirects(pipeSplit[0]);
        let program = argv.remove(0);
        let hasOutRedirect = match Shell::get_output_file(cmd_line) {
            Some(_) => { true }
            None => {
                if out_pipe {
                    true
                } else {
                    false
                }
            }
        };

        if pipeSplit.len() == 2 {
            return Shell::run_cmd(program, argv, Shell::handle_pipes(pipeSplit[1], true), hasOutRedirect);
        } else {
            return Shell::run_cmd(program, argv, Shell::get_input_file_contents(cmd_line), hasOutRedirect);
        }
    }

    fn run_cmd(program: &str, argv: &[~str], inputStr: Option<~str>, hasOutRedirect: bool) -> Option<~str> {
        if Shell::cmd_exists(program) {
            let mut options = run::ProcessOptions::new();
            options.in_fd = match inputStr {
                Some(_) => { None }
                None => { Some(0) }
            };

            options.out_fd = if hasOutRedirect {
                None
            } else {
                Some(1)
            };

            let mut process = run::Process::new(program, argv, options).unwrap();
            match inputStr {
                Some(string) => {
                    let buf = string.into_bytes();
                    process.input().write(buf);
                }
                None => {}
            }

            process.close_input();

            if hasOutRedirect {
                let processOutput = process.finish_with_output();
                return Some(str::from_utf8(processOutput.output).to_owned());
            } else {
                process.finish();
                return None;
            };
        } else {
            println!("{:s}: command not found", program);
            return None;
        }
    }

    fn cmd_exists(cmd_path: &str) -> bool {
        let ret = run::process_output("which", [cmd_path.to_owned()]);
        return ret.expect("exit code error.").status.success();
    }

    fn run_cd(cmd_line: &str) -> proc() {
        let params = cmd_line.to_owned();
        return proc() {
            let argv: ~[~str] = Shell::get_args(params);
            let pathOpt: Option<Path> = match argv.len() {
                1   =>  { os::homedir() }
                0   =>  { os::homedir() }
                _   =>  { Some(Path::new(argv[1])) }
            };

            match pathOpt {
                Some(path)   =>  {
                    if path.is_dir() {
                        os::change_dir(&path);
                    } else {
                        println!("Error: {:s} is not a directory", path.as_str().unwrap());
                    }
                }
                None        =>  {
                    println!("Error: Invalid path");
                }
            };
        };
    }

    fn run_history(cmd_line: &str, cmd_history: &[~str]) -> proc() {
        let history = cmd_history.to_owned();
        let params = cmd_line.to_owned();
        return proc() {
            let argv: ~[~str] = Shell::get_args(params);
            if (argv.len() > 1) {
                println!("Error: history does not take options (sadly).");
            }
            else {
                let mut i = 1;
                for entry in history.iter() {
                    println!("{:d} \t{:s}", i, entry.to_owned());
                    i = i + 1;
                }
            }
        };
    }

    fn split_on_last_pipe(cmd_line: &str) -> ~[~str] {
        return cmd_line.rsplitn('|', 1).filter_map(|x| Some(x.trim().to_owned())).to_owned_vec();
    }

    fn get_input_file_contents(cmd_line: &str) -> Option<~str> {
        return match cmd_line.splitn('<', 1).nth(1) {
            Some(inputFileCandidate) => {
                match inputFileCandidate.trim().splitn(' ', 1).nth(0) {
                    Some(inputFile) => {
                        match File::open(&Path::new(inputFile)) {
                            Some(mut file) => {
                                Some(file.read_to_str())
                            }
                            None => {
                                println!("File {:s} does not exist", inputFile);
                                None
                            }
                        }
                    }
                    None => { None }
                }
            }
            None => { None }
        };
    }

    fn get_output_file(cmd_line: &str) -> Option<~str> {
        return match cmd_line.splitn('>', 1).nth(1) {
            Some(inputFileCandidate) => {
                match inputFileCandidate.trim().splitn(' ', 1).nth(0) {
                    Some(inputFile) => { Some(inputFile.to_owned()) }
                    None => { None }
                }
            }
            None => { None }
        };
    }

    fn get_args_no_redirects(cmd_line: &str) -> ~[~str] {
        let mut activeRedirect = false;
        return cmd_line.split(' ').filter_map(|x| if x == ">" || x == "<" {
            activeRedirect = true;
            None
        } else if x == "" {
            None
        } else if activeRedirect {
            activeRedirect = false;
            None
        } else {
            Some(x.to_owned())
        }).to_owned_vec();
    }

    fn get_args(cmd_line: &str) -> ~[~str] {
        return cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();
    }
}

fn get_cmdline_from_args() -> Option<~str> {
    /* Begin processing program arguments and initiate the parameters. */
    let args = os::args();

    let opts = ~[
        getopts::optopt("c")
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_err_msg()) }
    };

    if matches.opt_present("c") {
        let cmd_str = match matches.opt_str("c") {
                                                Some(cmd_str) => {cmd_str.to_owned()},
                                                None => {~""}
                                              };
        return Some(cmd_str);
    } else {
        return None;
    }
}

fn main() {
    let opt_cmd_line = get_cmdline_from_args();

    match opt_cmd_line {
        Some(cmd_line) => Shell::run_cmdline_single(cmd_line),
        None           => Shell::new("gash > ").run()
    }
}
<|endoftext|>