<commit_before>use redox::*;

// nvp implementation version
pub const NV_VERSION: i32 = 0;

// nvlist header
//#[derive(Debug)]
pub struct NvList {
    pub version: i32,
    pub nvflag:  u32, // persistent flags
    pub pairs: Vec<(String, NvValue)>,
}

impl NvList {
    pub fn new(nvflag: u32) -> Self {
        NvList {
            version: NV_VERSION,
            nvflag: nvflag,
            pairs: Vec::new(),
        }
    }

    pub fn find(&self, name: &str) -> Option<&NvValue> {
        for pair in &self.pairs {
            if pair.0 == name {
                return Some(&pair.1);
            }
        }
        None
    }

    pub fn find_mut(&mut self, name: &str) -> Option<&mut NvValue> {
        for pair in &mut self.pairs {
            if pair.0 == name {
                return Some(&mut pair.1);
            }
        }
        None
    }

    pub fn get<'a, T: GetNvValue<'a>>(&'a self, name: &str) -> Option<T> {
        self.find(name).and_then(|x| GetNvValue::get(x))
    }
}

impl fmt::Debug for NvList {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f, "NvList {{ version: {:X}, nvflag: {:X}, pairs: [\n", self.version, self.nvflag));
        for &(ref name, ref value) in &self.pairs {
            if name.is_empty() { break; }
            try!(write!(f, "{} : {:?}\n", name, value));
        }
        try!(write!(f, "] }}\n"));
        Ok(())
    }
}

// TODO Auto implement Debug. format! currently crashes with big u32 values
//#[derive(Debug)]
pub enum NvValue {
    Unknown,
    Boolean,
    Byte(u8),
    Int16(i16),
    Uint16(u16),
    Int32(i32),
    Uint32(u32),
    Int64(i64),
    Uint64(u64),
    String(String),
    ByteArray(Vec<u8>),
    Int16Array(Vec<i16>),
    Uint16Array(Vec<u16>),
    Int32Array(Vec<i32>),
    Uint32Array(Vec<u32>),
    Int64Array(Vec<i64>),
    Uint64Array(Vec<u64>),
    StringArray(Vec<String>),
    HrTime(i64),
    NvList(NvList),
    NvListArray(Vec<NvList>),
    BooleanValue(bool),
    Int8(i8),
    Uint8(u8),
    BooleanArray(Vec<bool>),
    Int8Array(Vec<i8>),
    Uint8Array(Vec<u8>),
}

impl NvValue {
    pub fn data_type(&self) -> DataType {
        match *self {
            NvValue::Unknown => DataType::Unknown,
            NvValue::Boolean => DataType::Boolean,
            NvValue::Byte(_) => DataType::Byte,
            NvValue::Int16(_) => DataType::Int16,
            NvValue::Uint16(_) => DataType::Uint16,
            NvValue::Int32(_) => DataType::Int32,
            NvValue::Uint32(_) => DataType::Uint32,
            NvValue::Int64(_) => DataType::Int64,
            NvValue::Uint64(_) => DataType::Uint64,
            NvValue::String(_) => DataType::String,
            NvValue::ByteArray(_) => DataType::ByteArray,
            NvValue::Int16Array(_) => DataType::Int16Array,
            NvValue::Uint16Array(_) => DataType::Uint16Array,
            NvValue::Int32Array(_) => DataType::Int32Array,
            NvValue::Uint32Array(_) => DataType::Uint32Array,
            NvValue::Int64Array(_) => DataType::Int64Array,
            NvValue::Uint64Array(_) => DataType::Uint64Array,
            NvValue::StringArray(_) => DataType::StringArray,
            NvValue::HrTime(_) => DataType::HrTime,
            NvValue::NvList(_) => DataType::NvList,
            NvValue::NvListArray(_) => DataType::NvListArray,
            NvValue::BooleanValue(_) => DataType::BooleanValue,
            NvValue::Int8(_) => DataType::Int8,
            NvValue::Uint8(_) => DataType::Uint8,
            NvValue::BooleanArray(_) => DataType::BooleanArray,
            NvValue::Int8Array(_) => DataType::Int8Array,
            NvValue::Uint8Array(_) => DataType::Uint8Array,
        }
    }

    pub fn num_elements(&self) -> usize {
        match *self {
            NvValue::Unknown => 1,
            NvValue::Boolean => 1,
            NvValue::Byte(_) => 1,
            NvValue::Int16(_) => 1,
            NvValue::Uint16(_) => 1,
            NvValue::Int32(_) => 1,
            NvValue::Uint32(_) => 1,
            NvValue::Int64(_) => 1,
            NvValue::Uint64(_) => 1,
            NvValue::String(_) => 1,
            NvValue::ByteArray(ref a) => a.len(),
            NvValue::Int16Array(ref a) => a.len(),
            NvValue::Uint16Array(ref a) => a.len(),
            NvValue::Int32Array(ref a) => a.len(),
            NvValue::Uint32Array(ref a) => a.len(),
            NvValue::Int64Array(ref a) => a.len(),
            NvValue::Uint64Array(ref a) => a.len(),
            NvValue::StringArray(ref a) => a.len(),
            NvValue::HrTime(_) => 1,
            NvValue::NvList(_) => 1,
            NvValue::NvListArray(ref a) => a.len(),
            NvValue::BooleanValue(_) => 1,
            NvValue::Int8(_) => 1,
            NvValue::Uint8(_) => 1,
            NvValue::BooleanArray(ref a) => a.len(),
            NvValue::Int8Array(ref a) => a.len(),
            NvValue::Uint8Array(ref a) => a.len(),
        }
    }
}

impl fmt::Debug for NvValue {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            NvValue::Int64(v) => write!(f, "Int64(0x{:X})", v),
            NvValue::Uint64(v) => write!(f, "Uint64(0x{:X})", v),
            NvValue::NvList(ref v) => write!(f, "NvList({:?})", v),
            NvValue::NvListArray(ref v) => {
                try!(write!(f, "NvListArray(["));
                for nv_list in v {
                    try!(write!(f, "NvList({:?})", nv_list));
                }
                write!(f, "])")
            },
            NvValue::String(ref v) => { write!(f, "String({})", v) },
            _ => write!(f, "{:?}", self),
        }
    }
}

#[derive(Copy, Clone, Debug)]
pub enum DataType {
    Unknown = 0,
    Boolean,
    Byte,
    Int16,
    Uint16,
    Int32,
    Uint32,
    Int64,
    Uint64,
    String,
    ByteArray,
    Int16Array,
    Uint16Array,
    Int32Array,
    Uint32Array,
    Int64Array,
    Uint64Array,
    StringArray,
    HrTime,
    NvList,
    NvListArray,
    BooleanValue,
    Int8,
    Uint8,
    BooleanArray,
    Int8Array,
    Uint8Array,
}

impl DataType {
    pub fn from_u8(u: u8) -> Option<DataType> {
        match u {
            0 => Some(DataType::Unknown),
            1 => Some(DataType::Boolean),
            2 => Some(DataType::Byte),
            3 => Some(DataType::Int16),
            4 => Some(DataType::Uint16),
            5 => Some(DataType::Int32),
            6 => Some(DataType::Uint32),
            7 => Some(DataType::Int64),
            8 => Some(DataType::Uint64),
            9 => Some(DataType::String),
            10 => Some(DataType::ByteArray),
            11 => Some(DataType::Int16Array),
            12 => Some(DataType::Uint16Array),
            13 => Some(DataType::Int32Array),
            14 => Some(DataType::Uint32Array),
            15 => Some(DataType::Int64Array),
            16 => Some(DataType::Uint64Array),
            17 => Some(DataType::StringArray),
            18 => Some(DataType::HrTime),
            19 => Some(DataType::NvList),
            20 => Some(DataType::NvListArray),
            21 => Some(DataType::BooleanValue),
            22 => Some(DataType::Int8),
            23 => Some(DataType::Uint8),
            24 => Some(DataType::BooleanArray),
            25 => Some(DataType::Int8Array),
            26 => Some(DataType::Uint8Array),
            _ => None,
        }
    }

    pub fn to_u8(self) -> u8 {
        match self {
            DataType::Unknown => 0,
            DataType::Boolean => 1,
            DataType::Byte => 2,
            DataType::Int16 => 3,
            DataType::Uint16 => 4,
            DataType::Int32 => 5,
            DataType::Uint32 => 6,
            DataType::Int64 => 7,
            DataType::Uint64 => 8,
            DataType::String => 9,
            DataType::ByteArray => 10,
            DataType::Int16Array => 11,
            DataType::Uint16Array => 12,
            DataType::Int32Array => 13,
            DataType::Uint32Array => 14,
            DataType::Int64Array => 15,
            DataType::Uint64Array => 16,
            DataType::StringArray => 17,
            DataType::HrTime => 18,
            DataType::NvList => 19,
            DataType::NvListArray => 20,
            DataType::BooleanValue => 21,
            DataType::Int8 => 22,
            DataType::Uint8 => 23,
            DataType::BooleanArray => 24,
            DataType::Int8Array => 25,
            DataType::Uint8Array => 26,
        }
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////

pub trait GetNvValue<'a>: Sized {
    fn get(value: &'a NvValue) -> Option<Self>;
}

impl<'a> GetNvValue<'a> for bool {
    fn get(value: &'a NvValue) -> Option<Self> {
        match *value {
            NvValue::BooleanValue(v) => Some(v),
            _ => None,
        }
    }
}

impl<'a> GetNvValue<'a> for u8 {
    fn get(value: &'a NvValue) -> Option<Self> {
        match *value {
            NvValue::Byte(v) => Some(v),
            _ => None,
        }
    }
}

impl<'a> GetNvValue<'a> for u16 {
    fn get(value: &'a NvValue) -> Option<Self> {
        match *value {
            NvValue::Uint16(v) => Some(v),
            _ => None,
        }
    }
}

impl<'a> GetNvValue<'a> for u32 {
    fn get(value: &'a NvValue) -> Option<Self> {
        match *value {
            NvValue::Uint32(v) => Some(v),
            _ => None,
        }
    }
}

impl<'a> GetNvValue<'a> for u64 {
    fn get(value: &'a NvValue) -> Option<Self> {
        match *value {
            NvValue::Uint64(v) => Some(v),
            _ => None,
        }
    }
}

impl<'a> GetNvValue<'a> for i16 {
    fn get(value: &'a NvValue) -> Option<Self> {
        match *value {
            NvValue::Int16(v) => Some(v),
            _ => None,
        }
    }
}

impl<'a> GetNvValue<'a> for i32 {
    fn get(value: &'a NvValue) -> Option<Self> {
        match *value {
            NvValue::Int32(v) => Some(v),
            _ => None,
        }
    }
}

impl<'a> GetNvValue<'a> for i64 {
    fn get(value: &'a NvValue) -> Option<Self> {
        match *value {
            NvValue::Int64(v) => Some(v),
            _ => None,
        }
    }
}

impl<'a> GetNvValue<'a> for &'a NvList {
    fn get(value: &'a NvValue) -> Option<Self> {
        match *value {
            NvValue::NvList(ref v) => Some(v),
            _ => None,
        }
    }
}

impl<'a> GetNvValue<'a> for &'a Vec<NvList> {
    fn get(value: &'a NvValue) -> Option<Self> {
        match *value {
            NvValue::NvListArray(ref v) => Some(v),
            _ => None,
        }
    }
}
<commit_msg>impl GetNvValue for &String<commit_after>use redox::*;

// nvp implementation version
pub const NV_VERSION: i32 = 0;

// nvlist header
//#[derive(Debug)]
pub struct NvList {
    pub version: i32,
    pub nvflag:  u32, // persistent flags
    pub pairs: Vec<(String, NvValue)>,
}

impl NvList {
    pub fn new(nvflag: u32) -> Self {
        NvList {
            version: NV_VERSION,
            nvflag: nvflag,
            pairs: Vec::new(),
        }
    }

    pub fn find(&self, name: &str) -> Option<&NvValue> {
        for pair in &self.pairs {
            if pair.0 == name {
                return Some(&pair.1);
            }
        }
        None
    }

    pub fn find_mut(&mut self, name: &str) -> Option<&mut NvValue> {
        for pair in &mut self.pairs {
            if pair.0 == name {
                return Some(&mut pair.1);
            }
        }
        None
    }

    pub fn get<'a, T: GetNvValue<'a>>(&'a self, name: &str) -> Option<T> {
        self.find(name).and_then(|x| GetNvValue::get(x))
    }
}

impl fmt::Debug for NvList {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f, "NvList {{ version: {:X}, nvflag: {:X}, pairs: [\n", self.version, self.nvflag));
        for &(ref name, ref value) in &self.pairs {
            if name.is_empty() { break; }
            try!(write!(f, "{} : {:?}\n", name, value));
        }
        try!(write!(f, "] }}\n"));
        Ok(())
    }
}

// TODO Auto implement Debug. format! currently crashes with big u32 values
//#[derive(Debug)]
pub enum NvValue {
    Unknown,
    Boolean,
    Byte(u8),
    Int16(i16),
    Uint16(u16),
    Int32(i32),
    Uint32(u32),
    Int64(i64),
    Uint64(u64),
    String(String),
    ByteArray(Vec<u8>),
    Int16Array(Vec<i16>),
    Uint16Array(Vec<u16>),
    Int32Array(Vec<i32>),
    Uint32Array(Vec<u32>),
    Int64Array(Vec<i64>),
    Uint64Array(Vec<u64>),
    StringArray(Vec<String>),
    HrTime(i64),
    NvList(NvList),
    NvListArray(Vec<NvList>),
    BooleanValue(bool),
    Int8(i8),
    Uint8(u8),
    BooleanArray(Vec<bool>),
    Int8Array(Vec<i8>),
    Uint8Array(Vec<u8>),
}

impl NvValue {
    pub fn data_type(&self) -> DataType {
        match *self {
            NvValue::Unknown => DataType::Unknown,
            NvValue::Boolean => DataType::Boolean,
            NvValue::Byte(_) => DataType::Byte,
            NvValue::Int16(_) => DataType::Int16,
            NvValue::Uint16(_) => DataType::Uint16,
            NvValue::Int32(_) => DataType::Int32,
            NvValue::Uint32(_) => DataType::Uint32,
            NvValue::Int64(_) => DataType::Int64,
            NvValue::Uint64(_) => DataType::Uint64,
            NvValue::String(_) => DataType::String,
            NvValue::ByteArray(_) => DataType::ByteArray,
            NvValue::Int16Array(_) => DataType::Int16Array,
            NvValue::Uint16Array(_) => DataType::Uint16Array,
            NvValue::Int32Array(_) => DataType::Int32Array,
            NvValue::Uint32Array(_) => DataType::Uint32Array,
            NvValue::Int64Array(_) => DataType::Int64Array,
            NvValue::Uint64Array(_) => DataType::Uint64Array,
            NvValue::StringArray(_) => DataType::StringArray,
            NvValue::HrTime(_) => DataType::HrTime,
            NvValue::NvList(_) => DataType::NvList,
            NvValue::NvListArray(_) => DataType::NvListArray,
            NvValue::BooleanValue(_) => DataType::BooleanValue,
            NvValue::Int8(_) => DataType::Int8,
            NvValue::Uint8(_) => DataType::Uint8,
            NvValue::BooleanArray(_) => DataType::BooleanArray,
            NvValue::Int8Array(_) => DataType::Int8Array,
            NvValue::Uint8Array(_) => DataType::Uint8Array,
        }
    }

    pub fn num_elements(&self) -> usize {
        match *self {
            NvValue::Unknown => 1,
            NvValue::Boolean => 1,
            NvValue::Byte(_) => 1,
            NvValue::Int16(_) => 1,
            NvValue::Uint16(_) => 1,
            NvValue::Int32(_) => 1,
            NvValue::Uint32(_) => 1,
            NvValue::Int64(_) => 1,
            NvValue::Uint64(_) => 1,
            NvValue::String(_) => 1,
            NvValue::ByteArray(ref a) => a.len(),
            NvValue::Int16Array(ref a) => a.len(),
            NvValue::Uint16Array(ref a) => a.len(),
            NvValue::Int32Array(ref a) => a.len(),
            NvValue::Uint32Array(ref a) => a.len(),
            NvValue::Int64Array(ref a) => a.len(),
            NvValue::Uint64Array(ref a) => a.len(),
            NvValue::StringArray(ref a) => a.len(),
            NvValue::HrTime(_) => 1,
            NvValue::NvList(_) => 1,
            NvValue::NvListArray(ref a) => a.len(),
            NvValue::BooleanValue(_) => 1,
            NvValue::Int8(_) => 1,
            NvValue::Uint8(_) => 1,
            NvValue::BooleanArray(ref a) => a.len(),
            NvValue::Int8Array(ref a) => a.len(),
            NvValue::Uint8Array(ref a) => a.len(),
        }
    }
}

impl fmt::Debug for NvValue {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            NvValue::Int64(v) => write!(f, "Int64(0x{:X})", v),
            NvValue::Uint64(v) => write!(f, "Uint64(0x{:X})", v),
            NvValue::NvList(ref v) => write!(f, "NvList({:?})", v),
            NvValue::NvListArray(ref v) => {
                try!(write!(f, "NvListArray(["));
                for nv_list in v {
                    try!(write!(f, "NvList({:?})", nv_list));
                }
                write!(f, "])")
            },
            NvValue::String(ref v) => { write!(f, "String({})", v) },
            _ => write!(f, "{:?}", self),
        }
    }
}

#[derive(Copy, Clone, Debug)]
pub enum DataType {
    Unknown = 0,
    Boolean,
    Byte,
    Int16,
    Uint16,
    Int32,
    Uint32,
    Int64,
    Uint64,
    String,
    ByteArray,
    Int16Array,
    Uint16Array,
    Int32Array,
    Uint32Array,
    Int64Array,
    Uint64Array,
    StringArray,
    HrTime,
    NvList,
    NvListArray,
    BooleanValue,
    Int8,
    Uint8,
    BooleanArray,
    Int8Array,
    Uint8Array,
}

impl DataType {
    pub fn from_u8(u: u8) -> Option<DataType> {
        match u {
            0 => Some(DataType::Unknown),
            1 => Some(DataType::Boolean),
            2 => Some(DataType::Byte),
            3 => Some(DataType::Int16),
            4 => Some(DataType::Uint16),
            5 => Some(DataType::Int32),
            6 => Some(DataType::Uint32),
            7 => Some(DataType::Int64),
            8 => Some(DataType::Uint64),
            9 => Some(DataType::String),
            10 => Some(DataType::ByteArray),
            11 => Some(DataType::Int16Array),
            12 => Some(DataType::Uint16Array),
            13 => Some(DataType::Int32Array),
            14 => Some(DataType::Uint32Array),
            15 => Some(DataType::Int64Array),
            16 => Some(DataType::Uint64Array),
            17 => Some(DataType::StringArray),
            18 => Some(DataType::HrTime),
            19 => Some(DataType::NvList),
            20 => Some(DataType::NvListArray),
            21 => Some(DataType::BooleanValue),
            22 => Some(DataType::Int8),
            23 => Some(DataType::Uint8),
            24 => Some(DataType::BooleanArray),
            25 => Some(DataType::Int8Array),
            26 => Some(DataType::Uint8Array),
            _ => None,
        }
    }

    pub fn to_u8(self) -> u8 {
        match self {
            DataType::Unknown => 0,
            DataType::Boolean => 1,
            DataType::Byte => 2,
            DataType::Int16 => 3,
            DataType::Uint16 => 4,
            DataType::Int32 => 5,
            DataType::Uint32 => 6,
            DataType::Int64 => 7,
            DataType::Uint64 => 8,
            DataType::String => 9,
            DataType::ByteArray => 10,
            DataType::Int16Array => 11,
            DataType::Uint16Array => 12,
            DataType::Int32Array => 13,
            DataType::Uint32Array => 14,
            DataType::Int64Array => 15,
            DataType::Uint64Array => 16,
            DataType::StringArray => 17,
            DataType::HrTime => 18,
            DataType::NvList => 19,
            DataType::NvListArray => 20,
            DataType::BooleanValue => 21,
            DataType::Int8 => 22,
            DataType::Uint8 => 23,
            DataType::BooleanArray => 24,
            DataType::Int8Array => 25,
            DataType::Uint8Array => 26,
        }
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////

pub trait GetNvValue<'a>: Sized {
    fn get(value: &'a NvValue) -> Option<Self>;
}

impl<'a> GetNvValue<'a> for bool {
    fn get(value: &'a NvValue) -> Option<Self> {
        match *value {
            NvValue::BooleanValue(v) => Some(v),
            _ => None,
        }
    }
}

impl<'a> GetNvValue<'a> for u8 {
    fn get(value: &'a NvValue) -> Option<Self> {
        match *value {
            NvValue::Byte(v) => Some(v),
            _ => None,
        }
    }
}

impl<'a> GetNvValue<'a> for u16 {
    fn get(value: &'a NvValue) -> Option<Self> {
        match *value {
            NvValue::Uint16(v) => Some(v),
            _ => None,
        }
    }
}

impl<'a> GetNvValue<'a> for u32 {
    fn get(value: &'a NvValue) -> Option<Self> {
        match *value {
            NvValue::Uint32(v) => Some(v),
            _ => None,
        }
    }
}

impl<'a> GetNvValue<'a> for u64 {
    fn get(value: &'a NvValue) -> Option<Self> {
        match *value {
            NvValue::Uint64(v) => Some(v),
            _ => None,
        }
    }
}

impl<'a> GetNvValue<'a> for i16 {
    fn get(value: &'a NvValue) -> Option<Self> {
        match *value {
            NvValue::Int16(v) => Some(v),
            _ => None,
        }
    }
}

impl<'a> GetNvValue<'a> for i32 {
    fn get(value: &'a NvValue) -> Option<Self> {
        match *value {
            NvValue::Int32(v) => Some(v),
            _ => None,
        }
    }
}

impl<'a> GetNvValue<'a> for i64 {
    fn get(value: &'a NvValue) -> Option<Self> {
        match *value {
            NvValue::Int64(v) => Some(v),
            _ => None,
        }
    }
}

impl<'a> GetNvValue<'a> for &'a String {
    fn get(value: &'a NvValue) -> Option<Self> {
        match *value {
            NvValue::String(ref v) => Some(v),
            _ => None,
        }
    }
}

impl<'a> GetNvValue<'a> for &'a NvList {
    fn get(value: &'a NvValue) -> Option<Self> {
        match *value {
            NvValue::NvList(ref v) => Some(v),
            _ => None,
        }
    }
}

impl<'a> GetNvValue<'a> for &'a Vec<NvList> {
    fn get(value: &'a NvValue) -> Option<Self> {
        match *value {
            NvValue::NvListArray(ref v) => Some(v),
            _ => None,
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>add text.rs<commit_after>// The MIT License (MIT)

// Copyright (c) 2014 Y. T. CHUNG <zonyitoo@gmail.com>

// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#![allow(dead_code)]

use std::io::{BufRead, Read, Write, Cursor, BufReader};
use std::str;
use std::fmt;

use proto::{Operation, MemCachedResult};
use proto;

// Storage commands
const OP_SET: &'static str = "set";
const OP_ADD: &'static str = "add";
const OP_REPLACE: &'static str = "replace";
const OP_APPEND: &'static str = "append";
const OP_PREPEND: &'static str = "prepend";
const OP_CAS: &'static str = "cas";
const OP_DELETE: &'static str = "delete";
const OP_INCR: &'static str = "incr";
const OP_DECR: &'static str = "decr";
const OP_TOUCH: &'static str = "touch";
const OP_STATS: &'static str = "stats";
const OP_VERSION: &'static str = "version";
const OP_FLUSH_ALL: &'static str = "flush_all";
const OP_QUIT: &'static str = "quit";

// Retrival commands
const OP_GET: &'static str = "get";
const OP_GETS: &'static str = "gets";

const REPLY_ERROR: &'static str = "ERROR";
const REPLY_CLIENT_ERROR: &'static str = "CLIENT_ERROR";
const REPLY_SERVER_ERROR: &'static str = "SERVER_ERROR";

const REPLY_STORED: &'static str = "STORED";
const REPLY_NOT_STORED: &'static str = "NOT_STORED";
const REPLY_EXISTS: &'static str = "EXISTS";
const REPLY_NOT_FOUND: &'static str = "NOT_FOUND";
const REPLY_END: &'static str = "END";
const REPLY_VALUE: &'static str = "VALUE";
const REPLY_DELETED: &'static str = "DELETED";
const REPLY_TOUCHED: &'static str = "TOUCHED";
const REPLY_OK: &'static str = "OK";

#[derive(Debug, Clone)]
pub enum Reply {
    Error,
    ClientError(String),
    ServerError(String),

    NotStored,
    Exists,
    NotFound,
}

impl Reply {
    pub fn desc(&self) -> &'static str {
        match self {
            &Reply::Error => "error",
            &Reply::ClientError(..) => "client error",
            &Reply::ServerError(..) => "server error",

            &Reply::NotStored => "not stored",
            &Reply::Exists => "exists",
            &Reply::NotFound => "not found",
        }
    }
}

impl fmt::Display for Reply {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Reply::Error => write!(f, "error"),
            &Reply::ClientError(ref e) => write!(f, "client error: {}", e),
            &Reply::ServerError(ref e) => write!(f, "server error: {}", e),

            &Reply::NotStored => write!(f, "not stored"),
            &Reply::Exists => write!(f, "exists"),
            &Reply::NotFound => write!(f, "not found"),
        }
    }
}

#[derive(Debug)]
pub enum CommandType {
    Set,
    Add,
    Replace,
    Append,
    Prepend,
    Cas,
    Get,
    Gets,
}

pub struct TextProto<S: BufRead + Write + Send> {
    pub stream: S,
}

impl<S: BufRead + Write + Send> TextProto<S> {
    pub fn new(stream: S) -> TextProto<S> {
        TextProto {
            stream: stream,
        }
    }
}

impl<S: BufRead + Write + Send> Operation for TextProto<S> {
    fn set(&mut self, key: &[u8], value: &[u8], flags: u32, expiration: u32) -> MemCachedResult<()> {
        let strkey = match str::from_utf8(key) {
            Ok(s) => s,
            Err(..) => return Err(proto::Error::OtherError{
                desc: "Key has to be a valid utf-8 string",
                detail: None
            }),
        };
        let cmd = format!("{} {} {} {} {}\r\n", OP_SET, strkey, flags, expiration, value.len());
        try!(self.stream.write_all(cmd.as_bytes()));
        try!(self.stream.write(value));
        try!(self.stream.write(b"\r\n"));
        try!(self.stream.flush());

        let mut resp = String::new();
        try!(self.stream.read_line(&mut resp));
        let resp_str = resp.trim_right();

        let mut splitted = resp_str.split(' ');
        match (splitted.next(), splitted.next()) {
            (Some(REPLY_STORED), None) => {
                Ok(())
            },
            (Some(REPLY_NOT_STORED), None) => {
                Err(proto::Error::TextProtoError(Reply::NotStored))
            },
            (Some(REPLY_ERROR), None) => {
                Err(proto::Error::TextProtoError(Reply::Error))
            },
            (Some(REPLY_CLIENT_ERROR), Some(error)) => {
                return Err(proto::Error::TextProtoError(Reply::ClientError(error.to_owned())));
            },
            (Some(REPLY_SERVER_ERROR), Some(error)) => {
                return Err(proto::Error::TextProtoError(Reply::ServerError(error.to_owned())));
            },
            _ => {
                Err(proto::Error::OtherError {
                    desc: "Unknown reply",
                    detail: Some(resp_str.to_string())
                })
            }
        }
    }

    fn add(&mut self, key: &[u8], value: &[u8], flags: u32, expiration: u32) -> MemCachedResult<()> {
        let strkey = match str::from_utf8(key) {
            Ok(s) => s,
            Err(..) => return Err(proto::Error::OtherError{
                desc: "Key has to be a valid utf-8 string",
                detail: None
            }),
        };
        let cmd = format!("{} {} {} {} {}\r\n", OP_ADD, strkey, flags, expiration, value.len());
        try!(self.stream.write_all(cmd.as_bytes()));
        try!(self.stream.write(value));
        try!(self.stream.write(b"\r\n"));
        try!(self.stream.flush());

        let mut resp = String::new();
        try!(self.stream.read_line(&mut resp));
        let resp_str = resp.trim_right();

        let mut splitted = resp_str.split(' ');
        match (splitted.next(), splitted.next()) {
            (Some(REPLY_STORED), None) => {
                Ok(())
            },
            (Some(REPLY_NOT_STORED), None) => {
                Err(proto::Error::TextProtoError(Reply::NotStored))
            },
            (Some(REPLY_ERROR), None) => {
                Err(proto::Error::TextProtoError(Reply::Error))
            },
            (Some(REPLY_CLIENT_ERROR), Some(error)) => {
                return Err(proto::Error::TextProtoError(Reply::ClientError(error.to_owned())));
            },
            (Some(REPLY_SERVER_ERROR), Some(error)) => {
                return Err(proto::Error::TextProtoError(Reply::ServerError(error.to_owned())));
            },
            _ => {
                Err(proto::Error::OtherError {
                    desc: "Unknown reply",
                    detail: Some(resp_str.to_string())
                })
            }
        }
    }

    fn delete(&mut self, key: &[u8]) -> MemCachedResult<()> {
        let strkey = match str::from_utf8(key) {
            Ok(s) => s,
            Err(..) => return Err(proto::Error::OtherError{
                desc: "Key has to be a valid utf-8 string",
                detail: None
            }),
        };

        let cmd = format!("{} {}\r\n", OP_DELETE, strkey);
        try!(self.stream.write_all(cmd.as_bytes()));
        try!(self.stream.flush());

        let mut resp = String::new();
        try!(self.stream.read_line(&mut resp));
        let resp_str = resp.trim_right();

        let mut splitted = resp_str.split(' ');
        match (splitted.next(), splitted.next()) {
            (Some(REPLY_DELETED), None) => {
                Ok(())
            },
            (Some(REPLY_NOT_FOUND), None) => {
                Err(proto::Error::TextProtoError(Reply::NotFound))
            },
            (Some(REPLY_ERROR), None) => {
                Err(proto::Error::TextProtoError(Reply::Error))
            },
            (Some(REPLY_CLIENT_ERROR), Some(error)) => {
                return Err(proto::Error::TextProtoError(Reply::ClientError(error.to_owned())));
            },
            (Some(REPLY_SERVER_ERROR), Some(error)) => {
                return Err(proto::Error::TextProtoError(Reply::ServerError(error.to_owned())));
            },
            _ => {
                Err(proto::Error::OtherError {
                    desc: "Unknown reply",
                    detail: Some(resp_str.to_string())
                })
            }
        }
    }

    fn replace(&mut self, key: &[u8], value: &[u8], flags: u32, expiration: u32) -> MemCachedResult<()> {
        let strkey = match str::from_utf8(key) {
            Ok(s) => s,
            Err(..) => return Err(proto::Error::OtherError{
                desc: "Key has to be a valid utf-8 string",
                detail: None
            }),
        };
        let cmd = format!("{} {} {} {} {}\r\n", OP_REPLACE, strkey, flags, expiration, value.len());
        try!(self.stream.write_all(cmd.as_bytes()));
        try!(self.stream.write(value));
        try!(self.stream.write(b"\r\n"));
        try!(self.stream.flush());

        let mut resp = String::new();
        try!(self.stream.read_line(&mut resp));
        let resp_str = resp.trim_right();

        let mut splitted = resp_str.split(' ');
        match (splitted.next(), splitted.next()) {
            (Some(REPLY_STORED), None) => {
                Ok(())
            },
            (Some(REPLY_NOT_STORED), None) => {
                Err(proto::Error::TextProtoError(Reply::NotStored))
            },
            (Some(REPLY_ERROR), None) => {
                Err(proto::Error::TextProtoError(Reply::Error))
            },
            (Some(REPLY_CLIENT_ERROR), Some(error)) => {
                return Err(proto::Error::TextProtoError(Reply::ClientError(error.to_owned())));
            },
            (Some(REPLY_SERVER_ERROR), Some(error)) => {
                return Err(proto::Error::TextProtoError(Reply::ServerError(error.to_owned())));
            },
            _ => {
                Err(proto::Error::OtherError {
                    desc: "Unknown reply",
                    detail: Some(resp_str.to_string())
                })
            }
        }
    }

    fn get(&mut self, key: &[u8]) -> MemCachedResult<(Vec<u8>, u32)> {
        let strkey = match str::from_utf8(key) {
            Ok(s) => s,
            Err(..) => return Err(proto::Error::OtherError {
                desc: "Key has to be a valid utf-8 string",
                detail: None
            }),
        };
        let cmd = format!("{} {}\r\n", OP_GET, strkey);
        try!(self.stream.write_all(cmd.as_bytes()));
        try!(self.stream.flush());

        let mut resp = String::new();
        let (_key, flag, val_len) = {
            try!(self.stream.read_line(&mut resp));
            println!("RESP: {:?}", resp);

            let mut splitted = resp.trim_right().split(' ');
            match (splitted.next(), splitted.next(), splitted.next(), splitted.next()) {
                (Some(REPLY_VALUE), Some(key), Some(flag), Some(val_len)) => {
                    let flag = match flag.parse::<i32>() {
                        Ok(f) => f as u32,
                        Err(err) => return Err(proto::Error::OtherError {
                            desc: "Invalid flag",
                            detail: Some(err.to_string()),
                        }),
                    };

                    if val_len.len() == 0 {
                        return Err(proto::Error::OtherError {
                            desc: "Invalid value length",
                            detail: None,
                        });
                    }

                    let val_len = match val_len.parse::<u64>() {
                        Ok(vl) => vl,
                        Err(err) => return Err(proto::Error::OtherError {
                            desc: "Invalid value length",
                            detail: Some(err.to_string()),
                        }),
                    };

                    (key, flag, val_len)
                },
                (Some(REPLY_ERROR), _, _, _) => {
                    return Err(proto::Error::TextProtoError(Reply::Error));
                },
                (Some(REPLY_CLIENT_ERROR), Some(error), _, _) => {
                    return Err(proto::Error::TextProtoError(Reply::ClientError(error.to_owned())));
                },
                (Some(REPLY_SERVER_ERROR), Some(error), _, _) => {
                    return Err(proto::Error::TextProtoError(Reply::ServerError(error.to_owned())));
                },
                _ => {
                    return Err(proto::Error::OtherError {
                        desc: "Invalid Response",
                        detail: Some(resp.clone()),
                    });
                }
            }
        };

        let mut val = Vec::new();
        try!((&mut self.stream).take(val_len).read_to_end(&mut val));
        for _ in (&mut self.stream).take(2).bytes() {} // consumes \r\n

        let mut end = String::new();
        try!(self.stream.read_line(&mut end));
        let end = end.trim_right();

        if end.len() == 0 {
            return Err(proto::Error::OtherError {
                desc: "Invalid Response",
                detail: Some(end.to_owned()),
            });
        }

        match end {
            REPLY_END => Ok((val, flag)),
            _ => Err(proto::Error::OtherError {
                desc: "Invalid Response",
                detail: Some(end.to_owned()),
            })
        }
    }

    fn getk(&mut self, _key: &[u8]) -> MemCachedResult<(Vec<u8>, Vec<u8>, u32)> {
        panic!("TextProto does not support GetK command");
    }

    fn increment(&mut self, key: &[u8], amount: u64, _initial: u64, _expiration: u32) -> MemCachedResult<u64> {
        let strkey = match str::from_utf8(key) {
            Ok(s) => s,
            Err(..) => return Err(proto::Error::OtherError{
                desc: "Key has to be a valid utf-8 string",
                detail: None
            }),
        };
        let cmd = format!("{} {} {}\r\n", OP_INCR, strkey, amount);
        try!(self.stream.write_all(cmd.as_bytes()));
        try!(self.stream.flush());

        let mut resp = String::new();
        try!(self.stream.read_line(&mut resp));
        let resp_str = resp.trim_right();

        let mut splitted = resp_str.split(' ');
        match (splitted.next(), splitted.next()) {
            (Some(REPLY_NOT_STORED), None) => {
                Err(proto::Error::TextProtoError(Reply::NotStored))
            },
            (Some(REPLY_ERROR), None) => {
                Err(proto::Error::TextProtoError(Reply::Error))
            },
            (Some(REPLY_CLIENT_ERROR), Some(error)) => {
                return Err(proto::Error::TextProtoError(Reply::ClientError(error.to_owned())));
            },
            (Some(REPLY_SERVER_ERROR), Some(error)) => {
                return Err(proto::Error::TextProtoError(Reply::ServerError(error.to_owned())));
            },
            (Some(value), None) => {
                match value.parse::<u64>() {
                    Ok(val) => Ok(val),
                    Err(err) => return Err(proto::Error::OtherError {
                        desc: "Invalid value",
                        detail: Some(err.to_string()),
                    }),
                }
            },
            _ => {
                Err(proto::Error::OtherError {
                    desc: "Unknown reply",
                    detail: Some(resp_str.to_string())
                })
            }
        }
    }

    fn decrement(&mut self, key: &[u8], amount: u64, _initial: u64, _expiration: u32) -> MemCachedResult<u64> {
        let strkey = match str::from_utf8(key) {
            Ok(s) => s,
            Err(..) => return Err(proto::Error::OtherError{
                desc: "Key has to be a valid utf-8 string",
                detail: None
            }),
        };
        let cmd = format!("{} {} {}\r\n", OP_DECR, strkey, amount);
        try!(self.stream.write_all(cmd.as_bytes()));
        try!(self.stream.flush());

        let mut resp = String::new();
        try!(self.stream.read_line(&mut resp));
        let resp_str = resp.trim_right();

        let mut splitted = resp_str.split(' ');
        match (splitted.next(), splitted.next()) {
            (Some(REPLY_NOT_STORED), None) => {
                Err(proto::Error::TextProtoError(Reply::NotStored))
            },
            (Some(REPLY_ERROR), None) => {
                Err(proto::Error::TextProtoError(Reply::Error))
            },
            (Some(REPLY_CLIENT_ERROR), Some(error)) => {
                return Err(proto::Error::TextProtoError(Reply::ClientError(error.to_owned())));
            },
            (Some(REPLY_SERVER_ERROR), Some(error)) => {
                return Err(proto::Error::TextProtoError(Reply::ServerError(error.to_owned())));
            },
            (Some(value), None) => {
                match value.parse::<u64>() {
                    Ok(val) => Ok(val),
                    Err(err) => return Err(proto::Error::OtherError {
                        desc: "Invalid value",
                        detail: Some(err.to_string()),
                    }),
                }
            },
            _ => {
                Err(proto::Error::OtherError {
                    desc: "Unknown reply",
                    detail: Some(resp_str.to_string())
                })
            }
        }
    }

    fn append(&mut self, key: &[u8], value: &[u8]) -> MemCachedResult<()> {
        let strkey = match str::from_utf8(key) {
            Ok(s) => s,
            Err(..) => return Err(proto::Error::OtherError{
                desc: "Key has to be a valid utf-8 string",
                detail: None
            }),
        };
        let cmd = format!("{} {}\r\n", OP_APPEND, strkey);
        try!(self.stream.write_all(cmd.as_bytes()));
        try!(self.stream.write(value));
        try!(self.stream.write(b"\r\n"));
        try!(self.stream.flush());

        let mut resp = String::new();
        try!(self.stream.read_line(&mut resp));
        let resp_str = resp.trim_right();

        let mut splitted = resp_str.split(' ');
        match (splitted.next(), splitted.next()) {
            (Some(REPLY_STORED), None) => {
                Ok(())
            },
            (Some(REPLY_NOT_STORED), None) => {
                Err(proto::Error::TextProtoError(Reply::NotStored))
            },
            (Some(REPLY_ERROR), None) => {
                Err(proto::Error::TextProtoError(Reply::Error))
            },
            (Some(REPLY_CLIENT_ERROR), Some(error)) => {
                return Err(proto::Error::TextProtoError(Reply::ClientError(error.to_owned())));
            },
            (Some(REPLY_SERVER_ERROR), Some(error)) => {
                return Err(proto::Error::TextProtoError(Reply::ServerError(error.to_owned())));
            },
            _ => {
                Err(proto::Error::OtherError {
                    desc: "Unknown reply",
                    detail: Some(resp_str.to_string())
                })
            }
        }
    }

    fn prepend(&mut self, key: &[u8], value: &[u8]) -> MemCachedResult<()> {
        let strkey = match str::from_utf8(key) {
            Ok(s) => s,
            Err(..) => return Err(proto::Error::OtherError{
                desc: "Key has to be a valid utf-8 string",
                detail: None
            }),
        };
        let cmd = format!("{} {}\r\n", OP_PREPEND, strkey);
        try!(self.stream.write_all(cmd.as_bytes()));
        try!(self.stream.write(value));
        try!(self.stream.write(b"\r\n"));
        try!(self.stream.flush());

        let mut resp = String::new();
        try!(self.stream.read_line(&mut resp));
        let resp_str = resp.trim_right();

        let mut splitted = resp_str.split(' ');
        match (splitted.next(), splitted.next()) {
            (Some(REPLY_STORED), None) => {
                Ok(())
            },
            (Some(REPLY_NOT_STORED), None) => {
                Err(proto::Error::TextProtoError(Reply::NotStored))
            },
            (Some(REPLY_ERROR), None) => {
                Err(proto::Error::TextProtoError(Reply::Error))
            },
            (Some(REPLY_CLIENT_ERROR), Some(error)) => {
                return Err(proto::Error::TextProtoError(Reply::ClientError(error.to_owned())));
            },
            (Some(REPLY_SERVER_ERROR), Some(error)) => {
                return Err(proto::Error::TextProtoError(Reply::ServerError(error.to_owned())));
            },
            _ => {
                Err(proto::Error::OtherError {
                    desc: "Unknown reply",
                    detail: Some(resp_str.to_string())
                })
            }
        }
    }

    fn touch(&mut self, key: &[u8], expiration: u32) -> MemCachedResult<()> {
        let strkey = match str::from_utf8(key) {
            Ok(s) => s,
            Err(..) => return Err(proto::Error::OtherError{
                desc: "Key has to be a valid utf-8 string",
                detail: None
            }),
        };
        let cmd = format!("{} {} {}\r\n", OP_TOUCH, strkey, expiration);
        try!(self.stream.write_all(cmd.as_bytes()));
        try!(self.stream.flush());

        let mut resp = String::new();
        try!(self.stream.read_line(&mut resp));
        let resp_str = resp.trim_right();

        let mut splitted = resp_str.split(' ');
        match (splitted.next(), splitted.next()) {
            (Some(REPLY_TOUCHED), None) => {
                Ok(())
            },
            (Some(REPLY_NOT_FOUND), None) => {
                Err(proto::Error::TextProtoError(Reply::NotFound))
            },
            (Some(REPLY_ERROR), None) => {
                Err(proto::Error::TextProtoError(Reply::Error))
            },
            (Some(REPLY_CLIENT_ERROR), Some(error)) => {
                return Err(proto::Error::TextProtoError(Reply::ClientError(error.to_owned())));
            },
            (Some(REPLY_SERVER_ERROR), Some(error)) => {
                return Err(proto::Error::TextProtoError(Reply::ServerError(error.to_owned())));
            },
            _ => {
                Err(proto::Error::OtherError {
                    desc: "Unknown reply",
                    detail: Some(resp_str.to_string())
                })
            }
        }
    }
}

#[cfg(test)]
mod test {
    use std::net::TcpStream;
    use std::io::BufStream;
    use proto::text::TextProto;
    use proto::{Operation};

    const SERVER_ADDR: &'static str = "127.0.0.1:11211";

    fn get_client() -> TextProto<BufStream<TcpStream>> {
        let stream = TcpStream::connect(SERVER_ADDR).unwrap();
        TextProto::new(BufStream::new(stream))
    }

    #[test]
    fn test_set_get_delete() {
        let key = b"test:test_text";
        let val = b"val";

        let mut client = get_client();
        let set_resp = client.set(key, val, 0xdead, 200);
        assert!(set_resp.is_ok());

        let (get_val, flag) = client.get(key).unwrap();
        assert_eq!(flag, 0xdead);
        assert_eq!(&get_val[..], val);

        client.delete(key).unwrap();
    }

    #[test]
    fn test_add() {
        let key = b"test:test_add";
        let val = b"val";

        let mut client = get_client();
        client.add(key, val, 0xdead, 20).unwrap();

        let (get_val, flag) = client.get(key).unwrap();
        assert_eq!(flag, 0xdead);
        assert_eq!(&get_val[..], val);

        client.delete(key).unwrap();
    }

    #[test]
    fn test_replace() {
        let key = b"test:test_replace";
        let val = b"val";
        let replaced = b"replaced";

        let mut client = get_client();
        client.add(key, val, 0xdead, 20).unwrap();
        client.replace(key, replaced, 0xdeadbeef, 20).unwrap();

        let (get_val, flag) = client.get(key).unwrap();
        assert_eq!(flag, 0xdeadbeef);
        assert_eq!(&get_val[..], replaced);

        client.delete(key).unwrap();
    }
}
<|endoftext|>


<commit_before>//! HTTP Server
use std::io::{Listener, IoResult, EndOfFile};
use std::io::net::ip::{IpAddr, Port, SocketAddr};

use intertwine::{Intertwine, Intertwined};
use macceptor::MoveAcceptor;

pub use self::request::Request;
pub use self::response::Response;

use {HttpResult};
use net::{NetworkListener, NetworkAcceptor, NetworkStream,
          HttpAcceptor, HttpListener, HttpStream,
          Fresh};

pub mod request;
pub mod response;

/// A server can listen on a TCP socket.
///
/// Once listening, it will create a `Request`/`Response` pair for each
/// incoming connection, and hand them to the provided handler.
pub struct Server<L = HttpListener> {
    pairs: Vec<(IpAddr, Port)>
}

macro_rules! try_option(
    ($e:expr) => {{
        match $e {
            Some(v) => v,
            None => return None
        }
    }}
)

impl Server<HttpListener> {
    /// Creates a new server that will handle `HttpStream`s.
    pub fn http(ip: IpAddr, port: Port) -> Server {
        Server { pairs: vec![(ip, port)] }
    }

    /// Creates a server that can listen to many (ip, port) pairs.
    pub fn many(pairs: Vec<(IpAddr, Port)>) -> Server {
        Server { pairs: pairs }
    }
}

impl<L: NetworkListener<S, A>, S: NetworkStream, A: NetworkAcceptor<S>> Server<L> {
    /// Binds to a socket, and starts handling connections.
    ///
    /// This method has unbound type parameters, so can be used when you want to use
    /// something other than the provided HttpStream, HttpAcceptor, and HttpListener.
    pub fn listen_network<H, S, A, L>(self, handler: H) -> HttpResult<Listening<A>>
    where H: Handler<A, S>,
          S: NetworkStream,
          A: NetworkAcceptor<S>,
          L: NetworkListener<S, A>, {
        let mut acceptors = Vec::new();
        let mut sockets = Vec::new();
        for (ip, port) in self.pairs.move_iter() {
            let mut listener: L = try_io!(NetworkListener::<S, A>::bind(ip.to_string().as_slice(), port));

            sockets.push(try_io!(listener.socket_name()));

            let acceptor = try_io!(listener.listen());
            acceptors.push(acceptor.clone());
        }

        let connections = acceptors.clone()
            .move_iter()
            .map(|acceptor| acceptor.move_incoming())
            .intertwine();

        spawn(proc() {
            handler.handle(Incoming { from: connections });
        });

        Ok(Listening {
            acceptors: acceptors,
            sockets: sockets,
        })
    }

    /// Binds to a socket and starts handling connections.
    pub fn listen<H: Handler<HttpAcceptor, HttpStream>>(self, handler: H) -> HttpResult<Listening<HttpAcceptor>> {
        self.listen_network::<H, HttpStream, HttpAcceptor, HttpListener>(handler)
    }
}

/// An iterator over incoming connections, represented as pairs of
/// hyper Requests and Responses.
pub struct Incoming<S: Send = HttpStream> {
    from: Intertwined<IoResult<S>>
}

impl<S: NetworkStream + 'static> Iterator<(Request, Response<Fresh>)> for Incoming<S> {
    fn next(&mut self) -> Option<(Request, Response<Fresh>)> {
        for conn in self.from {
            match conn {
                Ok(stream) => {
                    debug!("Incoming stream");
                    let clone = stream.clone();
                    let req = match Request::new(stream) {
                        Ok(r) => r,
                        Err(err) => {
                            error!("creating Request: {}", err);
                            continue;
                        }
                    };
                    let mut res = Response::new(clone);
                    res.version = req.version;
                    return Some((req, res))
                },
                Err(ref e) if e.kind == EndOfFile => return None, // server closed
                Err(e) => {
                    error!("Connection failed: {}", e);
                    continue;
                }
            }
        }
        None
    }
}

/// A listening server, which can later be closed.
pub struct Listening<A = HttpAcceptor> {
    acceptors: Vec<A>,
    /// The socket addresses that the server is bound to.
    pub sockets: Vec<SocketAddr>,
}

impl<A: NetworkAcceptor<S>, S: NetworkStream> Listening<A> {
    /// Stop the server from listening to all of its socket addresses.
    ///
    /// If closing any of the servers acceptors fails, this function returns Err
    /// and does not close the rest of the acceptors.
    pub fn close(&mut self) -> HttpResult<()> {
        debug!("closing server");
        for acceptor in self.acceptors.mut_iter() {
            try_io!(acceptor.close());
        }
        Ok(())
    }
}

/// A handler that can handle incoming requests for a server.
pub trait Handler<A: NetworkAcceptor<S>, S: NetworkStream>: Send {
    /// Receives a `Request`/`Response` pair, and should perform some action on them.
    ///
    /// This could reading from the request, and writing to the response.
    fn handle(self, Incoming<S>);
}

impl<A: NetworkAcceptor<S>, S: NetworkStream> Handler<A, S> for fn(Incoming<S>) {
    fn handle(self, incoming: Incoming<S>) {
        (self)(incoming)
    }
}

<commit_msg>update deprecated syntax<commit_after>//! HTTP Server
use std::io::{Listener, IoResult, EndOfFile};
use std::io::net::ip::{IpAddr, Port, SocketAddr};

use intertwine::{Intertwine, Intertwined};
use macceptor::MoveAcceptor;

pub use self::request::Request;
pub use self::response::Response;

use {HttpResult};
use net::{NetworkListener, NetworkAcceptor, NetworkStream,
          HttpAcceptor, HttpListener, HttpStream,
          Fresh};

pub mod request;
pub mod response;

/// A server can listen on a TCP socket.
///
/// Once listening, it will create a `Request`/`Response` pair for each
/// incoming connection, and hand them to the provided handler.
pub struct Server<L = HttpListener> {
    pairs: Vec<(IpAddr, Port)>
}

macro_rules! try_option(
    ($e:expr) => {{
        match $e {
            Some(v) => v,
            None => return None
        }
    }}
)

impl Server<HttpListener> {
    /// Creates a new server that will handle `HttpStream`s.
    pub fn http(ip: IpAddr, port: Port) -> Server {
        Server { pairs: vec![(ip, port)] }
    }

    /// Creates a server that can listen to many (ip, port) pairs.
    pub fn many(pairs: Vec<(IpAddr, Port)>) -> Server {
        Server { pairs: pairs }
    }
}

impl<L: NetworkListener<S, A>, S: NetworkStream, A: NetworkAcceptor<S>> Server<L> {
    /// Binds to a socket, and starts handling connections.
    ///
    /// This method has unbound type parameters, so can be used when you want to use
    /// something other than the provided HttpStream, HttpAcceptor, and HttpListener.
    pub fn listen_network<H, S, A, L>(self, handler: H) -> HttpResult<Listening<A>>
    where H: Handler<A, S>,
          S: NetworkStream,
          A: NetworkAcceptor<S>,
          L: NetworkListener<S, A>, {
        let mut acceptors = Vec::new();
        let mut sockets = Vec::new();
        for (ip, port) in self.pairs.into_iter() {
            let mut listener: L = try_io!(NetworkListener::<S, A>::bind(ip.to_string().as_slice(), port));

            sockets.push(try_io!(listener.socket_name()));

            let acceptor = try_io!(listener.listen());
            acceptors.push(acceptor.clone());
        }

        let connections = acceptors.clone()
            .into_iter()
            .map(|acceptor| acceptor.move_incoming())
            .intertwine();

        spawn(proc() {
            handler.handle(Incoming { from: connections });
        });

        Ok(Listening {
            acceptors: acceptors,
            sockets: sockets,
        })
    }

    /// Binds to a socket and starts handling connections.
    pub fn listen<H: Handler<HttpAcceptor, HttpStream>>(self, handler: H) -> HttpResult<Listening<HttpAcceptor>> {
        self.listen_network::<H, HttpStream, HttpAcceptor, HttpListener>(handler)
    }
}

/// An iterator over incoming connections, represented as pairs of
/// hyper Requests and Responses.
pub struct Incoming<S: Send = HttpStream> {
    from: Intertwined<IoResult<S>>
}

impl<S: NetworkStream + 'static> Iterator<(Request, Response<Fresh>)> for Incoming<S> {
    fn next(&mut self) -> Option<(Request, Response<Fresh>)> {
        for conn in self.from {
            match conn {
                Ok(stream) => {
                    debug!("Incoming stream");
                    let clone = stream.clone();
                    let req = match Request::new(stream) {
                        Ok(r) => r,
                        Err(err) => {
                            error!("creating Request: {}", err);
                            continue;
                        }
                    };
                    let mut res = Response::new(clone);
                    res.version = req.version;
                    return Some((req, res))
                },
                Err(ref e) if e.kind == EndOfFile => return None, // server closed
                Err(e) => {
                    error!("Connection failed: {}", e);
                    continue;
                }
            }
        }
        None
    }
}

/// A listening server, which can later be closed.
pub struct Listening<A = HttpAcceptor> {
    acceptors: Vec<A>,
    /// The socket addresses that the server is bound to.
    pub sockets: Vec<SocketAddr>,
}

impl<A: NetworkAcceptor<S>, S: NetworkStream> Listening<A> {
    /// Stop the server from listening to all of its socket addresses.
    ///
    /// If closing any of the servers acceptors fails, this function returns Err
    /// and does not close the rest of the acceptors.
    pub fn close(&mut self) -> HttpResult<()> {
        debug!("closing server");
        for acceptor in self.acceptors.iter_mut() {
            try_io!(acceptor.close());
        }
        Ok(())
    }
}

/// A handler that can handle incoming requests for a server.
pub trait Handler<A: NetworkAcceptor<S>, S: NetworkStream>: Send {
    /// Receives a `Request`/`Response` pair, and should perform some action on them.
    ///
    /// This could reading from the request, and writing to the response.
    fn handle(self, Incoming<S>);
}

impl<A: NetworkAcceptor<S>, S: NetworkStream> Handler<A, S> for fn(Incoming<S>) {
    fn handle(self, incoming: Incoming<S>) {
        (self)(incoming)
    }
}

<|endoftext|>


<commit_before><commit_msg>Implemented BubbleSort in Rust<commit_after><|endoftext|>


<commit_before><commit_msg>A join based parallel version<commit_after><|endoftext|>


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

// ignore-android: FIXME(#10381)

// compile-flags:-g
// debugger:break issue12886.rs:29
// debugger:run
// debugger:next
// check:[...]30[...]s
// debugger:continue

// IF YOU MODIFY THIS FILE, BE CAREFUL TO ADAPT THE LINE NUMBERS IN THE DEBUGGER COMMANDS

// This test makes sure that gdb does not set unwanted breakpoints in inlined functions. If a
// breakpoint existed in unwrap(), then calling `next` would (when stopped at line 27) would stop
// in unwrap() instead of stepping over the function invocation. By making sure that `s` is
// contained in the output, after calling `next` just once, we can be sure that we did not stop in
// unwrap(). (The testing framework doesn't allow for checking that some text is *not* contained in
// the output, which is why we have to make the test in this kind of roundabout way)
fn bar() -> int {
    let s = Some(5).unwrap();
    s
}

fn main() {
    let _ = bar();
}
<|endoftext|>


<commit_before>// error-pattern: mismatched types

fn f(int x) {
}

fn main() {
  let () i;
  i = f();
}
<commit_msg>rustc: Fix error pattern in compile-fail/arg-count-mismatch.rs<commit_after>// error-pattern: parameters were supplied

fn f(int x) {
}

fn main() {
  let () i;
  i = f();
}
<|endoftext|>


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

// ignore-test

pub fn main() {
    match 22i {
        0 .. 3 => {} //~ ERROR expected `=>`, found `..`
        _ => {}
    }
}
<commit_msg>Enable a test for .. in range patterns.<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

pub fn main() {
    match 22i {
        0 .. 3 => {} //~ ERROR expected `=>`, found `..`
        _ => {}
    }
}
<|endoftext|>


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

// Regression test for #20582. This test caused an ICE related to
// inconsistent region erasure in trans.

struct Foo<'a> {
    buf: &'a[u8]
}

impl<'a> Iterator for Foo<'a> {
    type Item = &'a[u8];

    fn next(&mut self) -> Option<<Self as Iterator>::Item> {
        Some(self.buf)
    }
}

fn main() {
}
<|endoftext|>


<commit_before><commit_msg>Optimize: Do not attempt to print if output is a pipe<commit_after><|endoftext|>


<commit_before><commit_msg>Refactor imag-diary<commit_after><|endoftext|>


<commit_before><commit_msg>that's not in stable<commit_after><|endoftext|>


<commit_before><commit_msg>build.rs script<commit_after>use std::env;
use std::fs::File;
use std::io::Write;
use std::path::Path;
use std::process::Command;

fn tags() -> String {
    let output = Command::new("git").args(&["describe", "--abbrev=0"]).output().expect("Failed to execute git describe");
    String::from_utf8_lossy(&output.stdout).trim().to_string()
}

fn branch() -> String {
    let output = Command::new("git").args(&["rev-parse", "--abbrev-ref", "HEAD"]).output().expect("Failed to execute git rev-parse");
    String::from_utf8_lossy(&output.stdout).trim().to_string()
}

fn date() -> String {
    let output = Command::new("date").output().expect("Failed to execute date");
    String::from_utf8_lossy(&output.stdout).trim().to_string()
}

fn commit_sha() -> String {
    let output = Command::new("git").args(&["rev-parse", "HEAD"]).output().expect("Failed to execute git rev-parse");
    String::from_utf8_lossy(&output.stdout).trim().to_string()
}

fn local_changes() -> bool {
    let output = Command::new("git").args(&["diff", "--exit-code"]).output().expect("Failed to execute git diff");
    !output.status.success()
}

fn kernel_version() -> String {
    let output = Command::new("uname").arg("-r").output().expect("Failed to execute uname");
    String::from_utf8_lossy(&output.stdout).trim().to_string()
}

fn main() {
    let version = env!("CARGO_PKG_VERSION");
    let tag = tags();
    let tag_message = if !tag.is_empty() { format!("Tag: {}\n", tag) } else { String::new() };
    let mut change_message = "";

    if local_changes() {
        change_message = " with local changes";
    }

    let version_info = format!("RustyVisor Version: {}\nCommit: {}{}\n{}Branch: {}\nBuilt on: {}\nKernel version: {}", version, commit_sha(), change_message, tag_message, branch(), date(), kernel_version());

    let version_code = format!("const VERSION: &'static str = \"{}\";", version_info);

    let out_dir = env::var("OUT_DIR").unwrap();
    let dest_path = Path::new(&out_dir).join("version.rs");
    let mut f = File::create(&dest_path).unwrap();

    f.write_all(version_code.as_bytes()).unwrap();
}
<|endoftext|>


<commit_before><commit_msg>Zip integration tests<commit_after>// Copyright 2017 The Grin Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate  grin_util as util;

use std::fs::{self, File};
use std::path::Path;
use std::io::{self, Write};
use util::zip;

#[test]
fn zip_unzip() {
	let root = Path::new("./target");
	let zip_name = "./target/zipped.zip";

	fs::create_dir_all(root.join("./to_zip/sub")).unwrap();
	write_files(&root).unwrap();

	let zip_file = File::create(zip_name).unwrap();
	zip::compress(&root.join("./to_zip"), &zip_file).unwrap();
	zip_file.sync_all();

	let zip_path = Path::new(zip_name);
	assert!(zip_path.exists());
	assert!(zip_path.is_file());
	assert!(zip_path.metadata().unwrap().len() > 300);

	fs::create_dir_all(root.join("./dezipped")).unwrap();
	let zip_file = File::open(zip_name).unwrap();
	zip::decompress(zip_file, &root.join("./dezipped")).unwrap();

	assert!(root.join("to_zip/foo.txt").is_file());
	assert!(root.join("to_zip/bar.txt").is_file());
	assert!(root.join("to_zip/sub").is_dir());
	let lorem = root.join("to_zip/sub/lorem");
	assert!(lorem.is_file());
	assert!(lorem.metadata().unwrap().len() == 55);
}

fn write_files(root: &Path) -> io::Result<()> {
	let mut file = File::create(root.join("to_zip/foo.txt"))?;
	file.write_all(b"Hello, world!")?;
	let mut file = File::create(root.join("to_zip/bar.txt"))?;
	file.write_all(b"Goodbye, world!")?;
	let mut file = File::create(root.join("to_zip/sub/lorem"))?;
	file.write_all(b"Lorem ipsum dolor sit amet, consectetur adipiscing elit")?;
	Ok(())
}
<|endoftext|>


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

use std::env;
use std::process::Command;
use std::path::{Path, PathBuf};
use std::fs::File;
use std::io::Write;

struct Test {
    repo: &'static str,
    name: &'static str,
    sha: &'static str,
    lock: Option<&'static str>,
}

const TEST_REPOS: &'static [Test] = &[
    Test {
        name: "cargo",
        repo: "https://github.com/rust-lang/cargo",
        sha: "7d79da08238e3d47e0bc4406155bdcc45ccb8c82",
        lock: None,
    },
    Test {
        name: "iron",
        repo: "https://github.com/iron/iron",
        sha: "16c858ec2901e2992fe5e529780f59fa8ed12903",
        lock: Some(include_str!("lockfiles/iron-Cargo.lock")),
    },
];

fn main() {
    let args = env::args().collect::<Vec<_>>();
    let ref cargo = args[1];
    let out_dir = Path::new(&args[2]);
    let ref cargo = Path::new(cargo);

    for test in TEST_REPOS.iter().rev() {
        test_repo(cargo, out_dir, test);
    }
}

fn test_repo(cargo: &Path, out_dir: &Path, test: &Test) {
    println!("testing {}", test.repo);
    let dir = clone_repo(test, out_dir);
    if let Some(lockfile) = test.lock {
        File::create(&dir.join("Cargo.lock")).expect("")
            .write_all(lockfile.as_bytes()).expect("");
    }
    if !run_cargo_test(cargo, &dir) {
        panic!("tests failed for {}", test.repo);
    }
}

fn clone_repo(test: &Test, out_dir: &Path) -> PathBuf {
    let out_dir = out_dir.join(test.name);

    if !out_dir.join(".git").is_dir() {
        let status = Command::new("git")
            .arg("init")
            .arg(&out_dir)
            .status()
            .expect("");
        assert!(status.success());
    }

    // Try progressively deeper fetch depths to find the commit
    let mut found = false;
    for depth in &[0, 1, 10, 100, 1000, 100000] {
        if *depth > 0 {
            let status = Command::new("git")
                .arg("fetch")
                .arg(test.repo)
                .arg("master")
                .arg(&format!("--depth={}", depth))
                .current_dir(&out_dir)
                .status()
                .expect("");
            assert!(status.success());
        }

        let status = Command::new("git")
            .arg("reset")
            .arg(test.sha)
            .arg("--hard")
            .current_dir(&out_dir)
            .status()
            .expect("");

        if status.success() {
            found = true;
            break;
        }
    }

    if !found {
        panic!("unable to find commit {}", test.sha)
    }
    let status = Command::new("git")
        .arg("clean")
        .arg("-fdx")
        .current_dir(&out_dir)
        .status()
        .unwrap();
    assert!(status.success());

    out_dir
}

fn run_cargo_test(cargo_path: &Path, crate_path: &Path) -> bool {
    let status = Command::new(cargo_path)
        .arg("test")
        // Disable rust-lang/cargo's cross-compile tests
        .env("CFG_DISABLE_CROSS_TESTS", "1")
        .current_dir(crate_path)
        .status()
        .expect("");

    status.success()
}
<commit_msg>run rustfmt on cargotest folder in src/tools/cargotest<commit_after>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::env;
use std::process::Command;
use std::path::{Path, PathBuf};
use std::fs::File;
use std::io::Write;

struct Test {
    repo: &'static str,
    name: &'static str,
    sha: &'static str,
    lock: Option<&'static str>,
}

const TEST_REPOS: &'static [Test] = &[Test {
                                          name: "cargo",
                                          repo: "https://github.com/rust-lang/cargo",
                                          sha: "7d79da08238e3d47e0bc4406155bdcc45ccb8c82",
                                          lock: None,
                                      },
                                      Test {
                                          name: "iron",
                                          repo: "https://github.com/iron/iron",
                                          sha: "16c858ec2901e2992fe5e529780f59fa8ed12903",
                                          lock: Some(include_str!("lockfiles/iron-Cargo.lock")),
                                      }];

fn main() {
    let args = env::args().collect::<Vec<_>>();
    let ref cargo = args[1];
    let out_dir = Path::new(&args[2]);
    let ref cargo = Path::new(cargo);

    for test in TEST_REPOS.iter().rev() {
        test_repo(cargo, out_dir, test);
    }
}

fn test_repo(cargo: &Path, out_dir: &Path, test: &Test) {
    println!("testing {}", test.repo);
    let dir = clone_repo(test, out_dir);
    if let Some(lockfile) = test.lock {
        File::create(&dir.join("Cargo.lock"))
            .expect("")
            .write_all(lockfile.as_bytes())
            .expect("");
    }
    if !run_cargo_test(cargo, &dir) {
        panic!("tests failed for {}", test.repo);
    }
}

fn clone_repo(test: &Test, out_dir: &Path) -> PathBuf {
    let out_dir = out_dir.join(test.name);

    if !out_dir.join(".git").is_dir() {
        let status = Command::new("git")
                         .arg("init")
                         .arg(&out_dir)
                         .status()
                         .expect("");
        assert!(status.success());
    }

    // Try progressively deeper fetch depths to find the commit
    let mut found = false;
    for depth in &[0, 1, 10, 100, 1000, 100000] {
        if *depth > 0 {
            let status = Command::new("git")
                             .arg("fetch")
                             .arg(test.repo)
                             .arg("master")
                             .arg(&format!("--depth={}", depth))
                             .current_dir(&out_dir)
                             .status()
                             .expect("");
            assert!(status.success());
        }

        let status = Command::new("git")
                         .arg("reset")
                         .arg(test.sha)
                         .arg("--hard")
                         .current_dir(&out_dir)
                         .status()
                         .expect("");

        if status.success() {
            found = true;
            break;
        }
    }

    if !found {
        panic!("unable to find commit {}", test.sha)
    }
    let status = Command::new("git")
                     .arg("clean")
                     .arg("-fdx")
                     .current_dir(&out_dir)
                     .status()
                     .unwrap();
    assert!(status.success());

    out_dir
}

fn run_cargo_test(cargo_path: &Path, crate_path: &Path) -> bool {
    let status = Command::new(cargo_path)
        .arg("test")
        // Disable rust-lang/cargo's cross-compile tests
        .env("CFG_DISABLE_CROSS_TESTS", "1")
        .current_dir(crate_path)
        .status()
        .expect("");

    status.success()
}
<|endoftext|>


<commit_before><commit_msg>added Venue object<commit_after>use objects::Location;

/// Represents a venue
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct Venue {
    pub location: Location,
    pub title: String,
    pub address: String,
    pub foursquare_id: Option<String>,
}
<|endoftext|>


<commit_before><commit_msg>[Move stdlib] add basic test to ensure that generated files are up to date<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use std::process::Command;

fn assert_that_version_control_has_no_unstaged_changes() {
    let output = Command::new("git")
        .arg("status")
        .arg("--porcelain")
        .output()
        .unwrap();
    assert!(
        output.stdout.is_empty(),
        "Git repository should be in a clean state"
    );
    assert!(output.status.success());
}

#[test]
fn test_that_generated_file_are_up_to_date_in_git() {
    // Better not run the `stdlib` tool when the repository is not in a clean state.
    assert_that_version_control_has_no_unstaged_changes();

    assert!(Command::new("cargo")
        .arg("run")
        .arg("--release")
        .arg("-p")
        .arg("stdlib")
        .status()
        .unwrap()
        .success());

    // Running the stdlib tool should not create unstaged changes.
    assert_that_version_control_has_no_unstaged_changes();
}
<|endoftext|>


<commit_before>// -*- rust -*-

#[doc = "Classic Boolean logic reified as ADT"];

export t;
export not, and, or, xor, implies;
export eq, ne, is_true, is_false;
export from_str, to_str, all_values, to_bit;

#[doc = "The type of boolean logic values"]
type t = bool;

#[doc(
  brief = "Negation/Inverse",
  args(v = "Value to Negate/Invert"),
  return = "Negated/Inverted Value"
)]
pure fn not(v: t) -> t { !v }

#[doc(
  brief = "Conjunction",
  args(a = "value `a`",
       b = "value `b`"),
  return = "`a` AND `b`"
)]
pure fn and(a: t, b: t) -> t { a && b }

#[doc(
  brief = "Disjunction",
  args(a = "value `a`",
       b = "value `b`"),
  return = "`a` OR `b`"
)]
pure fn or(a: t, b: t) -> t { a || b }

#[doc(
  brief = "Exclusive or, i.e. `or(and(a, not(b)), and(not(a), b))`",
  args(a = "value `a`",
       b = "value `b`"),
  return = "`a` XOR `b`"
)]
pure fn xor(a: t, b: t) -> t { (a && !b) || (!a && b) }

#[doc(
  brief = "Implication in the logic, i.e. from `a` follows `b`",
  args(a = "value `a`",
       b = "value `b`"),
  return = "`a` IMPLIES `b`"
)]
pure fn implies(a: t, b: t) -> t { !a || b }

#[doc(
  brief = "true if truth values `a` and `b` are indistinguishable in the logic",
  args(a = "value `a`",
       b = "value `b`"),
  return = "`a` == `b`"
)]
pure fn eq(a: t, b: t) -> bool { a == b }

#[doc(
  brief = "true if truth values `a` and `b` are distinguishable in the logic",
  args(a = "value `a`",
       b = "value `b`"),
  return = "`a` != `b`"
)]
pure fn ne(a: t, b: t) -> bool { a != b }

#[doc(
  brief = "true if `v` represents truth in the logic",
  args(v = "value `v`"),
  return = "bool(`v`)"
)]
pure fn is_true(v: t) -> bool { v }

#[doc(
  brief = "true if `v` represents falsehood in the logic",
  args(v = "value `v`"),
  return = "bool(!`v`)"
)]
pure fn is_false(v: t) -> bool { !v }

#[doc(
  brief = "Parse logic value from `s`",
  args(v = "string value `s`"),
  return = "true if `s` equals \"true\", else false"
)]
pure fn from_str(s: str) -> t {
    alt s {
      "true" { true }
      "false" { false }
    }
}

#[doc(
  brief = "Convert `v` into a string",
  args(v = "truth value `v`"),
  return = "\"true\" if value `v` is true, else \"false\""
)]
pure fn to_str(v: t) -> str { if v { "true" } else { "false" } }

#[doc(
  brief = "Iterates over all truth values by passing them to `blk` in an unspecified order",
  args(v = "block value `v`"),
  return = "Undefined return value"
)]
fn all_values(blk: block(v: t)) {
    blk(true);
    blk(false);
}

#[doc(
  brief = "converts truth value to an 8 bit byte",
  args(v = "value `v`"),
  return = "returns byte with value 1 if `v` has truth value of true, else 0"
)]
pure fn to_bit(v: t) -> u8 { if v { 1u8 } else { 0u8 } }

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<commit_msg>make rustdocs more terse for bool.rs where it is obvious to programmers as per feedback from graydon<commit_after>// -*- rust -*-

#[doc = "Classic Boolean logic reified as ADT"];

export t;
export not, and, or, xor, implies;
export eq, ne, is_true, is_false;
export from_str, to_str, all_values, to_bit;

#[doc = "The type of boolean logic values"]
type t = bool;

#[doc(
  brief = "Negation/Inverse"
)]
pure fn not(v: t) -> t { !v }

#[doc(
  brief = "Conjunction"
)]
pure fn and(a: t, b: t) -> t { a && b }

#[doc(
  brief = "Disjunction"
)]
pure fn or(a: t, b: t) -> t { a || b }

#[doc(
  brief = "Exclusive or, i.e. `or(and(a, not(b)), and(not(a), b))`"
)]
pure fn xor(a: t, b: t) -> t { (a && !b) || (!a && b) }

#[doc(
  brief = "Implication in the logic, i.e. from `a` follows `b`"
)]
pure fn implies(a: t, b: t) -> t { !a || b }

#[doc(
  brief = "true if truth values `a` and `b` are indistinguishable in the logic"
)]
pure fn eq(a: t, b: t) -> bool { a == b }

#[doc(
  brief = "true if truth values `a` and `b` are distinguishable in the logic"
)]
pure fn ne(a: t, b: t) -> bool { a != b }

#[doc(
  brief = "true if `v` represents truth in the logic"
)]
pure fn is_true(v: t) -> bool { v }

#[doc(
  brief = "true if `v` represents falsehood in the logic"
)]
pure fn is_false(v: t) -> bool { !v }

#[doc(
  brief = "Parse logic value from `s`"
)]
pure fn from_str(s: str) -> t {
    alt s {
      "true" { true }
      "false" { false }
    }
}

#[doc(
  brief = "Convert `v` into a string"
)]
pure fn to_str(v: t) -> str { if v { "true" } else { "false" } }

#[doc(
  brief = "Iterates over all truth values by passing them to `blk` in an unspecified order"
)]
fn all_values(blk: block(v: t)) {
    blk(true);
    blk(false);
}

#[doc(
  brief = "converts truth value to an 8 bit byte"
)]
pure fn to_bit(v: t) -> u8 { if v { 1u8 } else { 0u8 } }

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<|endoftext|>


<commit_before>// Dynamic arenas.

// Arenas are used to quickly allocate objects that share a
// lifetime. The arena uses ~[u8] vectors as a backing store to
// allocate objects from. For each allocated object, the arena stores
// a pointer to the type descriptor followed by the
// object. (Potentially with alignment padding after each of them.)
// When the arena is destroyed, it iterates through all of its chunks,
// and uses the tydesc information to trace through the objects,
// calling the destructors on them.
// One subtle point that needs to be addressed is how to handle
// failures while running the user provided initializer function. It
// is important to not run the destructor on uninitalized objects, but
// how to detect them is somewhat subtle. Since alloc() can be invoked
// recursively, it is not sufficient to simply exclude the most recent
// object. To solve this without requiring extra space, we use the low
// order bit of the tydesc pointer to encode whether the object it
// describes has been fully initialized.

// A good extension of this scheme would be to segregate data with and
// without destructors in order to avoid the overhead in the
// plain-old-data case.

export arena, arena_with_size;

import list;
import list::{list, cons, nil};
import unsafe::reinterpret_cast;
import sys::TypeDesc;
import libc::size_t;

#[abi = "rust-intrinsic"]
extern mod rusti {
    fn move_val_init<T>(&dst: T, -src: T);
}
extern mod rustrt {
    #[rust_stack]
    fn rust_call_tydesc_glue(root: *u8, tydesc: *TypeDesc, field: size_t);
}
// This probably belongs somewhere else. Needs to be kept in sync with
// changes to glue...
const tydesc_drop_glue_index: size_t = 3 as size_t;

// The way arena uses arrays is really deeply awful. The arrays are
// allocated, and have capacities reserved, but the fill for the array
// will always stay at 0.
type chunk = {data: ~[u8], mut fill: uint};

struct arena {
    // The head is seperated out from the list as a unbenchmarked
    // microoptimization, to avoid needing to case on the list to
    // access the head.
    priv mut head: @chunk;
    priv mut chunks: @list<@chunk>;
    drop {
        unsafe {
            destroy_chunk(self.head);
            for list::each(self.chunks) |chunk| { destroy_chunk(chunk); }
        }
    }
}

fn chunk(size: uint) -> @chunk {
    let mut v = ~[];
    vec::reserve(v, size);
    @{ data: v, mut fill: 0u }
}

fn arena_with_size(initial_size: uint) -> arena {
    return arena {mut head: chunk(initial_size),
                  mut chunks: @nil};
}

fn arena() -> arena {
    arena_with_size(32u)
}

#[inline(always)]
fn round_up_to(base: uint, align: uint) -> uint {
    (base + (align - 1)) & !(align - 1)
}

// Walk down a chunk, running the destructors for any objects stored
// in it.
unsafe fn destroy_chunk(chunk: @chunk) {
    let mut idx = 0;
    let buf = vec::unsafe::to_ptr(chunk.data);
    let fill = chunk.fill;

    while idx < fill {
        let tydesc_data: *uint = reinterpret_cast(ptr::offset(buf, idx));
        let (tydesc, is_done) = un_bitpack_tydesc_ptr(*tydesc_data);
        let size = (*tydesc).size, align = (*tydesc).align;

        let after_tydesc = idx + sys::size_of::<*TypeDesc>();

        let start = round_up_to(after_tydesc, align);

        //debug!("freeing object: idx = %u, size = %u, align = %u, done = %b",
        //       start, size, align, is_done);
        if is_done {
            rustrt::rust_call_tydesc_glue(
                ptr::offset(buf, start), tydesc, tydesc_drop_glue_index);
        }

        // Find where the next tydesc lives
        idx = round_up_to(start + size, sys::pref_align_of::<*TypeDesc>());
    }
}

// We encode whether the object a tydesc describes has been
// initialized in the arena in the low bit of the tydesc pointer. This
// is necessary in order to properly do cleanup if a failure occurs
// during an initializer.
#[inline(always)]
unsafe fn bitpack_tydesc_ptr(p: *TypeDesc, is_done: bool) -> uint {
    let p_bits: uint = reinterpret_cast(p);
    p_bits | (is_done as uint)
}
#[inline(always)]
unsafe fn un_bitpack_tydesc_ptr(p: uint) -> (*TypeDesc, bool) {
    (reinterpret_cast(p & !1), p & 1 == 1)
}

impl &arena {
    fn alloc_grow(n_bytes: uint, align: uint) -> (*u8, *u8) {
        // Allocate a new chunk.
        let chunk_size = vec::capacity(self.head.data);
        let new_min_chunk_size = uint::max(n_bytes, chunk_size);
        self.chunks = @cons(self.head, self.chunks);
        self.head = chunk(uint::next_power_of_two(new_min_chunk_size + 1u));

        return self.alloc_inner(n_bytes, align);
    }

    #[inline(always)]
    fn alloc_inner(n_bytes: uint, align: uint) -> (*u8, *u8) {
        let head = self.head;

        let after_tydesc = head.fill + sys::size_of::<*TypeDesc>();

        let start = round_up_to(after_tydesc, align);
        let end = start + n_bytes;
        if end > vec::capacity(head.data) {
            return self.alloc_grow(n_bytes, align);
        }

        //debug!("idx = %u, size = %u, align = %u, fill = %u",
        //       start, n_bytes, align, head.fill);

        unsafe {
            let buf = vec::unsafe::to_ptr(head.data);
            let tydesc_p = ptr::offset(buf, head.fill);
            let p = ptr::offset(buf, start);
            head.fill = round_up_to(end, sys::pref_align_of::<*TypeDesc>());

            return (tydesc_p, p);
        }
    }

    #[inline(always)]
    fn alloc<T>(op: fn() -> T) -> &self/T {
        unsafe {
            let tydesc = sys::get_type_desc::<T>();
            let (ty_ptr, ptr) =
                self.alloc_inner((*tydesc).size, (*tydesc).align);
            let ty_ptr: *mut uint = reinterpret_cast(ty_ptr);
            let ptr: *mut T = reinterpret_cast(ptr);
            // Write in our tydesc along with a bit indicating that it
            // has *not* been initialized yet.
            *ty_ptr = reinterpret_cast(tydesc);
            // Actually initialize it
            rusti::move_val_init(*ptr, op());
            // Now that we are done, update the tydesc to indicate that
            // the object is there.
            *ty_ptr = bitpack_tydesc_ptr(tydesc, true);

            return reinterpret_cast(ptr);
        }
    }
}

#[test]
fn test_arena_destructors() {
    let arena = arena::arena();
    for uint::range(0, 10) |i| {
        // Arena allocate something with drop glue to make sure it
        // doesn't leak.
        do arena.alloc { @i };
        // Allocate something with funny size and alignment, to keep
        // things interesting.
        do arena.alloc { [0u8, 1u8, 2u8]/3 };
    }
}

#[test]
#[should_fail]
fn test_arena_destructors_fail() {
    let arena = arena::arena();
    // Put some stuff in the arena.
    for uint::range(0, 10) |i| {
        // Arena allocate something with drop glue to make sure it
        // doesn't leak.
        do arena.alloc { @i };
        // Allocate something with funny size and alignment, to keep
        // things interesting.
        do arena.alloc { [0u8, 1u8, 2u8]/3 };
    }
    // Now, fail while allocating
    do arena.alloc::<@int> {
        // First, recursively allocate something else; that needs to
        // get freed too.
        do arena.alloc { @20 };
        // Now fail.
        fail;
    };
}
<commit_msg>Have std::arena segregate POD data and non-POD data into different chunks.<commit_after>// Dynamic arenas.

// Arenas are used to quickly allocate objects that share a
// lifetime. The arena uses ~[u8] vectors as a backing store to
// allocate objects from. For each allocated object, the arena stores
// a pointer to the type descriptor followed by the
// object. (Potentially with alignment padding after each of them.)
// When the arena is destroyed, it iterates through all of its chunks,
// and uses the tydesc information to trace through the objects,
// calling the destructors on them.
// One subtle point that needs to be addressed is how to handle
// failures while running the user provided initializer function. It
// is important to not run the destructor on uninitalized objects, but
// how to detect them is somewhat subtle. Since alloc() can be invoked
// recursively, it is not sufficient to simply exclude the most recent
// object. To solve this without requiring extra space, we use the low
// order bit of the tydesc pointer to encode whether the object it
// describes has been fully initialized.

// As an optimization, objects with destructors are stored in
// different chunks than objects without destructors. This reduces
// overhead when initializing plain-old-data and means we don't need
// to waste time running the destructors of POD.

export arena, arena_with_size;

import list;
import list::{list, cons, nil};
import unsafe::reinterpret_cast;
import sys::TypeDesc;
import libc::size_t;

#[abi = "rust-intrinsic"]
extern mod rusti {
    fn move_val_init<T>(&dst: T, -src: T);
    fn needs_drop<T>() -> bool;
}
extern mod rustrt {
    #[rust_stack]
    fn rust_call_tydesc_glue(root: *u8, tydesc: *TypeDesc, field: size_t);
}
// This probably belongs somewhere else. Needs to be kept in sync with
// changes to glue...
const tydesc_drop_glue_index: size_t = 3 as size_t;

// The way arena uses arrays is really deeply awful. The arrays are
// allocated, and have capacities reserved, but the fill for the array
// will always stay at 0.
type chunk = {data: ~[u8], mut fill: uint, is_pod: bool};

struct arena {
    // The head is seperated out from the list as a unbenchmarked
    // microoptimization, to avoid needing to case on the list to
    // access the head.
    priv mut head: @chunk;
    priv mut pod_head: @chunk;
    priv mut chunks: @list<@chunk>;
    drop {
        unsafe {
            destroy_chunk(self.head);
            for list::each(self.chunks) |chunk| {
                if !chunk.is_pod { destroy_chunk(chunk); }
            }
        }
    }
}

fn chunk(size: uint, is_pod: bool) -> @chunk {
    let mut v = ~[];
    vec::reserve(v, size);
    @{ data: v, mut fill: 0u, is_pod: is_pod }
}

fn arena_with_size(initial_size: uint) -> arena {
    return arena {mut head: chunk(initial_size, false),
                  mut pod_head: chunk(initial_size, true),
                  mut chunks: @nil};
}

fn arena() -> arena {
    arena_with_size(32u)
}

#[inline(always)]
fn round_up_to(base: uint, align: uint) -> uint {
    (base + (align - 1)) & !(align - 1)
}

// Walk down a chunk, running the destructors for any objects stored
// in it.
unsafe fn destroy_chunk(chunk: @chunk) {
    let mut idx = 0;
    let buf = vec::unsafe::to_ptr(chunk.data);
    let fill = chunk.fill;

    while idx < fill {
        let tydesc_data: *uint = reinterpret_cast(ptr::offset(buf, idx));
        let (tydesc, is_done) = un_bitpack_tydesc_ptr(*tydesc_data);
        let size = (*tydesc).size, align = (*tydesc).align;

        let after_tydesc = idx + sys::size_of::<*TypeDesc>();

        let start = round_up_to(after_tydesc, align);

        //debug!("freeing object: idx = %u, size = %u, align = %u, done = %b",
        //       start, size, align, is_done);
        if is_done {
            rustrt::rust_call_tydesc_glue(
                ptr::offset(buf, start), tydesc, tydesc_drop_glue_index);
        }

        // Find where the next tydesc lives
        idx = round_up_to(start + size, sys::pref_align_of::<*TypeDesc>());
    }
}

// We encode whether the object a tydesc describes has been
// initialized in the arena in the low bit of the tydesc pointer. This
// is necessary in order to properly do cleanup if a failure occurs
// during an initializer.
#[inline(always)]
unsafe fn bitpack_tydesc_ptr(p: *TypeDesc, is_done: bool) -> uint {
    let p_bits: uint = reinterpret_cast(p);
    p_bits | (is_done as uint)
}
#[inline(always)]
unsafe fn un_bitpack_tydesc_ptr(p: uint) -> (*TypeDesc, bool) {
    (reinterpret_cast(p & !1), p & 1 == 1)
}

// The duplication between the POD and non-POD functions is annoying.
impl &arena {
    // Functions for the POD part of the arena
    fn alloc_pod_grow(n_bytes: uint, align: uint) -> *u8 {
        // Allocate a new chunk.
        let chunk_size = vec::capacity(self.pod_head.data);
        let new_min_chunk_size = uint::max(n_bytes, chunk_size);
        self.chunks = @cons(self.pod_head, self.chunks);
        self.pod_head =
            chunk(uint::next_power_of_two(new_min_chunk_size + 1u), true);

        return self.alloc_pod_inner(n_bytes, align);
    }

    #[inline(always)]
    fn alloc_pod_inner(n_bytes: uint, align: uint) -> *u8 {
        let head = self.pod_head;

        let start = round_up_to(head.fill, align);
        let end = start + n_bytes;
        if end > vec::capacity(head.data) {
            return self.alloc_pod_grow(n_bytes, align);
        }
        head.fill = end;

        //debug!("idx = %u, size = %u, align = %u, fill = %u",
        //       start, n_bytes, align, head.fill);

        unsafe {
            ptr::offset(vec::unsafe::to_ptr(head.data), start)
        }
    }

    #[inline(always)]
    fn alloc_pod<T>(op: fn() -> T) -> &self/T {
        unsafe {
            let tydesc = sys::get_type_desc::<T>();
            let ptr = self.alloc_pod_inner((*tydesc).size, (*tydesc).align);
            let ptr: *mut T = reinterpret_cast(ptr);
            rusti::move_val_init(*ptr, op());
            return reinterpret_cast(ptr);
        }
    }

    // Functions for the non-POD part of the arena
    fn alloc_nonpod_grow(n_bytes: uint, align: uint) -> (*u8, *u8) {
        // Allocate a new chunk.
        let chunk_size = vec::capacity(self.head.data);
        let new_min_chunk_size = uint::max(n_bytes, chunk_size);
        self.chunks = @cons(self.head, self.chunks);
        self.head =
            chunk(uint::next_power_of_two(new_min_chunk_size + 1u), false);

        return self.alloc_nonpod_inner(n_bytes, align);
    }

    #[inline(always)]
    fn alloc_nonpod_inner(n_bytes: uint, align: uint) -> (*u8, *u8) {
        let head = self.head;

        let tydesc_start = head.fill;
        let after_tydesc = head.fill + sys::size_of::<*TypeDesc>();
        let start = round_up_to(after_tydesc, align);
        let end = start + n_bytes;
        if end > vec::capacity(head.data) {
            return self.alloc_nonpod_grow(n_bytes, align);
        }
        head.fill = round_up_to(end, sys::pref_align_of::<*TypeDesc>());

        //debug!("idx = %u, size = %u, align = %u, fill = %u",
        //       start, n_bytes, align, head.fill);

        unsafe {
            let buf = vec::unsafe::to_ptr(head.data);
            return (ptr::offset(buf, tydesc_start), ptr::offset(buf, start));
        }
    }

    #[inline(always)]
    fn alloc_nonpod<T>(op: fn() -> T) -> &self/T {
        unsafe {
            let tydesc = sys::get_type_desc::<T>();
            let (ty_ptr, ptr) =
                self.alloc_nonpod_inner((*tydesc).size, (*tydesc).align);
            let ty_ptr: *mut uint = reinterpret_cast(ty_ptr);
            let ptr: *mut T = reinterpret_cast(ptr);
            // Write in our tydesc along with a bit indicating that it
            // has *not* been initialized yet.
            *ty_ptr = reinterpret_cast(tydesc);
            // Actually initialize it
            rusti::move_val_init(*ptr, op());
            // Now that we are done, update the tydesc to indicate that
            // the object is there.
            *ty_ptr = bitpack_tydesc_ptr(tydesc, true);

            return reinterpret_cast(ptr);
        }
    }

    // The external interface
    #[inline(always)]
    fn alloc<T>(op: fn() -> T) -> &self/T {
        if !rusti::needs_drop::<T>() {
            self.alloc_pod(op)
        } else { self.alloc_nonpod(op) }
    }
}

#[test]
fn test_arena_destructors() {
    let arena = arena::arena();
    for uint::range(0, 10) |i| {
        // Arena allocate something with drop glue to make sure it
        // doesn't leak.
        do arena.alloc { @i };
        // Allocate something with funny size and alignment, to keep
        // things interesting.
        do arena.alloc { [0u8, 1u8, 2u8]/3 };
    }
}

#[test]
#[should_fail]
fn test_arena_destructors_fail() {
    let arena = arena::arena();
    // Put some stuff in the arena.
    for uint::range(0, 10) |i| {
        // Arena allocate something with drop glue to make sure it
        // doesn't leak.
        do arena.alloc { @i };
        // Allocate something with funny size and alignment, to keep
        // things interesting.
        do arena.alloc { [0u8, 1u8, 2u8]/3 };
    }
    // Now, fail while allocating
    do arena.alloc::<@int> {
        // First, recursively allocate something else; that needs to
        // get freed too.
        do arena.alloc { @20 };
        // Now fail.
        fail;
    };
}
<|endoftext|>


<commit_before><commit_msg>generic load hardening test<commit_after>// Test LVI load hardening on SGX enclave code

// assembly-output: emit-asm
// compile-flags: --crate-type staticlib
// only-x86_64-fortanix-unknown-sgx

#[no_mangle]
pub extern fn plus_one(r: &mut u64) {
    *r = *r + 1;
}

// CHECK: plus_one
// CHECK: lfence
// CHECK-NEXT: addq
// CHECK: popq [[REGISTER:%[a-z]+]]
// CHECK-NEXT: lfence
// CHECK-NEXT: jmpq *[[REGISTER]]

<|endoftext|>