<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

// Functions for dealing with device mapper names.

use std::fmt;
use std::fmt::Display;

use devicemapper::{DmNameBuf, DmUuidBuf};

use super::super::super::engine::{FilesystemUuid, PoolUuid};

const FORMAT_VERSION: u16 = 1;

#[derive(Clone, Copy)]
pub enum FlexRole {
    MetadataVolume,
    ThinData,
    ThinMeta,
    ThinMetaSpare,
}

impl Display for FlexRole {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            FlexRole::MetadataVolume => write!(f, "mdv"),
            FlexRole::ThinData => write!(f, "thindata"),
            FlexRole::ThinMeta => write!(f, "thinmeta"),
            FlexRole::ThinMetaSpare => write!(f, "thinmetaspare"),
        }
    }
}

#[derive(Clone, Copy)]
pub enum ThinRole {
    Filesystem(FilesystemUuid),
}

impl Display for ThinRole {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ThinRole::Filesystem(uuid) => write!(f, "fs-{}", uuid.simple().to_string()),
        }
    }
}

#[derive(Clone, Copy)]
pub enum ThinPoolRole {
    Pool,
}

impl Display for ThinPoolRole {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ThinPoolRole::Pool => write!(f, "pool"),
        }
    }
}

/// The various roles taken on by DM devices in the cache tier.
#[derive(Clone, Copy)]
pub enum CacheRole {
    /// The DM cache device, contains the other three devices.
    #[allow(dead_code)]
    Cache,
    /// The cache sub-device of the DM cache device.
    #[allow(dead_code)]
    CacheSub,
    /// The meta sub-device of the DM cache device.
    #[allow(dead_code)]
    MetaSub,
    /// The origin sub-device of the DM cache device, holds the actual data.
    OriginSub,
}

impl Display for CacheRole {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            CacheRole::Cache => write!(f, "cache"),
            CacheRole::CacheSub => write!(f, "cachesub"),
            CacheRole::MetaSub => write!(f, "metasub"),
            CacheRole::OriginSub => write!(f, "originsub"),
        }
    }
}

/// Format a name & uuid for the flex layer.
///
/// Prerequisite: len(format!("{}", FORMAT_VERSION)
///             + len("stratis")                         7
///             + len("flex")                            4
///             + num_dashes                             4
///             + len(pool uuid)                         32
///             + max(len(FlexRole))                     13
///             < 128 (129 for UUID)
///
/// which is equivalent to len(format!("{}", FORMAT_VERSION) < 68 (69 for UUID)
pub fn format_flex_ids(pool_uuid: PoolUuid, role: FlexRole) -> (DmNameBuf, DmUuidBuf) {
    let value = format!("stratis-{}-{}-flex-{}",
                        FORMAT_VERSION,
                        pool_uuid.simple().to_string(),
                        role);
    (DmNameBuf::new(value.clone()).expect("FORMAT_VERSION display length < 68"),
     DmUuidBuf::new(value).expect("FORMAT_VERSION display length < 69"))

}

/// Format a name & uuid for the thin layer.
///
/// Prerequisite: len(format!("{}", FORMAT_VERSION)
///             + len("stratis")                         7
///             + len("thin")                            4
///             + num_dashes                             4
///             + len(pool uuid)                         32
///             + max(len(ThinRole))                     35
///             < 128 (129 for UUID)
///
/// which is equivalent to len(format!("{}", FORMAT_VERSION) < 46 (47 for UUID)
pub fn format_thin_ids(pool_uuid: PoolUuid, role: ThinRole) -> (DmNameBuf, DmUuidBuf) {
    let value = format!("stratis-{}-{}-thin-{}",
                        FORMAT_VERSION,
                        pool_uuid.simple().to_string(),
                        role);
    (DmNameBuf::new(value.clone()).expect("FORMAT_VERSION display length < 46"),
     DmUuidBuf::new(value).expect("FORMAT_VERSION display length < 47"))
}

/// Format a name & uuid for the thin pool layer.
///
/// Prerequisite: len(format!("{}", FORMAT_VERSION)
///             + len("stratis")                         7
///             + len("thinpool")                        8
///             + num_dashes                             4
///             + len(pool uuid)                         32
///             + max(len(ThinPoolRole))                 4
///             < 128 (129 for UUID)
///
/// which is equivalent to len(format!("{}", FORMAT_VERSION) < 73 (74 for UUID)
pub fn format_thinpool_ids(pool_uuid: PoolUuid, role: ThinPoolRole) -> (DmNameBuf, DmUuidBuf) {
    let value = format!("stratis-{}-{}-thinpool-{}",
                        FORMAT_VERSION,
                        pool_uuid.simple().to_string(),
                        role);
    (DmNameBuf::new(value.clone()).expect("FORMAT_VERSION display_length < 73"),
     DmUuidBuf::new(value).expect("FORMAT_VERSION display_length < 74"))
}

/// Format a name & uuid for dm devices in the backstore.
///
/// Prerequisite: len(format!("{}", FORMAT_VERSION)
///             + len("stratis")                         7
///             + len("physical")                        8
///             + num_dashes                             4
///             + len(pool uuid)                         32
///             + max(len(CacheRole))                    9
///             < 128 (129 for UUID)
///
/// which is equivalent to len(format!("{}", FORMAT_VERSION) < 68 (69 for UUID)
pub fn format_backstore_ids(pool_uuid: PoolUuid, role: CacheRole) -> (DmNameBuf, DmUuidBuf) {
    let value = format!("stratis-{}-{}-physical-{}",
                        FORMAT_VERSION,
                        pool_uuid.simple().to_string(),
                        role);
    (DmNameBuf::new(value.clone()).expect("FORMAT_VERSION display_length < 68"),
     DmUuidBuf::new(value).expect("FORMAT_VERSION display_length < 69"))
}
<commit_msg>Add 'private' to uuid for internal dm devices<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

// Functions for dealing with device mapper names.

use std::fmt;
use std::fmt::Display;

use devicemapper::{DmNameBuf, DmUuidBuf};

use super::super::super::engine::{FilesystemUuid, PoolUuid};

const FORMAT_VERSION: u16 = 1;

#[derive(Clone, Copy)]
pub enum FlexRole {
    MetadataVolume,
    ThinData,
    ThinMeta,
    ThinMetaSpare,
}

impl Display for FlexRole {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            FlexRole::MetadataVolume => write!(f, "mdv"),
            FlexRole::ThinData => write!(f, "thindata"),
            FlexRole::ThinMeta => write!(f, "thinmeta"),
            FlexRole::ThinMetaSpare => write!(f, "thinmetaspare"),
        }
    }
}

#[derive(Clone, Copy)]
pub enum ThinRole {
    Filesystem(FilesystemUuid),
}

impl Display for ThinRole {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ThinRole::Filesystem(uuid) => write!(f, "fs-{}", uuid.simple().to_string()),
        }
    }
}

#[derive(Clone, Copy)]
pub enum ThinPoolRole {
    Pool,
}

impl Display for ThinPoolRole {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ThinPoolRole::Pool => write!(f, "pool"),
        }
    }
}

/// The various roles taken on by DM devices in the cache tier.
#[derive(Clone, Copy)]
pub enum CacheRole {
    /// The DM cache device, contains the other three devices.
    #[allow(dead_code)]
    Cache,
    /// The cache sub-device of the DM cache device.
    #[allow(dead_code)]
    CacheSub,
    /// The meta sub-device of the DM cache device.
    #[allow(dead_code)]
    MetaSub,
    /// The origin sub-device of the DM cache device, holds the actual data.
    OriginSub,
}

impl Display for CacheRole {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            CacheRole::Cache => write!(f, "cache"),
            CacheRole::CacheSub => write!(f, "cachesub"),
            CacheRole::MetaSub => write!(f, "metasub"),
            CacheRole::OriginSub => write!(f, "originsub"),
        }
    }
}

/// Format a name & uuid for the flex layer.
///
/// Prerequisite: len(format!("{}", FORMAT_VERSION)
///             + len("stratis")                         7
///             + len("private")                         7
///             + len("flex")                            4
///             + num_dashes                             5
///             + len(pool uuid)                         32
///             + max(len(FlexRole))                     13
///             < 128 (129 for UUID)
///
/// which is equivalent to len(format!("{}", FORMAT_VERSION) < 60 (61 for UUID)
pub fn format_flex_ids(pool_uuid: PoolUuid, role: FlexRole) -> (DmNameBuf, DmUuidBuf) {
    let value = format!("stratis-{}-private-{}-flex-{}",
                        FORMAT_VERSION,
                        pool_uuid.simple().to_string(),
                        role);
    (DmNameBuf::new(value.clone()).expect("FORMAT_VERSION display length < 60"),
     DmUuidBuf::new(value).expect("FORMAT_VERSION display length < 61"))

}

/// Format a name & uuid for the thin layer.
///
/// Prerequisite: len(format!("{}", FORMAT_VERSION)
///             + len("stratis")                         7
///             + len("thin")                            4
///             + num_dashes                             4
///             + len(pool uuid)                         32
///             + max(len(ThinRole))                     35
///             < 128 (129 for UUID)
///
/// which is equivalent to len(format!("{}", FORMAT_VERSION) < 46 (47 for UUID)
pub fn format_thin_ids(pool_uuid: PoolUuid, role: ThinRole) -> (DmNameBuf, DmUuidBuf) {
    let value = format!("stratis-{}-{}-thin-{}",
                        FORMAT_VERSION,
                        pool_uuid.simple().to_string(),
                        role);
    (DmNameBuf::new(value.clone()).expect("FORMAT_VERSION display length < 46"),
     DmUuidBuf::new(value).expect("FORMAT_VERSION display length < 47"))
}

/// Format a name & uuid for the thin pool layer.
///
/// Prerequisite: len(format!("{}", FORMAT_VERSION)
///             + len("stratis")                         7
///             + len("private")                         7
///             + len("thinpool")                        8
///             + num_dashes                             5
///             + len(pool uuid)                         32
///             + max(len(ThinPoolRole))                 4
///             < 128 (129 for UUID)
///
/// which is equivalent to len(format!("{}", FORMAT_VERSION) < 65 (66 for UUID)
pub fn format_thinpool_ids(pool_uuid: PoolUuid, role: ThinPoolRole) -> (DmNameBuf, DmUuidBuf) {
    let value = format!("stratis-{}-private-{}-thinpool-{}",
                        FORMAT_VERSION,
                        pool_uuid.simple().to_string(),
                        role);
    (DmNameBuf::new(value.clone()).expect("FORMAT_VERSION display_length < 65"),
     DmUuidBuf::new(value).expect("FORMAT_VERSION display_length < 66"))
}

/// Format a name & uuid for dm devices in the backstore.
///
/// Prerequisite: len(format!("{}", FORMAT_VERSION)
///             + len("stratis")                         7
///             + len("private")                         7
///             + len("physical")                        8
///             + num_dashes                             5
///             + len(pool uuid)                         32
///             + max(len(CacheRole))                    9
///             < 128 (129 for UUID)
///
/// which is equivalent to len(format!("{}", FORMAT_VERSION) < 60 (61 for UUID)
pub fn format_backstore_ids(pool_uuid: PoolUuid, role: CacheRole) -> (DmNameBuf, DmUuidBuf) {
    let value = format!("stratis-{}-private-{}-physical-{}",
                        FORMAT_VERSION,
                        pool_uuid.simple().to_string(),
                        role);
    (DmNameBuf::new(value.clone()).expect("FORMAT_VERSION display_length < 60"),
     DmUuidBuf::new(value).expect("FORMAT_VERSION display_length < 61"))
}
<|endoftext|>


<commit_before>/**********************************************************\
|                                                          |
|                          hprose                          |
|                                                          |
| Official WebSite: http://www.hprose.com/                 |
|                   http://www.hprose.org/                 |
|                                                          |
\**********************************************************/
/**********************************************************\
 *                                                        *
 * io/reader.rs                                           *
 *                                                        *
 * hprose reader for Rust.                                *
 *                                                        *
 * LastModified: Sep 22, 2016                             *
 * Author: Chen Fei <cf@hprose.com>                       *
 *                                                        *
\**********************************************************/

extern crate test;

use super::tags::*;
use super::*;

use super::bool_decoder::bool_decode;
use super::i64_decoder::i64_decode;
use super::u64_decoder::u64_decode;
use super::f32_decoder::f32_decode;
use super::f64_decoder::f64_decode;
use super::string_decoder::string_decode;
use super::map_decoder::map_decode;

use std::fmt;
use std::f64;
use std::str;

/// A set of errors that can occur decoding byte slice
#[derive(Clone, PartialEq, Debug)]
pub enum DecoderError {
    ParserError(ParserError),
    CastError(&'static str, &'static str),
    UnexpectedTag(u8, Option<Bytes>)
}

impl fmt::Display for DecoderError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            DecoderError::CastError(src_type, dst_type) => write!(f, "can't convert {} to {}", src_type, dst_type),
            DecoderError::UnexpectedTag(tag, ref expect_tags_option) => {
                match *expect_tags_option {
                    // todo: format tag as 'c'(0xdd)
                    Some(ref expect_tags) => write!(f, "Tag '{:?}' expected, but '{}' found in stream", expect_tags, tag),
                    None => write!(f, "Unexpected serialize tag '{}' in stream", tag)
                }
            },
            _ => fmt::Debug::fmt(self, f)
        }
    }
}

pub type DecodeResult<T> = Result<T, DecoderError>;

/// Reader is a fine-grained operation struct for Hprose unserialization
pub struct Reader<'a> {
    pub byte_reader: ByteReader<'a>
}

impl<'a> Reader<'a> {
    #[inline]
    pub fn new(buf: &'a [u8], simple: bool) -> Reader<'a> {
        Reader {
            byte_reader: ByteReader::new(buf)
        }
    }

    #[inline]
    pub fn unserialize<T: Decodable>(&mut self) -> DecodeResult<T> {
        self.read()
    }

    #[inline]
    pub fn read<T: Decodable>(&mut self) -> DecodeResult<T> {
        Decodable::decode(self)
    }
}

impl<'a> Decoder for Reader<'a> {
    type Error = DecoderError;

    fn read_nil(&mut self) -> DecodeResult<()> {
        unimplemented!()
    }

    fn read_bool(&mut self) -> DecodeResult<bool> {
        self.byte_reader.read_byte().map_err(|e| DecoderError::ParserError(e)).and_then(|t| bool_decode(self, t))
    }

    fn read_i64(&mut self) -> DecodeResult<i64> {
        self.byte_reader.read_byte().map_err(|e| DecoderError::ParserError(e)).and_then(|t| i64_decode(self, t))
    }

    fn read_u64(&mut self) -> DecodeResult<u64> {
        self.byte_reader.read_byte().map_err(|e| DecoderError::ParserError(e)).and_then(|t| u64_decode(self, t))
    }

    fn read_f32(&mut self) -> DecodeResult<f32> {
        self.byte_reader.read_byte().map_err(|e| DecoderError::ParserError(e)).and_then(|t| f32_decode(self, t))
    }

    fn read_f64(&mut self) -> DecodeResult<f64> {
        self.byte_reader.read_byte().map_err(|e| DecoderError::ParserError(e)).and_then(|t| f64_decode(self, t))
    }

    fn read_char(&mut self) -> DecodeResult<char> {
        unimplemented!()
    }

    fn read_string_without_tag(&mut self) -> DecodeResult<String> {
        // todo: set reader ref
        self.byte_reader.read_string().map_err(|e| DecoderError::ParserError(e))
    }

    fn read_string(&mut self) -> DecodeResult<String> {
        self.byte_reader.read_byte().map_err(|e| DecoderError::ParserError(e)).and_then(|t| string_decode(self, t))
    }

    fn read_bytes(&mut self) -> DecodeResult<Bytes> {
        unimplemented!()
    }

    fn read_option<T, F>(&mut self, f: F) -> DecodeResult<T> where F: FnMut(&mut Reader<'a>, bool) -> DecodeResult<T> {
        unimplemented!()
    }

    fn read_seq<T, F>(&mut self, f: F) -> DecodeResult<T> where F: FnOnce(&mut Reader<'a>, usize) -> DecodeResult<T> {
        unimplemented!()
    }

    fn read_map<T, F>(&mut self, f: F) -> DecodeResult<T>
        where F: FnOnce(&mut Reader<'a>, usize) -> DecodeResult<T>
    {
        self.byte_reader.read_byte().map_err(|e| DecoderError::ParserError(e)).and_then(|t| map_decode(self, t, |d, len| f(d, len)))
    }
}

fn tag_to_str(tag: u8) -> Result<&'static str, DecoderError> {
    match tag {
        b'0'...b'9' | TAG_INTEGER => Ok("i32"),
        TAG_LONG => Ok("big int"),
        TAG_DOUBLE => Ok("f64"),
        TAG_NULL => Ok("nil"),
        TAG_EMPTY => Ok("empty string"),
        TAG_TRUE => Ok("true"),
        TAG_FALSE => Ok("false"),
        TAG_NAN => Ok("NaN"),
        TAG_INFINITY => Ok("Infinity"),
        TAG_DATE | TAG_TIME => Ok("time"),
        TAG_BYTES => Ok("bytes"),
        TAG_UTF8_CHAR | TAG_STRING => Ok("string"),
        TAG_GUID => Ok("GUID"),
        TAG_LIST => Ok("slice"),
        TAG_MAP => Ok("map"),
        TAG_CLASS | TAG_OBJECT => Ok("struct"),
        TAG_REF => Ok("reference"),
        _ => Err(DecoderError::UnexpectedTag(tag, None))
    }
}

pub fn cast_error(tag: u8, dst_type: &'static str) -> DecoderError {
    tag_to_str(tag)
        .map(|src_type| DecoderError::CastError(src_type, dst_type))
        .unwrap_or_else(|e| e)
}

#[cfg(test)]
mod tests {
    use super::test::Bencher;
    use super::super::*;

    use std::collections::HashMap;

    #[bench]
    fn benchmark_unserialize_bool(b: &mut Bencher) {
        let bytes = Writer::new(true).serialize(&true).bytes();
        b.bytes = bytes.len() as u64;
        b.iter(|| {
            Reader::new(&bytes).unserialize::<bool>().unwrap();
        });
    }

    #[bench]
    fn benchmark_unserialize_i64(b: &mut Bencher) {
        let bytes = Writer::new(true).serialize(&12345).bytes();
        b.bytes = bytes.len() as u64;
        b.iter(|| {
            Reader::new(&bytes).unserialize::<i64>().unwrap();
        });
    }

    #[bench]
    fn benchmark_unserialize_str(b: &mut Bencher) {
        let bytes = Writer::new(true).serialize("你好，🇨🇳").bytes();
        b.bytes = bytes.len() as u64;
        b.iter(|| {
            Reader::new(&bytes).unserialize::<String>().unwrap();
        });
    }

    #[bench]
    fn benchmark_unserialize_map(b: &mut Bencher) {
        let mut map = HashMap::new();
        map.insert("name", "Tom");
        map.insert("国家", "🇨🇳");
        let bytes = Writer::new(true).serialize(&map).bytes();
        b.bytes = bytes.len() as u64;
        b.iter(|| {
            Reader::new(&bytes).unserialize::<HashMap<String, String>>().unwrap();
        });
    }
}
<commit_msg>Fix bench unserialize issue.<commit_after>/**********************************************************\
|                                                          |
|                          hprose                          |
|                                                          |
| Official WebSite: http://www.hprose.com/                 |
|                   http://www.hprose.org/                 |
|                                                          |
\**********************************************************/
/**********************************************************\
 *                                                        *
 * io/reader.rs                                           *
 *                                                        *
 * hprose reader for Rust.                                *
 *                                                        *
 * LastModified: Sep 22, 2016                             *
 * Author: Chen Fei <cf@hprose.com>                       *
 *                                                        *
\**********************************************************/

extern crate test;

use super::tags::*;
use super::*;

use super::bool_decoder::bool_decode;
use super::i64_decoder::i64_decode;
use super::u64_decoder::u64_decode;
use super::f32_decoder::f32_decode;
use super::f64_decoder::f64_decode;
use super::string_decoder::string_decode;
use super::map_decoder::map_decode;

use std::fmt;
use std::f64;
use std::str;

/// A set of errors that can occur decoding byte slice
#[derive(Clone, PartialEq, Debug)]
pub enum DecoderError {
    ParserError(ParserError),
    CastError(&'static str, &'static str),
    UnexpectedTag(u8, Option<Bytes>)
}

impl fmt::Display for DecoderError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            DecoderError::CastError(src_type, dst_type) => write!(f, "can't convert {} to {}", src_type, dst_type),
            DecoderError::UnexpectedTag(tag, ref expect_tags_option) => {
                match *expect_tags_option {
                    // todo: format tag as 'c'(0xdd)
                    Some(ref expect_tags) => write!(f, "Tag '{:?}' expected, but '{}' found in stream", expect_tags, tag),
                    None => write!(f, "Unexpected serialize tag '{}' in stream", tag)
                }
            },
            _ => fmt::Debug::fmt(self, f)
        }
    }
}

pub type DecodeResult<T> = Result<T, DecoderError>;

/// Reader is a fine-grained operation struct for Hprose unserialization
pub struct Reader<'a> {
    pub byte_reader: ByteReader<'a>
}

impl<'a> Reader<'a> {
    #[inline]
    pub fn new(buf: &'a [u8], simple: bool) -> Reader<'a> {
        Reader {
            byte_reader: ByteReader::new(buf)
        }
    }

    #[inline]
    pub fn unserialize<T: Decodable>(&mut self) -> DecodeResult<T> {
        self.read()
    }

    #[inline]
    pub fn read<T: Decodable>(&mut self) -> DecodeResult<T> {
        Decodable::decode(self)
    }
}

impl<'a> Decoder for Reader<'a> {
    type Error = DecoderError;

    fn read_nil(&mut self) -> DecodeResult<()> {
        unimplemented!()
    }

    fn read_bool(&mut self) -> DecodeResult<bool> {
        self.byte_reader.read_byte().map_err(|e| DecoderError::ParserError(e)).and_then(|t| bool_decode(self, t))
    }

    fn read_i64(&mut self) -> DecodeResult<i64> {
        self.byte_reader.read_byte().map_err(|e| DecoderError::ParserError(e)).and_then(|t| i64_decode(self, t))
    }

    fn read_u64(&mut self) -> DecodeResult<u64> {
        self.byte_reader.read_byte().map_err(|e| DecoderError::ParserError(e)).and_then(|t| u64_decode(self, t))
    }

    fn read_f32(&mut self) -> DecodeResult<f32> {
        self.byte_reader.read_byte().map_err(|e| DecoderError::ParserError(e)).and_then(|t| f32_decode(self, t))
    }

    fn read_f64(&mut self) -> DecodeResult<f64> {
        self.byte_reader.read_byte().map_err(|e| DecoderError::ParserError(e)).and_then(|t| f64_decode(self, t))
    }

    fn read_char(&mut self) -> DecodeResult<char> {
        unimplemented!()
    }

    fn read_string_without_tag(&mut self) -> DecodeResult<String> {
        // todo: set reader ref
        self.byte_reader.read_string().map_err(|e| DecoderError::ParserError(e))
    }

    fn read_string(&mut self) -> DecodeResult<String> {
        self.byte_reader.read_byte().map_err(|e| DecoderError::ParserError(e)).and_then(|t| string_decode(self, t))
    }

    fn read_bytes(&mut self) -> DecodeResult<Bytes> {
        unimplemented!()
    }

    fn read_option<T, F>(&mut self, f: F) -> DecodeResult<T> where F: FnMut(&mut Reader<'a>, bool) -> DecodeResult<T> {
        unimplemented!()
    }

    fn read_seq<T, F>(&mut self, f: F) -> DecodeResult<T> where F: FnOnce(&mut Reader<'a>, usize) -> DecodeResult<T> {
        unimplemented!()
    }

    fn read_map<T, F>(&mut self, f: F) -> DecodeResult<T>
        where F: FnOnce(&mut Reader<'a>, usize) -> DecodeResult<T>
    {
        self.byte_reader.read_byte().map_err(|e| DecoderError::ParserError(e)).and_then(|t| map_decode(self, t, |d, len| f(d, len)))
    }
}

fn tag_to_str(tag: u8) -> Result<&'static str, DecoderError> {
    match tag {
        b'0'...b'9' | TAG_INTEGER => Ok("i32"),
        TAG_LONG => Ok("big int"),
        TAG_DOUBLE => Ok("f64"),
        TAG_NULL => Ok("nil"),
        TAG_EMPTY => Ok("empty string"),
        TAG_TRUE => Ok("true"),
        TAG_FALSE => Ok("false"),
        TAG_NAN => Ok("NaN"),
        TAG_INFINITY => Ok("Infinity"),
        TAG_DATE | TAG_TIME => Ok("time"),
        TAG_BYTES => Ok("bytes"),
        TAG_UTF8_CHAR | TAG_STRING => Ok("string"),
        TAG_GUID => Ok("GUID"),
        TAG_LIST => Ok("slice"),
        TAG_MAP => Ok("map"),
        TAG_CLASS | TAG_OBJECT => Ok("struct"),
        TAG_REF => Ok("reference"),
        _ => Err(DecoderError::UnexpectedTag(tag, None))
    }
}

pub fn cast_error(tag: u8, dst_type: &'static str) -> DecoderError {
    tag_to_str(tag)
        .map(|src_type| DecoderError::CastError(src_type, dst_type))
        .unwrap_or_else(|e| e)
}

#[cfg(test)]
mod tests {
    use super::test::Bencher;
    use super::super::*;

    use std::collections::HashMap;

    #[bench]
    fn benchmark_unserialize_bool(b: &mut Bencher) {
        let bytes = Writer::new(true).serialize(&true).bytes();
        b.bytes = bytes.len() as u64;
        b.iter(|| {
            Reader::new(&bytes, true).unserialize::<bool>().unwrap();
        });
    }

    #[bench]
    fn benchmark_unserialize_i64(b: &mut Bencher) {
        let bytes = Writer::new(true).serialize(&12345).bytes();
        b.bytes = bytes.len() as u64;
        b.iter(|| {
            Reader::new(&bytes, true).unserialize::<i64>().unwrap();
        });
    }

    #[bench]
    fn benchmark_unserialize_str(b: &mut Bencher) {
        let bytes = Writer::new(true).serialize("你好，🇨🇳").bytes();
        b.bytes = bytes.len() as u64;
        b.iter(|| {
            Reader::new(&bytes, true).unserialize::<String>().unwrap();
        });
    }

    #[bench]
    fn benchmark_unserialize_map(b: &mut Bencher) {
        let mut map = HashMap::new();
        map.insert("name", "Tom");
        map.insert("国家", "🇨🇳");
        let bytes = Writer::new(true).serialize(&map).bytes();
        b.bytes = bytes.len() as u64;
        b.iter(|| {
            Reader::new(&bytes, true).unserialize::<HashMap<String, String>>().unwrap();
        });
    }
}
<|endoftext|>


<commit_before>use super::Opcode;
use utils::u256::U256;
use vm::{Machine, Memory, Stack, PC};

// TODO: deal with gas limit and other Ethereum-specific things.

fn signed_abs(v: U256) -> U256 {
    let negative: U256 = U256::one() << 256;

    if v >= negative {
        !v + 1.into()
    } else {
        v
    }
}

impl Opcode {
    pub fn run<M: Memory, S: Stack>(&self, machine: &mut Machine<M, S>) {
        let pc = &mut machine.pc;
        let memory = &mut machine.memory;
        let stack = &mut machine.stack;
        let opcode = self.clone();

        match opcode {
            Opcode::STOP => {
                pc.stop();
            },

            Opcode::ADD => {
                let op1 = stack.pop();
                let op2 = stack.pop();
                stack.push(op1 + op2);
            },

            Opcode::MUL => {
                let op1 = stack.pop();
                let op2 = stack.pop();
                stack.push(op1 * op2);
            },

            Opcode::SUB => {
                let op1 = stack.pop();
                let op2 = stack.pop();
                stack.push(op1 - op2);
            },

            Opcode::DIV => {
                let op1 = stack.pop();
                let op2 = stack.pop();
                if op2 == 0.into() {
                    stack.push(0.into());
                } else {
                    stack.push(op1 / op2);
                }
            },

            Opcode::SDIV => {
                // This is signed division. So the U256 would need to
                // be treated as signed two's complement. We currently
                // convert it to both positive, and then deal with the
                // sign afterwards...

                let negative: U256 = U256::one() << 256;
                // This value is also -2^255 in two's complement.
                let max: U256 = U256::max_value();
                // This value is also -1 in two's complement.

                let op1 = stack.pop();
                let op2 = stack.pop();
                if op2 == 0.into() {
                    stack.push(0.into());
                } else if op1 == negative && op2 == max {
                    stack.push(negative);
                } else {
                    let aop1 = signed_abs(op1);
                    let aop2 = signed_abs(op2);
                    let r = op1 / op2;

                    if (op1 < negative && op2 < negative) || (op1 >= negative && op2 >= negative) {
                        stack.push(r);
                    } else {
                        let sr = !r + 1.into();
                        stack.push(sr);
                    }
                }
            },

            Opcode::MOD => {
                let op1 = stack.pop();
                let op2 = stack.pop();

                if op2 == 0.into() {
                    stack.push(0.into());
                } else {
                    stack.push(op1 - (op1 / op2) * op2);
                }
            },

            Opcode::SMOD => {
                let negative: U256 = U256::one() << 256;

                let op1 = stack.pop();
                let op2 = stack.pop();

                if op2 == 0.into() {
                    stack.push(0.into());
                } else {
                    let aop1 = signed_abs(op1);
                    let aop2 = signed_abs(op2);
                    let r = aop1 - (aop1 / aop2) * aop2;
                    if op1 < negative && op2 < negative {
                        stack.push(r);
                    } else if op1 >= negative && op2 < negative {
                        stack.push(!(op1 + r) + 1.into());
                    } else if op1 < negative && op2 >= negative {
                        stack.push(op1 + r);
                    } else if op1 >= negative && op2 >= negative {
                        stack.push(!r + 1.into());
                    }
                }
            },

            Opcode::ADDMOD => {
                let op1 = stack.pop();
                let op2 = stack.pop();
                let op3 = stack.pop();

                if op3 == 0.into() {
                    stack.push(0.into());
                } else {
                    // TODO: Handle the case where op1 + op2 > 2^256
                    let v = op1 + op2;
                    stack.push(v - (v / op3) * op3);
                }
            },

            Opcode::MULMOD => {
                let op1 = stack.pop();
                let op2 = stack.pop();
                let op3 = stack.pop();

                if op3 == 0.into() {
                    stack.push(0.into());
                } else {
                    // TODO: Handle the case where op1 * op2 > 2^256
                    let v = op1 * op2;
                    stack.push(v - (v / op3) * op3);
                }
            },

            Opcode::EXP => {
                let op1 = stack.pop();
                let mut op2 = stack.pop();
                let mut r: U256 = 1.into();

                while op2 != 0.into() {
                    r = r * op1;
                    op2 = op2 - 1.into();
                }
                stack.push(r);
            },

            Opcode::GT => {
                let op1 = stack.pop();
                let op2 = stack.pop();
                if op1 > op2 {
                    stack.push(op1);
                } else {
                    stack.push(op2);
                }
            }

            Opcode::LT => {
                let op1 = stack.pop();
                let op2 = stack.pop();
                if op1 < op2 {
                    stack.push(op1);
                } else {
                    stack.push(op2);
                }
            }

            // TODO: implement omitted opcodes.

            Opcode::PUSH(v) => {
                let val = pc.read(v);
                stack.push(val);
            },

            _ => {
                unimplemented!();
            }
        }
    }
}
<commit_msg>Problem: SIGNEXTEND is not implemented Solution: Implement it!<commit_after>use super::Opcode;
use utils::u256::U256;
use vm::{Machine, Memory, Stack, PC};

// TODO: deal with gas limit and other Ethereum-specific things.

fn signed_abs(v: U256) -> U256 {
    let negative: U256 = U256::one() << 256;

    if v >= negative {
        !v + 1.into()
    } else {
        v
    }
}

impl Opcode {
    pub fn run<M: Memory, S: Stack>(&self, machine: &mut Machine<M, S>) {
        let pc = &mut machine.pc;
        let memory = &mut machine.memory;
        let stack = &mut machine.stack;
        let opcode = self.clone();

        match opcode {
            Opcode::STOP => {
                pc.stop();
            },

            Opcode::ADD => {
                let op1 = stack.pop();
                let op2 = stack.pop();
                stack.push(op1 + op2);
            },

            Opcode::MUL => {
                let op1 = stack.pop();
                let op2 = stack.pop();
                stack.push(op1 * op2);
            },

            Opcode::SUB => {
                let op1 = stack.pop();
                let op2 = stack.pop();
                stack.push(op1 - op2);
            },

            Opcode::DIV => {
                let op1 = stack.pop();
                let op2 = stack.pop();
                if op2 == 0.into() {
                    stack.push(0.into());
                } else {
                    stack.push(op1 / op2);
                }
            },

            Opcode::SDIV => {
                // This is signed division. So the U256 would need to
                // be treated as signed two's complement. We currently
                // convert it to both positive, and then deal with the
                // sign afterwards...

                let negative: U256 = U256::one() << 256;
                // This value is also -2^255 in two's complement.
                let max: U256 = U256::max_value();
                // This value is also -1 in two's complement.

                let op1 = stack.pop();
                let op2 = stack.pop();
                if op2 == 0.into() {
                    stack.push(0.into());
                } else if op1 == negative && op2 == max {
                    stack.push(negative);
                } else {
                    let aop1 = signed_abs(op1);
                    let aop2 = signed_abs(op2);
                    let r = op1 / op2;

                    if (op1 < negative && op2 < negative) || (op1 >= negative && op2 >= negative) {
                        stack.push(r);
                    } else {
                        let sr = !r + 1.into();
                        stack.push(sr);
                    }
                }
            },

            Opcode::MOD => {
                let op1 = stack.pop();
                let op2 = stack.pop();

                if op2 == 0.into() {
                    stack.push(0.into());
                } else {
                    stack.push(op1 - (op1 / op2) * op2);
                }
            },

            Opcode::SMOD => {
                let negative: U256 = U256::one() << 256;

                let op1 = stack.pop();
                let op2 = stack.pop();

                if op2 == 0.into() {
                    stack.push(0.into());
                } else {
                    let aop1 = signed_abs(op1);
                    let aop2 = signed_abs(op2);
                    let r = aop1 - (aop1 / aop2) * aop2;
                    if op1 < negative && op2 < negative {
                        stack.push(r);
                    } else if op1 >= negative && op2 < negative {
                        stack.push(!(op1 + r) + 1.into());
                    } else if op1 < negative && op2 >= negative {
                        stack.push(op1 + r);
                    } else if op1 >= negative && op2 >= negative {
                        stack.push(!r + 1.into());
                    }
                }
            },

            Opcode::ADDMOD => {
                let op1 = stack.pop();
                let op2 = stack.pop();
                let op3 = stack.pop();

                if op3 == 0.into() {
                    stack.push(0.into());
                } else {
                    // TODO: Handle the case where op1 + op2 > 2^256
                    let v = op1 + op2;
                    stack.push(v - (v / op3) * op3);
                }
            },

            Opcode::MULMOD => {
                let op1 = stack.pop();
                let op2 = stack.pop();
                let op3 = stack.pop();

                if op3 == 0.into() {
                    stack.push(0.into());
                } else {
                    // TODO: Handle the case where op1 * op2 > 2^256
                    let v = op1 * op2;
                    stack.push(v - (v / op3) * op3);
                }
            },

            Opcode::EXP => {
                let op1 = stack.pop();
                let mut op2 = stack.pop();
                let mut r: U256 = 1.into();

                while op2 != 0.into() {
                    r = r * op1;
                    op2 = op2 - 1.into();
                }
                stack.push(r);
            },

            Opcode::SIGNEXTEND => {
                // TODO: Check this confines with the yello paper

                let mut op1 = stack.pop();
                let mut op2 = stack.pop();

                let mut negative: U256 = 1.into();
                let mut s = 0;
                while op2 != 0.into() {
                    negative = U256::one() << s;
                    s = s + 1;
                    op2 = op2 - 1.into();
                }

                if op1 >= negative {
                    while s <= 256 {
                        op1 = op1 + (U256::one() << s);
                        s = s + 1;
                    }
                    stack.push(op1);
                } else {
                    stack.push(op1);
                }
            },

            Opcode::GT => {
                let op1 = stack.pop();
                let op2 = stack.pop();
                if op1 > op2 {
                    stack.push(op1);
                } else {
                    stack.push(op2);
                }
            }

            Opcode::LT => {
                let op1 = stack.pop();
                let op2 = stack.pop();
                if op1 < op2 {
                    stack.push(op1);
                } else {
                    stack.push(op2);
                }
            }

            // TODO: implement omitted opcodes.

            Opcode::PUSH(v) => {
                let val = pc.read(v);
                stack.push(val);
            },

            _ => {
                unimplemented!();
            }
        }
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * 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.
 */

use std::collections::BTreeMap;
use std::collections::BTreeSet;
use std::collections::HashMap;
use std::collections::HashSet;
use std::hash::Hash;

use bytes::Bytes;
use ordered_float::OrderedFloat;

use crate::errors::ProtocolError;
use crate::Result;

/// Will be able to add missing types once #![feature(associated_consts)] lands
#[derive(PartialEq, Copy, Clone, Debug)]
#[repr(u8)]
pub enum TType {
    Stop = 0,
    Void = 1,
    Bool = 2,
    Byte = 3,
    // I08    = 3,
    Double = 4,
    I16 = 6,
    I32 = 8,
    I64 = 10,
    String = 11,
    // UTF7   = 11,
    Struct = 12,
    Map = 13,
    Set = 14,
    List = 15,
    UTF8 = 16,
    UTF16 = 17,
    Stream = 18,
    Float = 19,
}

impl TryFrom<i8> for TType {
    type Error = anyhow::Error;

    fn try_from(val: i8) -> Result<Self> {
        let ret = match val {
            0 => TType::Stop,
            1 => TType::Void,
            2 => TType::Bool,
            3 => TType::Byte,
            4 => TType::Double,
            6 => TType::I16,
            8 => TType::I32,
            10 => TType::I64,
            11 => TType::String,
            12 => TType::Struct,
            13 => TType::Map,
            14 => TType::Set,
            15 => TType::List,
            16 => TType::UTF8,
            17 => TType::UTF16,
            18 => TType::Stream,
            19 => TType::Float,
            _ => bail_err!(ProtocolError::InvalidTypeTag),
        };
        Ok(ret)
    }
}

impl From<TType> for String {
    fn from(t: TType) -> String {
        let tmp: &str = t.into();
        tmp.to_owned()
    }
}

impl From<TType> for &'static str {
    fn from(t: TType) -> &'static str {
        match t {
            TType::Stop => "STOP",
            TType::Void => "VOID",
            TType::Bool => "BOOL",
            TType::Byte => "BYTE",
            // TType::I08 => "I08",
            TType::Double => "DOUBLE",
            TType::I16 => "I16",
            TType::I32 => "I32",
            TType::I64 => "I64",
            TType::String => "STRING",
            // TType::UTF7 => "UTF7",
            TType::Struct => "STRUCT",
            TType::Map => "MAP",
            TType::Set => "SET",
            TType::List => "LIST",
            TType::UTF8 => "UTF8",
            TType::UTF16 => "UTF16",
            TType::Stream => "STREAM",
            TType::Float => "FLOAT",
        }
    }
}

// Get the ttype for a given type
pub trait GetTType {
    const TTYPE: TType;
}

impl GetTType for () {
    const TTYPE: TType = TType::Void;
}

impl GetTType for bool {
    const TTYPE: TType = TType::Bool;
}

impl GetTType for i8 {
    const TTYPE: TType = TType::Byte;
}

impl GetTType for i16 {
    const TTYPE: TType = TType::I16;
}

impl GetTType for i32 {
    const TTYPE: TType = TType::I32;
}

impl GetTType for i64 {
    const TTYPE: TType = TType::I64;
}

impl GetTType for f64 {
    const TTYPE: TType = TType::Double;
}

impl GetTType for f32 {
    const TTYPE: TType = TType::Float;
}

impl GetTType for OrderedFloat<f64> {
    const TTYPE: TType = TType::Double;
}

impl GetTType for OrderedFloat<f32> {
    const TTYPE: TType = TType::Float;
}

impl GetTType for String {
    const TTYPE: TType = TType::String;
}

impl GetTType for Bytes {
    const TTYPE: TType = TType::String;
}

// This only narrowly avoids a collision with Vec<T>, because
// it requires T: GetTType, but u8 does not impl it (only i8).
impl GetTType for Vec<u8> {
    const TTYPE: TType = TType::String;
}

impl<T> GetTType for BTreeSet<T>
where
    T: GetTType + Ord,
{
    const TTYPE: TType = TType::Set;
}

impl<T, S> GetTType for HashSet<T, S>
where
    T: GetTType + Hash + Eq,
    S: std::hash::BuildHasher,
{
    const TTYPE: TType = TType::Set;
}

impl<K, V> GetTType for BTreeMap<K, V>
where
    K: GetTType + Ord,
    V: GetTType,
{
    const TTYPE: TType = TType::Map;
}

impl<K, V, S> GetTType for HashMap<K, V, S>
where
    K: GetTType + Hash + Eq,
    V: GetTType,
    S: std::hash::BuildHasher,
{
    const TTYPE: TType = TType::Map;
}

impl<T> GetTType for Vec<T>
where
    T: GetTType,
{
    const TTYPE: TType = TType::List;
}
<commit_msg>Inline `TType::try_from`.<commit_after>/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * 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.
 */

use std::collections::BTreeMap;
use std::collections::BTreeSet;
use std::collections::HashMap;
use std::collections::HashSet;
use std::hash::Hash;

use bytes::Bytes;
use ordered_float::OrderedFloat;

use crate::errors::ProtocolError;
use crate::Result;

/// Will be able to add missing types once #![feature(associated_consts)] lands
#[derive(PartialEq, Copy, Clone, Debug)]
#[repr(u8)]
pub enum TType {
    Stop = 0,
    Void = 1,
    Bool = 2,
    Byte = 3,
    // I08    = 3,
    Double = 4,
    I16 = 6,
    I32 = 8,
    I64 = 10,
    String = 11,
    // UTF7   = 11,
    Struct = 12,
    Map = 13,
    Set = 14,
    List = 15,
    UTF8 = 16,
    UTF16 = 17,
    Stream = 18,
    Float = 19,
}

impl TryFrom<i8> for TType {
    type Error = anyhow::Error;

    #[inline]
    fn try_from(val: i8) -> Result<Self> {
        let ret = match val {
            0 => TType::Stop,
            1 => TType::Void,
            2 => TType::Bool,
            3 => TType::Byte,
            4 => TType::Double,
            6 => TType::I16,
            8 => TType::I32,
            10 => TType::I64,
            11 => TType::String,
            12 => TType::Struct,
            13 => TType::Map,
            14 => TType::Set,
            15 => TType::List,
            16 => TType::UTF8,
            17 => TType::UTF16,
            18 => TType::Stream,
            19 => TType::Float,
            _ => bail_err!(ProtocolError::InvalidTypeTag),
        };
        Ok(ret)
    }
}

impl From<TType> for String {
    fn from(t: TType) -> String {
        let tmp: &str = t.into();
        tmp.to_owned()
    }
}

impl From<TType> for &'static str {
    fn from(t: TType) -> &'static str {
        match t {
            TType::Stop => "STOP",
            TType::Void => "VOID",
            TType::Bool => "BOOL",
            TType::Byte => "BYTE",
            // TType::I08 => "I08",
            TType::Double => "DOUBLE",
            TType::I16 => "I16",
            TType::I32 => "I32",
            TType::I64 => "I64",
            TType::String => "STRING",
            // TType::UTF7 => "UTF7",
            TType::Struct => "STRUCT",
            TType::Map => "MAP",
            TType::Set => "SET",
            TType::List => "LIST",
            TType::UTF8 => "UTF8",
            TType::UTF16 => "UTF16",
            TType::Stream => "STREAM",
            TType::Float => "FLOAT",
        }
    }
}

// Get the ttype for a given type
pub trait GetTType {
    const TTYPE: TType;
}

impl GetTType for () {
    const TTYPE: TType = TType::Void;
}

impl GetTType for bool {
    const TTYPE: TType = TType::Bool;
}

impl GetTType for i8 {
    const TTYPE: TType = TType::Byte;
}

impl GetTType for i16 {
    const TTYPE: TType = TType::I16;
}

impl GetTType for i32 {
    const TTYPE: TType = TType::I32;
}

impl GetTType for i64 {
    const TTYPE: TType = TType::I64;
}

impl GetTType for f64 {
    const TTYPE: TType = TType::Double;
}

impl GetTType for f32 {
    const TTYPE: TType = TType::Float;
}

impl GetTType for OrderedFloat<f64> {
    const TTYPE: TType = TType::Double;
}

impl GetTType for OrderedFloat<f32> {
    const TTYPE: TType = TType::Float;
}

impl GetTType for String {
    const TTYPE: TType = TType::String;
}

impl GetTType for Bytes {
    const TTYPE: TType = TType::String;
}

// This only narrowly avoids a collision with Vec<T>, because
// it requires T: GetTType, but u8 does not impl it (only i8).
impl GetTType for Vec<u8> {
    const TTYPE: TType = TType::String;
}

impl<T> GetTType for BTreeSet<T>
where
    T: GetTType + Ord,
{
    const TTYPE: TType = TType::Set;
}

impl<T, S> GetTType for HashSet<T, S>
where
    T: GetTType + Hash + Eq,
    S: std::hash::BuildHasher,
{
    const TTYPE: TType = TType::Set;
}

impl<K, V> GetTType for BTreeMap<K, V>
where
    K: GetTType + Ord,
    V: GetTType,
{
    const TTYPE: TType = TType::Map;
}

impl<K, V, S> GetTType for HashMap<K, V, S>
where
    K: GetTType + Hash + Eq,
    V: GetTType,
    S: std::hash::BuildHasher,
{
    const TTYPE: TType = TType::Map;
}

impl<T> GetTType for Vec<T>
where
    T: GetTType,
{
    const TTYPE: TType = TType::List;
}
<|endoftext|>


<commit_before>use std::fmt;

#[derive(Debug)]
struct Structure(i32);

#[derive(Debug)]
struct Deep(Structure);

impl fmt::Display for Structure {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

// A structure holding 2 numbers `Debug` will be derived so the results can be contrasted with `Display`
#[derive(Debug)]
struct MinMax(i64, i64);

impl fmt::Display for MinMax {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({}, {})", self.0, self.1)
    }
}

// Define a structure where the fields are nameable for comparison.
#[derive(Debug)]
struct Point2 {
    x: f64,
    y: f64,
}

// Similarly, implement for Point2
impl fmt::Display for Point2 {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // Customize so only `x` and `y` are denoted.
        write!(f, "{{ x: {}, y: {} }}", self.x, self.y)
    }
}

fn main() {
    println!("Hello, formatted print!");

    println!("Arg 1:{} and arg 2:{}", "first", "second");

    println!("Args can be named: {first} and {second}", first=1, second="two");

    println!("We can fmt binary! {:b}", 5);

    println!("We can align text with spaces or zeros: {number:>width$}, {number:>0width$}",
             number=3,
             width=6);

    let pi: f32 = 3.14159;

    let pi_3 = format!("{:.3}", pi);
    let pi_5 = format!("{:.5}", pi);

    println!("Pi to 3 places: {} and to 5 places: {}", pi_3, pi_5);

    // e, pi, & golden ratio
    let special_nums = vec![2.71828, 3.14159, 1.61803];

    // some iteration over a vector.
    for special_num in &special_nums {
        println!("This is a special number: {val:.3}", val=special_num);
    }

    println!("\nDebugging stuff:");

    println!("Now {:?} is a thing!", Structure(3));

    println!("And Deep: {:?}", Deep(Structure(3)));

    println!("A MinMax: debug: {obj:?}  display: {obj}", obj=MinMax(23, 56));
    println!("A Point : debug: {obj:?}  display: {obj}", obj=Point2 { x: 3.3, y: 56. })

}
<commit_msg>Add Complex struct<commit_after>use std::fmt;

#[derive(Debug)]
struct Structure(i32);

#[derive(Debug)]
struct Deep(Structure);

impl fmt::Display for Structure {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

// A structure holding 2 numbers `Debug` will be derived so the results can be contrasted with `Display`
#[derive(Debug)]
struct MinMax(i64, i64);

impl fmt::Display for MinMax {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({}, {})", self.0, self.1)
    }
}

// Define a structure where the fields are nameable for comparison.
#[derive(Debug)]
struct Point2 {
    x: f64,
    y: f64,
}

// Similarly, implement for Point2
impl fmt::Display for Point2 {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // Customize so only `x` and `y` are denoted.
        write!(f, "{{ x: {}, y: {} }}", self.x, self.y)
    }
}

// My Complex structure
struct Complex {
    real: f64,
    imag: f64,
}

impl fmt::Display for Complex {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{real} + {imag}i", real=self.real, imag=self.imag)
    }
}

impl fmt::Debug for Complex {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Complex {{ real: {real}, imag: {imag} }}", real=self.real, imag=self.imag)
    }
}

fn main() {
    println!("Hello, formatted print!");

    println!("Arg 1:{} and arg 2:{}", "first", "second");

    println!("Args can be named: {first} and {second}", first=1, second="two");

    println!("We can fmt binary! {:b}", 5);

    println!("We can align text with spaces or zeros: {number:>width$}, {number:>0width$}",
             number=3,
             width=6);

    let pi: f32 = 3.14159;

    let pi_3 = format!("{:.3}", pi);
    let pi_5 = format!("{:.5}", pi);

    println!("Pi to 3 places: {} and to 5 places: {}", pi_3, pi_5);

    // e, pi, & golden ratio
    let special_nums = vec![2.71828, 3.14159, 1.61803];

    // some iteration over a vector.
    for special_num in &special_nums {
        println!("This is a special number: {val:.3}", val=special_num);
    }

    println!("\nDebugging stuff:");

    println!("Now {:?} is a thing!", Structure(3));

    println!("And Deep: {:?}", Deep(Structure(3)));

    println!("A MinMax: debug: {obj:?}  display: {obj}", obj=MinMax(23, 56));
    println!("A Point : debug: {obj:?}  display: {obj}", obj=Point2 { x: 3.3, y: 56. });
    println!("My Complex struct: {0}  Debugged: {0:?}", Complex { real: 4.6, imag: 8.9 });
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright (c) 2016 Jacob Peddicord <jacob@peddicord.net>
 */

use std::error::Error;
use std::ffi::CString;
use std::fs::{File, remove_file, remove_dir_all};
use std::path::{Path, PathBuf};
use libc::chown;
use walkdir::WalkDir;

pub fn own_path(path: &Path, uid: u32) -> Result<(), Box<Error>> {
    let path_str = match path.to_str() {
        Some(s) => s,
        None => return Err(From::from(format!("empty CString from path {}", path.display()))),
    };
    unsafe {
        let path_ptr = try!(CString::new(path_str)).as_ptr();
        if chown(path_ptr, uid, uid) != 0 {
            return Err(From::from(format!("chown failed on path {}", path.display())));
        }
    }
    Ok(())
}

pub fn own_dir(dir: &Path, uid: u32) -> Result<(), Box<Error>> {
    for entry in WalkDir::new(dir) {
        // there should never be any files that we can't chown here, but check anyway
        let e = try!(entry);
        try!(own_path(e.path(), uid));
    }
    Ok(())
}

pub struct Lock {
    path: PathBuf,
    pub uid: u32,
}

impl Lock {
    pub fn new(path: &Path, uid: u32) -> Result<Lock, Box<Error>> {
        try!(File::create(path));
        try!(own_path(path, uid));
        Ok(Lock {
               path: path.to_path_buf(),
               uid: uid,
           })
    }
}

impl Drop for Lock {
    fn drop(&mut self) {
        remove_file(self.path.as_path()).unwrap();
    }
}

pub struct OwnedDir {
    path: PathBuf,
}

impl OwnedDir {
    pub fn new(path: &Path, uid: u32) -> Result<OwnedDir, Box<Error>> {
        try!(own_dir(path, uid));
        Ok(OwnedDir { path: path.to_path_buf() })
    }
}

impl Drop for OwnedDir {
    fn drop(&mut self) {
        remove_dir_all(self.path.as_path()).unwrap();
    }
}
<commit_msg>Fix a scary memory bug<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright (c) 2016 Jacob Peddicord <jacob@peddicord.net>
 */

use std::io::Error as IOError;
use std::error::Error;
use std::ffi::CString;
use std::fs::{File, remove_file, remove_dir_all};
use std::path::{Path, PathBuf};
use libc::chown;
use walkdir::WalkDir;

pub fn own_path(path: &Path, uid: u32) -> Result<(), Box<Error>> {
    let path_str = match path.to_str() {
        Some(s) => s,
        None => return Err(From::from(format!("empty string from path {}", path.display()))),
    };
    // path and pointer must be separate! otherwise cpath will get deallocated too soon
    // (you can see it happen easily on a musl libc build)
    let cpath = try!(CString::new(path_str));
    let ptr = cpath.as_ptr();
    unsafe {
        if chown(ptr, uid, uid) != 0 {
            return Err(From::from(format!("chown failed on path {}: {:?}",
                                          path.display(),
                                          IOError::last_os_error())));
        }
    }
    Ok(())
}

pub fn own_dir(dir: &Path, uid: u32) -> Result<(), Box<Error>> {
    for entry in WalkDir::new(dir) {
        // there should never be any files that we can't chown here, but check anyway
        let e = try!(entry);
        try!(own_path(e.path(), uid));
    }
    Ok(())
}

pub struct Lock {
    path: PathBuf,
    pub uid: u32,
}

impl Lock {
    pub fn new(path: &Path, uid: u32) -> Result<Lock, Box<Error>> {
        try!(File::create(path));
        try!(own_path(path, uid));
        Ok(Lock {
               path: path.to_path_buf(),
               uid: uid,
           })
    }
}

impl Drop for Lock {
    fn drop(&mut self) {
        remove_file(self.path.as_path()).unwrap();
    }
}

pub struct OwnedDir {
    path: PathBuf,
}

impl OwnedDir {
    pub fn new(path: &Path, uid: u32) -> Result<OwnedDir, Box<Error>> {
        try!(own_dir(path, uid));
        Ok(OwnedDir { path: path.to_path_buf() })
    }
}

impl Drop for OwnedDir {
    fn drop(&mut self) {
        remove_dir_all(self.path.as_path()).unwrap();
    }
}
<|endoftext|>


<commit_before>//! # ACPI
//! Code to parse the ACPI tables

use core::intrinsics::{atomic_load, atomic_store};
use core::sync::atomic::Ordering;

use spin::Mutex;

use device::local_apic::LOCAL_APIC;
use interrupt;
use memory::{allocate_frames, Frame};
use paging::{entry, ActivePageTable, Page, PhysicalAddress, VirtualAddress};
use start::{kstart_ap, CPU_COUNT, AP_READY};

use self::dmar::{Dmar, DmarEntry};
use self::dsdt::Dsdt;
use self::fadt::Fadt;
use self::madt::{Madt, MadtEntry};
use self::rsdt::Rsdt;
use self::sdt::Sdt;
use self::xsdt::Xsdt;

mod dmar;
mod dsdt;
mod fadt;
mod madt;
mod rsdt;
mod sdt;
mod xsdt;

const TRAMPOLINE: usize = 0x7E00;
const AP_STARTUP: usize = TRAMPOLINE + 512;

fn get_sdt(sdt_address: usize, active_table: &mut ActivePageTable) -> &'static Sdt {
    {
        let page = Page::containing_address(VirtualAddress::new(sdt_address));
        if active_table.translate_page(page).is_none() {
            let frame = Frame::containing_address(PhysicalAddress::new(page.start_address().get()));
            let result = active_table.map_to(page, frame, entry::PRESENT | entry::NO_EXECUTE);
            result.flush(active_table);
        }
    }

    let sdt = unsafe { &*(sdt_address as *const Sdt) };

    // Map extra SDT frames if required
    {
        let start_page = Page::containing_address(VirtualAddress::new(sdt_address + 4096));
        let end_page = Page::containing_address(VirtualAddress::new(sdt_address + sdt.length as usize));
        for page in Page::range_inclusive(start_page, end_page) {
            if active_table.translate_page(page).is_none() {
                let frame = Frame::containing_address(PhysicalAddress::new(page.start_address().get()));
                let result = active_table.map_to(page, frame, entry::PRESENT | entry::NO_EXECUTE);
                result.flush(active_table);
            }
        }
    }

    sdt
}

fn parse_sdt(sdt: &'static Sdt, active_table: &mut ActivePageTable) {
    print!("  ");
    for &c in sdt.signature.iter() {
        print!("{}", c as char);
    }

    if let Some(fadt) = Fadt::new(sdt) {
        println!(": {:X}", fadt.dsdt);
        let dsdt = get_sdt(fadt.dsdt as usize, active_table);
        parse_sdt(dsdt, active_table);
        ACPI_TABLE.lock().fadt = Some(fadt);
    } else if let Some(dsdt) = Dsdt::new(sdt) {
        println!(": {}", dsdt.data().len());
        ACPI_TABLE.lock().dsdt = Some(dsdt);
    } else if let Some(madt) = Madt::new(sdt) {
        println!(": {:>08X}: {}", madt.local_address, madt.flags);

        let mut local_apic = unsafe { &mut LOCAL_APIC };

        let me = local_apic.id() as u8;

        if local_apic.x2 {
            println!("    X2APIC {}", me);
        } else {
            println!("    XAPIC {}: {:>08X}", me, local_apic.address);
        }

        let trampoline_frame = Frame::containing_address(PhysicalAddress::new(TRAMPOLINE));
        let trampoline_page = Page::containing_address(VirtualAddress::new(TRAMPOLINE));

        // Map trampoline
        let result = active_table.map_to(trampoline_page, trampoline_frame, entry::PRESENT | entry::WRITABLE);
        result.flush(active_table);

        for madt_entry in madt.iter() {
            println!("      {:?}", madt_entry);
            match madt_entry {
                MadtEntry::LocalApic(ap_local_apic) => if ap_local_apic.id == me {
                    println!("        This is my local APIC");
                } else {
                    if ap_local_apic.flags & 1 == 1 {
                        // Increase CPU ID
                        CPU_COUNT.fetch_add(1, Ordering::SeqCst);

                        // Allocate a stack
                        let stack_start = allocate_frames(64).expect("no more frames in acpi stack_start").start_address().get() + ::KERNEL_OFFSET;
                        let stack_end = stack_start + 64 * 4096;

                        let ap_ready = TRAMPOLINE as *mut u64;
                        let ap_cpu_id = unsafe { ap_ready.offset(1) };
                        let ap_page_table = unsafe { ap_ready.offset(2) };
                        let ap_stack_start = unsafe { ap_ready.offset(3) };
                        let ap_stack_end = unsafe { ap_ready.offset(4) };
                        let ap_code = unsafe { ap_ready.offset(5) };

                        // Set the ap_ready to 0, volatile
                        unsafe { atomic_store(ap_ready, 0) };
                        unsafe { atomic_store(ap_cpu_id, ap_local_apic.id as u64) };
                        unsafe { atomic_store(ap_page_table, active_table.address() as u64) };
                        unsafe { atomic_store(ap_stack_start, stack_start as u64) };
                        unsafe { atomic_store(ap_stack_end, stack_end as u64) };
                        unsafe { atomic_store(ap_code, kstart_ap as u64) };
                        AP_READY.store(false, Ordering::SeqCst);

                        print!("        AP {}:", ap_local_apic.id);

                        // Send INIT IPI
                        {
                            let mut icr = 0x4500;
                            if local_apic.x2 {
                                icr |= (ap_local_apic.id as u64) << 32;
                            } else {
                                icr |= (ap_local_apic.id as u64) << 56;
                            }
                            print!(" IPI...");
                            local_apic.set_icr(icr);
                        }

                        // Send START IPI
                        {
                            //Start at 0x0800:0000 => 0x8000. Hopefully the bootloader code is still there
                            let ap_segment = (AP_STARTUP >> 12) & 0xFF;
                            let mut icr = 0x4600 | ap_segment as u64;

                            if local_apic.x2 {
                                icr |= (ap_local_apic.id as u64) << 32;
                            } else {
                                icr |= (ap_local_apic.id as u64) << 56;
                            }

                            print!(" SIPI...");
                            local_apic.set_icr(icr);
                        }

                        // Wait for trampoline ready
                        print!(" Wait...");
                        while unsafe { atomic_load(ap_ready) } == 0 {
                            interrupt::pause();
                        }
                        print!(" Trampoline...");
                        while ! AP_READY.load(Ordering::SeqCst) {
                            interrupt::pause();
                        }
                        println!(" Ready");

                        active_table.flush_all();
                    } else {
                        println!("        CPU Disabled");
                    }
                },
                _ => ()
            }
        }

        // Unmap trampoline
        let result = active_table.unmap(trampoline_page);
        result.flush(active_table);
    } else if let Some(dmar) = Dmar::new(sdt) {
        println!(": {}: {}", dmar.addr_width, dmar.flags);

        for dmar_entry in dmar.iter() {
            println!("      {:?}", dmar_entry);
            match dmar_entry {
                DmarEntry::Drhd(dmar_drhd) => {
                    let drhd = dmar_drhd.get(active_table);

                    println!("VER: {:X}", drhd.version);
                    println!("CAP: {:X}", drhd.cap);
                    println!("EXT_CAP: {:X}", drhd.ext_cap);
                    println!("GCMD: {:X}", drhd.gl_cmd);
                    println!("GSTS: {:X}", drhd.gl_sts);
                    println!("RT: {:X}", drhd.root_table);
                },
                _ => ()
            }
        }
    } else {
        println!(": Unknown");
    }
}

/// Parse the ACPI tables to gather CPU, interrupt, and timer information
pub unsafe fn init(active_table: &mut ActivePageTable) {
    let start_addr = 0xE0000;
    let end_addr = 0xFFFFF;

    // Map all of the ACPI RSDP space
    {
        let start_frame = Frame::containing_address(PhysicalAddress::new(start_addr));
        let end_frame = Frame::containing_address(PhysicalAddress::new(end_addr));
        for frame in Frame::range_inclusive(start_frame, end_frame) {
            let page = Page::containing_address(VirtualAddress::new(frame.start_address().get()));
            let result = active_table.map_to(page, frame, entry::PRESENT | entry::NO_EXECUTE);
            result.flush(active_table);
        }
    }

    // Search for RSDP
    if let Some(rsdp) = RSDP::search(start_addr, end_addr) {
        let rxsdt = get_sdt(rsdp.sdt_address(), active_table);

        for &c in rxsdt.signature.iter() {
            print!("{}", c as char);
        }
        println!(":");
        if let Some(rsdt) = Rsdt::new(rxsdt) {
            for sdt_address in rsdt.iter() {
                let sdt = get_sdt(sdt_address, active_table);
                parse_sdt(sdt, active_table);
            }
        } else if let Some(xsdt) = Xsdt::new(rxsdt) {
            for sdt_address in xsdt.iter() {
                let sdt = get_sdt(sdt_address, active_table);
                parse_sdt(sdt, active_table);
            }
        } else {
            println!("UNKNOWN RSDT OR XSDT SIGNATURE");
        }
    } else {
        println!("NO RSDP FOUND");
    }

    /* TODO: Cleanup mapping when looking for RSDP
    // Unmap all of the ACPI RSDP space
    {
        let start_frame = Frame::containing_address(PhysicalAddress::new(start_addr));
        let end_frame = Frame::containing_address(PhysicalAddress::new(end_addr));
        for frame in Frame::range_inclusive(start_frame, end_frame) {
            let page = Page::containing_address(VirtualAddress::new(frame.start_address().get()));
            let result = active_table.unmap(page);
            result.flush(active_table);
        }
    }
    */
}

pub struct Acpi {
    pub fadt: Option<Fadt>,
    pub dsdt: Option<Dsdt>,
}

pub static ACPI_TABLE: Mutex<Acpi> = Mutex::new(Acpi { fadt: None, dsdt: None });

/// RSDP
#[derive(Copy, Clone, Debug)]
#[repr(packed)]
pub struct RSDP {
    signature: [u8; 8],
    checksum: u8,
    oemid: [u8; 6],
    revision: u8,
    rsdt_address: u32,
    length: u32,
    xsdt_address: u64,
    extended_checksum: u8,
    reserved: [u8; 3]
}

impl RSDP {
    /// Search for the RSDP
    pub fn search(start_addr: usize, end_addr: usize) -> Option<RSDP> {
        for i in 0 .. (end_addr + 1 - start_addr)/16 {
            let rsdp = unsafe { &*((start_addr + i * 16) as *const RSDP) };
            if &rsdp.signature == b"RSD PTR " {
                return Some(*rsdp);
            }
        }
        None
    }

    /// Get the RSDT or XSDT address
    pub fn sdt_address(&self) -> usize {
        if self.revision >= 2 {
            self.xsdt_address as usize
        } else {
            self.rsdt_address as usize
        }
    }
}
<commit_msg>Disable SMP startup, fix issue with reusing trampoline frame<commit_after>//! # ACPI
//! Code to parse the ACPI tables

use core::intrinsics::{atomic_load, atomic_store};
use core::sync::atomic::Ordering;

use spin::Mutex;

use device::local_apic::LOCAL_APIC;
use interrupt;
use memory::{allocate_frames, Frame};
use paging::{entry, ActivePageTable, Page, PhysicalAddress, VirtualAddress};
use start::{kstart_ap, CPU_COUNT, AP_READY};

use self::dmar::{Dmar, DmarEntry};
use self::dsdt::Dsdt;
use self::fadt::Fadt;
use self::madt::{Madt, MadtEntry};
use self::rsdt::Rsdt;
use self::sdt::Sdt;
use self::xsdt::Xsdt;

mod dmar;
mod dsdt;
mod fadt;
mod madt;
mod rsdt;
mod sdt;
mod xsdt;

const TRAMPOLINE: usize = 0x7E00;
const AP_STARTUP: usize = TRAMPOLINE + 512;

fn get_sdt(sdt_address: usize, active_table: &mut ActivePageTable) -> &'static Sdt {
    {
        let page = Page::containing_address(VirtualAddress::new(sdt_address));
        if active_table.translate_page(page).is_none() {
            let frame = Frame::containing_address(PhysicalAddress::new(page.start_address().get()));
            let result = active_table.map_to(page, frame, entry::PRESENT | entry::NO_EXECUTE);
            result.flush(active_table);
        }
    }

    let sdt = unsafe { &*(sdt_address as *const Sdt) };

    // Map extra SDT frames if required
    {
        let start_page = Page::containing_address(VirtualAddress::new(sdt_address + 4096));
        let end_page = Page::containing_address(VirtualAddress::new(sdt_address + sdt.length as usize));
        for page in Page::range_inclusive(start_page, end_page) {
            if active_table.translate_page(page).is_none() {
                let frame = Frame::containing_address(PhysicalAddress::new(page.start_address().get()));
                let result = active_table.map_to(page, frame, entry::PRESENT | entry::NO_EXECUTE);
                result.flush(active_table);
            }
        }
    }

    sdt
}

fn parse_sdt(sdt: &'static Sdt, active_table: &mut ActivePageTable) {
    print!("  ");
    for &c in sdt.signature.iter() {
        print!("{}", c as char);
    }

    if let Some(fadt) = Fadt::new(sdt) {
        println!(": {:X}", fadt.dsdt);
        let dsdt = get_sdt(fadt.dsdt as usize, active_table);
        parse_sdt(dsdt, active_table);
        ACPI_TABLE.lock().fadt = Some(fadt);
    } else if let Some(dsdt) = Dsdt::new(sdt) {
        println!(": {}", dsdt.data().len());
        ACPI_TABLE.lock().dsdt = Some(dsdt);
    } else if let Some(madt) = Madt::new(sdt) {
        println!(": {:>08X}: {}", madt.local_address, madt.flags);

        let mut local_apic = unsafe { &mut LOCAL_APIC };

        let me = local_apic.id() as u8;

        if local_apic.x2 {
            println!("    X2APIC {}", me);
        } else {
            println!("    XAPIC {}: {:>08X}", me, local_apic.address);
        }

        /*
        let trampoline_frame = Frame::containing_address(PhysicalAddress::new(TRAMPOLINE));
        let trampoline_page = Page::containing_address(VirtualAddress::new(TRAMPOLINE));

        // Map trampoline
        let result = active_table.map_to(trampoline_page, trampoline_frame, entry::PRESENT | entry::WRITABLE);
        result.flush(active_table);

        for madt_entry in madt.iter() {
            println!("      {:?}", madt_entry);
            match madt_entry {
                MadtEntry::LocalApic(ap_local_apic) => if ap_local_apic.id == me {
                    println!("        This is my local APIC");
                } else {
                    if ap_local_apic.flags & 1 == 1 {
                        // Increase CPU ID
                        CPU_COUNT.fetch_add(1, Ordering::SeqCst);

                        // Allocate a stack
                        let stack_start = allocate_frames(64).expect("no more frames in acpi stack_start").start_address().get() + ::KERNEL_OFFSET;
                        let stack_end = stack_start + 64 * 4096;

                        let ap_ready = TRAMPOLINE as *mut u64;
                        let ap_cpu_id = unsafe { ap_ready.offset(1) };
                        let ap_page_table = unsafe { ap_ready.offset(2) };
                        let ap_stack_start = unsafe { ap_ready.offset(3) };
                        let ap_stack_end = unsafe { ap_ready.offset(4) };
                        let ap_code = unsafe { ap_ready.offset(5) };

                        // Set the ap_ready to 0, volatile
                        unsafe { atomic_store(ap_ready, 0) };
                        unsafe { atomic_store(ap_cpu_id, ap_local_apic.id as u64) };
                        unsafe { atomic_store(ap_page_table, active_table.address() as u64) };
                        unsafe { atomic_store(ap_stack_start, stack_start as u64) };
                        unsafe { atomic_store(ap_stack_end, stack_end as u64) };
                        unsafe { atomic_store(ap_code, kstart_ap as u64) };
                        AP_READY.store(false, Ordering::SeqCst);

                        print!("        AP {}:", ap_local_apic.id);

                        // Send INIT IPI
                        {
                            let mut icr = 0x4500;
                            if local_apic.x2 {
                                icr |= (ap_local_apic.id as u64) << 32;
                            } else {
                                icr |= (ap_local_apic.id as u64) << 56;
                            }
                            print!(" IPI...");
                            local_apic.set_icr(icr);
                        }

                        // Send START IPI
                        {
                            //Start at 0x0800:0000 => 0x8000. Hopefully the bootloader code is still there
                            let ap_segment = (AP_STARTUP >> 12) & 0xFF;
                            let mut icr = 0x4600 | ap_segment as u64;

                            if local_apic.x2 {
                                icr |= (ap_local_apic.id as u64) << 32;
                            } else {
                                icr |= (ap_local_apic.id as u64) << 56;
                            }

                            print!(" SIPI...");
                            local_apic.set_icr(icr);
                        }

                        // Wait for trampoline ready
                        print!(" Wait...");
                        while unsafe { atomic_load(ap_ready) } == 0 {
                            interrupt::pause();
                        }
                        print!(" Trampoline...");
                        while ! AP_READY.load(Ordering::SeqCst) {
                            interrupt::pause();
                        }
                        println!(" Ready");

                        active_table.flush_all();
                    } else {
                        println!("        CPU Disabled");
                    }
                },
                _ => ()
            }
        }

        // Unmap trampoline
        let (result, _frame) = active_table.unmap_return(trampoline_page);
        result.flush(active_table);
        */
    } else if let Some(dmar) = Dmar::new(sdt) {
        println!(": {}: {}", dmar.addr_width, dmar.flags);

        for dmar_entry in dmar.iter() {
            println!("      {:?}", dmar_entry);
            match dmar_entry {
                DmarEntry::Drhd(dmar_drhd) => {
                    let drhd = dmar_drhd.get(active_table);

                    println!("VER: {:X}", drhd.version);
                    println!("CAP: {:X}", drhd.cap);
                    println!("EXT_CAP: {:X}", drhd.ext_cap);
                    println!("GCMD: {:X}", drhd.gl_cmd);
                    println!("GSTS: {:X}", drhd.gl_sts);
                    println!("RT: {:X}", drhd.root_table);
                },
                _ => ()
            }
        }
    } else {
        println!(": Unknown");
    }
}

/// Parse the ACPI tables to gather CPU, interrupt, and timer information
pub unsafe fn init(active_table: &mut ActivePageTable) {
    let start_addr = 0xE0000;
    let end_addr = 0xFFFFF;

    // Map all of the ACPI RSDP space
    {
        let start_frame = Frame::containing_address(PhysicalAddress::new(start_addr));
        let end_frame = Frame::containing_address(PhysicalAddress::new(end_addr));
        for frame in Frame::range_inclusive(start_frame, end_frame) {
            let page = Page::containing_address(VirtualAddress::new(frame.start_address().get()));
            let result = active_table.map_to(page, frame, entry::PRESENT | entry::NO_EXECUTE);
            result.flush(active_table);
        }
    }

    // Search for RSDP
    if let Some(rsdp) = RSDP::search(start_addr, end_addr) {
        let rxsdt = get_sdt(rsdp.sdt_address(), active_table);

        for &c in rxsdt.signature.iter() {
            print!("{}", c as char);
        }
        println!(":");
        if let Some(rsdt) = Rsdt::new(rxsdt) {
            for sdt_address in rsdt.iter() {
                let sdt = get_sdt(sdt_address, active_table);
                parse_sdt(sdt, active_table);
            }
        } else if let Some(xsdt) = Xsdt::new(rxsdt) {
            for sdt_address in xsdt.iter() {
                let sdt = get_sdt(sdt_address, active_table);
                parse_sdt(sdt, active_table);
            }
        } else {
            println!("UNKNOWN RSDT OR XSDT SIGNATURE");
        }
    } else {
        println!("NO RSDP FOUND");
    }

    /* TODO: Cleanup mapping when looking for RSDP
    // Unmap all of the ACPI RSDP space
    {
        let start_frame = Frame::containing_address(PhysicalAddress::new(start_addr));
        let end_frame = Frame::containing_address(PhysicalAddress::new(end_addr));
        for frame in Frame::range_inclusive(start_frame, end_frame) {
            let page = Page::containing_address(VirtualAddress::new(frame.start_address().get()));
            let result = active_table.unmap(page);
            result.flush(active_table);
        }
    }
    */
}

pub struct Acpi {
    pub fadt: Option<Fadt>,
    pub dsdt: Option<Dsdt>,
}

pub static ACPI_TABLE: Mutex<Acpi> = Mutex::new(Acpi { fadt: None, dsdt: None });

/// RSDP
#[derive(Copy, Clone, Debug)]
#[repr(packed)]
pub struct RSDP {
    signature: [u8; 8],
    checksum: u8,
    oemid: [u8; 6],
    revision: u8,
    rsdt_address: u32,
    length: u32,
    xsdt_address: u64,
    extended_checksum: u8,
    reserved: [u8; 3]
}

impl RSDP {
    /// Search for the RSDP
    pub fn search(start_addr: usize, end_addr: usize) -> Option<RSDP> {
        for i in 0 .. (end_addr + 1 - start_addr)/16 {
            let rsdp = unsafe { &*((start_addr + i * 16) as *const RSDP) };
            if &rsdp.signature == b"RSD PTR " {
                return Some(*rsdp);
            }
        }
        None
    }

    /// Get the RSDT or XSDT address
    pub fn sdt_address(&self) -> usize {
        if self.revision >= 2 {
            self.xsdt_address as usize
        } else {
            self.rsdt_address as usize
        }
    }
}
<|endoftext|>


<commit_before>use hyper::server::Request;
use std::sync::Mutex;
extern crate redis;
extern crate byteorder;

use common::*;
use self::byteorder::{BigEndian, WriteBytesExt};
use std::net::IpAddr;
use std::net::Ipv4Addr;
extern crate time;

pub fn announce(req: &Request, redis_connection: &Mutex<redis::Connection>) -> Result<Vec<u8>, String>
{
    let query_hashmap = query_hashmap(&req.uri);

    // Check we have everything we need
    let info_hash = try!(query_hashmap.get("info_hash")
        .ok_or_else(|| "No info_hash specified".to_owned())
        .and_then(|i| parse_info_hash(i)));
    let peer_id = try!(query_hashmap.get("peer_id")
        .ok_or_else(|| "No peer_id specified".to_owned())
        .and_then(|i| parse_peer_id(i)));
    let port = try!(query_hashmap.get("port")
        .ok_or_else(|| "No port specified".to_owned())
        .and_then(|i| i.parse::<u16>().map_err(|_| "Invalid port specified".to_owned())));
    let left = try!(query_hashmap.get("left")
        .ok_or_else(|| "No left specified".to_owned())
        .and_then(|i| i.parse::<u64>().map_err(|_| "Invalid left specified".to_owned())));
    let compact = try!(query_hashmap.get("compact")
        .ok_or_else(|| "No compact specified".to_owned())
        .and_then(|i| i.parse::<u64>().map_err(|_| "Invalid left specified".to_owned())));
    let ip = req.remote_addr.ip();

    // Generate compact peer entry
    let ip_v4 = match ip {
        IpAddr::V4(i) => i,
        _ => return Err("Ipv6 not implemented yet".to_owned()),
    };
    let peer_v4 = generate_peer_ipv4(ip_v4, port);

    // Get ready for redis queries
    let key_base = format!("torrent:{}", info_hash);
    let key_seeds = format!("{}:seeds", key_base);
    let key_peers = format!("{}:peers", key_base);
    let time_now = time::get_time().sec;
    let time_drop = time_now - 60;
    let mut pipe = redis::pipe();

    // Prune out old entries
    pipe.cmd("ZREMRANGEBYSCORE").arg(&*key_seeds).arg(0).arg(time_drop).ignore();
    pipe.cmd("ZREMRANGEBYSCORE").arg(&*key_peers).arg(0).arg(time_drop).ignore();

    // Get total count of peers/seeds
    pipe.cmd("ZCARD").arg(&*key_seeds);
    pipe.cmd("ZCARD").arg(&*key_peers);

    // Get peers and seeds
    let numwant = 50;
    pipe.cmd("ZRANGE").arg(&*key_seeds).arg(0).arg(numwant);
    pipe.cmd("ZRANGE").arg(&*key_peers).arg(0).arg(numwant);

    // Add
    if left == 0 {
        pipe.cmd("ZADD").arg(&*key_seeds).arg(time_now).arg(peer_v4).ignore();
    }
    else {
        pipe.cmd("ZADD").arg(&*key_peers).arg(time_now).arg(peer_v4).ignore();
    }

    // Unlock mutex and go!
    {
        let r = redis_connection.lock().unwrap();
        let _ : () = pipe.query(&(*r)).unwrap();
    }

    return Ok("worked".to_owned().into_bytes());
}

fn generate_peer_ipv4(ip: Ipv4Addr, port: u16) -> Vec<u8> {
    let mut retval = Vec::with_capacity(6);
    retval.extend(ip.octets().iter());
    retval.write_u16::<BigEndian>(port).unwrap();
    return retval;
}

#[test]
fn generate_peer_ipv4_test() {
    assert_eq!(generate_peer_ipv4(Ipv4Addr::new(127, 0, 0, 1), 0x3039), &[127, 0, 0, 1, 0x30, 0x39]);
}
<commit_msg>Get results from redis and create announce response <commit_after>use hyper::server::Request;
use std::sync::Mutex;
extern crate redis;
extern crate byteorder;

use common::*;
use self::byteorder::{BigEndian, WriteBytesExt};
use std::net::IpAddr;
use std::net::Ipv4Addr;
extern crate time;
use std::error::Error;

pub fn announce(req: &Request, redis_connection: &Mutex<redis::Connection>) -> Result<Vec<u8>, String>
{
    let query_hashmap = query_hashmap(&req.uri);

    // Check we have everything we need
    let info_hash = try!(query_hashmap.get("info_hash")
        .ok_or_else(|| "No info_hash specified".to_owned())
        .and_then(|i| parse_info_hash(i)));
    let peer_id = try!(query_hashmap.get("peer_id")
        .ok_or_else(|| "No peer_id specified".to_owned())
        .and_then(|i| parse_peer_id(i)));
    let port = try!(query_hashmap.get("port")
        .ok_or_else(|| "No port specified".to_owned())
        .and_then(|i| i.parse::<u16>().map_err(|_| "Invalid port specified".to_owned())));
    let left = try!(query_hashmap.get("left")
        .ok_or_else(|| "No left specified".to_owned())
        .and_then(|i| i.parse::<u64>().map_err(|_| "Invalid left specified".to_owned())));
    let compact = try!(query_hashmap.get("compact")
        .ok_or_else(|| "No compact specified".to_owned())
        .and_then(|i| i.parse::<u64>().map_err(|_| "Invalid left specified".to_owned())));
    let ip = req.remote_addr.ip();

    // Generate compact peer entry
    let ip_v4 = match ip {
        IpAddr::V4(i) => i,
        _ => return Err("Ipv6 not implemented yet".to_owned()),
    };
    let peer_v4 = generate_peer_ipv4(ip_v4, port);

    // Get ready for redis queries
    let key_base = format!("torrent:{}", info_hash);
    let key_seeds = format!("{}:seeds", key_base);
    let key_peers = format!("{}:peers", key_base);
    let time_now = time::get_time().sec;
    let time_drop = time_now - 60;
    let mut pipe = redis::pipe();

    // Prune out old entries
    pipe.cmd("ZREMRANGEBYSCORE").arg(&*key_seeds).arg(0).arg(time_drop).ignore();
    pipe.cmd("ZREMRANGEBYSCORE").arg(&*key_peers).arg(0).arg(time_drop).ignore();

    // Get total count of peers/seeds
    pipe.cmd("ZCARD").arg(&*key_seeds);
    pipe.cmd("ZCARD").arg(&*key_peers);

    // Get peers and seeds
    let numwant = 50;
    pipe.cmd("ZRANGE").arg(&*key_seeds).arg(0).arg(numwant);
    pipe.cmd("ZRANGE").arg(&*key_peers).arg(0).arg(numwant);

    // Add
    if left == 0 {
        pipe.cmd("ZADD").arg(&*key_seeds).arg(time_now).arg(peer_v4).ignore();
    }
    else {
        pipe.cmd("ZADD").arg(&*key_peers).arg(time_now).arg(peer_v4).ignore();
    }

    // Unlock mutex and go!
    let results: (u32, u32, Vec<Vec<u8>>, Vec<Vec<u8>>);
    {
        let r = redis_connection.lock().unwrap();
        results = try!(pipe.query(&(*r))
            .map_err(|e| format!("Redis error: {}", e.description())));
    }

    let (total_seeds, total_peers, seeds, peers) = results;

    // Begin building output
    let mut response: Vec<u8> = Vec::new();
    response.extend(format!("d8:completei{}e10:incompletei{}e8:intervali{}e5:peers",
        total_seeds, total_peers, 60).bytes());

    // dont give seeds to seeds
    if left == 0 {
        response.extend(format!("{}:", 6*peers.len()).bytes());
        for i in peers {
            response.extend(i);
        }
    }
    else {
        response.extend(format!("{}:", 6*seeds.len() + 6*peers.len()).bytes());
        for i in seeds {
            response.extend(i);
        }
        for i in peers {
            response.extend(i);
        }
    }
    response.extend(b"e");

    return Ok(response);
}

fn generate_peer_ipv4(ip: Ipv4Addr, port: u16) -> Vec<u8> {
    let mut retval = Vec::with_capacity(6);
    retval.extend(ip.octets().iter());
    retval.write_u16::<BigEndian>(port).unwrap();
    return retval;
}

#[test]
fn generate_peer_ipv4_test() {
    assert_eq!(generate_peer_ipv4(Ipv4Addr::new(127, 0, 0, 1), 0x3039), &[127, 0, 0, 1, 0x30, 0x39]);
}
<|endoftext|>


<commit_before>use rocket::State;
use rocket_contrib::Json;
use validation::user::UserSerializer;
use diesel::prelude::*;
use diesel;
use serde_json::Value;

use models::user::{UserModel, NewUser};
use schema::users;
use schema::users::dsl::*;
use helpers::db::DB;
use responses::{APIResponse, ok, created, conflict, unauthorized, unprocessable_entity,
                internal_server_error};
use RuntimeConfig;

/// Log the user in and return a response with an auth token.
///
/// Return UNAUTHORIZED in case the user can't be found or if the password is incorrect.
#[post("/login", data = "<user_in>", format = "application/json")]
pub fn login(
    user_in: Json<UserSerializer>,
    db: DB,
    rconfig: State<RuntimeConfig>,
) -> Result<APIResponse, APIResponse> {
    let user_q = users
        .filter(email.eq(user_in.email.clone()))
        .first::<UserModel>(&*db)
        .optional()?;

    // For privacy reasons, we'll not provide the exact reason for failure here (although this
    // could probably be timing attacked to find out whether users exist or not.
    let mut user = user_q.ok_or_else(|| unauthorized().message(
        "Username or password incorrect.",
    ))?;

    if !user.verify_password(user_in.password.as_str()) {
        return Err(unauthorized().message("Username or password incorrect."));
    }

    let token = if user.has_valid_auth_token(rconfig.0) {
        user.current_auth_token.ok_or_else(internal_server_error)?
    } else {
        user.generate_auth_token(&db)?
    };

    Ok(ok().data(json!({
        "user_id": user.id,
        "token": token,
    })))
}

/// Register a new user using email and password.
///
/// Return CONFLICT is a user with the same email already exists.
#[post("/register", data = "<user>", format = "application/json")]
pub fn register(user: Result<UserSerializer, Value>, db: DB) -> Result<APIResponse, APIResponse> {
    let user_data = user.map_err(unprocessable_entity)?;
    let results = users
        .filter(email.eq(user_data.email.clone()))
        .first::<UserModel>(&*db);
    if results.is_ok() {
        return Err(conflict().message("User already exists."));
    }

    let new_password_hash = UserModel::make_password_hash(user_data.password.as_str());
    let new_user = NewUser {
        email: user_data.email.clone(),
        password_hash: new_password_hash,
    };

    let user = diesel::insert(&new_user)
        .into(users::table)
        .get_result::<UserModel>(&*db)?;

    Ok(created().data(json!(&user)))
}
<commit_msg>Pass by reference instead of clone<commit_after>use rocket::State;
use rocket_contrib::Json;
use validation::user::UserSerializer;
use diesel::prelude::*;
use diesel;
use serde_json::Value;

use models::user::{UserModel, NewUser};
use schema::users;
use schema::users::dsl::*;
use helpers::db::DB;
use responses::{APIResponse, ok, created, conflict, unauthorized, unprocessable_entity,
                internal_server_error};
use RuntimeConfig;

/// Log the user in and return a response with an auth token.
///
/// Return UNAUTHORIZED in case the user can't be found or if the password is incorrect.
#[post("/login", data = "<user_in>", format = "application/json")]
pub fn login(
    user_in: Json<UserSerializer>,
    db: DB,
    rconfig: State<RuntimeConfig>,
) -> Result<APIResponse, APIResponse> {
    let user_q = users
        .filter(email.eq(&user_in.email))
        .first::<UserModel>(&*db)
        .optional()?;

    // For privacy reasons, we'll not provide the exact reason for failure here (although this
    // could probably be timing attacked to find out whether users exist or not.
    let mut user = user_q.ok_or_else(|| unauthorized().message(
        "Username or password incorrect.",
    ))?;

    if !user.verify_password(user_in.password.as_str()) {
        return Err(unauthorized().message("Username or password incorrect."));
    }

    let token = if user.has_valid_auth_token(rconfig.0) {
        user.current_auth_token.ok_or_else(internal_server_error)?
    } else {
        user.generate_auth_token(&db)?
    };

    Ok(ok().data(json!({
        "user_id": user.id,
        "token": token,
    })))
}

/// Register a new user using email and password.
///
/// Return CONFLICT is a user with the same email already exists.
#[post("/register", data = "<user>", format = "application/json")]
pub fn register(user: Result<UserSerializer, Value>, db: DB) -> Result<APIResponse, APIResponse> {
    let user_data = user.map_err(unprocessable_entity)?;
    let results = users
        .filter(email.eq(user_data.email.clone()))
        .first::<UserModel>(&*db);
    if results.is_ok() {
        return Err(conflict().message("User already exists."));
    }

    let new_password_hash = UserModel::make_password_hash(user_data.password.as_str());
    let new_user = NewUser {
        email: user_data.email.clone(),
        password_hash: new_password_hash,
    };

    let user = diesel::insert(&new_user)
        .into(users::table)
        .get_result::<UserModel>(&*db)?;

    Ok(created().data(json!(&user)))
}
<|endoftext|>