<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#[macro_use]
extern crate log;
extern crate uuid;
extern crate devicemapper;
extern crate libstratis;
#[macro_use]
mod util;

use devicemapper::DM;

use libstratis::engine::strat_engine::blockdev;
use libstratis::engine::strat_engine::blockdev::BlockDev;
use libstratis::engine::strat_engine::lineardev::LinearDev;
use libstratis::engine::strat_engine::metadata::MIN_MDA_SECTORS;
use libstratis::engine::strat_engine::thinpooldev::ThinPoolDev;
use libstratis::types::DataBlocks;
use libstratis::types::Sectors;

use std::path::{Path, PathBuf};

use util::blockdev_utils::clean_blockdev_headers;
use util::blockdev_utils::wait_for_dm;
use util::test_config::TestConfig;
use util::test_consts::DEFAULT_CONFIG_FILE;

use uuid::Uuid;

fn setup_supporting_devs(dm: &DM,
                         metadata_dev: &mut LinearDev,
                         data_dev: &mut LinearDev,
                         metadata_blockdev: &BlockDev,
                         data_blockdev: &BlockDev)
                         -> (PathBuf, PathBuf) {

    let meta_blockdevs = vec![metadata_blockdev];
    metadata_dev.concat(dm, &meta_blockdevs).unwrap();

    let data_blockdevs = vec![data_blockdev];
    data_dev.concat(dm, &data_blockdevs).unwrap();

    let metadata_path = metadata_dev.path().unwrap().unwrap();

    let data_path = data_dev.path().unwrap().unwrap();

    wait_for_dm();

    (metadata_path, data_path)
}
/// Validate the blockdev_paths are unique
/// Initialize the list for use with Stratis
/// Create a thin-pool via ThinPoolDev
/// Validate the resulting thin-pool dev and meta dev
fn test_thinpool_setup(dm: &DM,
                       thinpool_dev: &mut ThinPoolDev,
                       metadata_dev: &mut LinearDev,
                       data_dev: &mut LinearDev,
                       blockdev_paths: &Vec<&Path>) {

    let uuid = Uuid::new_v4();

    let unique_blockdevs = blockdev::resolve_devices(blockdev_paths).unwrap();

    let blockdev_map = blockdev::initialize(&uuid, unique_blockdevs, MIN_MDA_SECTORS, true)
        .unwrap();

    let (_first_key, metadata_blockdev) = blockdev_map.iter().next().unwrap();
    let (_last_key, data_blockdev) = blockdev_map.iter().next_back().unwrap();
    let (_start_sector, length) = data_blockdev.avail_range();

    let (metadata_path, data_path) =
        setup_supporting_devs(dm, metadata_dev, data_dev, metadata_blockdev, data_blockdev);

    thinpool_dev.setup(dm,
               length,
               Sectors(1024),
               DataBlocks(256000),
               &metadata_path,
               &data_path)
        .unwrap();

    wait_for_dm();
}

#[test]
/// Get list of safe to destroy devices.
/// Clean any headers from the devices.
/// Construct meta and data devices for use in the thin-pool
/// Test creating a thin-pool device
/// Teardown the DM device
pub fn test_thinpoolsetup_setup() {

    let dm = DM::new().unwrap();

    let mut test_config = TestConfig::new(DEFAULT_CONFIG_FILE);

    let _ = test_config.init();

    let safe_to_destroy_devs = match test_config.get_safe_to_destroy_devs() {
        Ok(devs) => {
            if devs.len() < 2 {
                warn!("test_thinpoolsetup_setup requires at least 2 devices to run.  Test not \
                       run.");
                return;
            }
            devs
        }
        Err(e) => {
            error!("Failed : get_safe_to_destroy_devs : {:?}", e);
            return;
        }
    };

    info!("safe_to_destroy_devs = {:?}", safe_to_destroy_devs);
    let device_paths = safe_to_destroy_devs.iter().map(|x| Path::new(x)).collect::<Vec<&Path>>();

    clean_blockdev_headers(&device_paths);
    info!("devices cleaned for test");

    let meta_name = "stratis_testing_thinpool_metadata";
    let mut metadata_dev = LinearDev::new(meta_name);

    let name = "stratis_testing_thinpool";
    let mut thinpool_dev = ThinPoolDev::new(name);

    let data_name = "stratis_testing_thinpool_datadev";
    let mut data_dev = LinearDev::new(data_name);

    test_thinpool_setup(&dm,
                        &mut thinpool_dev,
                        &mut metadata_dev,
                        &mut data_dev,
                        &device_paths);

    thinpool_dev.teardown(&dm).unwrap();

    data_dev.teardown(&dm).unwrap();

    metadata_dev.teardown(&dm).unwrap();
}
<commit_msg>Test creating a thin provisioned device on the thin-pool.<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#[macro_use]
extern crate log;
extern crate uuid;
extern crate devicemapper;
extern crate libstratis;
extern crate rand;
#[macro_use]
mod util;

use devicemapper::DM;

use libstratis::engine::strat_engine::blockdev;
use libstratis::engine::strat_engine::blockdev::BlockDev;
use libstratis::engine::strat_engine::lineardev::LinearDev;
use libstratis::engine::strat_engine::metadata::MIN_MDA_SECTORS;
use libstratis::engine::strat_engine::thindev::ThinDev;
use libstratis::engine::strat_engine::thinpooldev::ThinPoolDev;
use libstratis::types::DataBlocks;
use libstratis::types::Sectors;

use std::path::{Path, PathBuf};

use util::blockdev_utils::clean_blockdev_headers;
use util::blockdev_utils::wait_for_dm;
use util::test_config::TestConfig;
use util::test_consts::DEFAULT_CONFIG_FILE;

use uuid::Uuid;

fn setup_supporting_devs(dm: &DM,
                         metadata_dev: &mut LinearDev,
                         data_dev: &mut LinearDev,
                         metadata_blockdev: &BlockDev,
                         data_blockdev: &BlockDev)
                         -> (PathBuf, PathBuf) {

    let meta_blockdevs = vec![metadata_blockdev];
    metadata_dev.concat(dm, &meta_blockdevs).unwrap();

    let data_blockdevs = vec![data_blockdev];
    data_dev.concat(dm, &data_blockdevs).unwrap();

    let metadata_path = metadata_dev.path().unwrap().unwrap();

    let data_path = data_dev.path().unwrap().unwrap();

    wait_for_dm();

    (metadata_path, data_path)
}
/// Validate the blockdev_paths are unique
/// Initialize the list for use with Stratis
/// Create a thin-pool via ThinPoolDev
/// Validate the resulting thin-pool dev and meta dev
fn test_thinpool_setup(dm: &DM,
                       thinpool_dev: &mut ThinPoolDev,
                       metadata_dev: &mut LinearDev,
                       data_dev: &mut LinearDev,
                       blockdev_paths: &Vec<&Path>) {

    let uuid = Uuid::new_v4();

    let unique_blockdevs = blockdev::resolve_devices(blockdev_paths).unwrap();

    let blockdev_map = blockdev::initialize(&uuid, unique_blockdevs, MIN_MDA_SECTORS, true)
        .unwrap();

    let (_first_key, metadata_blockdev) = blockdev_map.iter().next().unwrap();
    let (_last_key, data_blockdev) = blockdev_map.iter().next_back().unwrap();
    let (_start_sector, length) = data_blockdev.avail_range();

    let (metadata_path, data_path) =
        setup_supporting_devs(dm, metadata_dev, data_dev, metadata_blockdev, data_blockdev);

    thinpool_dev.setup(dm,
               length,
               Sectors(1024),
               DataBlocks(256000),
               &metadata_path,
               &data_path)
        .unwrap();

    wait_for_dm();
}

#[test]
/// Get list of safe to destroy devices.
/// Clean any headers from the devices.
/// Construct meta and data devices for use in the thin-pool
/// Test creating a thin-pool device
/// Test create a thin device provisioned from the pool
/// Teardown the DM devices in the proper order
pub fn test_thinpoolsetup_setup() {

    let dm = DM::new().unwrap();

    let mut test_config = TestConfig::new(DEFAULT_CONFIG_FILE);

    let _ = test_config.init();

    let safe_to_destroy_devs = match test_config.get_safe_to_destroy_devs() {
        Ok(devs) => {
            if devs.len() < 2 {
                warn!("test_thinpoolsetup_setup requires at least 2 devices to run.  Test not \
                       run.");
                return;
            }
            devs
        }
        Err(e) => {
            error!("Failed : get_safe_to_destroy_devs : {:?}", e);
            return;
        }
    };

    info!("safe_to_destroy_devs = {:?}", safe_to_destroy_devs);
    let device_paths = safe_to_destroy_devs.iter().map(|x| Path::new(x)).collect::<Vec<&Path>>();

    clean_blockdev_headers(&device_paths);
    info!("devices cleaned for test");

    let meta_name = "stratis_testing_thinpool_metadata";
    let mut metadata_dev = LinearDev::new(meta_name);

    let name = "stratis_testing_thinpool";
    let mut thinpool_dev = ThinPoolDev::new(name);

    let data_name = "stratis_testing_thinpool_datadev";
    let mut data_dev = LinearDev::new(data_name);

    test_thinpool_setup(&dm,
                        &mut thinpool_dev,
                        &mut metadata_dev,
                        &mut data_dev,
                        &device_paths);

    let thindev_name = "stratis_testing_thindev";
    let mut thin_dev = ThinDev::new(thindev_name);
    let thin_id = rand::random::<u16>();
    thin_dev.setup(&dm, &mut thinpool_dev, thin_id as u32, &Sectors(300000)).unwrap();

    thin_dev.teardown(&dm).unwrap();

    thinpool_dev.teardown(&dm).unwrap();

    data_dev.teardown(&dm).unwrap();

    metadata_dev.teardown(&dm).unwrap();
}
<|endoftext|>


<commit_before>
extern crate ical;
extern crate rustc_serialize;

#[cfg(feature = "rustc-serialize")]
mod test {

    use std::path::Path;
    use std::fs::File;
    use std::error::Error;
    use std::io::{BufReader, BufRead};

    use ical::parser::Parser;
    use rustc_serialize::json::ToJson;

    fn run_file(in_path_vcf: &Path, res_path_json: &Path) {
        let res_file = File::open(res_path_json).unwrap();
        let mut res_reader = BufReader::new(res_file).lines();

        let parser = Parser::from_path(in_path_vcf).unwrap();

        for elem in parser {
            let expected = match res_reader.next().unwrap() {
                Ok(val) => val,
                Err(err) => return assert!(false, err),
            };

            match elem {
                Ok(val) => {
                    let output = val.to_json();
                    assert_eq!(expected, format!("{}", output));
                }
                Err(err) => {
                    println!("tutu");
                    assert_eq!(expected, format!("{}", err.description()));
                }
            };

        }
    }

    #[test]
    fn invalid_path() {
        let path = Path::new("this is an invalid path");

        match Parser::from_path(path) {
            Ok(_) => assert!(false, "File should be invalid"),
            Err(err) => assert_eq!(err.description(), "entity not found"),
        }
    }

    #[test]
    fn vcard() {
        let in_path_vcf = Path::new("./tests/parser/vcard.vcf");
        let out_path_json = Path::new("./tests/parser/vcard.json");

        run_file(in_path_vcf, out_path_json);
    }

    #[test]
    fn vcard_error() {
        let in_path_vcf = Path::new("./tests/parser/vcard_error.vcf");
        let out_path_json = Path::new("./tests/parser/vcard_error.json");

        run_file(in_path_vcf, out_path_json);
    }
}
<commit_msg>Remove unused test file.<commit_after><|endoftext|>


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

// Timing functions.
use extra::time::precise_time_ns;
use std::cell::Cell;
use std::comm::{Port, SharedChan};
use extra::sort::tim_sort;
use std::iterator::AdditiveIterator;

// front-end representation of the profiler used to communicate with the profiler
#[deriving(Clone)]
pub struct ProfilerChan {
    chan: SharedChan<ProfilerMsg>,
}

impl ProfilerChan {
    pub fn new(chan: Chan<ProfilerMsg>) -> ProfilerChan {
        ProfilerChan {
            chan: SharedChan::new(chan),
        }
    }
    pub fn send(&self, msg: ProfilerMsg) {
        self.chan.send(msg);
    }
}

#[deriving(Eq, Clone)]
pub enum ProfilerCategory {
    CompositingCategory,
    LayoutQueryCategory,
    LayoutPerformCategory,
    LayoutAuxInitCategory,
    LayoutSelectorMatchCategory,
    LayoutTreeBuilderCategory,
    LayoutMainCategory,
    LayoutShapingCategory,
    LayoutDispListBuildCategory,
    GfxRegenAvailableFontsCategory,
    RenderingDrawingCategory,
    RenderingPrepBuffCategory,
    RenderingCategory,
    // hackish but helps prevent errors when adding new categories
    NUM_BUCKETS,
}
// FIXME(#5873) this should be initialized by a NUM_BUCKETS cast,
static BUCKETS: uint = 13;
type ProfilerBuckets = [(ProfilerCategory, ~[float]), ..BUCKETS];

pub enum ProfilerMsg {
    // Normal message used for reporting time
    TimeMsg(ProfilerCategory, float),
    // Message used to force print the profiling metrics
    PrintMsg,
}

// back end of the profiler that handles data aggregation and performance metrics
pub struct Profiler {
    port: Port<ProfilerMsg>,
    buckets: ProfilerBuckets,
    last_msg: Option<ProfilerMsg>,
}

impl ProfilerCategory {
    // convenience function to not have to cast every time
    pub fn num_buckets() -> uint {
        NUM_BUCKETS as uint
    }

    // enumeration of all ProfilerCategory types
    // TODO(tkuehn): is there a better way to ensure proper order of categories?
    fn empty_buckets() -> ProfilerBuckets {
        let buckets = [
            (CompositingCategory, ~[]),
            (LayoutQueryCategory, ~[]),
            (LayoutPerformCategory, ~[]),
            (LayoutAuxInitCategory, ~[]),
            (LayoutSelectorMatchCategory, ~[]),
            (LayoutTreeBuilderCategory, ~[]),
            (LayoutMainCategory, ~[]),
            (LayoutShapingCategory, ~[]),
            (LayoutDispListBuildCategory, ~[]),
            (GfxRegenAvailableFontsCategory, ~[]),
            (RenderingDrawingCategory, ~[]),
            (RenderingPrepBuffCategory, ~[]),
            (RenderingCategory, ~[]),
        ];

        ProfilerCategory::check_order(&buckets);
        buckets
    }

    // ensure that the order of the buckets matches the order of the enum categories
    fn check_order(vec: &ProfilerBuckets) {
        for &(category, _) in vec.iter() {
            if category != vec[category as uint].first() {
                fail!("Enum category does not match bucket index. This is a bug.");
            }
        }
    }

    // some categories are subcategories of LayoutPerformCategory
    // and should be printed to indicate this
    pub fn format(self) -> ~str {
        let padding = match self {
            LayoutAuxInitCategory | LayoutSelectorMatchCategory | LayoutTreeBuilderCategory |
            LayoutMainCategory | LayoutDispListBuildCategory | LayoutShapingCategory=> " - ",
            _ => ""
        };
        fmt!("%s%?", padding, self)
    }
}

impl Profiler {
    pub fn create(port: Port<ProfilerMsg>) {
        let port = Cell::new(port);
        do spawn {
            let mut profiler = Profiler::new(port.take());
            profiler.start();
        }
    }

    pub fn new(port: Port<ProfilerMsg>) -> Profiler {
        Profiler {
            port: port,
            buckets: ProfilerCategory::empty_buckets(),
            last_msg: None,
        }
    }

    pub fn start(&mut self) {
        loop {
            let msg = self.port.try_recv();
            match msg {
               Some (msg) => self.handle_msg(msg),
               None => break
            }
        }
    }

    fn handle_msg(&mut self, msg: ProfilerMsg) {
        match msg {
            TimeMsg(category, t) => match self.buckets[category as uint] {
                //TODO(tkuehn): would be nice to have tuple.second_mut()
                (_, ref mut data) => data.push(t),
            },
            PrintMsg => match self.last_msg {
                // only print if more data has arrived since the last printout
                Some(TimeMsg(*)) => self.print_buckets(),
                _ => {}
            },
        };
        self.last_msg = Some(msg);
    }

    fn print_buckets(&mut self) {
        println(fmt!("%31s %15s %15s %15s %15s %15s",
                         "_category_", "_mean (ms)_", "_median (ms)_",
                         "_min (ms)_", "_max (ms)_", "_bucket size_"));
        for bucket in self.buckets.mut_iter() {
            let (category, data) = match *bucket {
                (category, ref mut data) => (category, data),
            };
            tim_sort(*data);
            let data_len = data.len();
            if data_len > 0 {
                let (mean, median, &min, &max) =
                    (data.iter().map(|&x|x).sum() / (data_len as float),
                     data[data_len / 2],
                     data.iter().min().unwrap(),
                     data.iter().max().unwrap());
                println(fmt!("%-30s: %15.4f %15.4f %15.4f %15.4f %15u",
                             category.format(), mean, median, min, max, data_len));
            }
        }
        println("");
    }
}

pub fn profile<T>(category: ProfilerCategory,
                  profiler_chan: ProfilerChan,
                  callback: &fn() -> T)
                  -> T {
    let start_time = precise_time_ns();
    let val = callback();
    let end_time = precise_time_ns();
    let ms = ((end_time - start_time) as float / 1000000f);
    profiler_chan.send(TimeMsg(category, ms));
    return val;
}

pub fn time<T>(msg: &str, callback: &fn() -> T) -> T{
    let start_time = precise_time_ns();
    let val = callback();
    let end_time = precise_time_ns();
    let ms = ((end_time - start_time) as float / 1000000f);
    if ms >= 5f {
        debug!("%s took %? ms", msg, ms);
    }
    return val;
}

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

// Timing functions.
use extra::time::precise_time_ns;
use std::cell::Cell;
use std::comm::{Port, SharedChan};
use extra::sort::tim_sort;
use std::iterator::AdditiveIterator;

// front-end representation of the profiler used to communicate with the profiler
#[deriving(Clone)]
pub struct ProfilerChan {
    chan: SharedChan<ProfilerMsg>,
}

impl ProfilerChan {
    pub fn new(chan: Chan<ProfilerMsg>) -> ProfilerChan {
        ProfilerChan {
            chan: SharedChan::new(chan),
        }
    }
    pub fn send(&self, msg: ProfilerMsg) {
        self.chan.send(msg);
    }
}

#[deriving(Eq, Clone)]
pub enum ProfilerCategory {
    CompositingCategory,
    LayoutQueryCategory,
    LayoutPerformCategory,
    LayoutAuxInitCategory,
    LayoutSelectorMatchCategory,
    LayoutTreeBuilderCategory,
    LayoutMainCategory,
    LayoutShapingCategory,
    LayoutDispListBuildCategory,
    GfxRegenAvailableFontsCategory,
    RenderingDrawingCategory,
    RenderingPrepBuffCategory,
    RenderingCategory,
    // hackish but helps prevent errors when adding new categories
    NumBuckets,
}
struct ProfilerBucket {
    category: ProfilerCategory,
    data: ~[float],
}
impl ProfilerBucket {
    fn new(category: ProfilerCategory) -> ProfilerBucket {
        ProfilerBucket {
            category: category,
            data: ~[],
        }
    }
}
// FIXME(rust#5873) this should be initialized by a NumBuckets cast,
type ProfilerBuckets = [ProfilerBucket, ..13];

pub enum ProfilerMsg {
    // Normal message used for reporting time
    TimeMsg(ProfilerCategory, float),
    // Message used to force print the profiling metrics
    PrintMsg,
}

// back end of the profiler that handles data aggregation and performance metrics
pub struct Profiler {
    port: Port<ProfilerMsg>,
    buckets: ProfilerBuckets,
    last_msg: Option<ProfilerMsg>,
}

impl ProfilerCategory {
    // convenience function to not have to cast every time
    pub fn num_buckets() -> uint {
        NumBuckets as uint
    }

    // enumeration of all ProfilerCategory types
    // TODO(tkuehn): is there a better way to ensure proper order of categories?
    fn empty_buckets() -> ProfilerBuckets {
        let buckets = [
            ProfilerBucket::new(CompositingCategory),
            ProfilerBucket::new(LayoutQueryCategory),
            ProfilerBucket::new(LayoutPerformCategory),
            ProfilerBucket::new(LayoutAuxInitCategory),
            ProfilerBucket::new(LayoutSelectorMatchCategory),
            ProfilerBucket::new(LayoutTreeBuilderCategory),
            ProfilerBucket::new(LayoutMainCategory),
            ProfilerBucket::new(LayoutShapingCategory),
            ProfilerBucket::new(LayoutDispListBuildCategory),
            ProfilerBucket::new(GfxRegenAvailableFontsCategory),
            ProfilerBucket::new(RenderingDrawingCategory),
            ProfilerBucket::new(RenderingPrepBuffCategory),
            ProfilerBucket::new(RenderingCategory),
        ];

        ProfilerCategory::check_order(&buckets);
        buckets
    }

    // ensure that the order of the buckets matches the order of the enum categories
    fn check_order(vec: &ProfilerBuckets) {
        for (i, bucket) in vec.iter().enumerate() {
            if bucket.category as uint != i {
                fail!("Enum category does not match bucket index. This is a bug.");
            }
        }
    }

    // some categories are subcategories of LayoutPerformCategory
    // and should be printed to indicate this
    pub fn format(self) -> ~str {
        let padding = match self {
            LayoutAuxInitCategory | LayoutSelectorMatchCategory | LayoutTreeBuilderCategory |
            LayoutMainCategory | LayoutDispListBuildCategory | LayoutShapingCategory=> " - ",
            _ => ""
        };
        fmt!("%s%?", padding, self)
    }
}

impl Profiler {
    pub fn create(port: Port<ProfilerMsg>) {
        let port = Cell::new(port);
        do spawn {
            let mut profiler = Profiler::new(port.take());
            profiler.start();
        }
    }

    pub fn new(port: Port<ProfilerMsg>) -> Profiler {
        Profiler {
            port: port,
            buckets: ProfilerCategory::empty_buckets(),
            last_msg: None,
        }
    }

    pub fn start(&mut self) {
        loop {
            let msg = self.port.try_recv();
            match msg {
               Some (msg) => self.handle_msg(msg),
               None => break
            }
        }
    }

    fn handle_msg(&mut self, msg: ProfilerMsg) {
        match msg {
            TimeMsg(category, t) => self.buckets[category as uint].data.push(t),
            PrintMsg => match self.last_msg {
                // only print if more data has arrived since the last printout
                Some(TimeMsg(*)) => self.print_buckets(),
                _ => ()
            },
        };
        self.last_msg = Some(msg);
    }

    fn print_buckets(&mut self) {
        println(fmt!("%31s %15s %15s %15s %15s %15s",
                         "_category_", "_mean (ms)_", "_median (ms)_",
                         "_min (ms)_", "_max (ms)_", "_bucket size_"));
        for &ProfilerBucket { category: ref category, data: ref mut data } in self.buckets.mut_iter() {
            tim_sort(*data);
            let data_len = data.len();
            if data_len > 0 {
                let (mean, median, &min, &max) =
                    (data.iter().map(|&x|x).sum() / (data_len as float),
                     data[data_len / 2],
                     data.iter().min().unwrap(),
                     data.iter().max().unwrap());
                println(fmt!("%-30s: %15.4f %15.4f %15.4f %15.4f %15u",
                             category.format(), mean, median, min, max, data_len));
            }
        }
        println("");
    }
}

pub fn profile<T>(category: ProfilerCategory,
                  profiler_chan: ProfilerChan,
                  callback: &fn() -> T)
                  -> T {
    let start_time = precise_time_ns();
    let val = callback();
    let end_time = precise_time_ns();
    let ms = ((end_time - start_time) as float / 1000000f);
    profiler_chan.send(TimeMsg(category, ms));
    return val;
}

pub fn time<T>(msg: &str, callback: &fn() -> T) -> T{
    let start_time = precise_time_ns();
    let val = callback();
    let end_time = precise_time_ns();
    let ms = ((end_time - start_time) as float / 1000000f);
    if ms >= 5f {
        debug!("%s took %? ms", msg, ms);
    }
    return val;
}

<|endoftext|>


<commit_before>// Implements http://rosettacode.org/wiki/Concurrent_computing
// not_tested
use std::io::timer::sleep;
use std::rand::random;
use std::time::duration::Duration;

fn main() {
    let strings = vec!["Enjoy", "Rosetta", "Code"];

    for s in strings.move_iter(){
        spawn(proc() {
            // We use a random u8 (so an integer from 0 to 255)
            sleep(Duration::milliseconds(random::<u8>() as i32));
            println!("{}", s);
        });
    }
}
<commit_msg>Fix concurrent_computing<commit_after>// Implements http://rosettacode.org/wiki/Concurrent_computing
// not_tested
use std::io::timer::sleep;
use std::rand::random;
use std::time::duration::Duration;

fn main() {
    let strings = vec!["Enjoy", "Rosetta", "Code"];

    for s in strings.move_iter(){
        spawn(proc() {
            // We use a random u8 (so an integer from 0 to 255)
            sleep(Duration::milliseconds(random::<u8>() as i64));
            println!("{}", s);
        });
    }
}
<|endoftext|>


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

extern crate pulse;

use std::thread;
use pulse::*;

#[test]
fn select_one() {
    let (p, t) = Signal::new();
    let mut select = Select::new();
    let id = select.add(p);
    t.pulse();
    let p = select.next().unwrap();
    assert_eq!(id, p.id());
}

#[test]
fn select_three() {
    let (p0, t0) = Signal::new();
    let (p1, t1) = Signal::new();
    let (p2, t2) = Signal::new();

    let mut select = Select::new();
    let id0 = select.add(p0);
    let id1 = select.add(p1);
    let id2 = select.add(p2);

    t0.pulse();
    let p = select.next().unwrap();
    assert_eq!(id0, p.id());

    t1.pulse();
    let p = select.next().unwrap();
    assert_eq!(id1, p.id());

    t2.pulse();
    let p = select.next().unwrap();
    assert_eq!(id2, p.id());

    let p = select.next();
    assert!(p.is_none());
}

#[test]
fn select_thread() {
    let (p0, t0) = Signal::new();
    let (p1, t1) = Signal::new();
    let (p2, t2) = Signal::new();

    let mut select = Select::new();
    let id0 = select.add(p0);
    let id1 = select.add(p1);
    let id2 = select.add(p2);

    thread::spawn(move || {
        thread::sleep_ms(10);
        t0.pulse();
        thread::sleep_ms(10);
        t1.pulse();
        thread::sleep_ms(10);
        t2.pulse();
    });

    let p = select.next().unwrap();
    assert_eq!(id0, p.id());
    let p = select.next().unwrap();
    assert_eq!(id1, p.id());
    let p = select.next().unwrap();
    assert_eq!(id2, p.id());
    let p = select.next();
    assert!(p.is_none());
}

#[test]
fn select_barrier() {
    let (p0, t0) = Signal::new();
    let (p1, t1) = Signal::new();
    let (p2, t2) = Signal::new();

    let mut select = Select::new();
    let _ = select.add(p0);
    let _ = select.add(p1);
    let _ = select.add(p2);

    thread::spawn(move || {
        thread::sleep_ms(10);
        t0.pulse();
        thread::sleep_ms(10);
        t1.pulse();
        thread::sleep_ms(10);
        t2.pulse();
    });

    select.into_barrier().signal().wait().unwrap();
}

#[test]
fn select_already_pulsed() {
    let (p0, t0) = Signal::new();
    t0.pulse();

    let mut select = Select::new();
    let id0 = select.add(p0);

    let p = select.next().unwrap();
    assert_eq!(id0, p.id());
    let p = select.next();
    assert!(p.is_none());
}<commit_msg>Added unit test for select::remove / select::next() race<commit_after>//   Copyright 2015 Colin Sherratt
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

extern crate pulse;

use std::thread;
use pulse::*;

#[test]
fn select_one() {
    let (p, t) = Signal::new();
    let mut select = Select::new();
    let id = select.add(p);
    t.pulse();
    let p = select.next().unwrap();
    assert_eq!(id, p.id());
}

#[test]
fn select_three() {
    let (p0, t0) = Signal::new();
    let (p1, t1) = Signal::new();
    let (p2, t2) = Signal::new();

    let mut select = Select::new();
    let id0 = select.add(p0);
    let id1 = select.add(p1);
    let id2 = select.add(p2);

    t0.pulse();
    let p = select.next().unwrap();
    assert_eq!(id0, p.id());

    t1.pulse();
    let p = select.next().unwrap();
    assert_eq!(id1, p.id());

    t2.pulse();
    let p = select.next().unwrap();
    assert_eq!(id2, p.id());

    let p = select.next();
    assert!(p.is_none());
}

#[test]
fn select_thread() {
    let (p0, t0) = Signal::new();
    let (p1, t1) = Signal::new();
    let (p2, t2) = Signal::new();

    let mut select = Select::new();
    let id0 = select.add(p0);
    let id1 = select.add(p1);
    let id2 = select.add(p2);

    thread::spawn(move || {
        thread::sleep_ms(10);
        t0.pulse();
        thread::sleep_ms(10);
        t1.pulse();
        thread::sleep_ms(10);
        t2.pulse();
    });

    let p = select.next().unwrap();
    assert_eq!(id0, p.id());
    let p = select.next().unwrap();
    assert_eq!(id1, p.id());
    let p = select.next().unwrap();
    assert_eq!(id2, p.id());
    let p = select.next();
    assert!(p.is_none());
}

#[test]
fn select_barrier() {
    let (p0, t0) = Signal::new();
    let (p1, t1) = Signal::new();
    let (p2, t2) = Signal::new();

    let mut select = Select::new();
    let _ = select.add(p0);
    let _ = select.add(p1);
    let _ = select.add(p2);

    thread::spawn(move || {
        thread::sleep_ms(10);
        t0.pulse();
        thread::sleep_ms(10);
        t1.pulse();
        thread::sleep_ms(10);
        t2.pulse();
    });

    select.into_barrier().signal().wait().unwrap();
}

#[test]
fn select_already_pulsed() {
    let (p0, t0) = Signal::new();
    t0.pulse();

    let mut select = Select::new();
    let id0 = select.add(p0);

    let p = select.next().unwrap();
    assert_eq!(id0, p.id());
    let p = select.next();
    assert!(p.is_none());
}

#[test]
fn select_remove() {
    let (p0, t0) = Signal::new();
    let (p1, t1) = Signal::new();

    let mut select = Select::new();
    let id0 = select.add(p0);
    let id1 = select.add(p1);

    thread::spawn(move || {
        // This should only matter if the bug still exists
        // this thread will otherwise unblock the select
        thread::sleep_ms(100);
        t1.pulse();
    });

    t0.pulse();
    select.remove(id0).unwrap();
    assert_eq!(id1, select.next().unwrap().id());
}
<|endoftext|>


<commit_before>extern crate rustracer as rt;
extern crate rand;
extern crate nalgebra as na;

use std::f32;
use rand::{Rng, StdRng, SeedableRng};
use rand::distributions::{Range, IndependentSample};
use na::{Norm, Dot};

use rt::{Point, Point2f};
use rt::ray::Ray;
use rt::sampling;
use rt::shapes::Shape;
use rt::shapes::sphere::Sphere;

fn pexp<T: Rng>(rng: &mut T, exp: f32) -> f32 {
    let range = Range::new(-exp, exp);
    let logu: f32 = range.ind_sample(rng);
    let base = 10.0_f32;
    base.powf(logu)
}

#[test]
fn full_sphere_reintersect() {
    let mut rng = StdRng::from_seed(&[0]);
    for i in 0..1000 {
        rng.reseed(&[i]);
        let radius = pexp(&mut rng, 4.0);
        let sphere = Sphere::new(na::one(), radius, -radius, radius, 360.0);
        test_reintersection_convex(&sphere, &mut rng);
    }
}

fn test_reintersection_convex<T: Shape>(shape: &T, rng: &mut StdRng) {
    // Ray origin
    let o = Point::new(pexp(rng, 8.0), pexp(rng, 8.0), pexp(rng, 8.0));

    // Destination
    let bounds = shape.world_bounds();
    let t = Point::new(rng.next_f32(), rng.next_f32(), rng.next_f32());
    let p = bounds.lerp(&t);
    let mut ray = Ray::new(o, p - o);
    if rng.next_f32() < 0.5 {
        ray.d = ray.d.normalize();
    }

    // We usually, but not always, get an intersection
    if let Some((isect, _t_hit)) = shape.intersect(&mut ray) {
        // Now trace a bunch of rays leaving the intersection point
        for i in 0..10000 {
            // Random direction leaving the intersection point
            let u = Point2f::new(rng.next_f32(), rng.next_f32());
            let mut w = sampling::uniform_sample_sphere(&u);
            if w.dot(&isect.n) < 0.0 {
                w = -w;
            }
            let mut ray_out = isect.spawn_ray(&w);
            assert!(!shape.intersect_p(&mut ray_out));
            assert!(shape.intersect(&mut ray_out).is_none());

        }
    }
}
<commit_msg>Fix test compilation<commit_after>extern crate rustracer as rt;
extern crate rand;
extern crate nalgebra as na;

use std::f32;
use rand::{Rng, StdRng, SeedableRng};
use rand::distributions::{Range, IndependentSample};
use na::{Norm, Dot};

use rt::{Point, Point2f};
use rt::ray::Ray;
use rt::sampling;
use rt::shapes::Shape;
use rt::shapes::sphere::Sphere;

fn pexp<T: Rng>(rng: &mut T, exp: f32) -> f32 {
    let range = Range::new(-exp, exp);
    let logu: f32 = range.ind_sample(rng);
    let base = 10.0_f32;
    base.powf(logu)
}

#[test]
fn full_sphere_reintersect() {
    let mut rng = StdRng::from_seed(&[0]);
    for i in 0..1000 {
        rng.reseed(&[i]);
        let radius = pexp(&mut rng, 4.0);
        let sphere = Sphere::new().radius(radius);
        test_reintersection_convex(&sphere, &mut rng);
    }
}

fn test_reintersection_convex<T: Shape>(shape: &T, rng: &mut StdRng) {
    // Ray origin
    let o = Point::new(pexp(rng, 8.0), pexp(rng, 8.0), pexp(rng, 8.0));

    // Destination
    let bounds = shape.world_bounds();
    let t = Point::new(rng.next_f32(), rng.next_f32(), rng.next_f32());
    let p = bounds.lerp(&t);
    let mut ray = Ray::new(o, p - o);
    if rng.next_f32() < 0.5 {
        ray.d = ray.d.normalize();
    }

    // We usually, but not always, get an intersection
    if let Some((isect, _t_hit)) = shape.intersect(&mut ray) {
        // Now trace a bunch of rays leaving the intersection point
        for i in 0..10000 {
            // Random direction leaving the intersection point
            let u = Point2f::new(rng.next_f32(), rng.next_f32());
            let mut w = sampling::uniform_sample_sphere(&u);
            if w.dot(&isect.n) < 0.0 {
                w = -w;
            }
            let mut ray_out = isect.spawn_ray(&w);
            assert!(!shape.intersect_p(&mut ray_out));
            assert!(shape.intersect(&mut ray_out).is_none());

        }
    }
}
<|endoftext|>


<commit_before>#![feature(plugin)]
#![plugin(parse_generics_poc)]

macro_rules! assert_eq_str {
    ($left:expr, $right:expr) => {
        assert_eq!($left.replace("\n", " "), $right.replace("\n", " "))
    };
}

#[test]
fn test_simple() {
    assert_eq_str!(
        parse_generics!(then stringify!(),),
        "{ \
            constr : [  ] , \
            ltimes : [  ] , \
            params : [  ] \
        } ,"
    );

    assert_eq_str!(
        parse_generics!(then stringify!(W),),
        "W { \
            constr : [  ] , \
            ltimes : [  ] , \
            params : [  ] \
        } ,"
    );

    assert_eq_str!(
        parse_generics!(then stringify!(), <>),
        "{ \
            constr : [  ] , \
            ltimes : [  ] , \
            params : [  ] \
        } ,"
    );

    assert_eq_str!(
        parse_generics!(then stringify!(), X),
        "{ \
            constr : [  ] , \
            ltimes : [  ] , \
            params : [  ] \
        } , X"
    );

    assert_eq_str!(
        parse_generics!(then stringify!(), <> X),
        "{ \
            constr : [  ] , \
            ltimes : [  ] , \
            params : [  ] \
        } , X"
    );

    assert_eq_str!(
        parse_generics!(then stringify!(), 'a X),
        "{ \
            constr : [  ] , \
            ltimes : [  ] , \
            params : [  ] \
        } , 'a X"
    );

    assert_eq_str!(
        parse_generics!(then stringify!(), <'a> X),
        "{ \
            constr : [ 'a , ] , \
            ltimes : [ 'a , ] , \
            params : [  ] \
        } , X"
    );

    assert_eq_str!(
        parse_generics!(then stringify!(), <'a, 'b> X),
        "{ \
            constr : [ 'a , 'b , ] , \
            ltimes : [ 'a , 'b , ] , \
            params : [  ] \
        } , X"
    );

    assert_eq_str!(
        parse_generics!(then stringify!(), <T> X),
        "{ \
            constr : [ T , ] , \
            ltimes : [  ] , \
            params : [ T , ] \
        } , X"
    );

    assert_eq_str!(
        parse_generics!(then stringify!(), <T, U> X),
        "{ \
            constr : [ T , U , ] , \
            ltimes : [  ] , \
            params : [ T , U , ] \
        } , X"
    );

    assert_eq_str!(
        parse_generics!(then stringify!(), <'a, 'b: 'a> X),
        "{ \
            constr : [ 'a , 'b : 'a , ] , \
            ltimes : [ 'a , 'b , ] , \
            params : [  ] \
        } , X"
    );

    assert_eq_str!(
        parse_generics!(then stringify!(), <'a, 'b: 'a + 'c> X),
        "{ \
            constr : [ 'a , 'b : 'a + 'c , ] , \
            ltimes : [ 'a , 'b , ] , \
            params : [  ] \
        } , X"
    );

    assert_eq_str!(
        parse_generics!(then stringify!(), <T: Copy> X),
        "{ \
            constr : [ T : Copy , ] , \
            ltimes : [  ] , \
            params : [ T , ] \
        } , X"
    );

    assert_eq_str!(
        parse_generics!(then stringify!(), <T: 'a> X),
        "{ \
            constr : [ T : 'a , ] , \
            ltimes : [  ] , \
            params : [ T , ] \
        } , X"
    );

    assert_eq_str!(
        parse_generics!(then stringify!(), <T: 'a + Copy + Clone> X),
        "{ \
            constr : [ T : 'a + Copy + Clone , ] , \
            ltimes : [  ] , \
            params : [ T , ] \
        } , X"
    );

    assert_eq_str!(
        parse_generics!(then stringify!(), <T: 'a + 'b + Copy + Clone> X),
        "{ \
            constr : [ T : 'a + 'b + Copy + Clone , ] , \
            ltimes : [  ] , \
            params : [ T , ] \
        } , X"
    );

    assert_eq_str!(
        parse_generics!(then stringify!(),
            <T: 'a + 'b + Copy + Clone + for<'c, 'd: 'e> Fn(&'c i32)> X),
        "{ \
            constr : [ T : 'a + 'b + Copy + Clone \
                + for < 'c , 'd : 'e > Fn ( &'c i32 , ) , ] , \
            ltimes : [  ] , \
            params : [ T , ] \
        } , X"
    );

    assert_eq_str!(
        parse_generics!(then stringify!(),
            <T: for<> Copy> X),
        "{ \
            constr : [ T : Copy , ] , \
            ltimes : [  ] , \
            params : [ T , ] \
        } , X"
    );
}
<commit_msg>More tests.<commit_after>#![feature(plugin)]
#![plugin(parse_generics_poc)]

macro_rules! assert_eq_str {
    ($left:expr, $right:expr) => {
        assert_eq!($left.replace("\n", " "), $right.replace("\n", " "))
    };
}

#[test]
fn test_simple() {
    assert_eq_str!(
        parse_generics!(then stringify!(),),
        "{ \
            constr : [  ] , \
            ltimes : [  ] , \
            params : [  ] \
        } ,"
    );

    assert_eq_str!(
        parse_generics!(then stringify!(W),),
        "W { \
            constr : [  ] , \
            ltimes : [  ] , \
            params : [  ] \
        } ,"
    );

    assert_eq_str!(
        parse_generics!(then stringify!(), <>),
        "{ \
            constr : [  ] , \
            ltimes : [  ] , \
            params : [  ] \
        } ,"
    );

    assert_eq_str!(
        parse_generics!(then stringify!(), X),
        "{ \
            constr : [  ] , \
            ltimes : [  ] , \
            params : [  ] \
        } , X"
    );

    assert_eq_str!(
        parse_generics!(then stringify!(), <> X),
        "{ \
            constr : [  ] , \
            ltimes : [  ] , \
            params : [  ] \
        } , X"
    );

    assert_eq_str!(
        parse_generics!(then stringify!(), 'a X),
        "{ \
            constr : [  ] , \
            ltimes : [  ] , \
            params : [  ] \
        } , 'a X"
    );

    assert_eq_str!(
        parse_generics!(then stringify!(), <'a> X),
        "{ \
            constr : [ 'a , ] , \
            ltimes : [ 'a , ] , \
            params : [  ] \
        } , X"
    );

    assert_eq_str!(
        parse_generics!(then stringify!(), <'a, 'b> X),
        "{ \
            constr : [ 'a , 'b , ] , \
            ltimes : [ 'a , 'b , ] , \
            params : [  ] \
        } , X"
    );

    assert_eq_str!(
        parse_generics!(then stringify!(), <T> X),
        "{ \
            constr : [ T , ] , \
            ltimes : [  ] , \
            params : [ T , ] \
        } , X"
    );

    assert_eq_str!(
        parse_generics!(then stringify!(), <T, U> X),
        "{ \
            constr : [ T , U , ] , \
            ltimes : [  ] , \
            params : [ T , U , ] \
        } , X"
    );

    assert_eq_str!(
        parse_generics!(then stringify!(), <'a, 'b: 'a> X),
        "{ \
            constr : [ 'a , 'b : 'a , ] , \
            ltimes : [ 'a , 'b , ] , \
            params : [  ] \
        } , X"
    );

    assert_eq_str!(
        parse_generics!(then stringify!(), <'a, 'b: 'a + 'c> X),
        "{ \
            constr : [ 'a , 'b : 'a + 'c , ] , \
            ltimes : [ 'a , 'b , ] , \
            params : [  ] \
        } , X"
    );

    assert_eq_str!(
        parse_generics!(then stringify!(), <T: Copy> X),
        "{ \
            constr : [ T : Copy , ] , \
            ltimes : [  ] , \
            params : [ T , ] \
        } , X"
    );

    assert_eq_str!(
        parse_generics!(then stringify!(), <T: std::marker::Copy> X),
        "{ \
            constr : [ T : std :: marker :: Copy , ] , \
            ltimes : [  ] , \
            params : [ T , ] \
        } , X"
    );

    assert_eq_str!(
        parse_generics!(then stringify!(), <T: ::std::marker::Copy> X),
        "{ \
            constr : [ T : :: std :: marker :: Copy , ] , \
            ltimes : [  ] , \
            params : [ T , ] \
        } , X"
    );

    assert_eq_str!(
        parse_generics!(then stringify!(), <T: 'a> X),
        "{ \
            constr : [ T : 'a , ] , \
            ltimes : [  ] , \
            params : [ T , ] \
        } , X"
    );

    assert_eq_str!(
        parse_generics!(then stringify!(), <T: 'a + Copy + Clone> X),
        "{ \
            constr : [ T : 'a + Copy + Clone , ] , \
            ltimes : [  ] , \
            params : [ T , ] \
        } , X"
    );

    assert_eq_str!(
        parse_generics!(then stringify!(), <T: 'a + 'b + Copy + Clone> X),
        "{ \
            constr : [ T : 'a + 'b + Copy + Clone , ] , \
            ltimes : [  ] , \
            params : [ T , ] \
        } , X"
    );

    assert_eq_str!(
        parse_generics!(then stringify!(),
            <T: 'a + 'b + Copy + Clone + for<'c, 'd: 'e> Fn()> X),
        "{ \
            constr : [ T : 'a + 'b + Copy + Clone \
                + for < 'c , 'd : 'e > Fn ( ) , ] , \
            ltimes : [  ] , \
            params : [ T , ] \
        } , X"
    );

    assert_eq_str!(
        parse_generics!(then stringify!(),
            <T: 'a + 'b + Copy + Clone + for<'c, 'd: 'e> Fn() -> &'c i32> X),
        "{ \
            constr : [ T : 'a + 'b + Copy + Clone \
                + for < 'c , 'd : 'e > Fn ( ) -> &'c i32 , ] , \
            ltimes : [  ] , \
            params : [ T , ] \
        } , X"
    );

    assert_eq_str!(
        parse_generics!(then stringify!(),
            <T: 'a + 'b + Copy + Clone + for<'c, 'd: 'e> Fn(&'c i32)> X),
        "{ \
            constr : [ T : 'a + 'b + Copy + Clone \
                + for < 'c , 'd : 'e > Fn ( &'c i32 , ) , ] , \
            ltimes : [  ] , \
            params : [ T , ] \
        } , X"
    );

    assert_eq_str!(
        parse_generics!(then stringify!(),
            <T: 'a + 'b + Copy + Clone + for<'c, 'd: 'e> Fn(&'c i32) -> &'d ()> X),
        "{ \
            constr : [ T : 'a + 'b + Copy + Clone \
                + for < 'c , 'd : 'e > Fn ( &'c i32 , ) -> &'d () , ] , \
            ltimes : [  ] , \
            params : [ T , ] \
        } , X"
    );

    assert_eq_str!(
        parse_generics!(then stringify!(),
            <T: for<> Copy> X),
        "{ \
            constr : [ T : Copy , ] , \
            ltimes : [  ] , \
            params : [ T , ] \
        } , X"
    );
}
<|endoftext|>


<commit_before>#[macro_use]
mod common;

use common::util::*;

static UTIL_NAME: &'static str = "stdbuf";

#[test]
fn test_stdbuf_unbuffered_stdout() {
    let (_, mut ucmd) = testing(UTIL_NAME);
    // This is a basic smoke test
    let result = ucmd.args(&["-o0", "head"])
                     .run_piped_stdin("The quick brown fox jumps over the lazy dog.");
    assert_eq!(result.stdout,
               "The quick brown fox jumps over the lazy dog.");
}
<commit_msg>tests/stdbuf: disable on non-linux os<commit_after>#[macro_use]
mod common;

use common::util::*;

static UTIL_NAME: &'static str = "stdbuf";

#[test]
fn test_stdbuf_unbuffered_stdout() {
    if cfg!(target_os="linux") {
        let (_, mut ucmd) = testing(UTIL_NAME);
        // This is a basic smoke test
        let result = ucmd.args(&["-o0", "head"])
                         .run_piped_stdin("The quick brown fox jumps over the lazy dog.");
        assert_eq!(result.stdout,
                   "The quick brown fox jumps over the lazy dog.");
    }
}
<|endoftext|>


<commit_before>#[cfg(feature = "ndarray_volumes")]
extern crate ndarray;
#[cfg(feature = "ndarray_volumes")]
extern crate nifti;
#[cfg(feature = "ndarray_volumes")]
extern crate tempfile;

#[cfg(feature = "ndarray_volumes")]
mod tests {
    use std::{
        fs,
        ops::{Add, Mul},
        path::{Path, PathBuf},
    };

    use ndarray::{Array, Array2, Axis, Dimension, IxDyn, ShapeBuilder};
    use tempfile::tempdir;

    use nifti::{
        header::{MAGIC_CODE_NI1, MAGIC_CODE_NIP1},
        object::NiftiObject,
        writer::{write_nifti, write_rgb_nifti},
        InMemNiftiObject, IntoNdArray, NiftiHeader, NiftiType,
    };

    fn get_temporary_path(ext: &str) -> PathBuf {
        let dir = tempdir().unwrap();
        let mut path = dir.into_path();
        if !ext.is_empty() {
            path.push(ext);
        }
        path
    }

    pub fn generate_nifti_header(
        dim: [u16; 8],
        scl_slope: f32,
        scl_inter: f32,
        datatype: i16,
    ) -> NiftiHeader {
        NiftiHeader {
            dim,
            datatype,
            bitpix: (NiftiType::Float32.size_of() * 8) as i16,
            magic: *MAGIC_CODE_NIP1,
            scl_slope,
            scl_inter,
            ..NiftiHeader::default()
        }
    }

    fn read_as_ndarray<P, D>(path: P) -> Array<f32, D>
    where
        P: AsRef<Path>,
        D: Dimension,
    {
        let nifti_object = InMemNiftiObject::from_file(path).expect("Nifti file is unreadable.");
        let volume = nifti_object.into_volume();
        let dyn_data = volume.into_ndarray().unwrap();
        dyn_data.into_dimensionality::<D>().unwrap()
    }

    fn test_write_read(arr: &Array<f32, IxDyn>, path: &str) {
        let path = get_temporary_path(path);
        let mut dim = [1; 8];
        dim[0] = arr.ndim() as u16;
        for (i, s) in arr.shape().iter().enumerate() {
            dim[i + 1] = *s as u16;
        }
        let header = generate_nifti_header(dim, 1.0, 0.0, 16);
        write_nifti(&path, &arr, Some(&header)).unwrap();

        let read_nifti: Array2<f32> = read_as_ndarray(path);
        assert!(read_nifti.all_close(&arr, 1e-10));
    }

    fn f_order_array() -> Array<f32, IxDyn> {
        let dim = vec![4, 4];
        let vec = (0..16).map(|x| x as f32).collect();
        Array::from_shape_vec(IxDyn(&dim).f(), vec).unwrap()
    }

    fn c_order_array() -> Array<f32, IxDyn> {
        let dim = vec![4, 4];
        let vec = (0..16).map(|x| x as f32).collect();
        Array::from_shape_vec(IxDyn(&dim), vec).unwrap()
    }

    #[test]
    fn fortran_writing() {
        // Test .nii
        let arr = f_order_array();
        test_write_read(&arr, "test.nii");
        let mut arr = f_order_array();
        arr.invert_axis(Axis(1));
        test_write_read(&arr, "test_non_contiguous.nii");

        // Test .nii.gz
        let arr = f_order_array();
        test_write_read(&arr, "test.nii.gz");
        let mut arr = f_order_array();
        arr.invert_axis(Axis(1));
        test_write_read(&arr, "test_non_contiguous.nii.gz");
    }

    #[test]
    fn c_writing() {
        // Test .nii
        let arr = c_order_array();
        test_write_read(&arr, "test.nii");

        let mut arr = c_order_array();
        arr.invert_axis(Axis(1));
        test_write_read(&arr, "test_non_contiguous.nii");

        // Test .nii.gz
        let arr = c_order_array();
        test_write_read(&arr, "test.nii.gz");

        let mut arr = c_order_array();
        arr.invert_axis(Axis(1));
        test_write_read(&arr, "test_non_contiguous.nii.gz");
    }

    #[test]
    fn header_slope_inter() {
        let arr = f_order_array();
        let slope = 2.2;
        let inter = 101.1;

        let path = get_temporary_path("test_slope_inter.nii");
        let mut dim = [1; 8];
        dim[0] = arr.ndim() as u16;
        for (i, s) in arr.shape().iter().enumerate() {
            dim[i + 1] = *s as u16;
        }
        let header = generate_nifti_header(dim, slope, inter, 16);
        let transformed_data = arr.mul(slope).add(inter);
        write_nifti(&path, &transformed_data, Some(&header)).unwrap();

        let read_nifti: Array2<f32> = read_as_ndarray(path);
        assert!(read_nifti.all_close(&transformed_data, 1e-10));
    }

    #[test]
    fn write_hdr_standard() {
        let mut data = Array::zeros((10, 11, 12));
        data[(5, 0, 0)] = 1.0;
        data[(6, 0, 0)] = 2.0;

        for fname in &["3d.hdr", "3d.hdr.gz"] {
            let path = get_temporary_path(fname);
            write_nifti(&path, &data, None).unwrap();
            let data_read = read_as_ndarray(path);
            assert_eq!(data, data_read);
        }
    }

    #[test]
    fn write_3d_rgb_hdr() {
        let mut data = Array::from_elem((3, 3, 3), [0u8, 0u8, 0u8]);
        data[(0, 0, 0)] = [55, 55, 0];
        data[(0, 0, 1)] = [55, 0, 55];
        data[(0, 1, 0)] = [0, 55, 55];

        let header_path = get_temporary_path("3d.hdr");
        let data_path = header_path.with_extension("img");
        write_rgb_nifti(&header_path, &data, None).unwrap();

        // Until we are able to read RGB images, we simply compare the bytes of the newly created
        // image to the bytes of the prepared 3D RGB image in ressources/rgb/. However, we need to
        // set the bytes of vox_offset to 0.0 and of magic to MAGIC_CODE_NI1. The data bytes should
        // be identical though.
        let mut gt_bytes = fs::read("resources/rgb/3D.nii").unwrap();
        for i in 110..114 {
            gt_bytes[i] = 0;
        }
        for i in 0..4 {
            gt_bytes[344 + i] = MAGIC_CODE_NI1[i];
        }
        assert_eq!(fs::read(header_path).unwrap(), &gt_bytes[..352]);
        assert_eq!(fs::read(data_path).unwrap(), &gt_bytes[352..]);
    }

    #[test]
    fn write_3d_rgb() {
        let mut data = Array::from_elem((3, 3, 3), [0u8, 0u8, 0u8]);
        data[(0, 0, 0)] = [55, 55, 0];
        data[(0, 0, 1)] = [55, 0, 55];
        data[(0, 1, 0)] = [0, 55, 55];

        let path = get_temporary_path("rgb.nii");
        write_rgb_nifti(&path, &data, None).unwrap();

        // Until we are able to read RGB images, we simply compare the bytes of the newly created
        // image to the bytes of the prepared 3D RGB image in ressources/rgb/.
        assert_eq!(
            fs::read(path).unwrap(),
            fs::read("resources/rgb/3D.nii").unwrap()
        );
    }

    #[test]
    fn write_4d_rgb() {
        let mut data = Array::from_elem((3, 3, 3, 2), [0u8, 0u8, 0u8]);
        data[(0, 0, 0, 0)] = [55, 55, 0];
        data[(0, 0, 1, 0)] = [55, 0, 55];
        data[(0, 1, 0, 0)] = [0, 55, 55];
        data[(0, 0, 0, 1)] = [55, 55, 0];
        data[(0, 1, 0, 1)] = [55, 0, 55];
        data[(1, 0, 0, 1)] = [0, 55, 55];

        let path = get_temporary_path("rgb.nii");
        write_rgb_nifti(&path, &data, None).unwrap();

        // Until we are able to read RGB images, we simply compare the bytes of the newly created
        // image to the bytes of the prepared 4D RGB image in ressources/rgb/.
        assert_eq!(
            fs::read(path).unwrap(),
            fs::read("resources/rgb/4D.nii").unwrap()
        );
    }
}
<commit_msg>Add a non contiguous writing test<commit_after>#[cfg(feature = "ndarray_volumes")]
extern crate ndarray;
#[cfg(feature = "ndarray_volumes")]
extern crate nifti;
#[cfg(feature = "ndarray_volumes")]
extern crate tempfile;

#[cfg(feature = "ndarray_volumes")]
mod tests {
    use std::{
        fs,
        ops::{Add, Mul},
        path::{Path, PathBuf},
    };

    use ndarray::{Array, Array2, Axis, Dimension, IxDyn, ShapeBuilder, s};
    use tempfile::tempdir;

    use nifti::{
        header::{MAGIC_CODE_NI1, MAGIC_CODE_NIP1},
        object::NiftiObject,
        writer::{write_nifti, write_rgb_nifti},
        InMemNiftiObject, IntoNdArray, NiftiHeader, NiftiType,
    };

    fn get_temporary_path(ext: &str) -> PathBuf {
        let dir = tempdir().unwrap();
        let mut path = dir.into_path();
        if !ext.is_empty() {
            path.push(ext);
        }
        path
    }

    pub fn generate_nifti_header(
        dim: [u16; 8],
        scl_slope: f32,
        scl_inter: f32,
        datatype: i16,
    ) -> NiftiHeader {
        NiftiHeader {
            dim,
            datatype,
            bitpix: (NiftiType::Float32.size_of() * 8) as i16,
            magic: *MAGIC_CODE_NIP1,
            scl_slope,
            scl_inter,
            ..NiftiHeader::default()
        }
    }

    fn read_as_ndarray<P, D>(path: P) -> Array<f32, D>
    where
        P: AsRef<Path>,
        D: Dimension,
    {
        let nifti_object = InMemNiftiObject::from_file(path).expect("Nifti file is unreadable.");
        let volume = nifti_object.into_volume();
        let dyn_data = volume.into_ndarray().unwrap();
        dyn_data.into_dimensionality::<D>().unwrap()
    }

    fn test_write_read(arr: &Array<f32, IxDyn>, path: &str) {
        let path = get_temporary_path(path);
        let mut dim = [1; 8];
        dim[0] = arr.ndim() as u16;
        for (i, s) in arr.shape().iter().enumerate() {
            dim[i + 1] = *s as u16;
        }
        let header = generate_nifti_header(dim, 1.0, 0.0, 16);
        write_nifti(&path, &arr, Some(&header)).unwrap();

        let read_nifti: Array2<f32> = read_as_ndarray(path);
        assert!(read_nifti.all_close(&arr, 1e-10));
    }

    fn f_order_array() -> Array<f32, IxDyn> {
        let dim = vec![4, 4];
        let vec = (0..16).map(|x| x as f32).collect();
        Array::from_shape_vec(IxDyn(&dim).f(), vec).unwrap()
    }

    fn c_order_array() -> Array<f32, IxDyn> {
        let dim = vec![4, 4];
        let vec = (0..16).map(|x| x as f32).collect();
        Array::from_shape_vec(IxDyn(&dim), vec).unwrap()
    }

    #[test]
    fn fortran_writing() {
        // Test .nii
        let arr = f_order_array();
        test_write_read(&arr, "test.nii");
        let mut arr = f_order_array();
        arr.invert_axis(Axis(1));
        test_write_read(&arr, "test_non_contiguous.nii");

        // Test .nii.gz
        let arr = f_order_array();
        test_write_read(&arr, "test.nii.gz");
        let mut arr = f_order_array();
        arr.invert_axis(Axis(1));
        test_write_read(&arr, "test_non_contiguous.nii.gz");
    }

    #[test]
    fn c_writing() {
        // Test .nii
        let arr = c_order_array();
        test_write_read(&arr, "test.nii");

        let mut arr = c_order_array();
        arr.invert_axis(Axis(1));
        test_write_read(&arr, "test_non_contiguous.nii");

        // Test .nii.gz
        let arr = c_order_array();
        test_write_read(&arr, "test.nii.gz");

        let mut arr = c_order_array();
        arr.invert_axis(Axis(1));
        test_write_read(&arr, "test_non_contiguous.nii.gz");
    }

    #[test]
    fn header_slope_inter() {
        let arr = f_order_array();
        let slope = 2.2;
        let inter = 101.1;

        let path = get_temporary_path("test_slope_inter.nii");
        let mut dim = [1; 8];
        dim[0] = arr.ndim() as u16;
        for (i, s) in arr.shape().iter().enumerate() {
            dim[i + 1] = *s as u16;
        }
        let header = generate_nifti_header(dim, slope, inter, 16);
        let transformed_data = arr.mul(slope).add(inter);
        write_nifti(&path, &transformed_data, Some(&header)).unwrap();

        let read_nifti: Array2<f32> = read_as_ndarray(path);
        assert!(read_nifti.all_close(&transformed_data, 1e-10));
    }

    #[test]
    fn write_hdr_standard() {
        let mut data = Array::zeros((10, 11, 12));
        data[(5, 0, 0)] = 1.0;
        data[(6, 0, 0)] = 2.0;

        for fname in &["3d.hdr", "3d.hdr.gz"] {
            let path = get_temporary_path(fname);
            write_nifti(&path, &data, None).unwrap();
            let data_read = read_as_ndarray(path);
            assert_eq!(data, data_read);
        }
    }

    #[test]
    fn write_non_contiguous() {
        let mut data = Array::from_elem((3, 4, 11), 1.5);
        data.slice_mut(s![.., .., ..;2]).fill(42.0);

        let path = get_temporary_path("non_contiguous_0.nii.gz");
        write_nifti(&path, &data.slice(s![.., .., ..;2]), None).unwrap();
        assert_eq!(read_as_ndarray(path), Array::from_elem((3, 4, 6), 42.0));

        let path = get_temporary_path("non_contiguous_1.nii.gz");
        write_nifti(&path, &data.slice(s![.., .., 1..;2]), None).unwrap();
        assert_eq!(read_as_ndarray(path), Array::from_elem((3, 4, 5), 1.5));
    }

    #[test]
    fn write_3d_rgb_hdr() {
        let mut data = Array::from_elem((3, 3, 3), [0u8, 0u8, 0u8]);
        data[(0, 0, 0)] = [55, 55, 0];
        data[(0, 0, 1)] = [55, 0, 55];
        data[(0, 1, 0)] = [0, 55, 55];

        let header_path = get_temporary_path("3d.hdr");
        let data_path = header_path.with_extension("img");
        write_rgb_nifti(&header_path, &data, None).unwrap();

        // Until we are able to read RGB images, we simply compare the bytes of the newly created
        // image to the bytes of the prepared 3D RGB image in ressources/rgb/. However, we need to
        // set the bytes of vox_offset to 0.0 and of magic to MAGIC_CODE_NI1. The data bytes should
        // be identical though.
        let mut gt_bytes = fs::read("resources/rgb/3D.nii").unwrap();
        for i in 110..114 {
            gt_bytes[i] = 0;
        }
        for i in 0..4 {
            gt_bytes[344 + i] = MAGIC_CODE_NI1[i];
        }
        assert_eq!(fs::read(header_path).unwrap(), &gt_bytes[..352]);
        assert_eq!(fs::read(data_path).unwrap(), &gt_bytes[352..]);
    }

    #[test]
    fn write_3d_rgb() {
        let mut data = Array::from_elem((3, 3, 3), [0u8, 0u8, 0u8]);
        data[(0, 0, 0)] = [55, 55, 0];
        data[(0, 0, 1)] = [55, 0, 55];
        data[(0, 1, 0)] = [0, 55, 55];

        let path = get_temporary_path("rgb.nii");
        write_rgb_nifti(&path, &data, None).unwrap();

        // Until we are able to read RGB images, we simply compare the bytes of the newly created
        // image to the bytes of the prepared 3D RGB image in ressources/rgb/.
        assert_eq!(
            fs::read(path).unwrap(),
            fs::read("resources/rgb/3D.nii").unwrap()
        );
    }

    #[test]
    fn write_4d_rgb() {
        let mut data = Array::from_elem((3, 3, 3, 2), [0u8, 0u8, 0u8]);
        data[(0, 0, 0, 0)] = [55, 55, 0];
        data[(0, 0, 1, 0)] = [55, 0, 55];
        data[(0, 1, 0, 0)] = [0, 55, 55];
        data[(0, 0, 0, 1)] = [55, 55, 0];
        data[(0, 1, 0, 1)] = [55, 0, 55];
        data[(1, 0, 0, 1)] = [0, 55, 55];

        let path = get_temporary_path("rgb.nii");
        write_rgb_nifti(&path, &data, None).unwrap();

        // Until we are able to read RGB images, we simply compare the bytes of the newly created
        // image to the bytes of the prepared 4D RGB image in ressources/rgb/.
        assert_eq!(
            fs::read(path).unwrap(),
            fs::read("resources/rgb/4D.nii").unwrap()
        );
    }
}
<|endoftext|>


<commit_before>// {
//   Derived from : Bjoern Hoehrmann work
//   Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
//   See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.

pub const UTF8_ACCEPT: u32 = 0;
pub const UTF8_REJECT: u32 = 1;

static UTF8D: &'static [u8] = &[
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 00..1f
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 20..3f
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 40..5f
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 60..7f
  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, // 80..9f
  7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, // a0..bf
  8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // c0..df
  0xa,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x3,0x3, // e0..ef
  0xb,0x6,0x6,0x6,0x5,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, // f0..ff
  0x0,0x1,0x2,0x3,0x5,0x8,0x7,0x1,0x1,0x1,0x4,0x6,0x1,0x1,0x1,0x1, // s0..s0
  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1, // s1..s2
  1,2,1,1,1,1,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1, // s3..s4
  1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,1,1,1,1, // s5..s6
  1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // s7..s8
];

/*
    state UTF8_ACCEPT => initial state or decoding successful
    state UTF8_REJECT => error
    state other => intermediate states need more inputs
*/
#[inline]
pub fn decode_byte(state: &mut u32, byte: u8, codep: &mut u32) -> u32 {

    let cp_type = UTF8D[byte as usize] as u32;

    *codep = if *state != UTF8_ACCEPT {
        (byte & 0x3f) as u32 | (*codep << 6)
    } else {
        (0xff >> cp_type) as u32 & (byte as u32)
    };

    *state = UTF8D[256 + (*state * 16) as usize + cp_type as usize] as u32;
    *state
}

// }

#[inline]
pub fn is_codepoint_start(byte: u8) -> bool {

    if byte < 0x80 {
        return true;
    }

    if byte >= 0xC2 && byte <= 0xDF {
        return true;
    }

    if byte >= 0xC2 && byte <= 0xDF {
        return true;
    }

    if byte >= 0xE0 && byte <= 0xEC {
        return true;
    }

    if byte >= 0xED && byte <= 0xEF {
        return true;
    }

    if byte >= 0xF0 && byte <= 0xF4 {
        return true;
    }

    false
}

// return 0 on error, or the number of written bytes
pub fn encode(codepoint: u32, out: &mut [u8; 4]) -> usize {
    if codepoint < 0x80 {
        out[0] = codepoint as u8;
        return 1;
    }

    if codepoint < 0x800 {
        out[0] = 0xC0 | (codepoint >> 6) as u8;
        out[1] = 0x80 | (codepoint & 0x3F) as u8;
        return 2;
    }

    if codepoint < 0xFFFF {
        out[0] = 0xE0 | (codepoint >> 12) as u8;
        out[1] = 0x80 | (codepoint >> 6) as u8;
        out[2] = 0x80 | (codepoint & 0x3F) as u8;
        return 3;
    }

    if codepoint < 0x10FFFF {
        out[0] = 0xF0 | (codepoint >> 18) as u8;
        out[1] = 0x80 | (codepoint >> 12) as u8;
        out[2] = 0x80 | (codepoint >> 6) as u8;
        out[3] = 0x80 | (codepoint & 0x3F) as u8;
        return 4;
    }

    0
}

// TODO: change this with temporary (cp, offset, size) until from_offset
pub fn get_previous_codepoint_start(data: &[u8], from_offset: u64) -> u64 {

    //                 cp    size   offset
    let mut cp_info: [(char, usize, u64); 8] = [
        ('\0', 0, 0),
        ('\0', 0, 0),
        ('\0', 0, 0),
        ('\0', 0, 0),
        ('\0', 0, 0),
        ('\0', 0, 0),
        ('\0', 0, 0),
        ('\0', 0, 0),
    ];
    let mut nr_cpinfo = 0;

    // rewind up to 4 bytes
    // and decode forward / save offset
    let mut off = if from_offset > 4 { from_offset - 4 } else { 0 };
    while off < from_offset {
        let (cp, _, size) = get_codepoint(data, off);

        cp_info[nr_cpinfo] = (cp, size, off);
        nr_cpinfo += 1;

        off += size as u64;
    }

    if nr_cpinfo != 0 {
        cp_info[nr_cpinfo - 1].2
    } else {
        from_offset
    }
}

pub fn get_next_codepoint_start(data: &[u8], from_offset: u64) -> u64 {
    let (_, _, size) = get_codepoint(data, from_offset);
    from_offset + size as u64
}

pub fn get_codepoint(data: &[u8], from_offset: u64) -> (char, u64, usize) {

    let mut state = 0;
    let mut codep = 0;
    let mut size = 0;

    for b in data.iter().skip(from_offset as usize) {

        size += 1;
        state = decode_byte(&mut state, *b, &mut codep);
        match state {
            0 => {
                break;
            }
            1 => {
                // decode error : invalid sequence
                codep = 0xfffd;
                size = 1; // force restart @ next byte
                break;
            }
            _ => {}
        }
    }

    // TODO return Result<(char, usize), status> -> state != 1|0 -> need mode data
    (::core::codec::text::u32_to_char(codep), from_offset, size)
}

pub fn get_prev_codepoint(data: &[u8], from_offset: u64) -> (char, u64, usize) {
    let offset = get_previous_codepoint_start(data, from_offset);
    get_codepoint(data, offset)
}

#[test]
fn test_codec_encode() {

    let expect_cp: [u8; 4] = [0xe2, 0x82, 0xac, 0x00];
    let mut mut_cp: [u8; 4] = [0x00, 0x00, 0x00, 0x00];

    let n = encode(0x20ac as u32, &mut mut_cp);
    assert_eq!(n, 3);
    assert_eq!(mut_cp, expect_cp);

}

#[test]
fn test_codec_decode() {

    use core::codec::text::u32_to_char;

    let mut state: u32 = 0;
    let mut codep: u32 = 0;

    let sequence: [u8; 4] = [0xe2, 0x82, 0xac, 0x00];
    for b in &sequence {
        println!("decode byte '{:x}'", *b);
        state = decode_byte(&mut state, *b, &mut codep);
        match state {
            UTF8_ACCEPT => {
                break;
            }
            UTF8_REJECT => {
                println!("invalid utf8 sequence");
                break;
            }
            _ => {
                continue;
            }
        }
    }

    println!("decoded codepoint value {:x}", codep);
    let c = u32_to_char(codep);
    println!("decoded codepoint char {}", c);

    assert_eq!(codep, 0x20ac);
}

#[test]
fn test2_codec_decode() {

    let data: [u8; 27] = [
        0xe2,
        0x82,
        0xac,
        0xe2,
        0x82,
        0x61,
        0x0a,
        0x82,
        0xac,
        0xe2,
        0x82,
        0x61,
        0x0a,
        0xac,
        0xe2,
        0x82,
        0x61,
        0x0a,
        0xe2,
        0x82,
        0x61,
        0x0a,
        0x82,
        0x61,
        0x0a,
        0x61,
        0x0a,
    ];

    let mut state: u32 = 0;
    let mut codep: u32 = 0;

    for b in &data {
        println!("decode byte '{:x}'", *b);
        state = decode_byte(&mut state, *b, &mut codep);
        println!("state  '{}'", state);
        match state {
            UTF8_ACCEPT => {
                println!("decoded cp = '{:?}'", codep);
                state = 0;
                codep = 0;
            }
            UTF8_REJECT => {
                println!("invalid utf8 sequence, restart");
                state = 0;
                codep = 0;
                state = decode_byte(&mut state, *b, &mut codep);
                match state {
                    UTF8_ACCEPT => {
                        println!("decoded cp = '{:?}'", codep);
                        state = 0;
                        codep = 0;
                    }
                    UTF8_REJECT => {
                        println!("invalid utf8 sequence, restart");
                        state = 0;
                        codep = 0;
                    }
                    _ => {}

                }
            }

            _ => {
                continue;
            }
        }
    }
}
<commit_msg>simplify utf8 decode<commit_after>// {
//   Derived from : Bjoern Hoehrmann work
//   Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
//   See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.

pub const UTF8_ACCEPT: u32 = 0;
pub const UTF8_REJECT: u32 = 1;

static UTF8D: &'static [u8] = &[
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 00..1f
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 20..3f
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 40..5f
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 60..7f
  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, // 80..9f
  7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, // a0..bf
  8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // c0..df
  0xa,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x3,0x3, // e0..ef
  0xb,0x6,0x6,0x6,0x5,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, // f0..ff
  0x0,0x1,0x2,0x3,0x5,0x8,0x7,0x1,0x1,0x1,0x4,0x6,0x1,0x1,0x1,0x1, // s0..s0
  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1, // s1..s2
  1,2,1,1,1,1,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1, // s3..s4
  1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,1,1,1,1, // s5..s6
  1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // s7..s8
];

/*
    state UTF8_ACCEPT => initial state or decoding successful
    state UTF8_REJECT => error
    state other => intermediate states need more inputs
*/
#[inline]
pub fn decode_byte(state: u32, byte: u8, codep: &mut u32) -> u32 {

    let cp_type = UTF8D[byte as usize] as u32;

    *codep = if state != UTF8_ACCEPT {
        (byte & 0x3f) as u32 | (*codep << 6)
    } else {
        (0xff >> cp_type) as u32 & (byte as u32)
    };

    UTF8D[256 + (state * 16) as usize + cp_type as usize] as u32
}

// }

#[inline]
pub fn is_codepoint_start(byte: u8) -> bool {

    if byte < 0x80 {
        return true;
    }

    if byte >= 0xC2 && byte <= 0xDF {
        return true;
    }

    if byte >= 0xC2 && byte <= 0xDF {
        return true;
    }

    if byte >= 0xE0 && byte <= 0xEC {
        return true;
    }

    if byte >= 0xED && byte <= 0xEF {
        return true;
    }

    if byte >= 0xF0 && byte <= 0xF4 {
        return true;
    }

    false
}

// return 0 on error, or the number of written bytes
pub fn encode(codepoint: u32, out: &mut [u8; 4]) -> usize {
    if codepoint < 0x80 {
        out[0] = codepoint as u8;
        return 1;
    }

    if codepoint < 0x800 {
        out[0] = 0xC0 | (codepoint >> 6) as u8;
        out[1] = 0x80 | (codepoint & 0x3F) as u8;
        return 2;
    }

    if codepoint < 0xFFFF {
        out[0] = 0xE0 | (codepoint >> 12) as u8;
        out[1] = 0x80 | (codepoint >> 6) as u8;
        out[2] = 0x80 | (codepoint & 0x3F) as u8;
        return 3;
    }

    if codepoint < 0x10FFFF {
        out[0] = 0xF0 | (codepoint >> 18) as u8;
        out[1] = 0x80 | (codepoint >> 12) as u8;
        out[2] = 0x80 | (codepoint >> 6) as u8;
        out[3] = 0x80 | (codepoint & 0x3F) as u8;
        return 4;
    }

    0
}

// TODO: change this with temporary (cp, offset, size) until from_offset
pub fn get_previous_codepoint_start(data: &[u8], from_offset: u64) -> u64 {

    //                 cp    size   offset
    let mut cp_info: [(char, usize, u64); 8] = [
        ('\0', 0, 0),
        ('\0', 0, 0),
        ('\0', 0, 0),
        ('\0', 0, 0),
        ('\0', 0, 0),
        ('\0', 0, 0),
        ('\0', 0, 0),
        ('\0', 0, 0),
    ];
    let mut nr_cpinfo = 0;

    // rewind up to 4 bytes
    // and decode forward / save offset
    let mut off = if from_offset > 4 { from_offset - 4 } else { 0 };
    while off < from_offset {
        let (cp, _, size) = get_codepoint(data, off);

        cp_info[nr_cpinfo] = (cp, size, off);
        nr_cpinfo += 1;

        off += size as u64;
    }

    if nr_cpinfo != 0 {
        cp_info[nr_cpinfo - 1].2
    } else {
        from_offset
    }
}

pub fn get_next_codepoint_start(data: &[u8], from_offset: u64) -> u64 {
    let (_, _, size) = get_codepoint(data, from_offset);
    from_offset + size as u64
}

pub fn get_codepoint(data: &[u8], from_offset: u64) -> (char, u64, usize) {

    let mut state = 0;
    let mut codep = 0;
    let mut size = 0;

    for b in data.iter().skip(from_offset as usize) {

        size += 1;
        state = decode_byte(state, *b, &mut codep);
        match state {
            0 => {
                break;
            }
            1 => {
                // decode error : invalid sequence
                codep = 0xfffd;
                size = 1; // force restart @ next byte
                break;
            }
            _ => {}
        }
    }

    // TODO return Result<(char, usize), status> -> state != 1|0 -> need mode data
    (::core::codec::text::u32_to_char(codep), from_offset, size)
}

pub fn get_prev_codepoint(data: &[u8], from_offset: u64) -> (char, u64, usize) {
    let offset = get_previous_codepoint_start(data, from_offset);
    get_codepoint(data, offset)
}

#[test]
fn test_codec_encode() {

    let expect_cp: [u8; 4] = [0xe2, 0x82, 0xac, 0x00];
    let mut mut_cp: [u8; 4] = [0x00, 0x00, 0x00, 0x00];

    let n = encode(0x20ac as u32, &mut mut_cp);
    assert_eq!(n, 3);
    assert_eq!(mut_cp, expect_cp);

}

#[test]
fn test_codec_decode() {

    use core::codec::text::u32_to_char;

    let mut state: u32 = 0;
    let mut codep: u32 = 0;

    let sequence: [u8; 4] = [0xe2, 0x82, 0xac, 0x00];
    for b in &sequence {
        println!("decode byte '{:x}'", *b);
        state = decode_byte(&mut state, *b, &mut codep);
        match state {
            UTF8_ACCEPT => {
                break;
            }
            UTF8_REJECT => {
                println!("invalid utf8 sequence");
                break;
            }
            _ => {
                continue;
            }
        }
    }

    println!("decoded codepoint value {:x}", codep);
    let c = u32_to_char(codep);
    println!("decoded codepoint char {}", c);

    assert_eq!(codep, 0x20ac);
}

#[test]
fn test2_codec_decode() {

    let data: [u8; 27] = [
        0xe2,
        0x82,
        0xac,
        0xe2,
        0x82,
        0x61,
        0x0a,
        0x82,
        0xac,
        0xe2,
        0x82,
        0x61,
        0x0a,
        0xac,
        0xe2,
        0x82,
        0x61,
        0x0a,
        0xe2,
        0x82,
        0x61,
        0x0a,
        0x82,
        0x61,
        0x0a,
        0x61,
        0x0a,
    ];

    let mut state: u32 = 0;
    let mut codep: u32 = 0;

    for b in &data {
        println!("decode byte '{:x}'", *b);
        state = decode_byte(&mut state, *b, &mut codep);
        println!("state  '{}'", state);
        match state {
            UTF8_ACCEPT => {
                println!("decoded cp = '{:?}'", codep);
                state = 0;
                codep = 0;
            }
            UTF8_REJECT => {
                println!("invalid utf8 sequence, restart");
                state = 0;
                codep = 0;
                state = decode_byte(&mut state, *b, &mut codep);
                match state {
                    UTF8_ACCEPT => {
                        println!("decoded cp = '{:?}'", codep);
                        state = 0;
                        codep = 0;
                    }
                    UTF8_REJECT => {
                        println!("invalid utf8 sequence, restart");
                        state = 0;
                        codep = 0;
                    }
                    _ => {}

                }
            }

            _ => {
                continue;
            }
        }
    }
}
<|endoftext|>


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

#[macro_use]
extern crate serde_json;

#[macro_use]
extern crate exonum_testkit;

extern crate exonum;
extern crate exonum_time;
extern crate timestamping;

use exonum::crypto::{gen_keypair, hash, Hash};
use exonum::helpers::{init_logger, Height};
use exonum::crypto::CryptoHash;
use exonum::blockchain::Transaction;
use exonum_testkit::{TestKitBuilder, TestKitApi, TestKit, ApiKind};
use exonum_time::{MockTimeProvider, TimeService};

use std::time::SystemTime;

use timestamping::Service;
use timestamping::transactions::TxTimestamp;
use timestamping::schema::{Timestamp, TimestampEntry};

fn init_testkit() -> (TestKit, MockTimeProvider) {
    let _ = init_logger();
    let mock_provider = MockTimeProvider::new(SystemTime::now());
    let mut testkit = TestKitBuilder::validator()
        .with_service(Service::new())
        .with_service(TimeService::with_provider(mock_provider.clone()))
        .create();
    testkit.create_blocks_until(Height(2)); // TimeService is None if no blocks were forged
    (testkit, mock_provider)
}

/// Assert transaction status
fn assert_status(api: &TestKitApi, tx: &Transaction, expected_status: &serde_json::Value) {
    let info: serde_json::Value = api.get(
        ApiKind::Explorer,
        &format!("v1/transactions/{}", &tx.hash().to_string()),
    );
    if let serde_json::Value::Object(mut info) = info {
        let tx_status = info.remove("status").unwrap();
        assert_eq!(tx_status, *expected_status);
    } else {
        panic!("Invalid transaction info format, object expected");
    }
}

#[test]
fn test_api_get_timestamp_nothing() {
    let (testkit, _) = init_testkit();
    let api = testkit.api();
    let entry: Option<TimestampEntry> =
        api.get(
            ApiKind::Service("timestamping"),
            &format!("/v1/timestamps/value/{}", Hash::zero().to_hex()),
        );
    assert!(entry.is_none());
}

#[test]
fn test_api_post_timestamp() {
    let (testkit, _) = init_testkit();

    let info = Timestamp::new(&Hash::zero(), "metadata");
    let keypair = gen_keypair();
    let tx = TxTimestamp::new(&keypair.0, info, &keypair.1);

    let api = testkit.api();
    let tx_hash: Hash = api.post(ApiKind::Service("timestamping"), "/v1/timestamps", &tx);
    let tx2 = tx.clone();

    assert_eq!(tx2, tx);
    assert_eq!(tx2.hash(), tx_hash);
}

#[test]
fn test_api_get_timestamp_proof() {
    let (mut testkit, _) = init_testkit();

    let keypair = gen_keypair();

    // Create timestamp
    let info = Timestamp::new(&Hash::zero(), "metadata");
    let tx = TxTimestamp::new(&keypair.0, info, &keypair.1);
    testkit.create_block_with_transactions(txvec![tx]);

    // get proof
    let api = testkit.api();
    let _: serde_json::Value = api.get(
        ApiKind::Service("timestamping"),
        &format!("/v1/timestamps/proof/{}", Hash::zero().to_hex()),
    );

    // TODO implement proof validation
}

#[test]
fn test_api_get_timestamp_entry() {
    let (mut testkit, _) = init_testkit();

    let keypair = gen_keypair();

    // Create timestamp
    let info = Timestamp::new(&Hash::zero(), "metadata");
    let tx = TxTimestamp::new(&keypair.0, info.clone(), &keypair.1);
    testkit.create_block_with_transactions(txvec![tx.clone()]);

    let api = testkit.api();
    let entry: Option<TimestampEntry> =
        api.get(
            ApiKind::Service("timestamping"),
            &format!("/v1/timestamps/value/{}", Hash::zero().to_hex()),
        );

    let entry = entry.unwrap();
    assert_eq!(entry.timestamp(), info);
    assert_eq!(entry.tx_hash(), &tx.hash());
}

#[test]
fn test_api_can_not_add_same_content_hash() {
    let (mut testkit, _) = init_testkit();
    let api = testkit.api();

    let keypair = gen_keypair();
    let content_hash = hash(&[1]);
    let timestamp1 = Timestamp::new(&content_hash, "metadata");
    let timestamp2 = Timestamp::new(&content_hash, "other metadata");
    let tx_ok = TxTimestamp::new(&keypair.0, timestamp1.clone(), &keypair.1);
    let tx_err = TxTimestamp::new(&keypair.0, timestamp2.clone(), &keypair.1);

    testkit.create_block_with_transaction(tx_ok.clone());
    assert_status(&api, &tx_ok, &json!({ "type": "success" }));

    testkit.create_block_with_transaction(tx_err.clone());
    assert_status(
        &api,
        &tx_err,
        &json!({ "type": "error", "code": 0, "description": "Content hash already exists" }),
    );
}
<commit_msg>Fix timestamping tests<commit_after>// Copyright 2018 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#[macro_use]
extern crate serde_json;

#[macro_use]
extern crate exonum_testkit;

extern crate exonum;
extern crate exonum_time;
extern crate timestamping;

use exonum::crypto::{gen_keypair, hash, Hash};
use exonum::helpers::{init_logger, Height};
use exonum::crypto::CryptoHash;
use exonum::blockchain::Transaction;
use exonum_testkit::{TestKitBuilder, TestKitApi, TestKit, ApiKind};
use exonum_time::{TimeService, time_provider::MockTimeProvider};

use std::time::SystemTime;

use timestamping::Service;
use timestamping::transactions::TxTimestamp;
use timestamping::schema::{Timestamp, TimestampEntry};

fn init_testkit() -> (TestKit, MockTimeProvider) {
    let _ = init_logger();
    let mock_provider = MockTimeProvider::new(SystemTime::now().into());
    let mut testkit = TestKitBuilder::validator()
        .with_service(Service::new())
        .with_service(TimeService::with_provider(mock_provider.clone()))
        .create();
    testkit.create_blocks_until(Height(2)); // TimeService is None if no blocks were forged
    (testkit, mock_provider)
}

/// Assert transaction status
fn assert_status(api: &TestKitApi, tx: &Transaction, expected_status: &serde_json::Value) {
    let info: serde_json::Value = api.get(
        ApiKind::Explorer,
        &format!("v1/transactions/{}", &tx.hash().to_string()),
    );
    if let serde_json::Value::Object(mut info) = info {
        let tx_status = info.remove("status").unwrap();
        assert_eq!(tx_status, *expected_status);
    } else {
        panic!("Invalid transaction info format, object expected");
    }
}

#[test]
fn test_api_get_timestamp_nothing() {
    let (testkit, _) = init_testkit();
    let api = testkit.api();
    let entry: Option<TimestampEntry> =
        api.get(
            ApiKind::Service("timestamping"),
            &format!("/v1/timestamps/value/{}", Hash::zero().to_hex()),
        );
    assert!(entry.is_none());
}

#[test]
fn test_api_post_timestamp() {
    let (testkit, _) = init_testkit();

    let info = Timestamp::new(&Hash::zero(), "metadata");
    let keypair = gen_keypair();
    let tx = TxTimestamp::new(&keypair.0, info, &keypair.1);

    let api = testkit.api();
    let tx_hash: Hash = api.post(ApiKind::Service("timestamping"), "/v1/timestamps", &tx);
    let tx2 = tx.clone();

    assert_eq!(tx2, tx);
    assert_eq!(tx2.hash(), tx_hash);
}

#[test]
fn test_api_get_timestamp_proof() {
    let (mut testkit, _) = init_testkit();

    let keypair = gen_keypair();

    // Create timestamp
    let info = Timestamp::new(&Hash::zero(), "metadata");
    let tx = TxTimestamp::new(&keypair.0, info, &keypair.1);
    testkit.create_block_with_transactions(txvec![tx]);

    // get proof
    let api = testkit.api();
    let _: serde_json::Value = api.get(
        ApiKind::Service("timestamping"),
        &format!("/v1/timestamps/proof/{}", Hash::zero().to_hex()),
    );

    // TODO implement proof validation
}

#[test]
fn test_api_get_timestamp_entry() {
    let (mut testkit, _) = init_testkit();

    let keypair = gen_keypair();

    // Create timestamp
    let info = Timestamp::new(&Hash::zero(), "metadata");
    let tx = TxTimestamp::new(&keypair.0, info.clone(), &keypair.1);
    testkit.create_block_with_transactions(txvec![tx.clone()]);

    let api = testkit.api();
    let entry: Option<TimestampEntry> =
        api.get(
            ApiKind::Service("timestamping"),
            &format!("/v1/timestamps/value/{}", Hash::zero().to_hex()),
        );

    let entry = entry.unwrap();
    assert_eq!(entry.timestamp(), info);
    assert_eq!(entry.tx_hash(), &tx.hash());
}

#[test]
fn test_api_can_not_add_same_content_hash() {
    let (mut testkit, _) = init_testkit();
    let api = testkit.api();

    let keypair = gen_keypair();
    let content_hash = hash(&[1]);
    let timestamp1 = Timestamp::new(&content_hash, "metadata");
    let timestamp2 = Timestamp::new(&content_hash, "other metadata");
    let tx_ok = TxTimestamp::new(&keypair.0, timestamp1.clone(), &keypair.1);
    let tx_err = TxTimestamp::new(&keypair.0, timestamp2.clone(), &keypair.1);

    testkit.create_block_with_transaction(tx_ok.clone());
    assert_status(&api, &tx_ok, &json!({ "type": "success" }));

    testkit.create_block_with_transaction(tx_err.clone());
    assert_status(
        &api,
        &tx_err,
        &json!({ "type": "error", "code": 0, "description": "Content hash already exists" }),
    );
}
<|endoftext|>


<commit_before>
use std::collections::BTreeMap;

#[cfg(feature = "amqp-build-specs")]
include!(concat!(env!("OUT_DIR"), "/amqp0.rs"));
#[cfg(not(feature = "amqp-build-specs"))]
include!(concat!("mod.pregen.rs"));

#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct Version {
    minor: u16,
    revision: u16,
}

#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct Spec {
    name: &'static str,
    classes: BTreeMap<&'static str, Class>,
    constants: BTreeMap<&'static str, Constant>,
    domains: BTreeMap<&'static str, &'static str>,
    frame_types: BTreeMap<&'static str, Constant>,
    response_codes: BTreeMap<&'static str, Constant>,
    version: Version,
}

#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct Class {
    name: &'static str,
    fields: Vec<ClassField>,
    index: u16,
    methods: Vec<ClassMethod>,
}

#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct ClassMethod {
    name: &'static str,
    index: u16,
    response: Option<&'static str>,
    fields: Vec<ClassMethodField>,
    is_synchronous: bool,

    chassis_server: Option<&'static str>,
    chassis_client: Option<&'static str>,
}

#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct ClassField {
    name: &'static str,
    domain: &'static str,
}

#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct ClassMethodField {
    name: &'static str,
    domain: &'static str,
    assertions: Vec<ClassMethodFieldAssertion>,
    is_reserved: bool,
}

#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub enum ClassMethodFieldAssertion {
    Null,
    NotNull,
    ChannelMax,
    NotZero,
    Enum(Vec<&'static str>),
    Length(usize),
    Regexp(&'static str),
    Syntax(&'static str),
}

#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct Constant {
    name: &'static str,
    value: u32,
    class: Option<&'static str>,
}

impl Spec {
    pub fn name(&self) -> &'static str {
        self.name
    }
    pub fn classes(&self) -> &BTreeMap<&'static str, Class> {
        &self.classes
    }
    pub fn domains(&self) -> &BTreeMap<&'static str, &'static str> {
        &self.domains
    }
    pub fn frame_types(&self) -> &BTreeMap<&'static str, Constant> {
        &self.frame_types
    }
    pub fn response_codes(&self) -> &BTreeMap<&'static str, Constant> {
        &self.response_codes
    }
    pub fn version(&self) -> &Version {
        &self.version
    }
}

impl Class {
    pub fn name(&self) -> &'static str {
        self.name
    }

    pub fn index(&self) -> u16 {
        self.index
    }

    pub fn methods(&self) -> &[ClassMethod] {
        &self.methods
    }
}

impl ClassField {
    pub fn name(&self) -> &'static str {
        &self.name
    }

    pub fn domain(&self) -> &'static str {
        self.domain
    }
}

impl ClassMethod {
    pub fn index(&self) -> u16 {
        self.index
    }
    pub fn name(&self) -> &str {
        &self.name
    }
    pub fn fields(&self) -> &[ClassMethodField] {
        &self.fields
    }
}

impl ClassMethodField {
    pub fn name(&self) -> &'static str {
        &self.name
    }

    pub fn domain(&self) -> &'static str {
        self.domain
    }

    pub fn assertions(&self) -> &[ClassMethodFieldAssertion] {
        &self.assertions
    }

    pub fn is_reserved(&self) -> bool {
        self.is_reserved
    }
}

impl Constant {
    pub fn name(&self) -> &'static str {
        self.name
    }

    pub fn value(&self) -> u32 {
        self.value
    }

    pub fn class(&self) -> Option<&'static str> {
        self.class
    }
}

impl Version {
    pub fn minor(&self) -> u16 {
        self.minor
    }

    pub fn revision(&self) -> u16 {
        self.revision
    }
}<commit_msg>[specs] Add Class::fields() method.<commit_after>
use std::collections::BTreeMap;

#[cfg(feature = "amqp-build-specs")]
include!(concat!(env!("OUT_DIR"), "/amqp0.rs"));
#[cfg(not(feature = "amqp-build-specs"))]
include!(concat!("mod.pregen.rs"));

#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct Version {
    minor: u16,
    revision: u16,
}

#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct Spec {
    name: &'static str,
    classes: BTreeMap<&'static str, Class>,
    constants: BTreeMap<&'static str, Constant>,
    domains: BTreeMap<&'static str, &'static str>,
    frame_types: BTreeMap<&'static str, Constant>,
    response_codes: BTreeMap<&'static str, Constant>,
    version: Version,
}

#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct Class {
    name: &'static str,
    fields: Vec<ClassField>,
    index: u16,
    methods: Vec<ClassMethod>,
}

#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct ClassMethod {
    name: &'static str,
    index: u16,
    response: Option<&'static str>,
    fields: Vec<ClassMethodField>,
    is_synchronous: bool,

    chassis_server: Option<&'static str>,
    chassis_client: Option<&'static str>,
}

#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct ClassField {
    name: &'static str,
    domain: &'static str,
}

#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct ClassMethodField {
    name: &'static str,
    domain: &'static str,
    assertions: Vec<ClassMethodFieldAssertion>,
    is_reserved: bool,
}

#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub enum ClassMethodFieldAssertion {
    Null,
    NotNull,
    ChannelMax,
    NotZero,
    Enum(Vec<&'static str>),
    Length(usize),
    Regexp(&'static str),
    Syntax(&'static str),
}

#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct Constant {
    name: &'static str,
    value: u32,
    class: Option<&'static str>,
}

impl Spec {
    pub fn name(&self) -> &'static str {
        self.name
    }
    pub fn classes(&self) -> &BTreeMap<&'static str, Class> {
        &self.classes
    }
    pub fn domains(&self) -> &BTreeMap<&'static str, &'static str> {
        &self.domains
    }
    pub fn frame_types(&self) -> &BTreeMap<&'static str, Constant> {
        &self.frame_types
    }
    pub fn response_codes(&self) -> &BTreeMap<&'static str, Constant> {
        &self.response_codes
    }
    pub fn version(&self) -> &Version {
        &self.version
    }
}

impl Class {
    pub fn name(&self) -> &'static str {
        self.name
    }

    pub fn fields(&self) -> &[ClassField] {
        &self.fields
    }

    pub fn index(&self) -> u16 {
        self.index
    }

    pub fn methods(&self) -> &[ClassMethod] {
        &self.methods
    }
}

impl ClassField {
    pub fn name(&self) -> &'static str {
        &self.name
    }

    pub fn domain(&self) -> &'static str {
        self.domain
    }
}

impl ClassMethod {
    pub fn index(&self) -> u16 {
        self.index
    }
    pub fn name(&self) -> &str {
        &self.name
    }
    pub fn fields(&self) -> &[ClassMethodField] {
        &self.fields
    }
}

impl ClassMethodField {
    pub fn name(&self) -> &'static str {
        &self.name
    }

    pub fn domain(&self) -> &'static str {
        self.domain
    }

    pub fn assertions(&self) -> &[ClassMethodFieldAssertion] {
        &self.assertions
    }

    pub fn is_reserved(&self) -> bool {
        self.is_reserved
    }
}

impl Constant {
    pub fn name(&self) -> &'static str {
        self.name
    }

    pub fn value(&self) -> u32 {
        self.value
    }

    pub fn class(&self) -> Option<&'static str> {
        self.class
    }
}

impl Version {
    pub fn minor(&self) -> u16 {
        self.minor
    }

    pub fn revision(&self) -> u16 {
        self.revision
    }
}<|endoftext|>


<commit_before>extern crate libnotify;

fn main() {
    let notify = libnotify::Context::new("hello").unwrap();
    let n = notify.new_notification("Hello, ", Some("World!"), None).unwrap();
    n.show().unwrap();
}
<commit_msg>Update `show` example<commit_after>extern crate libnotify;

fn main() {
    let notify = libnotify::Context::new("hello").unwrap();
    let n = notify.new_notification("This is the summary.",
                                    Some("This is the optional body text."),
                                    None).unwrap();
    n.show().unwrap();
}
<|endoftext|>