<commit_before>#![allow(dead_code)]

//! A wrapper around [cfitsio].
//!
//! This wrapper attempts to add some safety to the [cfitsio] library, and allows `.fits` files to
//! be read from rust.
//!
//! The main entry point to the code is `FitsFile::open` which creates a new file, and
//! `FitsFile::create` which creates a new file.
//!
//! [cfitsio]: https://heasarc.gsfc.nasa.gov/docs/software/fitsio/fitsio.html

pub mod raw;

extern crate libc;

use raw::*;
use libc::{c_int, c_char};
use std::ptr;
use std::ffi;

/// Internal function to get the fits error description from a status code
fn status_to_string(status: c_int) -> Option<String> {
    match status {
        0 => None,
        status => {
            let mut buffer: Vec<c_char> = vec![0; 31];
            unsafe {
                ffgerr(status, buffer.as_mut_ptr());
            }
            let result_str = String::from_utf8(buffer.iter()
                    .map(|&x| x as u8)
                    .filter(|&x| x != 0)
                    .collect())
                .unwrap();
            Some(result_str)
        }
    }
}

/// General type defining what kind of HDU we're talking about
#[derive(Eq, PartialEq, Debug)]
pub enum HduType {
    ImageHDU,
    AsciiTableHDU,
    BinTableHDU,
}

/// Wrapper around a C `fitsfile` pointer.
///
/// This handles [opening][FitsFile::open], [creating][FitsFile::create] and automatically
/// closing (through the `Drop` trait) the file.
///
/// All subsequent file access is controled through this object.
///
/// [FitsFile::open]: #method.open
/// [FitsFile::create]: #method.create
pub struct FitsFile {
    fptr: *mut fitsfile,
    status: c_int,
    pub filename: String,
}

impl FitsFile {
    /// Open a fits file for reading
    ///
    /// * `filename` - Filename to pass to `cfitsio`. Can conform to the
    /// [Extended Filename Syntax][extended-filename-syntax].
    ///
    /// [extended-filename-syntax]:
    ///     https://heasarc.gsfc.nasa.gov/docs/software/fitsio/c/c_user/node82.html
    ///
    /// Examples
    ///
    /// ```
    /// # use fitsio::FitsFile;
    /// # fn main() {
    ///     let f = FitsFile::open("testdata/full_example.fits");
    /// # }
    pub fn open(filename: &str) -> Self {
        let mut fptr = ptr::null_mut();
        let mut status = 0;
        let c_filename = ffi::CString::new(filename).unwrap();

        unsafe {
            ffopen(&mut fptr as *mut *mut fitsfile,
                   c_filename.as_ptr(),
                   0,
                   &mut status);
        }

        return match status {
            0 => {
                FitsFile {
                    fptr: fptr,
                    status: status,
                    filename: filename.to_string(),
                }
            }
            status => {
                panic!("Invalid status code: {}, msg: {}",
                       status,
                       status_to_string(status).unwrap())
            }
        };

    }

    /// Function to check that the status code is ok.
    ///
    /// If the value of `self.status` is not 0 then exit the current process as an error has
    /// occurred.
    fn check(&self) {
        match self.status {
            0 => {}
            status => {
                panic!("Status code {} encountered, msg: {}",
                       status,
                       status_to_string(status).unwrap())
            }
        }
    }

    /// Returns the current HDU number, 0-indexed
    ///
    /// The FITS standard is 1-indexed (thanks Fortran), so this function
    /// converts the indexing to be 0-based so the primary HDU is at
    /// index 0.
    ///
    /// # Examples
    ///
    /// ```
    /// # use fitsio::FitsFile;
    /// let f = FitsFile::open("testdata/full_example.fits");
    /// assert_eq!(f.current_hdu_number(), 0);
    /// ```
    pub fn current_hdu_number(&self) -> u32 {
        let mut hdu_num = 0;
        unsafe {
            ffghdn(self.fptr, &mut hdu_num);
        }
        self.check();
        assert!(hdu_num >= 1);
        (hdu_num - 1) as u32
    }

    /// Change the current HDU
    ///
    /// Examples
    ///
    /// ```
    /// # use fitsio::FitsFile;
    /// # fn main() {
    /// # let mut f = FitsFile::open("testdata/full_example.fits");
    /// assert_eq!(f.current_hdu_number(), 0);
    /// f.change_hdu(1);
    /// assert_eq!(f.current_hdu_number(), 1);
    /// # }
    /// ```
    pub fn change_hdu(&mut self, hdu_num: u32) {
        let mut _hdu_type = 0;
        unsafe {
            ffmahd(self.fptr,
                   (hdu_num + 1) as i32,
                   &mut _hdu_type,
                   &mut self.status);
        }
        self.check();
    }

    /// Get which type of HDU the current HDU is
    ///
    /// Results in one of the `HduType` options.
    ///
    /// # Examples
    ///
    /// ```
    /// # use fitsio::{FitsFile, HduType};
    /// # fn main() {
    /// let mut f = FitsFile::open("testdata/full_example.fits");
    /// // Primary HDUs are always image hdus
    /// assert_eq!(f.get_hdu_type(), HduType::ImageHDU);
    /// # }
    /// ```
    pub fn get_hdu_type(&mut self) -> HduType {
        let mut hdu_type = 3;
        unsafe {
            ffghdt(self.fptr, &mut hdu_type, &mut self.status);
        }
        self.check();

        match hdu_type {
            0 => HduType::ImageHDU,
            1 => HduType::AsciiTableHDU,
            2 => HduType::BinTableHDU,
            _ => panic!("Unknown hdu type: {}", hdu_type),
        }
    }

    /// Return a `FitsHDU` object for the specified HDU
    ///
    /// # Examples
    ///
    /// ```
    /// # use fitsio::{FitsFile, HduType};
    /// # fn main() {
    /// # let mut f = FitsFile::open("testdata/full_example.fits");
    /// let primary_hdu = f.get_hdu(0);
    /// assert_eq!(primary_hdu.hdu_type, HduType::ImageHDU);
    /// # }
    /// ```
    pub fn get_hdu(&mut self, index: usize) -> FitsHDU {
        self.change_hdu(index as u32);
        let hdu_type = self.get_hdu_type();
        FitsHDU {
            fitsfile: self,
            hdu_type: hdu_type,
        }
    }
}

impl Drop for FitsFile {
    fn drop(&mut self) {
        unsafe {
            ffclos(self.fptr, &mut self.status);
        }
    }
}

/// Wrapper around a FITS HDU
///
/// This struct is the main interface around reading and writing the file contents.
pub struct FitsHDU<'a> {
    fitsfile: &'a FitsFile,
    pub hdu_type: HduType,
}

impl<'a> FitsHDU<'a> {
    /// Read a header key as a string
    ///
    /// The user is responsible for converting the value type from a string to whatever type the
    /// header key contains.
    ///
    /// # Examples
    ///
    /// ```
    /// # use fitsio::FitsFile;
    /// # fn main() {
    /// let mut f = FitsFile::open("testdata/full_example.fits");
    /// let mut primary_hdu = f.get_hdu(0);
    /// // Image is 2-dimensional
    /// let naxis = primary_hdu.get_key("NAXIS").parse::<i32>().unwrap();
    /// assert_eq!(naxis, 2);
    /// # }
    /// ```
    pub fn get_key(&mut self, key: &str) -> String {
        let fptr = &self.fitsfile.fptr;
        let mut value: Vec<c_char> = vec![0; MAX_VALUE_LENGTH];
        let keyname = ffi::CString::new(key).unwrap();
        let mut status = 0;

        unsafe {
            ffgkys(*fptr,
                   keyname.as_ptr(),
                   value.as_mut_ptr(),
                   ptr::null_mut(),
                   &mut status);
        }

        match status {
            0 => {
                let value: Vec<u8> = value.iter()
                    .map(|&x| x as u8)
                    .filter(|&x| x != 0)
                    .collect();
                return String::from_utf8(value).unwrap();
            }
            _ => {
                panic!("Invalid status code: {}, msg: {}",
                       status,
                       status_to_string(status).unwrap())
            }
        }
    }
}

mod test {
    #[test]
    fn returning_error_messages() {
        use super::status_to_string;

        assert_eq!(status_to_string(105).unwrap(),
                   "couldn't create the named file");
    }

    #[test]
    fn opening_an_existing_file() {
        use super::FitsFile;

        let f = FitsFile::open("testdata/full_example.fits");
        assert_eq!(f.status, 0);
    }

    #[test]
    fn filename_is_stored() {
        use super::FitsFile;

        let f = FitsFile::open("testdata/full_example.fits");
        assert_eq!(f.filename, "testdata/full_example.fits");
    }

    #[test]
    fn change_hdu() {
        use super::FitsFile;

        let mut f = FitsFile::open("testdata/full_example.fits");
        f.change_hdu(1);
        assert_eq!(f.current_hdu_number(), 1u32);
    }

    #[test]
    fn getting_current_hdu_number() {
        use super::FitsFile;

        let f = FitsFile::open("testdata/full_example.fits");
        assert_eq!(f.current_hdu_number(), 0u32);
    }

    #[test]
    fn getting_hdu_object() {
        use super::{FitsFile, HduType};

        let mut f = FitsFile::open("testdata/full_example.fits");

        {
            let primary_hdu = f.get_hdu(0);
            assert_eq!(primary_hdu.hdu_type, HduType::ImageHDU);
        }

        {
            let table_hdu = f.get_hdu(1);
            assert_eq!(table_hdu.hdu_type, HduType::BinTableHDU);
        }
    }
}
<commit_msg>Add FitsFile::create<commit_after>#![allow(dead_code)]

//! A wrapper around [cfitsio].
//!
//! This wrapper attempts to add some safety to the [cfitsio] library, and allows `.fits` files to
//! be read from rust.
//!
//! The main entry point to the code is `FitsFile::open` which creates a new file, and
//! `FitsFile::create` which creates a new file.
//!
//! [cfitsio]: https://heasarc.gsfc.nasa.gov/docs/software/fitsio/fitsio.html

pub mod raw;

extern crate libc;

use raw::*;
use libc::{c_int, c_char};
use std::ptr;
use std::ffi;

/// Internal function to get the fits error description from a status code
fn status_to_string(status: c_int) -> Option<String> {
    match status {
        0 => None,
        status => {
            let mut buffer: Vec<c_char> = vec![0; 31];
            unsafe {
                ffgerr(status, buffer.as_mut_ptr());
            }
            let result_str = String::from_utf8(buffer.iter()
                    .map(|&x| x as u8)
                    .filter(|&x| x != 0)
                    .collect())
                .unwrap();
            Some(result_str)
        }
    }
}

/// General type defining what kind of HDU we're talking about
#[derive(Eq, PartialEq, Debug)]
pub enum HduType {
    ImageHDU,
    AsciiTableHDU,
    BinTableHDU,
}

/// Wrapper around a C `fitsfile` pointer.
///
/// This handles [opening][FitsFile::open], [creating][FitsFile::create] and automatically
/// closing (through the `Drop` trait) the file.
///
/// All subsequent file access is controled through this object.
///
/// [FitsFile::open]: #method.open
/// [FitsFile::create]: #method.create
pub struct FitsFile {
    fptr: *mut fitsfile,
    status: c_int,
    pub filename: String,
}

impl FitsFile {
    /// Open a fits file for reading
    ///
    /// * `filename` - Filename to pass to `cfitsio`. Can conform to the
    /// [Extended Filename Syntax][extended-filename-syntax].
    ///
    /// [extended-filename-syntax]:
    ///     https://heasarc.gsfc.nasa.gov/docs/software/fitsio/c/c_user/node82.html
    ///
    /// Examples
    ///
    /// ```
    /// # use fitsio::FitsFile;
    /// # fn main() {
    ///     let f = FitsFile::open("testdata/full_example.fits");
    /// # }
    pub fn open(filename: &str) -> Self {
        let mut fptr = ptr::null_mut();
        let mut status = 0;
        let c_filename = ffi::CString::new(filename).unwrap();

        unsafe {
            ffopen(&mut fptr as *mut *mut fitsfile,
                   c_filename.as_ptr(),
                   0,
                   &mut status);
        }

        return match status {
            0 => {
                FitsFile {
                    fptr: fptr,
                    status: status,
                    filename: filename.to_string(),
                }
            }
            status => {
                panic!("Invalid status code: {}, msg: {}",
                       status,
                       status_to_string(status).unwrap())
            }
        };

    }

    /// Create a new fits file
    ///
    /// An empty primary header is added so when the `drop` method is called, the file is valid.
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate fitsio;
    /// # extern crate tempdir;
    /// # use fitsio::FitsFile;
    /// # fn main() {
    /// # let tdir = tempdir::TempDir::new("fitsio-").unwrap();
    /// # let tdir_path = tdir.path();
    /// # let filename = tdir_path.join("test.fits");
    /// # let filename = filename.to_str().unwrap();
    /// let _ = FitsFile::create(filename);
    /// # }
    /// ```
    pub fn create(path: &str) -> Self {
        let mut fptr = ptr::null_mut();
        let mut status = 0;
        let c_filename = ffi::CString::new(path).unwrap();

        unsafe {
            ffinit(&mut fptr as *mut *mut fitsfile,
                   c_filename.as_ptr(),
                   &mut status);
        }

        return match status {
            0 => {
                FitsFile {
                    fptr: fptr,
                    status: status,
                    filename: path.to_string(),
                }
            }
            status => {
                panic!("Invalid status code: {}, msg: {}",
                       status,
                       status_to_string(status).unwrap())
            }
        };
    }

    /// Function to check that the status code is ok.
    ///
    /// If the value of `self.status` is not 0 then exit the current process as an error has
    /// occurred.
    fn check(&self) {
        match self.status {
            0 => {}
            status => {
                panic!("Status code {} encountered, msg: {}",
                       status,
                       status_to_string(status).unwrap())
            }
        }
    }

    /// Returns the current HDU number, 0-indexed
    ///
    /// The FITS standard is 1-indexed (thanks Fortran), so this function
    /// converts the indexing to be 0-based so the primary HDU is at
    /// index 0.
    ///
    /// # Examples
    ///
    /// ```
    /// # use fitsio::FitsFile;
    /// let f = FitsFile::open("testdata/full_example.fits");
    /// assert_eq!(f.current_hdu_number(), 0);
    /// ```
    pub fn current_hdu_number(&self) -> u32 {
        let mut hdu_num = 0;
        unsafe {
            ffghdn(self.fptr, &mut hdu_num);
        }
        self.check();
        assert!(hdu_num >= 1);
        (hdu_num - 1) as u32
    }

    /// Change the current HDU
    ///
    /// Examples
    ///
    /// ```
    /// # use fitsio::FitsFile;
    /// # fn main() {
    /// # let mut f = FitsFile::open("testdata/full_example.fits");
    /// assert_eq!(f.current_hdu_number(), 0);
    /// f.change_hdu(1);
    /// assert_eq!(f.current_hdu_number(), 1);
    /// # }
    /// ```
    pub fn change_hdu(&mut self, hdu_num: u32) {
        let mut _hdu_type = 0;
        unsafe {
            ffmahd(self.fptr,
                   (hdu_num + 1) as i32,
                   &mut _hdu_type,
                   &mut self.status);
        }
        self.check();
    }

    /// Get which type of HDU the current HDU is
    ///
    /// Results in one of the `HduType` options.
    ///
    /// # Examples
    ///
    /// ```
    /// # use fitsio::{FitsFile, HduType};
    /// # fn main() {
    /// let mut f = FitsFile::open("testdata/full_example.fits");
    /// // Primary HDUs are always image hdus
    /// assert_eq!(f.get_hdu_type(), HduType::ImageHDU);
    /// # }
    /// ```
    pub fn get_hdu_type(&mut self) -> HduType {
        let mut hdu_type = 3;
        unsafe {
            ffghdt(self.fptr, &mut hdu_type, &mut self.status);
        }
        self.check();

        match hdu_type {
            0 => HduType::ImageHDU,
            1 => HduType::AsciiTableHDU,
            2 => HduType::BinTableHDU,
            _ => panic!("Unknown hdu type: {}", hdu_type),
        }
    }

    /// Return a `FitsHDU` object for the specified HDU
    ///
    /// # Examples
    ///
    /// ```
    /// # use fitsio::{FitsFile, HduType};
    /// # fn main() {
    /// # let mut f = FitsFile::open("testdata/full_example.fits");
    /// let primary_hdu = f.get_hdu(0);
    /// assert_eq!(primary_hdu.hdu_type, HduType::ImageHDU);
    /// # }
    /// ```
    pub fn get_hdu(&mut self, index: usize) -> FitsHDU {
        self.change_hdu(index as u32);
        let hdu_type = self.get_hdu_type();
        FitsHDU {
            fitsfile: self,
            hdu_type: hdu_type,
        }
    }
}

impl Drop for FitsFile {
    fn drop(&mut self) {
        unsafe {
            ffclos(self.fptr, &mut self.status);
        }
    }
}

/// Wrapper around a FITS HDU
///
/// This struct is the main interface around reading and writing the file contents.
pub struct FitsHDU<'a> {
    fitsfile: &'a FitsFile,
    pub hdu_type: HduType,
}

impl<'a> FitsHDU<'a> {
    /// Read a header key as a string
    ///
    /// The user is responsible for converting the value type from a string to whatever type the
    /// header key contains.
    ///
    /// # Examples
    ///
    /// ```
    /// # use fitsio::FitsFile;
    /// # fn main() {
    /// let mut f = FitsFile::open("testdata/full_example.fits");
    /// let mut primary_hdu = f.get_hdu(0);
    /// // Image is 2-dimensional
    /// let naxis = primary_hdu.get_key("NAXIS").parse::<i32>().unwrap();
    /// assert_eq!(naxis, 2);
    /// # }
    /// ```
    pub fn get_key(&mut self, key: &str) -> String {
        let fptr = &self.fitsfile.fptr;
        let mut value: Vec<c_char> = vec![0; MAX_VALUE_LENGTH];
        let keyname = ffi::CString::new(key).unwrap();
        let mut status = 0;

        unsafe {
            ffgkys(*fptr,
                   keyname.as_ptr(),
                   value.as_mut_ptr(),
                   ptr::null_mut(),
                   &mut status);
        }

        match status {
            0 => {
                let value: Vec<u8> = value.iter()
                    .map(|&x| x as u8)
                    .filter(|&x| x != 0)
                    .collect();
                return String::from_utf8(value).unwrap();
            }
            _ => {
                panic!("Invalid status code: {}, msg: {}",
                       status,
                       status_to_string(status).unwrap())
            }
        }
    }
}

mod test {
    #[test]
    fn returning_error_messages() {
        use super::status_to_string;

        assert_eq!(status_to_string(105).unwrap(),
                   "couldn't create the named file");
    }

    #[test]
    fn opening_an_existing_file() {
        use super::FitsFile;

        let f = FitsFile::open("testdata/full_example.fits");
        assert_eq!(f.status, 0);
    }

    #[test]
    fn creating_a_new_file() {
        extern crate tempdir;

        use super::FitsFile;
        let tdir = tempdir::TempDir::new("fitsio-").unwrap();
        let tdir_path = tdir.path();
        let filename = tdir_path.join("test.fits");
        assert!(!filename.exists());

        let _ = FitsFile::create(filename.to_str().unwrap());
        assert!(filename.exists());
    }

    #[test]
    fn filename_is_stored() {
        use super::FitsFile;

        let f = FitsFile::open("testdata/full_example.fits");
        assert_eq!(f.filename, "testdata/full_example.fits");
    }

    #[test]
    fn change_hdu() {
        use super::FitsFile;

        let mut f = FitsFile::open("testdata/full_example.fits");
        f.change_hdu(1);
        assert_eq!(f.current_hdu_number(), 1u32);
    }

    #[test]
    fn getting_current_hdu_number() {
        use super::FitsFile;

        let f = FitsFile::open("testdata/full_example.fits");
        assert_eq!(f.current_hdu_number(), 0u32);
    }

    #[test]
    fn getting_hdu_object() {
        use super::{FitsFile, HduType};

        let mut f = FitsFile::open("testdata/full_example.fits");

        {
            let primary_hdu = f.get_hdu(0);
            assert_eq!(primary_hdu.hdu_type, HduType::ImageHDU);
        }

        {
            let table_hdu = f.get_hdu(1);
            assert_eq!(table_hdu.hdu_type, HduType::BinTableHDU);
        }
    }
}
<|endoftext|>


<commit_before>//! An implementation of Google Protobuf's Variable-Length Integers

use std::collections::VecDeque;

/// The maximum number of bytes used by a 32-bit Varint
pub const VARINT_32_MAX_BYTES: usize = 5;

/// The maximum number of bytes used by a 32-bit Varint
pub const VARINT_64_MAX_BYTES: usize = 10;

/// Checks to see if the most signifigant bit exists in the specified byte
pub fn most_signifigant_bit_exists(input: u8) -> bool {
    input & 0b10000000 != 0
}

/// A struct defining a variable-length integer
#[derive(Clone, Debug)]
pub struct Varint {

    /// The internal data representation
    pub data: VecDeque<u8>

}

impl Varint {

    /// Gets the number of bytes currently contained by this Varint
    pub fn number_of_bytes(&self) -> usize {
        self.data.len()
    }

}

/// Transforms a signed int to an unsigned int via zig-zag transformation
pub fn zigzag_signed_int(input: i32) -> u32 {
    ((input << 1) ^ (input >> 31)) as u32
}

/// Transforms a signed long to an unsigned long via zig-zag transformation
pub fn zigzag_signed_long(input: i64) -> u64 {
    ((input << 1) ^ (input >> 63)) as u64
}

/// Transforms an unsigned int to a signed int via zig-zag transformation
pub fn zigzag_unsigned_int(input: u32) -> i32 {
    ((input >> 1) as i32) ^ (-((input & 1) as i32))
}

/// Transforms an unsignigned long to a signed long via zig-zag transformation
pub fn zigzag_unsigned_long(input: u64) -> i64 {
    ((input >> 1) as i64) ^ (-((input & 1) as i64))
}

/// Encodes a signed i32 as a Varint
pub fn encode_signed_varint32(input: i32) -> Varint {
    encode_unsigned_varint32(zigzag_signed_int(input))
}

/// Encodes a signed i64 as a Varint
pub fn encode_signed_varint64(input: i64) -> Varint {
    encode_unsigned_varint64(zigzag_signed_long(input))
}

/// Encodes an unsigned u32 as a Varint.
pub fn encode_unsigned_varint32(input: u32) -> Varint {

    let mut returnable: Varint = Varint { data: VecDeque::<u8>::new() };

    let mut value: u32 = input;

    if value == 0 {
        returnable.data.push_back(0);
        return returnable;
    } else {

        while value >= 1 {
            let mut next_byte: u8 = (value & 0b01111111) as u8;

            value >>= 7;

            if value >= 1 {
                next_byte |= 0b10000000;
            }

            returnable.data.push_back(next_byte);
        }

        return returnable;
    }

}

/// Encodes an unsigned u64 as a Varint.
pub fn encode_unsigned_varint64(input: u64) -> Varint {

    let mut returnable: Varint = Varint { data: VecDeque::<u8>::new() };

    let mut value: u64 = input;

    if value == 0 {
        returnable.data.push_back(0);
        return returnable;
    } else {

        while value >= 1 {
            let mut next_byte: u8 = (value & 0b01111111) as u8;

            value >>= 7;

            if value >= 1 {
                next_byte |= 0b10000000;
            }

            returnable.data.push_back(next_byte);
        }

        return returnable;
    }

}

/// Decodes an unsigned varint32, returning a result of either a u32 or a string explaining the error
pub fn decode_unsigned_varint32(input: &mut Varint) -> Result<u32, &'static str> {
    if input.number_of_bytes() == 0 {
        return Err("Varint somehow has zero bytes! Are you decoding something you wrote?");
    } else if input.number_of_bytes() > VARINT_32_MAX_BYTES {
        return Err("Varint is larger than VARINT_32_MAX_BYTES");
    } else if input.number_of_bytes() == 1 {
        let returnable = input.data.pop_front();

        if returnable.is_none() {
            return Err("Only byte contained in a VecDeque is a byte but is also None. You might want to run memtest");
        } else {
            return Ok(returnable.unwrap() as u32);
        }
    } else {
        let mut shift_amount: u32 = 0;
        let mut decoded_value: u32 = 0;
        while input.number_of_bytes() >= 1 {
            let byte_result = input.data.pop_front();

            if byte_result.is_none() {
                return Err("Byte contained in a VecDeque is a byte that is also None. Run memtest, please");
            } else {
                let byte_value = byte_result.unwrap();

                decoded_value |= ((byte_value & 0b01111111) as u32) << shift_amount; //<< 0 for first byte

                if (decoded_value & 0b10000000) == 0 {
                    return Ok(decoded_value);
                } else {
                    shift_amount += 7;
                }
            }
        }

        Err("No bytes were marked as the end byte. Check your numbers or run a memtest")
    }
}

/// Decodes an unsigned varint64, returning a result of either a u64 or a string explaining the error
pub fn decode_unsigned_varint64(input: &mut Varint) -> Result<u64, &'static str> {
    if input.number_of_bytes() == 0 {
        return Err("Varint somehow has zero bytes! Are you decoding something you wrote?");
    } else if input.number_of_bytes() > VARINT_64_MAX_BYTES {
        return Err("Varint is larger than VARINT_64_MAX_BYTES");
    } else if input.number_of_bytes() == 1 {
        let returnable = input.data.pop_front();

        if returnable.is_none() {
            return Err("Only byte contained in a VecDeque is a byte but is also None. You might want to run memtest");
        } else {
            return Ok(returnable.unwrap() as u64);
        }
    } else {
        let mut shift_amount: u64 = 0;
        let mut decoded_value: u64 = 0;
        while input.number_of_bytes() >= 1 {
            let byte_result = input.data.pop_front();

            if byte_result.is_none() {
                return Err("Byte contained in a VecDeque is a byte that is also None. Run memtest, please");
            } else {
                let byte_value = byte_result.unwrap();

                decoded_value |= ((byte_value & 0b01111111) as u64) << shift_amount; //<< 0 for first byte

                if (decoded_value & 0b10000000) == 0 {
                    return Ok(decoded_value);
                } else {
                    shift_amount += 7;
                }
            }
        }

        Err("No bytes were marked as the end byte. Check your numbers or run a memtest")
    }
}

#[cfg(test)]
mod test {

    use super::*;

    use std::collections::VecDeque;

    #[test]
    fn test_zigzag_signed_value() {
        let mut signed: i32 = 0;

        assert_eq!(signed, zigzag_signed_int(signed) as i32);

        signed = -1;

        assert_eq!(1, zigzag_signed_int(signed));

        signed = 1;

        assert_eq!(2, zigzag_signed_int(signed));

        signed = -2;

        assert_eq!(3, zigzag_signed_int(signed));

        let mut signed: i64 = 9223372036854775806;

        assert_eq!(18446744073709551612, zigzag_signed_long(signed));

        signed = -9223372036854775808;

        assert_eq!(18446744073709551615, zigzag_signed_long(signed));
    }

    #[test]
    fn test_new_varint_has_no_bytes() {

        let abc: Varint = Varint { data: VecDeque::<u8>::new() };

        assert_eq!(0, abc.number_of_bytes());

    }

    #[test]
    fn test_most_signifigant_bit() {
        let mut value: u8 = 1;

        assert!(most_signifigant_bit_exists(value) == false);

        value = 120;

        assert!(most_signifigant_bit_exists(value) == false);

        value = 128;

        assert!(most_signifigant_bit_exists(value) == true);

        value = 129;

        assert!(most_signifigant_bit_exists(value) == true);
    }

}<commit_msg>Test unsigned zigzags<commit_after>//! An implementation of Google Protobuf's Variable-Length Integers

use std::collections::VecDeque;

/// The maximum number of bytes used by a 32-bit Varint
pub const VARINT_32_MAX_BYTES: usize = 5;

/// The maximum number of bytes used by a 32-bit Varint
pub const VARINT_64_MAX_BYTES: usize = 10;

/// Checks to see if the most signifigant bit exists in the specified byte
pub fn most_signifigant_bit_exists(input: u8) -> bool {
    input & 0b10000000 != 0
}

/// A struct defining a variable-length integer
#[derive(Clone, Debug)]
pub struct Varint {

    /// The internal data representation
    pub data: VecDeque<u8>

}

impl Varint {

    /// Gets the number of bytes currently contained by this Varint
    pub fn number_of_bytes(&self) -> usize {
        self.data.len()
    }

}

/// Transforms a signed int to an unsigned int via zig-zag transformation
pub fn zigzag_signed_int(input: i32) -> u32 {
    ((input << 1) ^ (input >> 31)) as u32
}

/// Transforms a signed long to an unsigned long via zig-zag transformation
pub fn zigzag_signed_long(input: i64) -> u64 {
    ((input << 1) ^ (input >> 63)) as u64
}

/// Transforms an unsigned int to a signed int via zig-zag transformation
pub fn zigzag_unsigned_int(input: u32) -> i32 {
    ((input >> 1) as i32) ^ (-((input & 1) as i32))
}

/// Transforms an unsignigned long to a signed long via zig-zag transformation
pub fn zigzag_unsigned_long(input: u64) -> i64 {
    ((input >> 1) as i64) ^ (-((input & 1) as i64))
}

/// Encodes a signed i32 as a Varint
pub fn encode_signed_varint32(input: i32) -> Varint {
    encode_unsigned_varint32(zigzag_signed_int(input))
}

/// Encodes a signed i64 as a Varint
pub fn encode_signed_varint64(input: i64) -> Varint {
    encode_unsigned_varint64(zigzag_signed_long(input))
}

/// Encodes an unsigned u32 as a Varint.
pub fn encode_unsigned_varint32(input: u32) -> Varint {

    let mut returnable: Varint = Varint { data: VecDeque::<u8>::new() };

    let mut value: u32 = input;

    if value == 0 {
        returnable.data.push_back(0);
        return returnable;
    } else {

        while value >= 1 {
            let mut next_byte: u8 = (value & 0b01111111) as u8;

            value >>= 7;

            if value >= 1 {
                next_byte |= 0b10000000;
            }

            returnable.data.push_back(next_byte);
        }

        return returnable;
    }

}

/// Encodes an unsigned u64 as a Varint.
pub fn encode_unsigned_varint64(input: u64) -> Varint {

    let mut returnable: Varint = Varint { data: VecDeque::<u8>::new() };

    let mut value: u64 = input;

    if value == 0 {
        returnable.data.push_back(0);
        return returnable;
    } else {

        while value >= 1 {
            let mut next_byte: u8 = (value & 0b01111111) as u8;

            value >>= 7;

            if value >= 1 {
                next_byte |= 0b10000000;
            }

            returnable.data.push_back(next_byte);
        }

        return returnable;
    }

}

/// Decodes an unsigned varint32, returning a result of either a u32 or a string explaining the error
pub fn decode_unsigned_varint32(input: &mut Varint) -> Result<u32, &'static str> {
    if input.number_of_bytes() == 0 {
        return Err("Varint somehow has zero bytes! Are you decoding something you wrote?");
    } else if input.number_of_bytes() > VARINT_32_MAX_BYTES {
        return Err("Varint is larger than VARINT_32_MAX_BYTES");
    } else if input.number_of_bytes() == 1 {
        let returnable = input.data.pop_front();

        if returnable.is_none() {
            return Err("Only byte contained in a VecDeque is a byte but is also None. You might want to run memtest");
        } else {
            return Ok(returnable.unwrap() as u32);
        }
    } else {
        let mut shift_amount: u32 = 0;
        let mut decoded_value: u32 = 0;
        while input.number_of_bytes() >= 1 {
            let byte_result = input.data.pop_front();

            if byte_result.is_none() {
                return Err("Byte contained in a VecDeque is a byte that is also None. Run memtest, please");
            } else {
                let byte_value = byte_result.unwrap();

                decoded_value |= ((byte_value & 0b01111111) as u32) << shift_amount; //<< 0 for first byte

                if (decoded_value & 0b10000000) == 0 {
                    return Ok(decoded_value);
                } else {
                    shift_amount += 7;
                }
            }
        }

        Err("No bytes were marked as the end byte. Check your numbers or run a memtest")
    }
}

/// Decodes an unsigned varint64, returning a result of either a u64 or a string explaining the error
pub fn decode_unsigned_varint64(input: &mut Varint) -> Result<u64, &'static str> {
    if input.number_of_bytes() == 0 {
        return Err("Varint somehow has zero bytes! Are you decoding something you wrote?");
    } else if input.number_of_bytes() > VARINT_64_MAX_BYTES {
        return Err("Varint is larger than VARINT_64_MAX_BYTES");
    } else if input.number_of_bytes() == 1 {
        let returnable = input.data.pop_front();

        if returnable.is_none() {
            return Err("Only byte contained in a VecDeque is a byte but is also None. You might want to run memtest");
        } else {
            return Ok(returnable.unwrap() as u64);
        }
    } else {
        let mut shift_amount: u64 = 0;
        let mut decoded_value: u64 = 0;
        while input.number_of_bytes() >= 1 {
            let byte_result = input.data.pop_front();

            if byte_result.is_none() {
                return Err("Byte contained in a VecDeque is a byte that is also None. Run memtest, please");
            } else {
                let byte_value = byte_result.unwrap();

                decoded_value |= ((byte_value & 0b01111111) as u64) << shift_amount; //<< 0 for first byte

                if (decoded_value & 0b10000000) == 0 {
                    return Ok(decoded_value);
                } else {
                    shift_amount += 7;
                }
            }
        }

        Err("No bytes were marked as the end byte. Check your numbers or run a memtest")
    }
}

#[cfg(test)]
mod test {

    use super::*;

    use std::collections::VecDeque;

    #[test]
    fn test_zigzag_unsigned_value() {
        let mut unsigned: u32 = 0;

        assert_eq!(unsigned, zigzag_unsigned_int(unsigned) as u32);

        unsigned = 1;

        assert_eq!(-1, zigzag_unsigned_int(unsigned));

        unsigned = 2;

        assert_eq!(1, zigzag_unsigned_int(unsigned));

        let unsigned: u64 = 18446744073709551612;

        assert_eq!(9223372036854775806, zigzag_unsigned_long(unsigned));
    }

    #[test]
    fn test_zigzag_signed_value() {
        let mut signed: i32 = 0;

        assert_eq!(signed, zigzag_signed_int(signed) as i32);

        signed = -1;

        assert_eq!(1, zigzag_signed_int(signed));

        signed = 1;

        assert_eq!(2, zigzag_signed_int(signed));

        signed = -2;

        assert_eq!(3, zigzag_signed_int(signed));

        let mut signed: i64 = 9223372036854775806;

        assert_eq!(18446744073709551612, zigzag_signed_long(signed));

        signed = -9223372036854775808;

        assert_eq!(18446744073709551615, zigzag_signed_long(signed));
    }

    #[test]
    fn test_new_varint_has_no_bytes() {

        let abc: Varint = Varint { data: VecDeque::<u8>::new() };

        assert_eq!(0, abc.number_of_bytes());

    }

    #[test]
    fn test_most_signifigant_bit() {
        let mut value: u8 = 1;

        assert!(most_signifigant_bit_exists(value) == false);

        value = 120;

        assert!(most_signifigant_bit_exists(value) == false);

        value = 128;

        assert!(most_signifigant_bit_exists(value) == true);

        value = 129;

        assert!(most_signifigant_bit_exists(value) == true);
    }

}<|endoftext|>


<commit_before>//! **arrayvec** provides the types `ArrayVec` and `ArrayString`:
//! array-backed vector and string types, which store their contents inline.
//!
//! The arrayvec package has the following cargo features:
//!
//! - `std`
//!   - Optional, enabled by default
//!   - Use libstd; disable to use `no_std` instead.
//!
//! - `serde`
//!   - Optional
//!   - Enable serialization for ArrayVec and ArrayString using serde 1.x
//!
//! - `unstable-const-fn`
//!   - Optional
//!   - Makes [`ArrayVec::new`] and [`ArrayString::new`] `const fn`s,
//!     using the nightly `const_fn` feature.
//!   - Unstable and requires nightly.
//!
//! ## Rust Version
//!
//! This version of arrayvec requires Rust 1.36 or later.
//!
#![doc(html_root_url="https://docs.rs/arrayvec/0.5/")]
#![cfg_attr(not(feature="std"), no_std)]
#![cfg_attr(feature="unstable-const-fn", feature(const_fn, const_maybe_uninit_assume_init))]

#[cfg(feature="serde")]
extern crate serde;

#[cfg(not(feature="std"))]
extern crate core as std;

mod arrayvec_impl;
mod arrayvec;
mod array_string;
mod char;
mod errors;

pub use crate::array_string::ArrayString;
pub use crate::errors::CapacityError;

pub use crate::arrayvec::{ArrayVec, IntoIter, Drain};
<commit_msg>DOC: Update MSRV doc to Rust 1.51<commit_after>//! **arrayvec** provides the types `ArrayVec` and `ArrayString`:
//! array-backed vector and string types, which store their contents inline.
//!
//! The arrayvec package has the following cargo features:
//!
//! - `std`
//!   - Optional, enabled by default
//!   - Use libstd; disable to use `no_std` instead.
//!
//! - `serde`
//!   - Optional
//!   - Enable serialization for ArrayVec and ArrayString using serde 1.x
//!
//! - `unstable-const-fn`
//!   - Optional
//!   - Makes [`ArrayVec::new`] and [`ArrayString::new`] `const fn`s,
//!     using the nightly `const_fn` feature.
//!   - Unstable and requires nightly.
//!
//! ## Rust Version
//!
//! This version of arrayvec requires Rust 1.51 or later.
//!
#![doc(html_root_url="https://docs.rs/arrayvec/0.5/")]
#![cfg_attr(not(feature="std"), no_std)]
#![cfg_attr(feature="unstable-const-fn", feature(const_fn, const_maybe_uninit_assume_init))]

#[cfg(feature="serde")]
extern crate serde;

#[cfg(not(feature="std"))]
extern crate core as std;

mod arrayvec_impl;
mod arrayvec;
mod array_string;
mod char;
mod errors;

pub use crate::array_string::ArrayString;
pub use crate::errors::CapacityError;

pub use crate::arrayvec::{ArrayVec, IntoIter, Drain};
<|endoftext|>


<commit_before>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! SOS: the Stupid Operating System
//!
//! SOS is a simple, tiny toy OS implemented in Rust.
//!
//! I'm writing this mostly for fun, to learn more about OS design and kernel //! hacking, so don't expect anything new or exciting out of this project.

#![crate_name = "sos_kernel"]
#![crate_type = "staticlib"]
#![feature(asm)]
#![feature(no_std, lang_items)]
#![feature(const_fn, unique, core_str_ext, core_slice_ext)]
#![feature(slice_patterns)]
#![no_std]

extern crate rlibc;
extern crate spin;

pub mod arch;
#[macro_use]
pub mod io;
pub mod util;
pub mod panic;

/// Kernel main loop
#[no_mangle]
pub extern fn kernel_main() {
    println!("Hello from the kernel!");
    println!("Intializing interrupts...")
    arch::interrupts::initialize();
    loop { }
}
<commit_msg>Fix missing semicolon in kernel main loop (AUGH!)<commit_after>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! SOS: the Stupid Operating System
//!
//! SOS is a simple, tiny toy OS implemented in Rust.
//!
//! I'm writing this mostly for fun, to learn more about OS design and kernel //! hacking, so don't expect anything new or exciting out of this project.

#![crate_name = "sos_kernel"]
#![crate_type = "staticlib"]
#![feature(asm)]
#![feature(no_std, lang_items)]
#![feature(const_fn, unique, core_str_ext, core_slice_ext)]
#![feature(slice_patterns)]
#![no_std]

extern crate rlibc;
extern crate spin;

pub mod arch;
#[macro_use]
pub mod io;
pub mod util;
pub mod panic;

/// Kernel main loop
#[no_mangle]
pub extern fn kernel_main() {
    println!("Hello from the kernel!");
    println!("Intializing interrupts...");
    arch::interrupts::initialize();
    loop { }
}
<|endoftext|>


<commit_before>//! Provides the Concat reader-iterator adaptor, a reader each of whose instances is built from an
//! iterator of readers and takes its contents from the iterator's items sequentially. Thus, the
//! contents read from a Concat instance will be the concatenation of the items' contents, as if by
//! repeatedly chaining them.

use std::io::{Read, Result};

pub fn concat<I>(iter: I) -> Concat<I> where I: Iterator, <I as Iterator>::Item: Read {
where R: Read, I: Iterator<Item=R> {
    let curr = iter.next();

    Cat {
        iter: iter,
        curr: curr,
    }
}

pub struct Concat<I> where I: Iterator, <I as Iterator>::Item: Read {
    iter: I,
    curr: Option<<I as Iterator>::Item>,
}

impl<I> Concat<I> where I: Iterator, <I as Iterator>::Item: Read {
    /// Returns a reference to the item last read, or None if the iterator has been exhausted.
    ///
    /// This is useful for error handling and reporting: if a read operation fails, the reference
    /// returned will point to the item which caused the the error.
    pub fn current(&self) -> Option<&<I as Iterator>::Item> {
        self.curr.as_ref()
    }
}

impl<I> Read for Concat<I> where I: Iterator, <I as Iterator>::Item: Read {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        let n = match self.curr {
            None => 0,
            Some(ref mut r) => try!(r.read(buf)),
        };

        if n > 0 || buf.len() == 0 || self.curr.is_none() {
            Ok(n)
        } else {
            // The current reader reached the end so we have to advance the iterator and try again.
            self.curr = self.iter.next();
            self.read(buf)
        }
    }
}
<commit_msg>implement From<I> trait<commit_after>//! Provides the Concat reader-iterator adaptor, a reader each of whose instances is built from an
//! iterator of readers and takes its contents from the iterator's items sequentially. Thus, the
//! contents read from a Concat instance will be the concatenation of the items' contents, as if by
//! repeatedly chaining them.

use std::io::{Read, Result};

pub fn concat<I>(iter: I) -> Concat<I> where I: Iterator, <I as Iterator>::Item: Read {
    Concat::<I>::from(iter)
}

pub struct Concat<I> where I: Iterator, <I as Iterator>::Item: Read {
    iter: I,
    curr: Option<<I as Iterator>::Item>,
}

impl<I> Concat<I> where I: Iterator, <I as Iterator>::Item: Read {
    /// Returns a reference to the item last read, or None if the iterator has been exhausted.
    ///
    /// This is useful for error handling and reporting: if a read operation fails, the reference
    /// returned will point to the item which caused the the error.
    pub fn current(&self) -> Option<&<I as Iterator>::Item> {
        self.curr.as_ref()
    }
}

impl<I> From<I> for Concat<I> where I: Iterator, <I as Iterator>::Item: Read {
    fn from(mut iter: I) -> Concat<I> {
        let curr = iter.next();

        Concat {
            iter: iter,
            curr: curr,
        }
    }
}

impl<I> Read for Concat<I> where I: Iterator, <I as Iterator>::Item: Read {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        let n = match self.curr {
            None => 0,
            Some(ref mut r) => try!(r.read(buf)),
        };

        if n > 0 || buf.len() == 0 || self.curr.is_none() {
            Ok(n)
        } else {
            // The current reader reached the end so we have to advance the iterator and try again.
            self.curr = self.iter.next();
            self.read(buf)
        }
    }
}
<|endoftext|>


<commit_before>#![feature(asm, const_fn, dropck_parametricity)]

#![no_std]

use core::cell::UnsafeCell;
use core::ops::{Deref, DerefMut};
use core::ptr;
use core::sync::atomic::{AtomicBool, AtomicPtr, fence, Ordering};

pub struct Slot {
    next: AtomicPtr<AtomicBool>
}

pub struct Guard<'a, T: ?Sized + 'a> {
    lock: &'a Lock<T>,
    slot: &'a Slot
}

pub struct Lock<T: ?Sized> {
    queue: AtomicPtr<Slot>,
    data: UnsafeCell<T>
}

unsafe impl<T: Send> Sync for Lock<T> { }
unsafe impl<T: Send> Send for Lock<T> { }

/// Do something to wait in spinlocks and use less CPU
#[inline(always)]

#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
fn pause() {
    unsafe { asm!("pause" :::: "volatile"); }
}

#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
fn pause() { }

impl Slot {
    pub const fn new() -> Slot {
        Slot {
            next: AtomicPtr::new(ptr::null_mut())
        }
    }
}

impl<T> Lock<T> {
    pub const fn new(value: T) -> Lock<T> {
        Lock {
            queue: AtomicPtr::new(ptr::null_mut()),
            data: UnsafeCell::new(value)
        }
    }

    pub fn into_inner(self) -> T {
        unsafe {
            self.data.into_inner()
        }
    }
}

impl<T: ?Sized> Lock<T> {
    pub fn lock<'a>(&'a self, slot: &'a mut Slot) -> Guard<'a, T> {
        slot.next = AtomicPtr::new(ptr::null_mut());
        let pred = self.queue.swap(slot, Ordering::Relaxed);
        if !pred.is_null() {
            let pred = unsafe { &*pred };
            let locked = AtomicBool::new(true);
            pred.next.store(&locked as *const _ as *mut _, Ordering::Relaxed);
            while locked.load(Ordering::Relaxed) {
                pause();
            }
        }
        fence(Ordering::Acquire);

        Guard {
            lock: self,
            slot: slot
        }
    }

    pub fn get_mut(&mut self) -> &mut T {
        unsafe { &mut *self.data.get() }
    }
}

impl<'a, T: ?Sized> Deref for Guard<'a, T> {
    type Target = T;
    fn deref(&self) -> &T {
        unsafe { &*self.lock.data.get() }
    }
}

impl<'a, T: ?Sized> DerefMut for Guard<'a, T> {
    fn deref_mut(&mut self) -> &mut T {
        unsafe { &mut *self.lock.data.get() }
    }
}

impl<'a, T: ?Sized> Drop for Guard<'a, T> {
    #[unsafe_destructor_blind_to_params]
    fn drop(&mut self) {
        let succ = self.slot.next.load(Ordering::SeqCst);
        if succ.is_null() {
            let slot_ptr = self.slot as *const _ as *mut _;
            if self.lock.queue.compare_and_swap(slot_ptr, ptr::null_mut(), Ordering::SeqCst) != slot_ptr {
                let mut succ;
                loop {
                    succ = self.slot.next.load(Ordering::SeqCst);
                    if !succ.is_null() {
                        break;
                    }
                    pause();
                }
                let succ = unsafe { &*succ };
                succ.store(false, Ordering::SeqCst);
            }
        } else {
            let succ = unsafe { &*succ };
            succ.store(false, Ordering::SeqCst);
        }
    }
}

#[cfg(test)]
mod test {
    extern crate std;

    use super::{Lock, Slot};

    // Mostly stoled from the Rust standard Mutex implementation's tests, so

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

    use self::std::sync::Arc;
    use self::std::sync::mpsc::channel;
    use self::std::sync::atomic::{AtomicUsize, Ordering};
    use self::std::thread;

    #[derive(Eq, PartialEq, Debug)]
    struct NonCopy(i32);

    #[test]
    fn smoke() {
        let mut slot = Slot::new();
        let m = Lock::new(());
        drop(m.lock(&mut slot));
        drop(m.lock(&mut slot));
    }

    #[test]
    fn lots_and_lots() {
        static LOCK: Lock<u32> = Lock::new(0);
        const ITERS: u32 = 1000;
        const CONCURRENCY: u32 = 3;

        fn inc() {
            let mut slot = Slot::new();
            for _ in 0..ITERS {
                let mut g = LOCK.lock(&mut slot);
                *g += 1;
            }
        };

        let (tx, rx) = channel();
        for _ in 0..CONCURRENCY {
            let tx2 = tx.clone();
            thread::spawn(move|| { inc(); tx2.send(()).unwrap(); });
            let tx2 = tx.clone();
            thread::spawn(move|| { inc(); tx2.send(()).unwrap(); });
        }

        drop(tx);
        for _ in 0..2 * CONCURRENCY {
            rx.recv().unwrap();
        }
        let mut slot = Slot::new();
        assert_eq!(*LOCK.lock(&mut slot), ITERS * CONCURRENCY * 2);
    }

    #[test]
    fn test_into_inner() {
        let m = Lock::new(NonCopy(10));
        assert_eq!(m.into_inner(), NonCopy(10));
    }

    #[test]
    fn test_into_inner_drop() {
        struct Foo(Arc<AtomicUsize>);
        impl Drop for Foo {
            fn drop(&mut self) {
                self.0.fetch_add(1, Ordering::SeqCst);
            }
        }
        let num_drops = Arc::new(AtomicUsize::new(0));
        let m = Lock::new(Foo(num_drops.clone()));
        assert_eq!(num_drops.load(Ordering::SeqCst), 0);
        {
            let _inner = m.into_inner();
            assert_eq!(num_drops.load(Ordering::SeqCst), 0);
        }
        assert_eq!(num_drops.load(Ordering::SeqCst), 1);
    }

    #[test]
    fn test_get_mut() {
        let mut m = Lock::new(NonCopy(10));
        *m.get_mut() = NonCopy(20);
        assert_eq!(m.into_inner(), NonCopy(20));
    }

    #[test]
    fn test_lock_arc_nested() {
        // Tests nested locks and access
        // to underlying data.
        let arc = Arc::new(Lock::new(1));
        let arc2 = Arc::new(Lock::new(arc));
        let (tx, rx) = channel();
        let _t = thread::spawn(move|| {
            let mut slot1 = Slot::new();
            let mut slot2 = Slot::new();

            let lock = arc2.lock(&mut slot1);
            let lock2 = lock.lock(&mut slot2);
            assert_eq!(*lock2, 1);
            tx.send(()).unwrap();
        });
        rx.recv().unwrap();
    }

    #[test]
    fn test_lock_arc_access_in_unwind() {
        let arc = Arc::new(Lock::new(1));
        let arc2 = arc.clone();
        let _ = thread::spawn(move|| -> () {
            struct Unwinder {
                i: Arc<Lock<i32>>,
            }
            impl Drop for Unwinder {
                fn drop(&mut self) {
                    let mut slot = Slot::new();
                    *self.i.lock(&mut slot) += 1;
                }
            }
            let _u = Unwinder { i: arc2 };
            panic!();
        }).join();
        let mut slot = Slot::new();
        let lock = arc.lock(&mut slot);
        assert_eq!(*lock, 2);
    }

    #[test]
    fn test_lock_unsized() {
        let mut slot = Slot::new();
        let lock: &Lock<[i32]> = &Lock::new([1, 2, 3]);
        {
            let b = &mut *lock.lock(&mut slot);
            b[0] = 4;
            b[2] = 5;
        }
        let comp: &[i32] = &[4, 2, 5];
        assert_eq!(&*lock.lock(&mut slot), comp);
    }
}
<commit_msg>Add a try_lock function<commit_after>#![feature(asm, const_fn, dropck_parametricity)]

#![no_std]

use core::cell::UnsafeCell;
use core::ops::{Deref, DerefMut};
use core::ptr;
use core::sync::atomic::{AtomicBool, AtomicPtr, fence, Ordering};

pub struct Slot {
    next: AtomicPtr<AtomicBool>
}

pub struct Guard<'a, T: ?Sized + 'a> {
    lock: &'a Lock<T>,
    slot: &'a Slot
}

pub struct Lock<T: ?Sized> {
    queue: AtomicPtr<Slot>,
    data: UnsafeCell<T>
}

unsafe impl<T: Send> Sync for Lock<T> { }
unsafe impl<T: Send> Send for Lock<T> { }

/// Do something to wait in spinlocks and use less CPU
#[inline(always)]

#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
fn pause() {
    unsafe { asm!("pause" :::: "volatile"); }
}

#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
fn pause() { }

impl Slot {
    pub const fn new() -> Slot {
        Slot {
            next: AtomicPtr::new(ptr::null_mut())
        }
    }
}

impl<T> Lock<T> {
    pub const fn new(value: T) -> Lock<T> {
        Lock {
            queue: AtomicPtr::new(ptr::null_mut()),
            data: UnsafeCell::new(value)
        }
    }

    pub fn into_inner(self) -> T {
        unsafe {
            self.data.into_inner()
        }
    }
}

impl<T: ?Sized> Lock<T> {
    pub fn try_lock<'a>(&'a self, slot: &'a mut Slot) -> Option<Guard<'a, T>> {
        slot.next = AtomicPtr::new(ptr::null_mut());

        if self.queue.compare_and_swap(ptr::null_mut(), slot, Ordering::Relaxed).is_null() {
            fence(Ordering::Acquire);

            Some(Guard {
                lock: self,
                slot: slot
            })
        } else {
            None
        }
    }

    pub fn lock<'a>(&'a self, slot: &'a mut Slot) -> Guard<'a, T> {
        slot.next = AtomicPtr::new(ptr::null_mut());
        let pred = self.queue.swap(slot, Ordering::Relaxed);
        if !pred.is_null() {
            let pred = unsafe { &*pred };
            let locked = AtomicBool::new(true);
            pred.next.store(&locked as *const _ as *mut _, Ordering::Relaxed);
            while locked.load(Ordering::Relaxed) {
                pause();
            }
        }
        fence(Ordering::Acquire);

        Guard {
            lock: self,
            slot: slot
        }
    }

    pub fn get_mut(&mut self) -> &mut T {
        unsafe { &mut *self.data.get() }
    }
}

impl<'a, T: ?Sized> Deref for Guard<'a, T> {
    type Target = T;
    fn deref(&self) -> &T {
        unsafe { &*self.lock.data.get() }
    }
}

impl<'a, T: ?Sized> DerefMut for Guard<'a, T> {
    fn deref_mut(&mut self) -> &mut T {
        unsafe { &mut *self.lock.data.get() }
    }
}

impl<'a, T: ?Sized> Drop for Guard<'a, T> {
    #[unsafe_destructor_blind_to_params]
    fn drop(&mut self) {
        let succ = self.slot.next.load(Ordering::SeqCst);
        if succ.is_null() {
            let slot_ptr = self.slot as *const _ as *mut _;
            if self.lock.queue.compare_and_swap(slot_ptr, ptr::null_mut(), Ordering::SeqCst) != slot_ptr {
                let mut succ;
                loop {
                    succ = self.slot.next.load(Ordering::SeqCst);
                    if !succ.is_null() {
                        break;
                    }
                    pause();
                }
                let succ = unsafe { &*succ };
                succ.store(false, Ordering::SeqCst);
            }
        } else {
            let succ = unsafe { &*succ };
            succ.store(false, Ordering::SeqCst);
        }
    }
}

#[cfg(test)]
mod test {
    extern crate std;

    use super::{Lock, Slot};

    // Mostly stoled from the Rust standard Mutex implementation's tests, so

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

    use self::std::sync::Arc;
    use self::std::sync::mpsc::channel;
    use self::std::sync::atomic::{AtomicUsize, Ordering};
    use self::std::thread;

    #[derive(Eq, PartialEq, Debug)]
    struct NonCopy(i32);

    #[test]
    fn smoke() {
        let mut slot = Slot::new();
        let m = Lock::new(());
        drop(m.lock(&mut slot));
        drop(m.lock(&mut slot));
    }

    #[test]
    fn lots_and_lots() {
        static LOCK: Lock<u32> = Lock::new(0);
        const ITERS: u32 = 1000;
        const CONCURRENCY: u32 = 3;

        fn inc() {
            let mut slot = Slot::new();
            for _ in 0..ITERS {
                let mut g = LOCK.lock(&mut slot);
                *g += 1;
            }
        };

        let (tx, rx) = channel();
        for _ in 0..CONCURRENCY {
            let tx2 = tx.clone();
            thread::spawn(move|| { inc(); tx2.send(()).unwrap(); });
            let tx2 = tx.clone();
            thread::spawn(move|| { inc(); tx2.send(()).unwrap(); });
        }

        drop(tx);
        for _ in 0..2 * CONCURRENCY {
            rx.recv().unwrap();
        }
        let mut slot = Slot::new();
        assert_eq!(*LOCK.lock(&mut slot), ITERS * CONCURRENCY * 2);
    }

    #[test]
    fn try_lock() {
        let mut slot = Slot::new();
        let m = Lock::new(());
        *m.try_lock(&mut slot).unwrap() = ();
    }

    #[test]
    fn test_into_inner() {
        let m = Lock::new(NonCopy(10));
        assert_eq!(m.into_inner(), NonCopy(10));
    }

    #[test]
    fn test_into_inner_drop() {
        struct Foo(Arc<AtomicUsize>);
        impl Drop for Foo {
            fn drop(&mut self) {
                self.0.fetch_add(1, Ordering::SeqCst);
            }
        }
        let num_drops = Arc::new(AtomicUsize::new(0));
        let m = Lock::new(Foo(num_drops.clone()));
        assert_eq!(num_drops.load(Ordering::SeqCst), 0);
        {
            let _inner = m.into_inner();
            assert_eq!(num_drops.load(Ordering::SeqCst), 0);
        }
        assert_eq!(num_drops.load(Ordering::SeqCst), 1);
    }

    #[test]
    fn test_get_mut() {
        let mut m = Lock::new(NonCopy(10));
        *m.get_mut() = NonCopy(20);
        assert_eq!(m.into_inner(), NonCopy(20));
    }

    #[test]
    fn test_lock_arc_nested() {
        // Tests nested locks and access
        // to underlying data.
        let arc = Arc::new(Lock::new(1));
        let arc2 = Arc::new(Lock::new(arc));
        let (tx, rx) = channel();
        let _t = thread::spawn(move|| {
            let mut slot1 = Slot::new();
            let mut slot2 = Slot::new();

            let lock = arc2.lock(&mut slot1);
            let lock2 = lock.lock(&mut slot2);
            assert_eq!(*lock2, 1);
            tx.send(()).unwrap();
        });
        rx.recv().unwrap();
    }

    #[test]
    fn test_lock_arc_access_in_unwind() {
        let arc = Arc::new(Lock::new(1));
        let arc2 = arc.clone();
        let _ = thread::spawn(move|| -> () {
            struct Unwinder {
                i: Arc<Lock<i32>>,
            }
            impl Drop for Unwinder {
                fn drop(&mut self) {
                    let mut slot = Slot::new();
                    *self.i.lock(&mut slot) += 1;
                }
            }
            let _u = Unwinder { i: arc2 };
            panic!();
        }).join();
        let mut slot = Slot::new();
        let lock = arc.lock(&mut slot);
        assert_eq!(*lock, 2);
    }

    #[test]
    fn test_lock_unsized() {
        let mut slot = Slot::new();
        let lock: &Lock<[i32]> = &Lock::new([1, 2, 3]);
        {
            let b = &mut *lock.lock(&mut slot);
            b[0] = 4;
            b[2] = 5;
        }
        let comp: &[i32] = &[4, 2, 5];
        assert_eq!(&*lock.lock(&mut slot), comp);
    }
}
<|endoftext|>


<commit_before>#![cfg_attr(test, feature(test))]

extern crate rustc_serialize;
extern crate encoding;
extern crate time;
extern crate chrono;
extern crate rand;

#[macro_use]
extern crate lazy_static;

pub use header::{
    Header,
    HeaderMap,
    HeaderIter,
    FromHeader,
    ToHeader,
    ToFoldedHeader,
};
pub use address::{Address, Mailbox};
pub use message::{
    MimeMessage,
    MimeMultipartType,
};

pub mod rfc5322;
pub mod rfc2047;
pub mod rfc2045;
pub mod rfc822;
pub mod mimeheaders;
mod header;
mod address;
mod message;
mod results;
<commit_msg>Make ParserResult publicly usable<commit_after>#![cfg_attr(test, feature(test))]

extern crate rustc_serialize;
extern crate encoding;
extern crate time;
extern crate chrono;
extern crate rand;

#[macro_use]
extern crate lazy_static;

pub use header::{
    Header,
    HeaderMap,
    HeaderIter,
    FromHeader,
    ToHeader,
    ToFoldedHeader,
};
pub use address::{Address, Mailbox};
pub use message::{
    MimeMessage,
    MimeMultipartType,
};

pub mod rfc5322;
pub mod rfc2047;
pub mod rfc2045;
pub mod rfc822;
pub mod mimeheaders;
mod header;
mod address;
mod message;
pub mod results;
<|endoftext|>


<commit_before>extern crate xml;

use std::ascii::AsciiExt;
use std::default::Default;
use std::io;
use xml::{Element, ElementBuilder, Parser, Xml};

trait ElementUtils {
    fn tag_with_text(&mut self, child_name: &'static str, child_body: &str);
    fn tag_with_text_opt(&mut self, child_name: &'static str, child_body: &Option<String>);
}

impl ElementUtils for Element {
    fn tag_with_text(&mut self, child_name: &'static str, child_body: &str) {
        self.tag(elem_with_text(child_name, child_body));
    }

    fn tag_with_text_opt(&mut self, child_name: &'static str, child_body: &Option<String>) {
        if let Some(ref c) = *child_body {
            self.tag_with_text(child_name, &c);
        }
    }
}

fn elem_with_text(tag_name: &'static str, chars: &str) -> Element {
    let mut elem = Element::new(tag_name.to_string(), None, vec![]);
    elem.text(chars.to_string());
    elem
}

trait ViaXml {
    fn to_xml(&self) -> Element;
    fn from_xml(element: Element) -> Result<Self, &'static str>;
}

/// RSS
///
/// "At the top level, a RSS document is a \<rss\> element, with a mandatory attribute called
/// version, that specifies the version of RSS that the document conforms to. If it conforms to
/// this specification, the version attribute must be 2.0."
///
/// [RSS 2.0 Specification § RSS]
/// (http://cyber.law.harvard.edu/rss/rss.html#whatIsRss)
#[derive(Default)]
pub struct Rss(pub Channel);

impl ViaXml for Rss {
    fn to_xml(&self) -> Element {
        let mut rss = Element::new("rss".to_string(), None, vec![("version".to_string(), None, "2.0".to_string())]);

        let &Rss(ref channel) = self;
        rss.tag(channel.to_xml());

        rss
    }

    fn from_xml(rss_elem: Element) -> Result<Self, &'static str> {
        if rss_elem.name.to_ascii_lowercase() != "rss" {
            panic!("Expected <rss>, found <{}>", rss_elem.name);
        }

        let channel_elem = match rss_elem.get_child("channel", None) {
            Some(elem) => elem,
            None => return Err("No <channel> element found in <rss>"),
        };

        let channel = try!(ViaXml::from_xml(channel_elem.clone()));

        Ok(Rss(channel))
    }
}

impl Rss {
    pub fn to_string(&self) -> String {
        let mut ret = format!("{}", Xml::PINode("xml version='1.0' encoding='UTF-8'".to_string()));
        ret.push_str(&format!("{}", self.to_xml()));
        ret
    }

    pub fn from_read(reader: &mut io::Read) -> Result<Self, &'static str> {
        let mut rss_string = String::new();

        if let Err(..) = reader.read_to_string(&mut rss_string) {
            return Err("Error reading string from reader");
        }

        let mut parser = Parser::new();
        parser.feed_str(&rss_string);

        let mut builder = ElementBuilder::new();

        for event in parser {
            if let Some(Ok(element)) = builder.handle_event(event) {
                return ViaXml::from_xml(element);
            }
        }

        Err("RSS read error")
    }
}

/// Channel
///
/// "Subordinate to the \<rss\> element is a single \<channel\> element, which contains information
/// about the channel (metadata) and its contents."
///
/// [RSS 2.0 Specification § Channel]
/// (http://cyber.law.harvard.edu/rss/rss.html#requiredChannelElements)
///
/// ## Examples
///
/// ```
/// use rss::Channel;
/// use std::default::Default;
///
/// let channel = Channel {
///     title: "My Blog".to_string(),
///     link: "http://myblog.com".to_string(),
///     description: "Where I write stuff".to_string(),
///     items: vec![],
///     ..Default::default()
/// };
/// ```
#[derive(Default)]
pub struct Channel {
    pub title: String,
    pub link: String,
    pub description: String,
    pub items: Vec<Item>,
    pub language: Option<String>,
    pub copyright: Option<String>,
    pub managing_editor: Option<String>,
    pub web_master: Option<String>,
    pub pub_date: Option<String>,
    pub last_build_date: Option<String>,
    pub categories: Vec<Category>,
    pub generator: Option<String>,
    pub docs: Option<String>,
    // pub cloud:
    // pub ttl:
    pub image: Option<String>,
    pub rating: Option<String>,
    // pub text_input:
    pub skip_hours: Option<String>,
    pub skip_days: Option<String>,
}

impl ViaXml for Channel {
    fn to_xml(&self) -> Element {
        let mut channel = Element::new("channel".to_string(), None, vec![]);

        channel.tag_with_text("title", &self.title);
        channel.tag_with_text("link", &self.link);
        channel.tag_with_text("description", &self.description);

        for item in &self.items {
            channel.tag(item.to_xml());
        }

        channel.tag_with_text_opt("language", &self.language);
        channel.tag_with_text_opt("copyright", &self.copyright);
        channel.tag_with_text_opt("managingEditor", &self.managing_editor);
        channel.tag_with_text_opt("webMaster", &self.web_master);
        channel.tag_with_text_opt("pubDate", &self.pub_date);
        channel.tag_with_text_opt("lastBuildDate", &self.last_build_date);
        channel.tag_with_text_opt("generator", &self.generator);
        channel.tag_with_text_opt("docs", &self.docs);
        channel.tag_with_text_opt("image", &self.image);
        channel.tag_with_text_opt("rating", &self.rating);
        channel.tag_with_text_opt("skipHours", &self.skip_hours);
        channel.tag_with_text_opt("skipDays", &self.skip_days);

        for category in &self.categories {
            channel.tag(category.to_xml());
        }

        channel
    }

    fn from_xml(element: Element) -> Result<Self, &'static str> {
        let title = match element.get_child("title", None) {
            Some(element) => element.content_str(),
            None => return Err("<channel> is missing required <title> element"),
        };

        let link = match element.get_child("link", None) {
            Some(element) => element.content_str(),
            None => return Err("<channel> is missing required <link> element"),
        };

        let description = match element.get_child("description", None) {
            Some(element) => element.content_str(),
            None => return Err("<channel> is missing required <description> element"),
        };

        let items = element.get_children("item", None)
            .map(|e| ViaXml::from_xml(e.clone()).unwrap())
            .collect();

        let categories = element.get_children("category", None)
            .map(|e| ViaXml::from_xml(e.clone()).unwrap())
            .collect();

        Ok(Channel {
            title: title,
            link: link,
            description: description,
            items: items,
            categories: categories,
            ..Default::default()  // TODO
        })
    }
}

/// Item
///
/// [RSS 2.0 Specification § Item]
/// (http://cyber.law.harvard.edu/rss/rss.html#hrelementsOfLtitemgt)
#[derive(Default)]
pub struct Item {
    pub title: Option<String>,
    pub link: Option<String>,
    pub description: Option<String>,
    pub author: Option<String>,
    pub categories: Vec<Category>,
    pub comments: Option<String>,
    // pub enclosure
    // pub guid
    // pub pubDate
    // pub source
}

impl ViaXml for Item {
    fn to_xml(&self) -> Element {
        let mut item = Element::new("item".to_string(), None, vec![]);

        item.tag_with_text_opt("title", &self.title);
        item.tag_with_text_opt("link", &self.link);
        item.tag_with_text_opt("description", &self.description);
        item.tag_with_text_opt("author", &self.author);
        item.tag_with_text_opt("comments", &self.comments);

        for category in &self.categories {
            item.tag(category.to_xml());
        }

        item
    }

    fn from_xml(element: Element) -> Result<Self, &'static str> {
        let title = element.get_child("title", None).map(Element::content_str);
        let link = element.get_child("link", None).map(Element::content_str);
        let description = element.get_child("description", None).map(Element::content_str);
        let author = element.get_child("author", None).map(Element::content_str);
        let comments = element.get_child("comments", None).map(Element::content_str);

        let categories = element.get_children("category", None)
            .map(|e| ViaXml::from_xml(e.clone()).unwrap())
            .collect();

        Ok(Item {
            title: title,
            link: link,
            description: description,
            categories: categories,
            author: author,
            comments: comments,
        })
    }
}

/// Category
///
/// [RSS 2.0 Specification § Category]
/// (http://cyber.law.harvard.edu/rss/rss.html#ltcategorygtSubelementOfLtitemgt)
#[derive(Default)]
pub struct Category {
    pub domain: Option<String>,
    pub value: String,
}

impl ViaXml for Category {
    fn to_xml(&self) -> Element {
        let mut category = match self.domain {
            Some(ref d) => Element::new("category".to_string(), None, vec![("domain".to_string(), None, d.clone())]),
            None => Element::new("category".to_string(), None, vec![]),
        };
        category.text(self.value.clone());
        category
    }

    fn from_xml(elem: Element) -> Result<Self, &'static str> {
        let domain = elem.get_attribute("domain", None).map(|s| s.to_string());
        let value = elem.content_str();

        Ok(Category {
            domain: domain,
            value: value,
        })
    }
}

#[cfg(test)]
mod test {
    use std::default::Default;
    use std::fs::File;
    use super::{Rss, Item, Channel};

    #[test]
    fn test_basic_to_string() {
        let item = Item {
            title: Some("My first post!".to_string()),
            link: Some("http://myblog.com/post1".to_string()),
            description: Some("This is my first post".to_string()),
            ..Default::default()
        };

        let channel = Channel {
            title: "My Blog".to_string(),
            link: "http://myblog.com".to_string(),
            description: "Where I write stuff".to_string(),
            items: vec![item],
            ..Default::default()
        };

        let rss = Rss(channel);
        assert_eq!(rss.to_string(), "<?xml version=\'1.0\' encoding=\'UTF-8\'?><rss version=\'2.0\'><channel><title>My Blog</title><link>http://myblog.com</link><description>Where I write stuff</description><item><title>My first post!</title><link>http://myblog.com/post1</link><description>This is my first post</description></item></channel></rss>");
    }

    #[test]
    fn test_from_file() {
        let mut file = File::open("test-data/pinboard.xml").unwrap();
        let rss = Rss::from_read(&mut file).unwrap();
        assert!(rss.to_string().len() > 0);
    }

    #[test]
    #[should_panic]
    fn test_from_read_no_channels() {
        let mut rss_bytes = "<rss></rss>".as_bytes();
        let Rss(_) = Rss::from_read(&mut rss_bytes).unwrap();
    }

    #[test]
    #[should_panic]
    fn test_from_read_one_channel_no_properties() {
        let mut rss_bytes = "<rss><channel></channel></rss>".as_bytes();
        let Rss(_) = Rss::from_read(&mut rss_bytes).unwrap();
    }

    #[test]
    fn test_from_read_one_channel() {
        let mut rss_bytes = "<rss><channel><title>Hello world!</title><description></description><link></link></channel></rss>".as_bytes();
        let Rss(channel) = Rss::from_read(&mut rss_bytes).unwrap();
        assert_eq!("Hello world!", channel.title);
    }
}
<commit_msg>Encode <ttl><commit_after>extern crate xml;

use std::ascii::AsciiExt;
use std::default::Default;
use std::io;
use xml::{Element, ElementBuilder, Parser, Xml};

trait ElementUtils {
    fn tag_with_text(&mut self, child_name: &'static str, child_body: &str);
    fn tag_with_text_opt(&mut self, child_name: &'static str, child_body: &Option<String>);
}

impl ElementUtils for Element {
    fn tag_with_text(&mut self, child_name: &'static str, child_body: &str) {
        self.tag(elem_with_text(child_name, child_body));
    }

    fn tag_with_text_opt(&mut self, child_name: &'static str, child_body: &Option<String>) {
        if let Some(ref c) = *child_body {
            self.tag_with_text(child_name, &c);
        }
    }
}

fn elem_with_text(tag_name: &'static str, chars: &str) -> Element {
    let mut elem = Element::new(tag_name.to_string(), None, vec![]);
    elem.text(chars.to_string());
    elem
}

trait ViaXml {
    fn to_xml(&self) -> Element;
    fn from_xml(element: Element) -> Result<Self, &'static str>;
}

/// RSS
///
/// "At the top level, a RSS document is a \<rss\> element, with a mandatory attribute called
/// version, that specifies the version of RSS that the document conforms to. If it conforms to
/// this specification, the version attribute must be 2.0."
///
/// [RSS 2.0 Specification § RSS]
/// (http://cyber.law.harvard.edu/rss/rss.html#whatIsRss)
#[derive(Default)]
pub struct Rss(pub Channel);

impl ViaXml for Rss {
    fn to_xml(&self) -> Element {
        let mut rss = Element::new("rss".to_string(), None, vec![("version".to_string(), None, "2.0".to_string())]);

        let &Rss(ref channel) = self;
        rss.tag(channel.to_xml());

        rss
    }

    fn from_xml(rss_elem: Element) -> Result<Self, &'static str> {
        if rss_elem.name.to_ascii_lowercase() != "rss" {
            panic!("Expected <rss>, found <{}>", rss_elem.name);
        }

        let channel_elem = match rss_elem.get_child("channel", None) {
            Some(elem) => elem,
            None => return Err("No <channel> element found in <rss>"),
        };

        let channel = try!(ViaXml::from_xml(channel_elem.clone()));

        Ok(Rss(channel))
    }
}

impl Rss {
    pub fn to_string(&self) -> String {
        let mut ret = format!("{}", Xml::PINode("xml version='1.0' encoding='UTF-8'".to_string()));
        ret.push_str(&format!("{}", self.to_xml()));
        ret
    }

    pub fn from_read(reader: &mut io::Read) -> Result<Self, &'static str> {
        let mut rss_string = String::new();

        if let Err(..) = reader.read_to_string(&mut rss_string) {
            return Err("Error reading string from reader");
        }

        let mut parser = Parser::new();
        parser.feed_str(&rss_string);

        let mut builder = ElementBuilder::new();

        for event in parser {
            if let Some(Ok(element)) = builder.handle_event(event) {
                return ViaXml::from_xml(element);
            }
        }

        Err("RSS read error")
    }
}

/// Channel
///
/// "Subordinate to the \<rss\> element is a single \<channel\> element, which contains information
/// about the channel (metadata) and its contents."
///
/// [RSS 2.0 Specification § Channel]
/// (http://cyber.law.harvard.edu/rss/rss.html#requiredChannelElements)
///
/// ## Examples
///
/// ```
/// use rss::Channel;
/// use std::default::Default;
///
/// let channel = Channel {
///     title: "My Blog".to_string(),
///     link: "http://myblog.com".to_string(),
///     description: "Where I write stuff".to_string(),
///     items: vec![],
///     ..Default::default()
/// };
/// ```
#[derive(Default)]
pub struct Channel {
    pub title: String,
    pub link: String,
    pub description: String,
    pub items: Vec<Item>,
    pub language: Option<String>,
    pub copyright: Option<String>,
    pub managing_editor: Option<String>,
    pub web_master: Option<String>,
    pub pub_date: Option<String>,
    pub last_build_date: Option<String>,
    pub categories: Vec<Category>,
    pub generator: Option<String>,
    pub docs: Option<String>,
    // pub cloud:
    pub ttl: Option<String>,  // TODO: change this to Option<i32>?
    pub image: Option<String>,
    pub rating: Option<String>,
    // pub text_input:
    pub skip_hours: Option<String>,
    pub skip_days: Option<String>,
}

impl ViaXml for Channel {
    fn to_xml(&self) -> Element {
        let mut channel = Element::new("channel".to_string(), None, vec![]);

        channel.tag_with_text("title", &self.title);
        channel.tag_with_text("link", &self.link);
        channel.tag_with_text("description", &self.description);

        for item in &self.items {
            channel.tag(item.to_xml());
        }

        channel.tag_with_text_opt("language", &self.language);
        channel.tag_with_text_opt("copyright", &self.copyright);
        channel.tag_with_text_opt("managingEditor", &self.managing_editor);
        channel.tag_with_text_opt("webMaster", &self.web_master);
        channel.tag_with_text_opt("pubDate", &self.pub_date);
        channel.tag_with_text_opt("lastBuildDate", &self.last_build_date);
        channel.tag_with_text_opt("generator", &self.generator);
        channel.tag_with_text_opt("docs", &self.docs);
        channel.tag_with_text_opt("ttl", &self.ttl);
        channel.tag_with_text_opt("image", &self.image);
        channel.tag_with_text_opt("rating", &self.rating);
        channel.tag_with_text_opt("skipHours", &self.skip_hours);
        channel.tag_with_text_opt("skipDays", &self.skip_days);

        for category in &self.categories {
            channel.tag(category.to_xml());
        }

        channel
    }

    fn from_xml(element: Element) -> Result<Self, &'static str> {
        let title = match element.get_child("title", None) {
            Some(element) => element.content_str(),
            None => return Err("<channel> is missing required <title> element"),
        };

        let link = match element.get_child("link", None) {
            Some(element) => element.content_str(),
            None => return Err("<channel> is missing required <link> element"),
        };

        let description = match element.get_child("description", None) {
            Some(element) => element.content_str(),
            None => return Err("<channel> is missing required <description> element"),
        };

        let items = element.get_children("item", None)
            .map(|e| ViaXml::from_xml(e.clone()).unwrap())
            .collect();

        let categories = element.get_children("category", None)
            .map(|e| ViaXml::from_xml(e.clone()).unwrap())
            .collect();

        Ok(Channel {
            title: title,
            link: link,
            description: description,
            items: items,
            categories: categories,
            ..Default::default()  // TODO
        })
    }
}

/// Item
///
/// [RSS 2.0 Specification § Item]
/// (http://cyber.law.harvard.edu/rss/rss.html#hrelementsOfLtitemgt)
#[derive(Default)]
pub struct Item {
    pub title: Option<String>,
    pub link: Option<String>,
    pub description: Option<String>,
    pub author: Option<String>,
    pub categories: Vec<Category>,
    pub comments: Option<String>,
    // pub enclosure
    // pub guid
    // pub pubDate
    // pub source
}

impl ViaXml for Item {
    fn to_xml(&self) -> Element {
        let mut item = Element::new("item".to_string(), None, vec![]);

        item.tag_with_text_opt("title", &self.title);
        item.tag_with_text_opt("link", &self.link);
        item.tag_with_text_opt("description", &self.description);
        item.tag_with_text_opt("author", &self.author);
        item.tag_with_text_opt("comments", &self.comments);

        for category in &self.categories {
            item.tag(category.to_xml());
        }

        item
    }

    fn from_xml(element: Element) -> Result<Self, &'static str> {
        let title = element.get_child("title", None).map(Element::content_str);
        let link = element.get_child("link", None).map(Element::content_str);
        let description = element.get_child("description", None).map(Element::content_str);
        let author = element.get_child("author", None).map(Element::content_str);
        let comments = element.get_child("comments", None).map(Element::content_str);

        let categories = element.get_children("category", None)
            .map(|e| ViaXml::from_xml(e.clone()).unwrap())
            .collect();

        Ok(Item {
            title: title,
            link: link,
            description: description,
            categories: categories,
            author: author,
            comments: comments,
        })
    }
}

/// Category
///
/// [RSS 2.0 Specification § Category]
/// (http://cyber.law.harvard.edu/rss/rss.html#ltcategorygtSubelementOfLtitemgt)
#[derive(Default)]
pub struct Category {
    pub domain: Option<String>,
    pub value: String,
}

impl ViaXml for Category {
    fn to_xml(&self) -> Element {
        let mut category = match self.domain {
            Some(ref d) => Element::new("category".to_string(), None, vec![("domain".to_string(), None, d.clone())]),
            None => Element::new("category".to_string(), None, vec![]),
        };
        category.text(self.value.clone());
        category
    }

    fn from_xml(elem: Element) -> Result<Self, &'static str> {
        let domain = elem.get_attribute("domain", None).map(|s| s.to_string());
        let value = elem.content_str();

        Ok(Category {
            domain: domain,
            value: value,
        })
    }
}

#[cfg(test)]
mod test {
    use std::default::Default;
    use std::fs::File;
    use super::{Rss, Item, Channel};

    #[test]
    fn test_basic_to_string() {
        let item = Item {
            title: Some("My first post!".to_string()),
            link: Some("http://myblog.com/post1".to_string()),
            description: Some("This is my first post".to_string()),
            ..Default::default()
        };

        let channel = Channel {
            title: "My Blog".to_string(),
            link: "http://myblog.com".to_string(),
            description: "Where I write stuff".to_string(),
            items: vec![item],
            ..Default::default()
        };

        let rss = Rss(channel);
        assert_eq!(rss.to_string(), "<?xml version=\'1.0\' encoding=\'UTF-8\'?><rss version=\'2.0\'><channel><title>My Blog</title><link>http://myblog.com</link><description>Where I write stuff</description><item><title>My first post!</title><link>http://myblog.com/post1</link><description>This is my first post</description></item></channel></rss>");
    }

    #[test]
    fn test_from_file() {
        let mut file = File::open("test-data/pinboard.xml").unwrap();
        let rss = Rss::from_read(&mut file).unwrap();
        assert!(rss.to_string().len() > 0);
    }

    #[test]
    #[should_panic]
    fn test_from_read_no_channels() {
        let mut rss_bytes = "<rss></rss>".as_bytes();
        let Rss(_) = Rss::from_read(&mut rss_bytes).unwrap();
    }

    #[test]
    #[should_panic]
    fn test_from_read_one_channel_no_properties() {
        let mut rss_bytes = "<rss><channel></channel></rss>".as_bytes();
        let Rss(_) = Rss::from_read(&mut rss_bytes).unwrap();
    }

    #[test]
    fn test_from_read_one_channel() {
        let mut rss_bytes = "<rss><channel><title>Hello world!</title><description></description><link></link></channel></rss>".as_bytes();
        let Rss(channel) = Rss::from_read(&mut rss_bytes).unwrap();
        assert_eq!("Hello world!", channel.title);
    }
}
<|endoftext|>


<commit_before>use std::str::FromStr;
use std::fmt::{self, Display};

mod read;
pub use read::{Error, Parser};

mod write;
pub use write::Writer;

/// A unit of time for the `$timescale` command
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum TimescaleUnit {
    S, MS, US, NS, PS, FS,
}

impl FromStr for TimescaleUnit {
    type Err = Error;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        use self::TimescaleUnit::*;
        match s {
            "s"  => Ok(S),
            "ms" => Ok(MS),
            "us" => Ok(US),
            "ns" => Ok(NS),
            "ps" => Ok(PS),
            "fs" => Ok(FS),
            _ => Err(Error::Parse("Invalid timescale unit"))
        }
    }
}

impl Display for TimescaleUnit {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::TimescaleUnit::*;
        write!(f, "{}", match *self {
            S  => "s",
            MS => "ms",
            US => "us",
            NS => "ns",
            PS => "ps",
            FS => "fs",
        })
    }
}

/// A VCD scalar value
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum Value {
    /// Logic high (prefixed with `V` to make a valid Rust identifier
    V0,

    /// Logic low (prefixed with `V` to make a valid Rust identifier
    V1,

    /// An uninitialized or unknown value
    X,

    /// The "high-impedance" value
    Z,
}

impl Value {
    fn parse(v: u8) -> Result<Value, Error> {
        use Value::*;
        match v {
            b'0' => Ok(V0),
            b'1' => Ok(V1),
            b'x' | b'X' => Ok(X),
            b'z' | b'Z' => Ok(Z),
            _ => Err(Error::Parse("Invalid wire value"))
        }
    }
}

impl FromStr for Value {
    type Err = Error;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Value::parse(*s.as_bytes().get(0).unwrap_or(&b' '))
    }
}

impl Display for Value {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use Value::*;
        write!(f, "{}", match *self {
            V0  => "0",
            V1 => "1",
            X => "x",
            Z => "z",
        })
    }
}

/// A type of scope, as used in the `$scope` command
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum ScopeType {
    Module,
    Task,
    Function,
    Begin,
    Fork,
}

impl FromStr for ScopeType {
    type Err = Error;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        use self::ScopeType::*;
        match s {
            "module" => Ok(Module),
            "task" => Ok(Task),
            "function" => Ok(Function),
            "begin" => Ok(Begin),
            "fork" => Ok(Fork),
            _ => Err(Error::Parse("Invalid scope type"))
        }
    }
}

impl Display for ScopeType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::ScopeType::*;
        write!(f, "{}", match *self {
            Module => "module",
            Task  => "task",
            Function => "function",
            Begin  => "begin",
            Fork  => "fork",
        })
    }
}

/// A type of variable, as used in the `$var` command
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum VarType {
    //Event,
    //Integer,
    //Parameter,
    Real,
    Reg,
    //Supply0,
    //Supply1,
    //Time,
    //Tri,
    //Triant,
    //Trior,
    //Trireg,
    //Tri0,
    //Tri1,
    //Wand,
    Wire,
    //Wor,
}

impl FromStr for VarType {
    type Err = Error;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        use self::VarType::*;
        match s {
            "wire" => Ok(Wire),
            "reg" => Ok(Reg),
            "real" => Ok(Real),
            _ => Err(Error::Parse("Invalid var type"))
        }
    }
}

impl Display for VarType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::VarType::*;
        write!(f, "{}", match *self {
            Wire => "wire",
            Reg => "reg",
            Real => "real",
        })
    }
}

/// An ID used within the file to refer to a particular variable.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct IdCode(u32);

impl IdCode {
    fn new(v: &[u8]) -> Result<IdCode, Error> {
        let mut result = 0u32;
        for &i in v {
            result = result << 7 | ((i - b'!') as u32);
        }
        Ok(IdCode(result))
    }
}

impl FromStr for IdCode {
    type Err = Error;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        IdCode::new(s.as_bytes())
    }
}

impl From<u32> for IdCode {
    fn from(i: u32) -> IdCode { IdCode(i) }
}

impl Display for IdCode {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut i = self.0;
        loop {
            try!(write!(f, "{}", ((i&0x7f) as u8 + b'!') as char));
            i = i >> 7;
            if i == 0 { break; }
        }
        Ok(())
    }
}

/// Information on a VCD scope as represented by a `$scope` command and its children
#[derive(Debug, Clone)]
pub struct Scope {
    pub scope_type: ScopeType,
    pub identifier: String,
    pub children: Vec<ScopeItem>
}

impl Default for Scope {
    fn default() -> Scope {
        Scope { scope_type: ScopeType::Module, identifier: "".to_string(), children: Vec::new() }
    }
}

/// Information on a VCD variable as represented by a `$var` command.
#[derive(Debug, Clone)]
pub struct Var {
    pub var_type: VarType,
    pub size: u32,
    pub code: IdCode,
    pub reference: String,
}

/// An item in a scope -- either a child scope or a variable
#[derive(Debug, Clone)]
pub enum ScopeItem {
    Scope(Scope),
    Var(Var),
}

/// An element in a VCD file
#[derive(Debug, PartialEq, Clone)]
pub enum Command {
    /// A `$comment` command
    Comment(String),

    /// A `$date` command
    Date(String),

    /// A `$version` command
    Version(String),

    /// A `$timescale` command
    Timescale(u32, TimescaleUnit),

    /// A `$scope` command
    ScopeDef(ScopeType, String),

    /// An `$upscope` command
    Upscope,

    /// A `$var` command
    VarDef(VarType, u32, IdCode, String),

    /// An `$enddefinitions` command
    Enddefinitions,

    /// A `#xxx` timestamp
    Timestamp(u64),

    /// A `0a` change to a scalar variable
    ChangeScalar(IdCode, Value),

    /// A `b0000 a` change to a vector variable
    ChangeVector(IdCode, Vec<Value>),

    /// A `r1.234 a` change to a real variable
    ChangeReal(IdCode, f64),

    /// A `sSTART a` change to a (real?) variable
    ChangeString(IdCode, String),

    /// A beginning of a simulation command. Unlike header commands, which are parsed atomically,
    /// simulation commands emit a Begin, followed by the data changes within them, followed by
    /// End.
    Begin(SimulationCommand),

    /// An end of a simulation command.
    End(SimulationCommand)
}

/// A simulation command type, used in Command::Begin and Command::End
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum SimulationCommand {
    Dumpall,
    Dumpoff,
    Dumpon,
    Dumpvars,
}

impl Display for SimulationCommand {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::SimulationCommand::*;
        write!(f, "{}", match *self {
            Dumpall  => "dumpall",
            Dumpoff  => "dumpoff",
            Dumpon   => "dumpon",
            Dumpvars => "dumpvars",
        })
    }
}

/// Structure containing the data from the header of a VCD file
#[derive(Debug, Default)]
pub struct Header {
    pub comment: Option<String>,
    pub date: Option<String>,
    pub version: Option<String>,
    pub timescale: Option<(u32, TimescaleUnit)>,
    pub scope: Scope,
}
<commit_msg>Fix IdCode generation to stay within printable ASCII range<commit_after>use std::str::FromStr;
use std::fmt::{self, Display};

mod read;
pub use read::{Error, Parser};

mod write;
pub use write::Writer;

/// A unit of time for the `$timescale` command
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum TimescaleUnit {
    S, MS, US, NS, PS, FS,
}

impl FromStr for TimescaleUnit {
    type Err = Error;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        use self::TimescaleUnit::*;
        match s {
            "s"  => Ok(S),
            "ms" => Ok(MS),
            "us" => Ok(US),
            "ns" => Ok(NS),
            "ps" => Ok(PS),
            "fs" => Ok(FS),
            _ => Err(Error::Parse("Invalid timescale unit"))
        }
    }
}

impl Display for TimescaleUnit {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::TimescaleUnit::*;
        write!(f, "{}", match *self {
            S  => "s",
            MS => "ms",
            US => "us",
            NS => "ns",
            PS => "ps",
            FS => "fs",
        })
    }
}

/// A VCD scalar value
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum Value {
    /// Logic high (prefixed with `V` to make a valid Rust identifier
    V0,

    /// Logic low (prefixed with `V` to make a valid Rust identifier
    V1,

    /// An uninitialized or unknown value
    X,

    /// The "high-impedance" value
    Z,
}

impl Value {
    fn parse(v: u8) -> Result<Value, Error> {
        use Value::*;
        match v {
            b'0' => Ok(V0),
            b'1' => Ok(V1),
            b'x' | b'X' => Ok(X),
            b'z' | b'Z' => Ok(Z),
            _ => Err(Error::Parse("Invalid wire value"))
        }
    }
}

impl FromStr for Value {
    type Err = Error;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Value::parse(*s.as_bytes().get(0).unwrap_or(&b' '))
    }
}

impl Display for Value {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use Value::*;
        write!(f, "{}", match *self {
            V0  => "0",
            V1 => "1",
            X => "x",
            Z => "z",
        })
    }
}

/// A type of scope, as used in the `$scope` command
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum ScopeType {
    Module,
    Task,
    Function,
    Begin,
    Fork,
}

impl FromStr for ScopeType {
    type Err = Error;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        use self::ScopeType::*;
        match s {
            "module" => Ok(Module),
            "task" => Ok(Task),
            "function" => Ok(Function),
            "begin" => Ok(Begin),
            "fork" => Ok(Fork),
            _ => Err(Error::Parse("Invalid scope type"))
        }
    }
}

impl Display for ScopeType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::ScopeType::*;
        write!(f, "{}", match *self {
            Module => "module",
            Task  => "task",
            Function => "function",
            Begin  => "begin",
            Fork  => "fork",
        })
    }
}

/// A type of variable, as used in the `$var` command
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum VarType {
    //Event,
    //Integer,
    //Parameter,
    Real,
    Reg,
    //Supply0,
    //Supply1,
    //Time,
    //Tri,
    //Triant,
    //Trior,
    //Trireg,
    //Tri0,
    //Tri1,
    //Wand,
    Wire,
    //Wor,
}

impl FromStr for VarType {
    type Err = Error;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        use self::VarType::*;
        match s {
            "wire" => Ok(Wire),
            "reg" => Ok(Reg),
            "real" => Ok(Real),
            _ => Err(Error::Parse("Invalid var type"))
        }
    }
}

impl Display for VarType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::VarType::*;
        write!(f, "{}", match *self {
            Wire => "wire",
            Reg => "reg",
            Real => "real",
        })
    }
}

/// An ID used within the file to refer to a particular variable.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct IdCode(u32);

const ID_CHAR_MIN: u8 = b'!';
const ID_CHAR_MAX: u8 = b'~';
const NUM_ID_CHARS: u32 = (ID_CHAR_MAX - ID_CHAR_MIN + 1) as u32;

impl IdCode {
    fn new(v: &[u8]) -> Result<IdCode, Error> {
        let mut result = 0u32;
        for &i in v {
            if i < ID_CHAR_MIN || i > ID_CHAR_MAX { return Err(Error::Parse("Invalid ID character")) }
            result = result * NUM_ID_CHARS + ((i - ID_CHAR_MIN) as u32);
        }
        Ok(IdCode(result))
    }
}

impl FromStr for IdCode {
    type Err = Error;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        IdCode::new(s.as_bytes())
    }
}

impl From<u32> for IdCode {
    fn from(i: u32) -> IdCode { IdCode(i) }
}

impl Display for IdCode {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut i = self.0;
        loop {
            try!(write!(f, "{}", ((i % NUM_ID_CHARS) as u8 + ID_CHAR_MIN) as char));
            i = i / NUM_ID_CHARS;
            if i == 0 { break; }
        }
        Ok(())
    }
}

/// Information on a VCD scope as represented by a `$scope` command and its children
#[derive(Debug, Clone)]
pub struct Scope {
    pub scope_type: ScopeType,
    pub identifier: String,
    pub children: Vec<ScopeItem>
}

impl Default for Scope {
    fn default() -> Scope {
        Scope { scope_type: ScopeType::Module, identifier: "".to_string(), children: Vec::new() }
    }
}

/// Information on a VCD variable as represented by a `$var` command.
#[derive(Debug, Clone)]
pub struct Var {
    pub var_type: VarType,
    pub size: u32,
    pub code: IdCode,
    pub reference: String,
}

/// An item in a scope -- either a child scope or a variable
#[derive(Debug, Clone)]
pub enum ScopeItem {
    Scope(Scope),
    Var(Var),
}

/// An element in a VCD file
#[derive(Debug, PartialEq, Clone)]
pub enum Command {
    /// A `$comment` command
    Comment(String),

    /// A `$date` command
    Date(String),

    /// A `$version` command
    Version(String),

    /// A `$timescale` command
    Timescale(u32, TimescaleUnit),

    /// A `$scope` command
    ScopeDef(ScopeType, String),

    /// An `$upscope` command
    Upscope,

    /// A `$var` command
    VarDef(VarType, u32, IdCode, String),

    /// An `$enddefinitions` command
    Enddefinitions,

    /// A `#xxx` timestamp
    Timestamp(u64),

    /// A `0a` change to a scalar variable
    ChangeScalar(IdCode, Value),

    /// A `b0000 a` change to a vector variable
    ChangeVector(IdCode, Vec<Value>),

    /// A `r1.234 a` change to a real variable
    ChangeReal(IdCode, f64),

    /// A `sSTART a` change to a (real?) variable
    ChangeString(IdCode, String),

    /// A beginning of a simulation command. Unlike header commands, which are parsed atomically,
    /// simulation commands emit a Begin, followed by the data changes within them, followed by
    /// End.
    Begin(SimulationCommand),

    /// An end of a simulation command.
    End(SimulationCommand)
}

/// A simulation command type, used in Command::Begin and Command::End
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum SimulationCommand {
    Dumpall,
    Dumpoff,
    Dumpon,
    Dumpvars,
}

impl Display for SimulationCommand {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::SimulationCommand::*;
        write!(f, "{}", match *self {
            Dumpall  => "dumpall",
            Dumpoff  => "dumpoff",
            Dumpon   => "dumpon",
            Dumpvars => "dumpvars",
        })
    }
}

/// Structure containing the data from the header of a VCD file
#[derive(Debug, Default)]
pub struct Header {
    pub comment: Option<String>,
    pub date: Option<String>,
    pub version: Option<String>,
    pub timescale: Option<(u32, TimescaleUnit)>,
    pub scope: Scope,
}
<|endoftext|>