<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/.

// Code to handle initial setup steps for a pool.
// Initial setup steps are steps that do not alter the environment.

use std::collections::{HashMap, HashSet};
use std::fs::OpenOptions;
use std::path::PathBuf;

use serde_json;

use devicemapper::{devnode_to_devno, Device};

use stratis::{ErrorEnum, StratisError, StratisResult};

use super::super::super::types::{BlockDevTier, PoolUuid};

use super::super::serde_structs::{BackstoreSave, PoolSave};

use super::blockdev::StratBlockDev;
use super::device::{blkdev_size, is_stratis_device};
use super::metadata::BDA;
use super::util::get_stratis_block_devices;

/// Find all Stratis devices.
///
/// Returns a map of pool uuids to a map of devices to devnodes for each pool.
pub fn find_all() -> StratisResult<HashMap<PoolUuid, HashMap<Device, PathBuf>>> {
    let mut pool_map = HashMap::new();

    for devnode in get_stratis_block_devices()? {
        match devnode_to_devno(&devnode)? {
            None => continue,
            Some(devno) => {
                is_stratis_device(&devnode)?.and_then(|pool_uuid| {
                    pool_map
                        .entry(pool_uuid)
                        .or_insert_with(HashMap::new)
                        .insert(Device::from(devno), devnode)
                });
            }
        }
    }
    Ok(pool_map)
}

/// Get the most recent metadata from a set of Devices for a given pool UUID.
/// Returns None if no metadata found for this pool.
#[allow(implicit_hasher)]
pub fn get_metadata(
    pool_uuid: PoolUuid,
    devnodes: &HashMap<Device, PathBuf>,
) -> StratisResult<Option<PoolSave>> {
    // Get pairs of device nodes and matching BDAs
    // If no BDA, or BDA UUID does not match pool UUID, skip.
    // If there is an error reading the BDA, error. There could have been
    // vital information on that BDA, for example, it may have contained
    // the newest metadata.
    let mut bdas = Vec::new();
    for devnode in devnodes.values() {
        let bda = BDA::load(&mut OpenOptions::new().read(true).open(devnode)?)?;
        if let Some(bda) = bda {
            if bda.pool_uuid() == pool_uuid {
                bdas.push((devnode, bda));
            }
        }
    }

    // Most recent time should never be None if this was a properly
    // created pool; this allows for the method to be called in other
    // circumstances.
    let most_recent_time = {
        match bdas.iter()
            .filter_map(|&(_, ref bda)| bda.last_update_time())
            .max()
        {
            Some(time) => time,
            None => return Ok(None),
        }
    };

    // Try to read from all available devnodes that could contain most
    // recent metadata. In the event of errors, continue to try until all are
    // exhausted.
    for &(devnode, ref bda) in bdas.iter()
        .filter(|&&(_, ref bda)| bda.last_update_time() == Some(most_recent_time))
    {
        let poolsave = OpenOptions::new()
            .read(true)
            .open(devnode)
            .ok()
            .and_then(|mut f| bda.load_state(&mut f).ok())
            .and_then(|opt| opt)
            .and_then(|data| serde_json::from_slice(&data).ok());

        if poolsave.is_some() {
            return Ok(poolsave);
        }
    }

    // If no data has yet returned, we have an error. That is, we should have
    // some metadata, because we have a most recent time, but we failed to
    // get any.
    let err_str = "timestamp indicates data was written, but no data successfully read";
    Err(StratisError::Engine(ErrorEnum::NotFound, err_str.into()))
}

/// Get all the blockdevs corresponding to this pool that can be obtained from
/// the given devices.
/// Returns an error if a BDA can not be read or can not be found on any
/// blockdev in devnodes.
/// Returns an error if the blockdevs obtained do not match the metadata.
/// Returns a tuple, of which the first are the data devs, and the second
/// are the devs that support the cache tier.
/// Precondition: Every device in devnodes has already been determined to
/// belong to the pool with the specified pool uuid.
#[allow(implicit_hasher)]
pub fn get_blockdevs(
    pool_uuid: PoolUuid,
    backstore_save: &BackstoreSave,
    devnodes: &HashMap<Device, PathBuf>,
) -> StratisResult<(Vec<StratBlockDev>, Vec<StratBlockDev>)> {
    let recorded_data_map: HashMap<_, _> = backstore_save
        .data_devs
        .iter()
        .map(|bds| (bds.uuid, bds))
        .collect();

    let recorded_cache_map: HashMap<_, _> = match backstore_save.cache_devs {
        Some(ref cache_devs) => cache_devs.iter().map(|bds| (bds.uuid, bds)).collect(),
        None => HashMap::new(),
    };

    let mut segment_table = HashMap::new();
    for seg in &backstore_save.data_segments {
        segment_table
            .entry(seg.0)
            .or_insert_with(Vec::default)
            .push((seg.1, seg.2))
    }
    if let Some(ref segs) = backstore_save.cache_segments {
        for seg in segs {
            segment_table
                .entry(seg.0)
                .or_insert_with(Vec::default)
                .push((seg.1, seg.2))
        }
    }
    if let Some(ref segs) = backstore_save.meta_segments {
        for seg in segs {
            segment_table
                .entry(seg.0)
                .or_insert_with(Vec::default)
                .push((seg.1, seg.2))
        }
    }

    let (mut datadevs, mut cachedevs) = (vec![], vec![]);
    for (device, devnode) in devnodes {
        let bda = BDA::load(&mut OpenOptions::new().read(true).open(devnode)?)?.ok_or_else(|| {
            StratisError::Engine(ErrorEnum::NotFound,
                                                 format!("Device {} with devnode {} was previously determined to belong to pool with uuid {} but no BDA was found",
                                                 device,
                                                 devnode.display(),
                                                 pool_uuid))
        })?;

        // Return an error if apparent size of Stratis block device appears to
        // have decreased since metadata was recorded or if size of block
        // device could not be obtained.
        blkdev_size(&OpenOptions::new().read(true).open(devnode)?).and_then(|actual_size| {
            let actual_size_sectors = actual_size.sectors();
            let recorded_size = bda.dev_size();
            if actual_size_sectors < recorded_size {
                let err_msg = format!(
                    "Stratis device with device number {}, devnode {}, pool UUID {} and device UUID {} had recorded size ({}), but actual size is less at ({})",
                    device,
                    devnode.display(),
                    bda.pool_uuid(),
                    bda.dev_uuid(),
                    recorded_size,
                    actual_size
                );
                Err(StratisError::Engine(ErrorEnum::Error, err_msg))
            } else {
                Ok(())
            }
        })?;

        let dev_uuid = bda.dev_uuid();

        // Locate the device in the metadata using its uuid. Return the device
        // metadata and whether it was a cache or a datadev.
        let (tier, bd_save) = recorded_data_map
            .get(&dev_uuid)
            .map(|bd_save| (BlockDevTier::Data, bd_save))
            .or_else(|| {
                recorded_cache_map
                    .get(&dev_uuid)
                    .map(|bd_save| (BlockDevTier::Cache, bd_save))
            })
            .ok_or_else(|| {
                let err_msg = format!(
                        "Stratis device with device number {}, devnode {}, pool UUID {} and device UUID {} had no record in pool metadata",
                        device,
                        devnode.display(),
                        bda.pool_uuid(),
                        bda.dev_uuid()
                    );
                StratisError::Engine(ErrorEnum::NotFound, err_msg)
            })?;

        // This should always succeed since the actual size is at
        // least the recorded size, so all segments should be
        // available to be allocated. If this fails, the most likely
        // conclusion is metadata corruption.
        let segments = segment_table.get(&dev_uuid);
        match tier {
            BlockDevTier::Data => &mut datadevs,
            BlockDevTier::Cache => &mut cachedevs,
        }.push(StratBlockDev::new(
            *device,
            devnode.to_owned(),
            bda,
            segments.unwrap_or(&vec![]),
            bd_save.user_info.clone(),
            bd_save.hardware_info.clone(),
        )?);
    }

    // Verify that datadevs found match datadevs recorded.
    let current_data_uuids: HashSet<_> = datadevs.iter().map(|b| b.uuid()).collect();
    let recorded_data_uuids: HashSet<_> = recorded_data_map.keys().cloned().collect();
    if current_data_uuids != recorded_data_uuids {
        let err_msg = "Recorded data dev UUIDs != discovered datadev UUIDs";
        return Err(StratisError::Engine(ErrorEnum::Invalid, err_msg.into()));
    }

    if datadevs.len() != current_data_uuids.len() {
        let err_msg = "Duplicate data devices found in environment";
        return Err(StratisError::Engine(ErrorEnum::Invalid, err_msg.into()));
    }

    // Verify that cachedevs found match cachedevs recorded.
    let current_cache_uuids: HashSet<_> = cachedevs.iter().map(|b| b.uuid()).collect();
    let recorded_cache_uuids: HashSet<_> = recorded_cache_map.keys().cloned().collect();
    if current_cache_uuids != recorded_cache_uuids {
        let err_msg = "Recorded cache dev UUIDs != discovered cachedev UUIDs";
        return Err(StratisError::Engine(ErrorEnum::Invalid, err_msg.into()));
    }

    if cachedevs.len() != current_cache_uuids.len() {
        let err_msg = "Duplicate cache devices found in environment";
        return Err(StratisError::Engine(ErrorEnum::Invalid, err_msg.into()));
    }

    Ok((datadevs, cachedevs))
}
<commit_msg>State some types explicitly<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/.

// Code to handle initial setup steps for a pool.
// Initial setup steps are steps that do not alter the environment.

use std::collections::{HashMap, HashSet};
use std::fs::OpenOptions;
use std::path::PathBuf;

use serde_json;

use devicemapper::{devnode_to_devno, Device, Sectors};

use stratis::{ErrorEnum, StratisError, StratisResult};

use super::super::super::types::{BlockDevTier, DevUuid, PoolUuid};

use super::super::serde_structs::{BackstoreSave, BlockDevSave, PoolSave};

use super::blockdev::StratBlockDev;
use super::device::{blkdev_size, is_stratis_device};
use super::metadata::BDA;
use super::util::get_stratis_block_devices;

/// Find all Stratis devices.
///
/// Returns a map of pool uuids to a map of devices to devnodes for each pool.
pub fn find_all() -> StratisResult<HashMap<PoolUuid, HashMap<Device, PathBuf>>> {
    let mut pool_map = HashMap::new();

    for devnode in get_stratis_block_devices()? {
        match devnode_to_devno(&devnode)? {
            None => continue,
            Some(devno) => {
                is_stratis_device(&devnode)?.and_then(|pool_uuid| {
                    pool_map
                        .entry(pool_uuid)
                        .or_insert_with(HashMap::new)
                        .insert(Device::from(devno), devnode)
                });
            }
        }
    }
    Ok(pool_map)
}

/// Get the most recent metadata from a set of Devices for a given pool UUID.
/// Returns None if no metadata found for this pool.
#[allow(implicit_hasher)]
pub fn get_metadata(
    pool_uuid: PoolUuid,
    devnodes: &HashMap<Device, PathBuf>,
) -> StratisResult<Option<PoolSave>> {
    // Get pairs of device nodes and matching BDAs
    // If no BDA, or BDA UUID does not match pool UUID, skip.
    // If there is an error reading the BDA, error. There could have been
    // vital information on that BDA, for example, it may have contained
    // the newest metadata.
    let mut bdas = Vec::new();
    for devnode in devnodes.values() {
        let bda = BDA::load(&mut OpenOptions::new().read(true).open(devnode)?)?;
        if let Some(bda) = bda {
            if bda.pool_uuid() == pool_uuid {
                bdas.push((devnode, bda));
            }
        }
    }

    // Most recent time should never be None if this was a properly
    // created pool; this allows for the method to be called in other
    // circumstances.
    let most_recent_time = {
        match bdas.iter()
            .filter_map(|&(_, ref bda)| bda.last_update_time())
            .max()
        {
            Some(time) => time,
            None => return Ok(None),
        }
    };

    // Try to read from all available devnodes that could contain most
    // recent metadata. In the event of errors, continue to try until all are
    // exhausted.
    for &(devnode, ref bda) in bdas.iter()
        .filter(|&&(_, ref bda)| bda.last_update_time() == Some(most_recent_time))
    {
        let poolsave = OpenOptions::new()
            .read(true)
            .open(devnode)
            .ok()
            .and_then(|mut f| bda.load_state(&mut f).ok())
            .and_then(|opt| opt)
            .and_then(|data| serde_json::from_slice(&data).ok());

        if poolsave.is_some() {
            return Ok(poolsave);
        }
    }

    // If no data has yet returned, we have an error. That is, we should have
    // some metadata, because we have a most recent time, but we failed to
    // get any.
    let err_str = "timestamp indicates data was written, but no data successfully read";
    Err(StratisError::Engine(ErrorEnum::NotFound, err_str.into()))
}

/// Get all the blockdevs corresponding to this pool that can be obtained from
/// the given devices.
/// Returns an error if a BDA can not be read or can not be found on any
/// blockdev in devnodes.
/// Returns an error if the blockdevs obtained do not match the metadata.
/// Returns a tuple, of which the first are the data devs, and the second
/// are the devs that support the cache tier.
/// Precondition: Every device in devnodes has already been determined to
/// belong to the pool with the specified pool uuid.
#[allow(implicit_hasher)]
pub fn get_blockdevs(
    pool_uuid: PoolUuid,
    backstore_save: &BackstoreSave,
    devnodes: &HashMap<Device, PathBuf>,
) -> StratisResult<(Vec<StratBlockDev>, Vec<StratBlockDev>)> {
    let recorded_data_map: HashMap<DevUuid, &BlockDevSave> = backstore_save
        .data_devs
        .iter()
        .map(|bds| (bds.uuid, bds))
        .collect();

    let recorded_cache_map: HashMap<DevUuid, &BlockDevSave> = match backstore_save.cache_devs {
        Some(ref cache_devs) => cache_devs.iter().map(|bds| (bds.uuid, bds)).collect(),
        None => HashMap::new(),
    };

    let mut segment_table: HashMap<DevUuid, Vec<(Sectors, Sectors)>> = HashMap::new();
    for seg in &backstore_save.data_segments {
        segment_table
            .entry(seg.0)
            .or_insert_with(Vec::default)
            .push((seg.1, seg.2))
    }
    if let Some(ref segs) = backstore_save.cache_segments {
        for seg in segs {
            segment_table
                .entry(seg.0)
                .or_insert_with(Vec::default)
                .push((seg.1, seg.2))
        }
    }
    if let Some(ref segs) = backstore_save.meta_segments {
        for seg in segs {
            segment_table
                .entry(seg.0)
                .or_insert_with(Vec::default)
                .push((seg.1, seg.2))
        }
    }

    let (mut datadevs, mut cachedevs) = (vec![], vec![]);
    for (device, devnode) in devnodes {
        let bda = BDA::load(&mut OpenOptions::new().read(true).open(devnode)?)?.ok_or_else(|| {
            StratisError::Engine(ErrorEnum::NotFound,
                                                 format!("Device {} with devnode {} was previously determined to belong to pool with uuid {} but no BDA was found",
                                                 device,
                                                 devnode.display(),
                                                 pool_uuid))
        })?;

        // Return an error if apparent size of Stratis block device appears to
        // have decreased since metadata was recorded or if size of block
        // device could not be obtained.
        blkdev_size(&OpenOptions::new().read(true).open(devnode)?).and_then(|actual_size| {
            let actual_size_sectors = actual_size.sectors();
            let recorded_size = bda.dev_size();
            if actual_size_sectors < recorded_size {
                let err_msg = format!(
                    "Stratis device with device number {}, devnode {}, pool UUID {} and device UUID {} had recorded size ({}), but actual size is less at ({})",
                    device,
                    devnode.display(),
                    bda.pool_uuid(),
                    bda.dev_uuid(),
                    recorded_size,
                    actual_size
                );
                Err(StratisError::Engine(ErrorEnum::Error, err_msg))
            } else {
                Ok(())
            }
        })?;

        let dev_uuid = bda.dev_uuid();

        // Locate the device in the metadata using its uuid. Return the device
        // metadata and whether it was a cache or a datadev.
        let (tier, bd_save) = recorded_data_map
            .get(&dev_uuid)
            .map(|bd_save| (BlockDevTier::Data, bd_save))
            .or_else(|| {
                recorded_cache_map
                    .get(&dev_uuid)
                    .map(|bd_save| (BlockDevTier::Cache, bd_save))
            })
            .ok_or_else(|| {
                let err_msg = format!(
                        "Stratis device with device number {}, devnode {}, pool UUID {} and device UUID {} had no record in pool metadata",
                        device,
                        devnode.display(),
                        bda.pool_uuid(),
                        bda.dev_uuid()
                    );
                StratisError::Engine(ErrorEnum::NotFound, err_msg)
            })?;

        // This should always succeed since the actual size is at
        // least the recorded size, so all segments should be
        // available to be allocated. If this fails, the most likely
        // conclusion is metadata corruption.
        let segments = segment_table.get(&dev_uuid);
        match tier {
            BlockDevTier::Data => &mut datadevs,
            BlockDevTier::Cache => &mut cachedevs,
        }.push(StratBlockDev::new(
            *device,
            devnode.to_owned(),
            bda,
            segments.unwrap_or(&vec![]),
            bd_save.user_info.clone(),
            bd_save.hardware_info.clone(),
        )?);
    }

    // Verify that datadevs found match datadevs recorded.
    let current_data_uuids: HashSet<_> = datadevs.iter().map(|b| b.uuid()).collect();
    let recorded_data_uuids: HashSet<_> = recorded_data_map.keys().cloned().collect();
    if current_data_uuids != recorded_data_uuids {
        let err_msg = "Recorded data dev UUIDs != discovered datadev UUIDs";
        return Err(StratisError::Engine(ErrorEnum::Invalid, err_msg.into()));
    }

    if datadevs.len() != current_data_uuids.len() {
        let err_msg = "Duplicate data devices found in environment";
        return Err(StratisError::Engine(ErrorEnum::Invalid, err_msg.into()));
    }

    // Verify that cachedevs found match cachedevs recorded.
    let current_cache_uuids: HashSet<_> = cachedevs.iter().map(|b| b.uuid()).collect();
    let recorded_cache_uuids: HashSet<_> = recorded_cache_map.keys().cloned().collect();
    if current_cache_uuids != recorded_cache_uuids {
        let err_msg = "Recorded cache dev UUIDs != discovered cachedev UUIDs";
        return Err(StratisError::Engine(ErrorEnum::Invalid, err_msg.into()));
    }

    if cachedevs.len() != current_cache_uuids.len() {
        let err_msg = "Duplicate cache devices found in environment";
        return Err(StratisError::Engine(ErrorEnum::Invalid, err_msg.into()));
    }

    Ok((datadevs, cachedevs))
}
<|endoftext|>


<commit_before>use std::default::Default;

extern crate time;

extern crate ansi_term;
use ansi_term::Colour::{Red, Green, Yellow, Blue, Purple, Cyan};

extern crate mysql;
use mysql::conn::MyOpts;
use mysql::conn::pool::MyPool;
use mysql::value::from_row;
use std::collections::BTreeMap;

pub mod error;
use self::error::Error;

pub mod model;
pub mod api_result;

extern crate rustc_serialize;
use rustc_serialize::json::{self, ToJson, Json};

fn main() {
    println!("--- {} ---", Red
        //.blink()
        .bold().paint("Test error Model").to_string());

    let code    = Error::get_code(&Error::Success);
    let message = Error::get_message(&Error::Success);
    println!("{{\"code\": {},\"message\":{:?}}}", code, message);

    println!("--- END ---");

    println!("\n--- {} ---", Green.bold().paint("Time").to_string());
    let time_now = time::now();
    println!("{:?}", time_now);

    let time = time::get_time();
    println!("{:?}", time);

    let time_str = time::strftime("%Y-%m-%d %H:%M:%S", &time_now);
    println!("{:?}", time_str);
    println!("--- END ---");

    println!("\n--- {} ---", Yellow.bold().paint("JSON encode decode").to_string());
    let json_str = "{\"code\":0,\"message\":\"OK\",\"data\":{\"keyword\":\"Rust, api, php, nginx\"},\"ip\":[\"192.168.0.168\",\"127.0.0.1\"]}";
    println!("json_str: {}", Blue.paint(json_str.to_string()));
    //let json: api_result::Body = json::decode(&json_str).unwrap();
    let mut obj: BTreeMap<String, json::Json> = BTreeMap::new();
    obj.insert("os".to_string(), json::Json::from_str("{\"page\": 11, \"os\": \"Linux, Unix, MacOS\"}").unwrap_or_else(|e| { panic!("failed to execute process: {}", e) }));
    obj.insert("test".to_string(), json::Json::from_str("[\"just test\"]").unwrap_or_else(|e| { panic!("failed to execute process: {}", e) }));
    let json_obj = api_result::Body {
        code: code,
        message: message.to_string(),
        data: obj,
    };
    let encode_str = json_obj.to_json();
    println!("encode_str: {}", encode_str.to_string());
    println!("--- END ---");

    println!("\n--- {} ---", Purple.bold().paint("BTreeMap".to_string()));
    // BTreeMap 的 key 只能是同一种类型
    let mut map   = BTreeMap::new();
    let mut n_map = BTreeMap::new();
    n_map.insert(0, "Hi, world");
    n_map.insert(1, "a");
    n_map.insert(2, "b");
    map.insert("key", "value");
    map.insert("os", "linux terminal");
    let n_keys: Vec<_>      = n_map.keys().cloned().collect();
    let n_values: Vec<&str> = n_map.values().cloned().collect();
    let keys: Vec<&str>   = map.keys().cloned().collect();
    let values: Vec<&str> = map.values().cloned().collect();
    println!("n_map->keys:   {:?}", n_keys);
    println!("n_map->values: {:?}", n_values);
    println!("map->keys:   {:?}", keys);
    println!("map->values: {:?}", values);
    for (k, v) in map.iter() {
        println!("map.{} = {}", k, v);
    }
    println!("--- END ---");

    println!("\n--- {} ---", Cyan.bold().paint("UserModel"));
    let empty_user = model::user::UserModel::create_empty();
    // error: cannot assign to immutable field
    //empty_user.id = 110;
    println!("empty_user -> {}", empty_user);
    let mut user = model::user::UserModel::create(1, "Admin".to_string(), "15801398759".to_string(), "abc@qq.com".to_string());
    println!("debug for user: {}", user);
    user.id = 100;
    user.nickname = "OP".to_string();
    println!("debug for user after modify: {}", user);
    let user_json = json::encode(&user).unwrap();
    println!("user_json: {}", user_json);

    // CREATE TABLE  `test`.`user` (
    //  `id` INT( 11 ) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT  '主键',
    //  `nickname` VARCHAR( 128 ) NOT NULL ,
    //  `mobile` VARCHAR( 32 ) NOT NULL ,
    //  `email` VARCHAR( 64 ) NOT NULL
    // ) ENGINE = INNODB;
    println!("\n--- {} ---", Red.bold().paint("MySQL example".to_string()));
    let opts = MyOpts {
        user: Some("dev".to_string()),
        pass: Some("dev".to_string()),
        //init: vec!["SET NAMES utf8; use test;".to_owned()],
        ..Default::default()
    };
    let pool = MyPool::new(opts).unwrap();
    //let nickname = user.nickname;
    //let mobile   = user.mobile;
    //let email    = user.email;
    //let res = pool.prepare("INSERT INTO test.user SET nickname = ?, mobile = ?, email = ?").and_then(|mut stmt| {
    //    stmt.execute((nickname, mobile, email));
    //    Ok(())
    //});
    //println!("res: {:?}", res);
    let mut users = vec![
        model::user::UserModel{id : 1, nickname: "admin".to_string(), mobile: "15811119890".to_string(), email: "158@qq.com".to_string()},
    ];
    users.push(user);
    for mut stmt in pool.prepare(r"INSERT INTO test.user
            (id, nickname, mobile, email)
            VALUES
            (NULL, ?, ?, ?)").into_iter() {
        for p in users.iter() {
            // `execute` takes ownership of `params` so we pass account name by reference.
            // Unwrap each result just to make sure no errors happended.
            stmt.execute((&p.nickname, &p.mobile, &p.email)).unwrap();
        }
    }
}
<commit_msg>加入备注.<commit_after>use std::default::Default;

extern crate time;

extern crate ansi_term;
use ansi_term::Colour::{Red, Green, Yellow, Blue, Purple, Cyan};

extern crate mysql;
use mysql::conn::MyOpts;
use mysql::conn::pool::MyPool;
use mysql::value::from_row;
use std::collections::BTreeMap;

pub mod error;
use self::error::Error;

pub mod model;
pub mod api_result;

extern crate rustc_serialize;
use rustc_serialize::json::{self, ToJson, Json};

fn main() {
    println!("--- {} ---", Red
        //.blink()
        .bold().paint("Test error Model").to_string());

    let code    = Error::get_code(&Error::Success);
    let message = Error::get_message(&Error::Success);
    println!("{{\"code\": {},\"message\":{:?}}}", code, message);

    println!("--- END ---");

    println!("\n--- {} ---", Green.bold().paint("Time").to_string());
    let time_now = time::now();
    println!("{:?}", time_now);

    let time = time::get_time();
    println!("{:?}", time);

    let time_str = time::strftime("%Y-%m-%d %H:%M:%S", &time_now);
    println!("{:?}", time_str);
    println!("--- END ---");

    println!("\n--- {} ---", Yellow.bold().paint("JSON encode decode").to_string());
    let json_str = "{\"code\":0,\"message\":\"OK\",\"data\":{\"keyword\":\"Rust, api, php, nginx\"},\"ip\":[\"192.168.0.168\",\"127.0.0.1\"]}";
    println!("json_str: {}", Blue.paint(json_str.to_string()));
    //let json: api_result::Body = json::decode(&json_str).unwrap();
    let mut obj: BTreeMap<String, json::Json> = BTreeMap::new();
    obj.insert("os".to_string(), json::Json::from_str("{\"page\": 11, \"os\": \"Linux, Unix, MacOS\"}").unwrap_or_else(|e| { panic!("failed to execute process: {}", e) }));
    obj.insert("test".to_string(), json::Json::from_str("[\"just test\"]").unwrap_or_else(|e| { panic!("failed to execute process: {}", e) }));
    let json_obj = api_result::Body {
        code: code,
        message: message.to_string(),
        data: obj,
    };
    let encode_str = json_obj.to_json();
    println!("encode_str: {}", encode_str.to_string());
    println!("--- END ---");

    println!("\n--- {} ---", Purple.bold().paint("BTreeMap".to_string()));
    // BTreeMap 的 key 只能是同一种类型
    let mut map   = BTreeMap::new();
    let mut n_map = BTreeMap::new();
    n_map.insert(0, "Hi, world");
    n_map.insert(1, "a");
    n_map.insert(2, "b");
    map.insert("key", "value");
    map.insert("os", "linux terminal");
    let n_keys: Vec<_>      = n_map.keys().cloned().collect();
    let n_values: Vec<&str> = n_map.values().cloned().collect();
    let keys: Vec<&str>   = map.keys().cloned().collect();
    let values: Vec<&str> = map.values().cloned().collect();
    println!("n_map->keys:   {:?}", n_keys);
    println!("n_map->values: {:?}", n_values);
    println!("map->keys:   {:?}", keys);
    println!("map->values: {:?}", values);
    for (k, v) in map.iter() {
        println!("map.{} = {}", k, v);
    }
    println!("--- END ---");

    println!("\n--- {} ---", Cyan.bold().paint("UserModel"));
    let empty_user = model::user::UserModel::create_empty();
    // error: cannot assign to immutable field
    //empty_user.id = 110;
    println!("empty_user -> {}", empty_user);
    let mut user = model::user::UserModel::create(1, "Admin".to_string(), "15801398759".to_string(), "abc@qq.com".to_string());
    println!("debug for user: {}", user);
    user.id = 100;
    user.nickname = "OP".to_string();
    println!("debug for user after modify: {}", user);
    let user_json = json::encode(&user).unwrap();
    println!("user_json: {}", user_json);

    // CREATE TABLE  `test`.`user` (
    //  `id` INT( 11 ) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT  '主键',
    //  `nickname` VARCHAR( 128 ) NOT NULL ,
    //  `mobile` VARCHAR( 32 ) NOT NULL ,
    //  `email` VARCHAR( 64 ) NOT NULL
    // ) ENGINE = INNODB;
    println!("\n--- {} ---", Red.bold().paint("MySQL example".to_string()));
    let opts = MyOpts {
        user: Some("dev".to_string()),
        pass: Some("dev".to_string()),
        //init: vec!["SET NAMES utf8; use test;".to_owned()], // 加入此行无法写数据.
        ..Default::default()
    };
    let pool = MyPool::new(opts).unwrap();
    //let nickname = user.nickname;
    //let mobile   = user.mobile;
    //let email    = user.email;
    //let res = pool.prepare("INSERT INTO test.user SET nickname = ?, mobile = ?, email = ?").and_then(|mut stmt| {
    //    stmt.execute((nickname, mobile, email));
    //    Ok(())
    //});
    //println!("res: {:?}", res);
    let mut users = vec![
        model::user::UserModel{id : 1, nickname: "admin".to_string(), mobile: "15811119890".to_string(), email: "158@qq.com".to_string()},
    ];
    users.push(user);
    for mut stmt in pool.prepare(r"INSERT INTO test.user
            (id, nickname, mobile, email)
            VALUES
            (NULL, ?, ?, ?)").into_iter() {
        for p in users.iter() {
            // `execute` takes ownership of `params` so we pass account name by reference.
            // Unwrap each result just to make sure no errors happended.
            stmt.execute((&p.nickname, &p.mobile, &p.email)).unwrap();
        }
    }
}
<|endoftext|>


<commit_before>//! # Basic Subclass example
//!
//! This file creates a `GtkApplication` and a `GtkApplicationWindow` subclass
//! and showcases how you can override virtual funcitons such as `startup`
//! and `activate` and how to interact with the GObjects and their private
//! structs.

#[macro_use]
extern crate glib;
extern crate gio;
extern crate gtk;

extern crate once_cell;

use gio::prelude::*;
use gtk::prelude::*;

use gio::subclass::application::ApplicationImplExt;
use gio::ApplicationFlags;
use glib::subclass;
use glib::subclass::prelude::*;
use glib::translate::*;
use gtk::subclass::prelude::*;

use once_cell::unsync::OnceCell;
use std::cell::Cell;

#[derive(Debug)]
struct WindowWidgets {
    headerbar: gtk::HeaderBar,
    increment: gtk::Button,
    label: gtk::Label,
}

// This is the private part of our `SimpleWindow` object.
// Its where state and widgets are stored when they don't
// need to be publicly accesible.
#[derive(Debug)]
pub struct SimpleWindowPrivate {
    widgets: OnceCell<WindowWidgets>,
    counter: Cell<u64>,
}

impl ObjectSubclass for SimpleWindowPrivate {
    const NAME: &'static str = "SimpleWindowPrivate";
    type ParentType = gtk::ApplicationWindow;
    type Instance = subclass::simple::InstanceStruct<Self>;
    type Class = subclass::simple::ClassStruct<Self>;

    glib_object_subclass!();

    fn new() -> Self {
        Self {
            widgets: OnceCell::new(),
            counter: Cell::new(0),
        }
    }
}

impl ObjectImpl for SimpleWindowPrivate {
    glib_object_impl!();

    // Here we are overriding the glib::Objcet::contructed
    // method. Its what gets called when we create our Object
    // and where we can initialize things.
    fn constructed(&self, obj: &glib::Object) {
        self.parent_constructed(obj);

        let self_ = obj.downcast_ref::<SimpleWindow>().unwrap();

        let headerbar = gtk::HeaderBar::new();
        let increment = gtk::Button::new_with_label("Increment!");
        let label = gtk::Label::new(Some("Press the Increment Button!"));

        headerbar.set_title(Some("Hello World!"));
        headerbar.set_show_close_button(true);
        headerbar.pack_start(&increment);

        // Connect our method `on_increment_clicked` to be called
        // when the increment button is clicked.
        increment.connect_clicked(clone!(@weak self_ => move |_| {
            let priv_ = SimpleWindowPrivate::from_instance(&self_);
            priv_.on_increment_clicked();
        }));

        self_.add(&label);
        self_.set_titlebar(Some(&headerbar));
        self_.set_default_size(640, 480);

        self.widgets
            .set(WindowWidgets {
                headerbar,
                label,
                increment,
            })
            .expect("Failed to initialize window state");
    }
}

impl SimpleWindowPrivate {
    fn on_increment_clicked(&self) {
        self.counter.set(self.counter.get() + 1);
        let w = self.widgets.get().unwrap();
        w.label
            .set_text(&format!("Counter is {}", self.counter.get()));
    }
}

impl WidgetImpl for SimpleWindowPrivate {}
impl ContainerImpl for SimpleWindowPrivate {}
impl BinImpl for SimpleWindowPrivate {}
impl WindowImpl for SimpleWindowPrivate {}
impl ApplicationWindowImpl for SimpleWindowPrivate {}

glib_wrapper! {
    pub struct SimpleWindow(
        Object<subclass::simple::InstanceStruct<SimpleWindowPrivate>,
        subclass::simple::ClassStruct<SimpleWindowPrivate>,
        SimpleAppWindowClass>)
        @extends gtk::Widget, gtk::Container, gtk::Bin, gtk::Window, gtk::ApplicationWindow;

    match fn {
        get_type => || SimpleWindowPrivate::get_type().to_glib(),
    }
}

impl SimpleWindow {
    pub fn new(app: &gtk::Application) -> Self {
        glib::Object::new(Self::static_type(), &[("application", app)])
            .expect("Failed to create SimpleWindow")
            .downcast::<SimpleWindow>()
            .expect("Created SimpleWindow is of wrong type")
    }
}

#[derive(Debug)]
pub struct SimpleApplicationPrivate {
    window: OnceCell<SimpleWindow>,
}

impl ObjectSubclass for SimpleApplicationPrivate {
    const NAME: &'static str = "SimpleApplicationPrivate";
    type ParentType = gtk::Application;
    type Instance = subclass::simple::InstanceStruct<Self>;
    type Class = subclass::simple::ClassStruct<Self>;

    glib_object_subclass!();

    fn new() -> Self {
        Self {
            window: OnceCell::new(),
        }
    }
}

impl ObjectImpl for SimpleApplicationPrivate {
    glib_object_impl!();
}

// When our application starts, the `startup` signal will be fired.
// This gives us a chance to perform initialisation tasks that are not directly
// related to showing a new window. After this, depending on how
// the application is started, either `activate` or `open` will be called next.
impl ApplicationImpl for SimpleApplicationPrivate {
    // `gio::Application::activate` is what gets called when the
    // application is launched by the desktop environment and
    // aksed to present itself.
    fn activate(&self, app: &gio::Application) {
        let app = app.downcast_ref::<gtk::Application>().unwrap();
        let priv_ = SimpleApplicationPrivate::from_instance(app);
        let window = priv_
            .window
            .get()
            .expect("Should always be initiliazed in gio_application_startup");
        window.show_all();
        window.present();
    }

    // `gio::Application` is bit special. It does not get initialized
    // when `new` is called and the object created, but rather
    // once the `startup` signal is emitted and the `gio::Application::startup`
    // is called.
    //
    // Due to this, we create and initialize the `SimpleWindow` widget
    // here. Widgets can't be created before `startup` has been called.
    fn startup(&self, app: &gio::Application) {
        self.parent_startup(app);

        let app = app.downcast_ref::<gtk::Application>().unwrap();
        let priv_ = SimpleApplicationPrivate::from_instance(app);
        let window = SimpleWindow::new(&app);
        priv_
            .window
            .set(window)
            .expect("Failed to initialize application window");
    }
}

impl GtkApplicationImpl for SimpleApplicationPrivate {}

glib_wrapper! {
    pub struct SimpleApplication(
        Object<subclass::simple::InstanceStruct<SimpleApplicationPrivate>,
        subclass::simple::ClassStruct<SimpleApplicationPrivate>,
        SimpleApplicationClass>)
        @extends gio::Application, gtk::Application;

    match fn {
        get_type => || SimpleApplicationPrivate::get_type().to_glib(),
    }
}

impl SimpleApplication {
    pub fn new() -> Self {
        glib::Object::new(
            Self::static_type(),
            &[
                ("application-id", &"org.gtk-rs.SimpleApplication"),
                ("flags", &ApplicationFlags::empty()),
            ],
        )
        .expect("Failed to create SimpleApp")
        .downcast()
        .expect("Created simpleapp is of wrong type")
    }
}

fn main() {
    gtk::init().expect("Failed to initialize gtk");

    let app = SimpleApplication::new();

    let args: Vec<String> = std::env::args().collect();
    app.run(&args);
}
<commit_msg>Fix use from prelude<commit_after>//! # Basic Subclass example
//!
//! This file creates a `GtkApplication` and a `GtkApplicationWindow` subclass
//! and showcases how you can override virtual funcitons such as `startup`
//! and `activate` and how to interact with the GObjects and their private
//! structs.

#[macro_use]
extern crate glib;
extern crate gio;
extern crate gtk;

extern crate once_cell;

use gio::prelude::*;
use gtk::prelude::*;

use gio::subclass::prelude::*;
use gio::ApplicationFlags;
use glib::subclass;
use glib::subclass::prelude::*;
use glib::translate::*;
use gtk::subclass::prelude::*;

use once_cell::unsync::OnceCell;
use std::cell::Cell;

#[derive(Debug)]
struct WindowWidgets {
    headerbar: gtk::HeaderBar,
    increment: gtk::Button,
    label: gtk::Label,
}

// This is the private part of our `SimpleWindow` object.
// Its where state and widgets are stored when they don't
// need to be publicly accesible.
#[derive(Debug)]
pub struct SimpleWindowPrivate {
    widgets: OnceCell<WindowWidgets>,
    counter: Cell<u64>,
}

impl ObjectSubclass for SimpleWindowPrivate {
    const NAME: &'static str = "SimpleWindowPrivate";
    type ParentType = gtk::ApplicationWindow;
    type Instance = subclass::simple::InstanceStruct<Self>;
    type Class = subclass::simple::ClassStruct<Self>;

    glib_object_subclass!();

    fn new() -> Self {
        Self {
            widgets: OnceCell::new(),
            counter: Cell::new(0),
        }
    }
}

impl ObjectImpl for SimpleWindowPrivate {
    glib_object_impl!();

    // Here we are overriding the glib::Objcet::contructed
    // method. Its what gets called when we create our Object
    // and where we can initialize things.
    fn constructed(&self, obj: &glib::Object) {
        self.parent_constructed(obj);

        let self_ = obj.downcast_ref::<SimpleWindow>().unwrap();

        let headerbar = gtk::HeaderBar::new();
        let increment = gtk::Button::new_with_label("Increment!");
        let label = gtk::Label::new(Some("Press the Increment Button!"));

        headerbar.set_title(Some("Hello World!"));
        headerbar.set_show_close_button(true);
        headerbar.pack_start(&increment);

        // Connect our method `on_increment_clicked` to be called
        // when the increment button is clicked.
        increment.connect_clicked(clone!(@weak self_ => move |_| {
            let priv_ = SimpleWindowPrivate::from_instance(&self_);
            priv_.on_increment_clicked();
        }));

        self_.add(&label);
        self_.set_titlebar(Some(&headerbar));
        self_.set_default_size(640, 480);

        self.widgets
            .set(WindowWidgets {
                headerbar,
                label,
                increment,
            })
            .expect("Failed to initialize window state");
    }
}

impl SimpleWindowPrivate {
    fn on_increment_clicked(&self) {
        self.counter.set(self.counter.get() + 1);
        let w = self.widgets.get().unwrap();
        w.label
            .set_text(&format!("Counter is {}", self.counter.get()));
    }
}

impl WidgetImpl for SimpleWindowPrivate {}
impl ContainerImpl for SimpleWindowPrivate {}
impl BinImpl for SimpleWindowPrivate {}
impl WindowImpl for SimpleWindowPrivate {}
impl ApplicationWindowImpl for SimpleWindowPrivate {}

glib_wrapper! {
    pub struct SimpleWindow(
        Object<subclass::simple::InstanceStruct<SimpleWindowPrivate>,
        subclass::simple::ClassStruct<SimpleWindowPrivate>,
        SimpleAppWindowClass>)
        @extends gtk::Widget, gtk::Container, gtk::Bin, gtk::Window, gtk::ApplicationWindow;

    match fn {
        get_type => || SimpleWindowPrivate::get_type().to_glib(),
    }
}

impl SimpleWindow {
    pub fn new(app: &gtk::Application) -> Self {
        glib::Object::new(Self::static_type(), &[("application", app)])
            .expect("Failed to create SimpleWindow")
            .downcast::<SimpleWindow>()
            .expect("Created SimpleWindow is of wrong type")
    }
}

#[derive(Debug)]
pub struct SimpleApplicationPrivate {
    window: OnceCell<SimpleWindow>,
}

impl ObjectSubclass for SimpleApplicationPrivate {
    const NAME: &'static str = "SimpleApplicationPrivate";
    type ParentType = gtk::Application;
    type Instance = subclass::simple::InstanceStruct<Self>;
    type Class = subclass::simple::ClassStruct<Self>;

    glib_object_subclass!();

    fn new() -> Self {
        Self {
            window: OnceCell::new(),
        }
    }
}

impl ObjectImpl for SimpleApplicationPrivate {
    glib_object_impl!();
}

// When our application starts, the `startup` signal will be fired.
// This gives us a chance to perform initialisation tasks that are not directly
// related to showing a new window. After this, depending on how
// the application is started, either `activate` or `open` will be called next.
impl ApplicationImpl for SimpleApplicationPrivate {
    // `gio::Application::activate` is what gets called when the
    // application is launched by the desktop environment and
    // aksed to present itself.
    fn activate(&self, app: &gio::Application) {
        let app = app.downcast_ref::<gtk::Application>().unwrap();
        let priv_ = SimpleApplicationPrivate::from_instance(app);
        let window = priv_
            .window
            .get()
            .expect("Should always be initiliazed in gio_application_startup");
        window.show_all();
        window.present();
    }

    // `gio::Application` is bit special. It does not get initialized
    // when `new` is called and the object created, but rather
    // once the `startup` signal is emitted and the `gio::Application::startup`
    // is called.
    //
    // Due to this, we create and initialize the `SimpleWindow` widget
    // here. Widgets can't be created before `startup` has been called.
    fn startup(&self, app: &gio::Application) {
        self.parent_startup(app);

        let app = app.downcast_ref::<gtk::Application>().unwrap();
        let priv_ = SimpleApplicationPrivate::from_instance(app);
        let window = SimpleWindow::new(&app);
        priv_
            .window
            .set(window)
            .expect("Failed to initialize application window");
    }
}

impl GtkApplicationImpl for SimpleApplicationPrivate {}

glib_wrapper! {
    pub struct SimpleApplication(
        Object<subclass::simple::InstanceStruct<SimpleApplicationPrivate>,
        subclass::simple::ClassStruct<SimpleApplicationPrivate>,
        SimpleApplicationClass>)
        @extends gio::Application, gtk::Application;

    match fn {
        get_type => || SimpleApplicationPrivate::get_type().to_glib(),
    }
}

impl SimpleApplication {
    pub fn new() -> Self {
        glib::Object::new(
            Self::static_type(),
            &[
                ("application-id", &"org.gtk-rs.SimpleApplication"),
                ("flags", &ApplicationFlags::empty()),
            ],
        )
        .expect("Failed to create SimpleApp")
        .downcast()
        .expect("Created simpleapp is of wrong type")
    }
}

fn main() {
    gtk::init().expect("Failed to initialize gtk");

    let app = SimpleApplication::new();

    let args: Vec<String> = std::env::args().collect();
    app.run(&args);
}
<|endoftext|>


<commit_before>use std::fmt::Debug;
use std::cmp::Ordering::*;

enum Find { Any, After }

#[derive(Debug)]
struct Node<K> {
    key: K,
    left: Tree<K>,
    right: Tree<K>,
}

#[derive(Debug)]
pub struct Tree<K> {
    inner: Option<Box<Node<K>>>
}

impl<K: Ord+Debug> Tree<K> {
   pub fn new() -> Tree<K> {
        Tree { inner: None }
    }

    pub fn leaf(key: K) -> Tree<K> {
        let node = Node {
            key: key,
            left: Tree::new(),
            right: Tree::new()
        };

        Tree { inner: Some(Box::new(node)) }
    }

    pub fn has(&mut self, key: K) -> bool {
        let tree = self.find_mut(&key, Find::Any);

        tree.is_node()
    }

    pub fn insert(&mut self, key: K) {
        let tree = self.find_mut(&key, Find::After);

        *tree = Tree::leaf(key);
    }

    pub fn delete(&mut self, key: K) {
        let tree = self.find_mut(&key, Find::Any);

        if tree.is_node() {
            if tree.right_mut().is_node() {
                let succ = {
                    let succ = tree.right_mut().first_mut();
                    let mut taken = succ.take();
                    *succ = taken.right_mut().take();
                    taken
                };
                tree.node_mut().key = succ.into_key();
            } else {
                *tree = tree.left_mut().take();
            }
        }
    }

    fn find_mut(&mut self, key: &K, strategy: Find) -> &mut Self {
        let mut cur = self;

        loop {
            let temp = cur;
            if temp.is_node() {
                cur = match temp.key().cmp(key) {
                    Less    => temp.right_mut(),
                    Greater => temp.left_mut(),
                    Equal   => {
                        match strategy {
                            Find::After => temp.right_mut(),
                            Find::Any   => return temp
                        }
                    }
                };
            } else {
                return temp
            }
        }
    }

    fn first_mut(&mut self) -> &mut Self {
        if self.is_empty() { return self }

        let mut cur = self;
        loop {
            let temp = cur;
            if temp.left_mut().is_node() {
                cur = temp.left_mut()
            } else {
                return temp
            }
        }
    }

    fn into_node(self)      -> Node<K>      { *self.inner.unwrap() }
    fn into_key(self)       -> K            { self.into_node().key }

    fn take(&mut self)      -> Self         { Tree { inner: self.inner.take() } }
    fn node_mut(&mut self)  -> &mut Node<K> { self.inner.as_mut().unwrap() }
    fn left_mut(&mut self)  -> &mut Self    { &mut self.node_mut().left }
    fn right_mut(&mut self) -> &mut Self    { &mut self.node_mut().right }

    fn node(&self)          -> &Node<K>     { self.inner.as_ref().unwrap() }
    fn key(&self)           -> &K           { &self.node().key }
    fn is_node(&self)       -> bool         { self.inner.is_some() }
    fn is_empty(&self)      -> bool         { self.inner.is_none() }
}

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

    #[test]
    fn insert() {
        let mut bst = Tree::new();

        bst.insert(5);
        bst.insert(2);

        assert_eq!(
            (0..10).map(|i| bst.has(i)).collect::<Vec<_>>(),
            [false, false, true, false, false, true, false, false, false, false]
        );

        bst.insert(3);
        bst.insert(1);
        bst.insert(7);

        assert_eq!(
            (0..10).map(|i| bst.has(i)).collect::<Vec<_>>(),
            [false, true, true, true, false, true, false, true, false, false]
        );
    }

    #[test]
    fn insert_and_delete() {
        let mut bst = Tree::new();

        const F: bool = false;
        const T: bool = true;

        bst.insert(7);
        bst.insert(3);
        bst.insert(11);
        bst.insert(1);
        bst.insert(5);
        bst.insert(9);
        bst.insert(13);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [F, T, F, T, F, T, F, T, F, T, F, T, F, T, F]);

        bst.insert(0);
        bst.insert(2);
        bst.insert(4);
        bst.insert(6);
        bst.insert(8);
        bst.insert(10);
        bst.insert(12);
        bst.insert(14);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [T, T, T, T, T, T, T, T, T, T, T, T, T, T, T]);

        bst.delete(7);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [T, T, T, T, T, T, T, F, T, T, T, T, T, T, T]);
        bst.delete(3);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [T, T, T, F, T, T, T, F, T, T, T, T, T, T, T]);
        bst.delete(11);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [T, T, T, F, T, T, T, F, T, T, T, F, T, T, T]);
        bst.delete(1);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [T, F, T, F, T, T, T, F, T, T, T, F, T, T, T]);
        bst.delete(5);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [T, F, T, F, T, F, T, F, T, T, T, F, T, T, T]);
        bst.delete(9);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [T, F, T, F, T, F, T, F, T, F, T, F, T, T, T]);
        bst.delete(13);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [T, F, T, F, T, F, T, F, T, F, T, F, T, F, T]);
        bst.delete(0);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [F, F, T, F, T, F, T, F, T, F, T, F, T, F, T]);
        bst.delete(2);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [F, F, F, F, T, F, T, F, T, F, T, F, T, F, T]);
        bst.delete(4);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [F, F, F, F, F, F, T, F, T, F, T, F, T, F, T]);
        bst.delete(6);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [F, F, F, F, F, F, F, F, T, F, T, F, T, F, T]);
        bst.delete(8);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [F, F, F, F, F, F, F, F, F, F, T, F, T, F, T]);
        bst.delete(10);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [F, F, F, F, F, F, F, F, F, F, F, F, T, F, T]);
        bst.delete(12);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [F, F, F, F, F, F, F, F, F, F, F, F, F, F, T]);
        bst.delete(14);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [F, F, F, F, F, F, F, F, F, F, F, F, F, F, F]);
    }

    #[test]
    fn insert_and_delete_duplicates() {
        let mut bst = Tree::new();

        bst.insert(0);
        bst.insert(1);
        bst.insert(0);
        bst.insert(1);
        bst.insert(0);
        bst.insert(1);

        println!("{:#?}", bst);

        assert_eq!(
            (0..2).map(|i| bst.has(i)).collect::<Vec<_>>(),
            [true, true]
        );

        bst.delete(0);
        println!("{:#?}", bst);
        bst.delete(0);
        bst.delete(1);

        assert_eq!(
            (0..2).map(|i| bst.has(i)).collect::<Vec<_>>(),
            [true, true]
        );

        bst.delete(0);

        assert_eq!(
            (0..2).map(|i| bst.has(i)).collect::<Vec<_>>(),
            [false, true]
        );
    }
}
<commit_msg>fix up bst<commit_after>use std::fmt::Debug;
use std::cmp::Ordering::*;

enum Find { Any, After }

#[derive(Debug)]
struct Node<K> {
    key: K,
    left: Tree<K>,
    right: Tree<K>,
}

#[derive(Debug)]
pub struct Tree<K> {
    inner: Option<Box<Node<K>>>
}

impl<K: Ord+Debug> Tree<K> {
   pub fn new() -> Tree<K> {
        Tree { inner: None }
    }

    pub fn leaf(key: K) -> Tree<K> {
        let node = Node {
            key: key,
            left: Tree::new(),
            right: Tree::new()
        };

        Tree { inner: Some(Box::new(node)) }
    }

    pub fn has(&mut self, key: K) -> bool {
        let tree = self.find(&key, Find::Any);

        tree.is_node()
    }

    pub fn insert(&mut self, key: K) {
        let tree = self.find(&key, Find::After);

        *tree = Tree::leaf(key);
    }

    pub fn delete(&mut self, key: K) {
        let tree = self.find(&key, Find::Any);

        if tree.is_node() {
            if tree.right().is_node() {
                let succ = {
                    let succ = tree.right().first();
                    let mut taken = succ.take();
                    *succ = taken.right().take();
                    taken
                };
                tree.node_mut().key = succ.into_key();
            } else {
                *tree = tree.left().take();
            }
        }
    }

    fn find(&mut self, key: &K, strategy: Find) -> &mut Self {
        if self.is_empty() { return self }

        match self.key().cmp(key) {
            Less    => self.right().find(key, strategy),
            Greater => self.left().find(key, strategy),
            Equal   => {
                match strategy {
                    Find::After => self.right().find(key, strategy),
                    Find::Any   => self
                }
            }
        }
    }

    fn first(&mut self) -> &mut Self {
        if self.is_empty() { return self }

        if self.left().is_node() {
            self.left().first()
        } else {
            self
        }
    }

    fn into_node(self)      -> Node<K>      { *self.inner.unwrap() }
    fn into_key(self)       -> K            { self.into_node().key }

    fn take(&mut self)      -> Self         { Tree { inner: self.inner.take() } }
    fn node_mut(&mut self)  -> &mut Node<K> { self.inner.as_mut().unwrap() }
    fn left(&mut self)      -> &mut Self    { &mut self.node_mut().left }
    fn right(&mut self)     -> &mut Self    { &mut self.node_mut().right }

    fn node(&self)          -> &Node<K>     { self.inner.as_ref().unwrap() }
    fn key(&self)           -> &K           { &self.node().key }
    fn is_node(&self)       -> bool         { self.inner.is_some() }
    fn is_empty(&self)      -> bool         { self.inner.is_none() }
}

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

    #[test]
    fn insert() {
        let mut bst = Tree::new();

        bst.insert(5);
        bst.insert(2);

        assert_eq!(
            (0..10).map(|i| bst.has(i)).collect::<Vec<_>>(),
            [false, false, true, false, false, true, false, false, false, false]
        );

        bst.insert(3);
        bst.insert(1);
        bst.insert(7);

        assert_eq!(
            (0..10).map(|i| bst.has(i)).collect::<Vec<_>>(),
            [false, true, true, true, false, true, false, true, false, false]
        );
    }

    #[test]
    fn insert_and_delete() {
        let mut bst = Tree::new();

        const F: bool = false;
        const T: bool = true;

        bst.insert(7);
        bst.insert(3);
        bst.insert(11);
        bst.insert(1);
        bst.insert(5);
        bst.insert(9);
        bst.insert(13);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [F, T, F, T, F, T, F, T, F, T, F, T, F, T, F]);

        bst.insert(0);
        bst.insert(2);
        bst.insert(4);
        bst.insert(6);
        bst.insert(8);
        bst.insert(10);
        bst.insert(12);
        bst.insert(14);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [T, T, T, T, T, T, T, T, T, T, T, T, T, T, T]);

        bst.delete(7);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [T, T, T, T, T, T, T, F, T, T, T, T, T, T, T]);
        bst.delete(3);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [T, T, T, F, T, T, T, F, T, T, T, T, T, T, T]);
        bst.delete(11);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [T, T, T, F, T, T, T, F, T, T, T, F, T, T, T]);
        bst.delete(1);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [T, F, T, F, T, T, T, F, T, T, T, F, T, T, T]);
        bst.delete(5);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [T, F, T, F, T, F, T, F, T, T, T, F, T, T, T]);
        bst.delete(9);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [T, F, T, F, T, F, T, F, T, F, T, F, T, T, T]);
        bst.delete(13);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [T, F, T, F, T, F, T, F, T, F, T, F, T, F, T]);
        bst.delete(0);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [F, F, T, F, T, F, T, F, T, F, T, F, T, F, T]);
        bst.delete(2);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [F, F, F, F, T, F, T, F, T, F, T, F, T, F, T]);
        bst.delete(4);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [F, F, F, F, F, F, T, F, T, F, T, F, T, F, T]);
        bst.delete(6);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [F, F, F, F, F, F, F, F, T, F, T, F, T, F, T]);
        bst.delete(8);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [F, F, F, F, F, F, F, F, F, F, T, F, T, F, T]);
        bst.delete(10);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [F, F, F, F, F, F, F, F, F, F, F, F, T, F, T]);
        bst.delete(12);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [F, F, F, F, F, F, F, F, F, F, F, F, F, F, T]);
        bst.delete(14);
        assert_eq!((0..15).map(|i| bst.has(i)).collect::<Vec<_>>(), [F, F, F, F, F, F, F, F, F, F, F, F, F, F, F]);
    }

    #[test]
    fn insert_and_delete_duplicates() {
        let mut bst = Tree::new();

        bst.insert(0);
        bst.insert(1);
        bst.insert(0);
        bst.insert(1);
        bst.insert(0);
        bst.insert(1);

        println!("{:#?}", bst);

        assert_eq!(
            (0..2).map(|i| bst.has(i)).collect::<Vec<_>>(),
            [true, true]
        );

        bst.delete(0);
        println!("{:#?}", bst);
        bst.delete(0);
        bst.delete(1);

        assert_eq!(
            (0..2).map(|i| bst.has(i)).collect::<Vec<_>>(),
            [true, true]
        );

        bst.delete(0);

        assert_eq!(
            (0..2).map(|i| bst.has(i)).collect::<Vec<_>>(),
            [false, true]
        );
    }
}
<|endoftext|>


<commit_before><commit_msg>Fixed recursion stack problem.<commit_after><|endoftext|>


<commit_before><commit_msg>added reader comments<commit_after><|endoftext|>


<commit_before>#![allow(non_upper_case_globals, non_camel_case_types)]

use core_foundation as cf;

pub type FSEventStreamRef = *mut ::std::os::raw::c_void;

pub type FSEventStreamCallback = extern "C" fn(
    FSEventStreamRef,            //ConstFSEventStreamRef streamRef
    *mut ::std::os::raw::c_void, // void *clientCallBackInfo
    usize,                       // size_t numEvents
    *mut ::std::os::raw::c_void, // void *eventPaths
    *mut ::std::os::raw::c_void, // const FSEventStreamEventFlags eventFlags[]
    *mut ::std::os::raw::c_void, // const FSEventStreamEventId eventIds[]
);

pub type FSEventStreamEventId = u64;

pub const kFSEventStreamEventIdSinceNow: FSEventStreamEventId = 0xFFFFFFFFFFFFFFFF;

pub type FSEventStreamCreateFlags = u32;

pub const kFSEventStreamCreateFlagNone: FSEventStreamCreateFlags = 0x00000000;
pub const kFSEventStreamCreateFlagUseCFTypes: FSEventStreamCreateFlags = 0x00000001;
pub const kFSEventStreamCreateFlagNoDefer: FSEventStreamCreateFlags = 0x00000002;
pub const kFSEventStreamCreateFlagWatchRoot: FSEventStreamCreateFlags = 0x00000004;
pub const kFSEventStreamCreateFlagIgnoreSelf: FSEventStreamCreateFlags = 0x00000008;
pub const kFSEventStreamCreateFlagFileEvents: FSEventStreamCreateFlags = 0x00000010;

#[repr(C)]
pub struct FSEventStreamContext {
    pub version: cf::CFIndex,
    pub info: *mut ::std::os::raw::c_void,
    pub retain: *mut ::std::os::raw::c_void,
    pub copy_description: *mut ::std::os::raw::c_void,
}
// impl Clone for FSEventStreamContext { }
// impl Copy for FSEventStreamContext { }

#[link(name = "CoreServices", kind = "framework")]
extern "C" {

    pub fn FSEventStreamCreate(
        allocator: cf::CFRef,
        callback: *const FSEventStreamCallback,
        context: *const FSEventStreamContext,
        pathsToWatch: cf::CFMutableArrayRef,
        sinceWhen: FSEventStreamEventId,
        latency: cf::CFTimeInterval,
        flags: FSEventStreamCreateFlags,
    ) -> FSEventStreamRef;

    pub fn FSEventStreamShow(stream_ref: FSEventStreamRef);
    pub fn FSEventStreamScheduleWithRunLoop(
        stream_ref: FSEventStreamRef,
        run_loop: cf::CFRunLoopRef,
        run_loop_mode: cf::CFStringRef,
    );

    pub fn FSEventStreamUnscheduleFromRunLoop(
        stream_ref: FSEventStreamRef,
        run_loop: cf::CFRunLoopRef,
        run_loop_mode: cf::CFStringRef,
    );

    pub fn FSEventStreamStart(stream_ref: FSEventStreamRef) -> bool;
    pub fn FSEventStreamFlushSync(stream_ref: FSEventStreamRef);
    pub fn FSEventStreamStop(stream_ref: FSEventStreamRef);
    pub fn FSEventStreamInvalidate(stream_ref: FSEventStreamRef);
    pub fn FSEventStreamRelease(stream_ref: FSEventStreamRef);

}
<commit_msg>fsevent-sys: Add missing consts.<commit_after>#![allow(non_upper_case_globals, non_camel_case_types)]

use core_foundation as cf;

pub type FSEventStreamRef = *mut ::std::os::raw::c_void;

pub type FSEventStreamCallback = extern "C" fn(
    FSEventStreamRef,            //ConstFSEventStreamRef streamRef
    *mut ::std::os::raw::c_void, // void *clientCallBackInfo
    usize,                       // size_t numEvents
    *mut ::std::os::raw::c_void, // void *eventPaths
    *mut ::std::os::raw::c_void, // const FSEventStreamEventFlags eventFlags[]
    *mut ::std::os::raw::c_void, // const FSEventStreamEventId eventIds[]
);

pub type FSEventStreamEventId = u64;

pub const kFSEventStreamEventIdSinceNow: FSEventStreamEventId = 0xFFFFFFFFFFFFFFFF;

pub type FSEventStreamCreateFlags = u32;

pub const kFSEventStreamCreateFlagNone: FSEventStreamCreateFlags = 0x00000000;
pub const kFSEventStreamCreateFlagUseCFTypes: FSEventStreamCreateFlags = 0x00000001;
pub const kFSEventStreamCreateFlagNoDefer: FSEventStreamCreateFlags = 0x00000002;
pub const kFSEventStreamCreateFlagWatchRoot: FSEventStreamCreateFlags = 0x00000004;
pub const kFSEventStreamCreateFlagIgnoreSelf: FSEventStreamCreateFlags = 0x00000008;
pub const kFSEventStreamCreateFlagFileEvents: FSEventStreamCreateFlags = 0x00000010;
pub const kFSEventStreamCreateFlagMarkSelf: FSEventStreamCreateFlags = 0x00000020;
pub const kFSEventStreamCreateFlagUseExtendedData: FSEventStreamCreateFlags = 0x00000040;

pub type FSEventStreamEventFlags = u32;

pub const kFSEventStreamEventFlagNone: FSEventStreamEventFlags = 0x00000000;
pub const kFSEventStreamEventFlagMustScanSubDirs: FSEventStreamEventFlags = 0x00000001;
pub const kFSEventStreamEventFlagUserDropped: FSEventStreamEventFlags = 0x00000002;
pub const kFSEventStreamEventFlagKernelDropped: FSEventStreamEventFlags = 0x00000004;
pub const kFSEventStreamEventFlagEventIdsWrapped: FSEventStreamEventFlags = 0x00000008;
pub const kFSEventStreamEventFlagHistoryDone: FSEventStreamEventFlags = 0x00000010;
pub const kFSEventStreamEventFlagRootChanged: FSEventStreamEventFlags = 0x00000020;
pub const kFSEventStreamEventFlagMount: FSEventStreamEventFlags = 0x00000040;
pub const kFSEventStreamEventFlagUnmount: FSEventStreamEventFlags = 0x00000080;
pub const kFSEventStreamEventFlagItemCreated: FSEventStreamEventFlags = 0x00000100;
pub const kFSEventStreamEventFlagItemRemoved: FSEventStreamEventFlags = 0x00000200;
pub const kFSEventStreamEventFlagItemInodeMetaMod: FSEventStreamEventFlags = 0x00000400;
pub const kFSEventStreamEventFlagItemRenamed: FSEventStreamEventFlags = 0x00000800;
pub const kFSEventStreamEventFlagItemModified: FSEventStreamEventFlags = 0x00001000;
pub const kFSEventStreamEventFlagItemFinderInfoMod: FSEventStreamEventFlags = 0x00002000;
pub const kFSEventStreamEventFlagItemChangeOwner: FSEventStreamEventFlags = 0x00004000;
pub const kFSEventStreamEventFlagItemXattrMod: FSEventStreamEventFlags = 0x00008000;
pub const kFSEventStreamEventFlagItemIsFile: FSEventStreamEventFlags = 0x00010000;
pub const kFSEventStreamEventFlagItemIsDir: FSEventStreamEventFlags = 0x00020000;
pub const kFSEventStreamEventFlagItemIsSymlink: FSEventStreamEventFlags = 0x00040000;
pub const kFSEventStreamEventFlagOwnEvent: FSEventStreamEventFlags = 0x00080000;
pub const kFSEventStreamEventFlagItemIsHardlink: FSEventStreamEventFlags = 0x00100000;
pub const kFSEventStreamEventFlagItemIsLastHardlink: FSEventStreamEventFlags = 0x00200000;
pub const kFSEventStreamEventFlagItemCloned: FSEventStreamEventFlags = 0x00400000;

#[repr(C)]
pub struct FSEventStreamContext {
    pub version: cf::CFIndex,
    pub info: *mut ::std::os::raw::c_void,
    pub retain: *mut ::std::os::raw::c_void,
    pub copy_description: *mut ::std::os::raw::c_void,
}
// impl Clone for FSEventStreamContext { }
// impl Copy for FSEventStreamContext { }

#[link(name = "CoreServices", kind = "framework")]
extern "C" {

    pub fn FSEventStreamCreate(
        allocator: cf::CFRef,
        callback: *const FSEventStreamCallback,
        context: *const FSEventStreamContext,
        pathsToWatch: cf::CFMutableArrayRef,
        sinceWhen: FSEventStreamEventId,
        latency: cf::CFTimeInterval,
        flags: FSEventStreamCreateFlags,
    ) -> FSEventStreamRef;

    pub fn FSEventStreamShow(stream_ref: FSEventStreamRef);
    pub fn FSEventStreamScheduleWithRunLoop(
        stream_ref: FSEventStreamRef,
        run_loop: cf::CFRunLoopRef,
        run_loop_mode: cf::CFStringRef,
    );

    pub fn FSEventStreamUnscheduleFromRunLoop(
        stream_ref: FSEventStreamRef,
        run_loop: cf::CFRunLoopRef,
        run_loop_mode: cf::CFStringRef,
    );

    pub fn FSEventStreamStart(stream_ref: FSEventStreamRef) -> bool;
    pub fn FSEventStreamFlushSync(stream_ref: FSEventStreamRef);
    pub fn FSEventStreamStop(stream_ref: FSEventStreamRef);
    pub fn FSEventStreamInvalidate(stream_ref: FSEventStreamRef);
    pub fn FSEventStreamRelease(stream_ref: FSEventStreamRef);

}
<|endoftext|>


<commit_before>/* Copyright (C)  2016 nokaa <nokaa@cock.li>
 * This software is licensed under the terms of the
 * GNU Affero General Public License. You should have
 * received a copy of this license with this software.
 * The license may also be found at https://gnu.org/licenses/agpl.txt
 */

use super::Term;

pub fn handle(term: &mut Term, ch: char) {
    match ch {
        '\x1b' => { // Escape key
            term.editor.switch_mode();
        }
        '\x7f' => { // Backspace key
            let line = term.current_line() + term.cursor.pos.y;
            term.cursor.save_pos();

            if term.cursor.pos.x == 0 {
                let mut rem = term.editor.contents[line].clone();
                let pos = term.editor.contents[line - 1].len() - 1;

                term.editor.contents[line - 1].remove(pos);
                term.editor.contents[line - 1].append(&mut rem);
                term.editor.contents.remove(line);

                if term.cursor.pos.y != 0 {
                    term.cursor.pos.y -= 1;
                }

                term.cursor.pos.x = pos;
                term.redraw_file();
            } else {
                term.cursor.pos.x -= 1;
                let pos = term.cursor.pos.x;

                term.editor.contents[line].remove(pos);
                term.redraw_file();
            }
        }
        '\r' => {
            let line = term.current_line() + term.cursor.pos.y;
            let pos = term.cursor.pos.x;

            let mut rem = term.editor.contents[line].split_off(pos);
            rem.push(b'\n');
            term.editor.contents.insert(line + 1, rem);

            term.cursor.save_pos();
            term.cursor.pos.x = 0;
            term.cursor.pos.y += 1;

            term.redraw_file();
        }
        '\t' => {
            for i in 0..4 {
                let x = term.cursor.pos.x + i;
                term.term[(x, term.cursor.pos.y)].set_ch(' ');
            }

            term.cursor.save_pos();
            term.cursor.pos.x += 4;
        }
        c @ _ => {
            let line = term.current_line() + term.cursor.pos.y;
            let pos = term.cursor.pos.x;

            term.editor.contents[line].insert(pos, c as u8);

            term.cursor.save_pos();
            term.cursor.pos.x += 1;
            term.redraw_file();
        }
    }
}
<commit_msg>Cursor moves left one when leaving insert mode<commit_after>/* Copyright (C)  2016 nokaa <nokaa@cock.li>
 * This software is licensed under the terms of the
 * GNU Affero General Public License. You should have
 * received a copy of this license with this software.
 * The license may also be found at https://gnu.org/licenses/agpl.txt
 */

use super::Term;

pub fn handle(term: &mut Term, ch: char) {
    match ch {
        '\x1b' => { // Escape key
            term.cursor.save_pos();
            if term.cursor.pos.x > 0 {
                term.cursor.pos.x -= 1;
            }

            term.editor.switch_mode();
        }
        '\x7f' => { // Backspace key
            let line = term.current_line() + term.cursor.pos.y;
            term.cursor.save_pos();

            if term.cursor.pos.x == 0 {
                let mut rem = term.editor.contents[line].clone();
                let pos = term.editor.contents[line - 1].len() - 1;

                term.editor.contents[line - 1].remove(pos);
                term.editor.contents[line - 1].append(&mut rem);
                term.editor.contents.remove(line);

                if term.cursor.pos.y != 0 {
                    term.cursor.pos.y -= 1;
                }

                term.cursor.pos.x = pos;
                term.redraw_file();
            } else {
                term.cursor.pos.x -= 1;
                let pos = term.cursor.pos.x;

                term.editor.contents[line].remove(pos);
                term.redraw_file();
            }
        }
        '\r' => {
            let line = term.current_line() + term.cursor.pos.y;
            let pos = term.cursor.pos.x;

            let mut rem = term.editor.contents[line].split_off(pos);
            rem.push(b'\n');
            term.editor.contents.insert(line + 1, rem);

            term.cursor.save_pos();
            term.cursor.pos.x = 0;
            term.cursor.pos.y += 1;

            term.redraw_file();
        }
        '\t' => {
            for i in 0..4 {
                let x = term.cursor.pos.x + i;
                term.term[(x, term.cursor.pos.y)].set_ch(' ');
            }

            term.cursor.save_pos();
            term.cursor.pos.x += 4;
        }
        c @ _ => {
            let line = term.current_line() + term.cursor.pos.y;
            let pos = term.cursor.pos.x;

            term.editor.contents[line].insert(pos, c as u8);

            term.cursor.save_pos();
            term.cursor.pos.x += 1;
            term.redraw_file();
        }
    }
}
<|endoftext|>


<commit_before>use core::mem;
use core::cell::Cell;
use hil::Controller;
use hil::alarm::{Alarm, AlarmClient, Freq16KHz};
use peripheral_registers::{RTC1_BASE, RTC1};
use peripheral_interrupts::NvicIdx;
use chip;
use nvic;

fn rtc1() -> &'static RTC1 {
    unsafe { mem::transmute(RTC1_BASE as usize) }
}

pub struct Rtc {
    callback: Cell<Option<&'static AlarmClient>>
}

pub static mut RTC : Rtc = Rtc {
    callback: Cell::new(None),
};

impl Controller for Rtc {
    type Config = &'static AlarmClient;

    fn configure(&self, client: &'static AlarmClient) {
        self.callback.set(Some(client));

        // FIXME: what to do here?
        //self.start();
        // Set counter incrementing frequency to 16KHz
        // rtc1().prescaler.set(1);
    }
}

// CLEAR, STOP, START and TRIGOVRFLW tasks have up to 46us delay to process.
// See 18.1.8 "TASK and EVENT jitter/delay" on the nRF51 Reference Manual.
//
// wait_task() will delay approximately this time. For a 16 MHz CPU,
// 1us == 16 instructions (assuming each instruction takes one cycle).
#[inline(never)]
fn wait_task() {
    // The inner loop instructions are: 14 NOPs + 1 SUBS + 1 CMP
    unsafe {
        asm!(
            "movs r0, #47\n\
            1:\n\
            nop\n\
            nop\n\
            nop\n\
            nop\n\
            nop\n\
            nop\n\
            nop\n\
            nop\n\
            nop\n\
            nop\n\
            nop\n\
            nop\n\
            nop\n\
            nop\n\
            subs r0, #1\n\
            cmp r0, #0\n\
            bne.n 1b"
            : /* no output */
            : /* no input */
            : "{r0}"
        );
   }
}

const COMPARE0_EVENT: u32 = 1 << 16;

impl Rtc {

    fn start(&self) {
        nvic::clear_pending(NvicIdx::RTC1);
        nvic::enable(NvicIdx::RTC1);
        rtc1().tasks_start.set(1);
        wait_task();
    }

    fn stop(&self) {
        nvic::disable(NvicIdx::RTC1);
        rtc1().intenclr.set(COMPARE0_EVENT);
        rtc1().cc[0].set(0);
        rtc1().tasks_stop.set(1);
        wait_task();
    }

    fn is_running(&self) -> bool {
        rtc1().evten.get() & (COMPARE0_EVENT) == (COMPARE0_EVENT)
    }

    pub fn handle_interrupt(&self) {
        self.callback.get().map(|cb| {
            cb.fired();
        });
    }
}

impl Alarm for Rtc {
    type Frequency = Freq16KHz;

    fn now(&self) -> u32 {
        rtc1().counter.get()
    }

    fn disable_alarm(&self) {
        self.stop();
    }

    fn set_alarm(&self, tics: u32) {
        rtc1().cc[0].set(tics);
        rtc1().intenset.set(COMPARE0_EVENT);
        self.start();
    }

    fn get_alarm(&self) -> u32 {
        rtc1().cc[0].get()
    }

    fn is_armed(&self) -> bool {
       self.is_running()
    }
}

#[no_mangle]
#[allow(non_snake_case)]
pub unsafe extern fn RTC1_Handler() {
    use common::Queue;
    nvic::clear_pending(NvicIdx::RTC1);
    nvic::disable(NvicIdx::RTC1);
    chip::INTERRUPT_QUEUE.as_mut().unwrap().enqueue(NvicIdx::RTC1);
}
<commit_msg>Fix clobber in assembly.<commit_after>use core::mem;
use core::cell::Cell;
use hil::Controller;
use hil::alarm::{Alarm, AlarmClient, Freq16KHz};
use peripheral_registers::{RTC1_BASE, RTC1};
use peripheral_interrupts::NvicIdx;
use chip;
use nvic;

fn rtc1() -> &'static RTC1 {
    unsafe { mem::transmute(RTC1_BASE as usize) }
}

pub struct Rtc {
    callback: Cell<Option<&'static AlarmClient>>
}

pub static mut RTC : Rtc = Rtc {
    callback: Cell::new(None),
};

impl Controller for Rtc {
    type Config = &'static AlarmClient;

    fn configure(&self, client: &'static AlarmClient) {
        self.callback.set(Some(client));

        // FIXME: what to do here?
        //self.start();
        // Set counter incrementing frequency to 16KHz
        // rtc1().prescaler.set(1);
    }
}

// CLEAR, STOP, START and TRIGOVRFLW tasks have up to 46us delay to process.
// See 18.1.8 "TASK and EVENT jitter/delay" on the nRF51 Reference Manual.
//
// wait_task() will delay approximately this time. For a 16 MHz CPU,
// 1us == 16 instructions (assuming each instruction takes one cycle).
#[inline(never)]
fn wait_task() {
    // The inner loop instructions are: 14 NOPs + 1 SUBS + 1 CMP
    unsafe {
        asm!(
            "movs r0, #47\n\
            1:\n\
            nop\n\
            nop\n\
            nop\n\
            nop\n\
            nop\n\
            nop\n\
            nop\n\
            nop\n\
            nop\n\
            nop\n\
            nop\n\
            nop\n\
            nop\n\
            nop\n\
            subs r0, #1\n\
            cmp r0, #0\n\
            bne.n 1b"
            : /* no output */
            : /* no input */
            : "r0"
        );
   }
}

const COMPARE0_EVENT: u32 = 1 << 16;

impl Rtc {

    fn start(&self) {
        nvic::clear_pending(NvicIdx::RTC1);
        nvic::enable(NvicIdx::RTC1);
        rtc1().tasks_start.set(1);
        wait_task();
    }

    fn stop(&self) {
        nvic::disable(NvicIdx::RTC1);
        rtc1().intenclr.set(COMPARE0_EVENT);
        rtc1().cc[0].set(0);
        rtc1().tasks_stop.set(1);
        wait_task();
    }

    fn is_running(&self) -> bool {
        rtc1().evten.get() & (COMPARE0_EVENT) == (COMPARE0_EVENT)
    }

    pub fn handle_interrupt(&self) {
        self.callback.get().map(|cb| {
            cb.fired();
        });
    }
}

impl Alarm for Rtc {
    type Frequency = Freq16KHz;

    fn now(&self) -> u32 {
        rtc1().counter.get()
    }

    fn disable_alarm(&self) {
        self.stop();
    }

    fn set_alarm(&self, tics: u32) {
        rtc1().cc[0].set(tics);
        rtc1().intenset.set(COMPARE0_EVENT);
        self.start();
    }

    fn get_alarm(&self) -> u32 {
        rtc1().cc[0].get()
    }

    fn is_armed(&self) -> bool {
       self.is_running()
    }
}

#[no_mangle]
#[allow(non_snake_case)]
pub unsafe extern fn RTC1_Handler() {
    use common::Queue;
    nvic::clear_pending(NvicIdx::RTC1);
    nvic::disable(NvicIdx::RTC1);
    chip::INTERRUPT_QUEUE.as_mut().unwrap().enqueue(NvicIdx::RTC1);
}
<|endoftext|>


<commit_before><commit_msg>cleanup termination protocol<commit_after><|endoftext|>


<commit_before><commit_msg>Add more tests: inserting more than one sibling and relative_to when there is more than one sibling<commit_after><|endoftext|>


<commit_before>use llvm_sys::core::LLVMGetTypeKind;
use llvm_sys::LLVMTypeKind;
use llvm_sys::prelude::LLVMTypeRef;

use types::{IntType, VoidType, FunctionType, PointerType, VectorType, ArrayType, StructType, FloatType};
use types::traits::AsTypeRef;

macro_rules! enum_type_set {
    ($enum_name:ident: $($args:ident),*) => (
        #[derive(Debug, EnumAsGetters, EnumIntoGetters, EnumIsA, PartialEq, Eq)]
        pub enum $enum_name {
            $(
                $args($args),
            )*
        }

        impl AsTypeRef for $enum_name {
            fn as_type_ref(&self) -> LLVMTypeRef {
                match *self {
                    $(
                        $enum_name::$args(ref t) => t.as_type_ref(),
                    )*
                }
            }
        }

        $(
            impl From<$args> for $enum_name {
                fn from(value: $args) -> $enum_name {
                    $enum_name::$args(value)
                }
            }
        )*
    );
}

enum_type_set! {AnyTypeEnum: IntType, FunctionType, FloatType, PointerType, StructType, ArrayType, VoidType, VectorType}
enum_type_set! {BasicTypeEnum: IntType, FloatType, PointerType, StructType, ArrayType, VectorType}

impl AnyTypeEnum {
    pub(crate) fn new(type_: LLVMTypeRef) -> AnyTypeEnum {
        let type_kind = unsafe {
            LLVMGetTypeKind(type_)
        };

        match type_kind {
            LLVMTypeKind::LLVMVoidTypeKind => AnyTypeEnum::VoidType(VoidType::new(type_)),
            LLVMTypeKind::LLVMHalfTypeKind |
            LLVMTypeKind::LLVMFloatTypeKind |
            LLVMTypeKind::LLVMDoubleTypeKind |
            LLVMTypeKind::LLVMX86_FP80TypeKind |
            LLVMTypeKind::LLVMFP128TypeKind |
            LLVMTypeKind::LLVMPPC_FP128TypeKind => AnyTypeEnum::FloatType(FloatType::new(type_)),
            LLVMTypeKind::LLVMLabelTypeKind => panic!("FIXME: Unsupported type: Label"),
            LLVMTypeKind::LLVMIntegerTypeKind => AnyTypeEnum::IntType(IntType::new(type_)),
            LLVMTypeKind::LLVMFunctionTypeKind => AnyTypeEnum::FunctionType(FunctionType::new(type_)),
            LLVMTypeKind::LLVMStructTypeKind => AnyTypeEnum::StructType(StructType::new(type_)),
            LLVMTypeKind::LLVMArrayTypeKind => AnyTypeEnum::ArrayType(ArrayType::new(type_)),
            LLVMTypeKind::LLVMPointerTypeKind => AnyTypeEnum::PointerType(PointerType::new(type_)),
            LLVMTypeKind::LLVMVectorTypeKind => AnyTypeEnum::VectorType(VectorType::new(type_)),
            LLVMTypeKind::LLVMMetadataTypeKind => panic!("FIXME: Unsupported type: Metadata"),
            LLVMTypeKind::LLVMX86_MMXTypeKind => panic!("FIXME: Unsupported type: MMX"),
            // LLVMTypeKind::LLVMTokenTypeKind => panic!("FIXME: Unsupported type: Token"), // Different version?
        }
    }
}

impl BasicTypeEnum {
    pub(crate) fn new(type_: LLVMTypeRef) -> BasicTypeEnum {
        let type_kind = unsafe {
            LLVMGetTypeKind(type_)
        };

        match type_kind {
            LLVMTypeKind::LLVMHalfTypeKind |
            LLVMTypeKind::LLVMFloatTypeKind |
            LLVMTypeKind::LLVMDoubleTypeKind |
            LLVMTypeKind::LLVMX86_FP80TypeKind |
            LLVMTypeKind::LLVMFP128TypeKind |
            LLVMTypeKind::LLVMPPC_FP128TypeKind => BasicTypeEnum::FloatType(FloatType::new(type_)),
            LLVMTypeKind::LLVMIntegerTypeKind => BasicTypeEnum::IntType(IntType::new(type_)),
            LLVMTypeKind::LLVMStructTypeKind => BasicTypeEnum::StructType(StructType::new(type_)),
            LLVMTypeKind::LLVMPointerTypeKind => BasicTypeEnum::PointerType(PointerType::new(type_)),
            LLVMTypeKind::LLVMArrayTypeKind => BasicTypeEnum::ArrayType(ArrayType::new(type_)),
            LLVMTypeKind::LLVMVectorTypeKind => BasicTypeEnum::VectorType(VectorType::new(type_)),
            LLVMTypeKind::LLVMMetadataTypeKind => unreachable!("Unsupported type: Metadata"),
            LLVMTypeKind::LLVMX86_MMXTypeKind => unreachable!("Unsupported type: MMX"),
            LLVMTypeKind::LLVMLabelTypeKind => unreachable!("Unsupported type: Label"),
            LLVMTypeKind::LLVMVoidTypeKind => unreachable!("Unsupported type: VoidType"),
            LLVMTypeKind::LLVMFunctionTypeKind => unreachable!("Unsupported type: FunctionType"),
        }
    }
}
<commit_msg>Types enums can now be cloned and copied.<commit_after>use llvm_sys::core::LLVMGetTypeKind;
use llvm_sys::LLVMTypeKind;
use llvm_sys::prelude::LLVMTypeRef;

use types::{IntType, VoidType, FunctionType, PointerType, VectorType, ArrayType, StructType, FloatType};
use types::traits::AsTypeRef;

macro_rules! enum_type_set {
    ($enum_name:ident: $($args:ident),*) => (
        #[derive(Debug, EnumAsGetters, EnumIntoGetters, EnumIsA, PartialEq, Eq, Clone, Copy)]
        pub enum $enum_name {
            $(
                $args($args),
            )*
        }

        impl AsTypeRef for $enum_name {
            fn as_type_ref(&self) -> LLVMTypeRef {
                match *self {
                    $(
                        $enum_name::$args(ref t) => t.as_type_ref(),
                    )*
                }
            }
        }

        $(
            impl From<$args> for $enum_name {
                fn from(value: $args) -> $enum_name {
                    $enum_name::$args(value)
                }
            }
        )*
    );
}

enum_type_set! {AnyTypeEnum: IntType, FunctionType, FloatType, PointerType, StructType, ArrayType, VoidType, VectorType}
enum_type_set! {BasicTypeEnum: IntType, FloatType, PointerType, StructType, ArrayType, VectorType}

impl AnyTypeEnum {
    pub(crate) fn new(type_: LLVMTypeRef) -> AnyTypeEnum {
        let type_kind = unsafe {
            LLVMGetTypeKind(type_)
        };

        match type_kind {
            LLVMTypeKind::LLVMVoidTypeKind => AnyTypeEnum::VoidType(VoidType::new(type_)),
            LLVMTypeKind::LLVMHalfTypeKind |
            LLVMTypeKind::LLVMFloatTypeKind |
            LLVMTypeKind::LLVMDoubleTypeKind |
            LLVMTypeKind::LLVMX86_FP80TypeKind |
            LLVMTypeKind::LLVMFP128TypeKind |
            LLVMTypeKind::LLVMPPC_FP128TypeKind => AnyTypeEnum::FloatType(FloatType::new(type_)),
            LLVMTypeKind::LLVMLabelTypeKind => panic!("FIXME: Unsupported type: Label"),
            LLVMTypeKind::LLVMIntegerTypeKind => AnyTypeEnum::IntType(IntType::new(type_)),
            LLVMTypeKind::LLVMFunctionTypeKind => AnyTypeEnum::FunctionType(FunctionType::new(type_)),
            LLVMTypeKind::LLVMStructTypeKind => AnyTypeEnum::StructType(StructType::new(type_)),
            LLVMTypeKind::LLVMArrayTypeKind => AnyTypeEnum::ArrayType(ArrayType::new(type_)),
            LLVMTypeKind::LLVMPointerTypeKind => AnyTypeEnum::PointerType(PointerType::new(type_)),
            LLVMTypeKind::LLVMVectorTypeKind => AnyTypeEnum::VectorType(VectorType::new(type_)),
            LLVMTypeKind::LLVMMetadataTypeKind => panic!("FIXME: Unsupported type: Metadata"),
            LLVMTypeKind::LLVMX86_MMXTypeKind => panic!("FIXME: Unsupported type: MMX"),
            // LLVMTypeKind::LLVMTokenTypeKind => panic!("FIXME: Unsupported type: Token"), // Different version?
        }
    }
}

impl BasicTypeEnum {
    pub(crate) fn new(type_: LLVMTypeRef) -> BasicTypeEnum {
        let type_kind = unsafe {
            LLVMGetTypeKind(type_)
        };

        match type_kind {
            LLVMTypeKind::LLVMHalfTypeKind |
            LLVMTypeKind::LLVMFloatTypeKind |
            LLVMTypeKind::LLVMDoubleTypeKind |
            LLVMTypeKind::LLVMX86_FP80TypeKind |
            LLVMTypeKind::LLVMFP128TypeKind |
            LLVMTypeKind::LLVMPPC_FP128TypeKind => BasicTypeEnum::FloatType(FloatType::new(type_)),
            LLVMTypeKind::LLVMIntegerTypeKind => BasicTypeEnum::IntType(IntType::new(type_)),
            LLVMTypeKind::LLVMStructTypeKind => BasicTypeEnum::StructType(StructType::new(type_)),
            LLVMTypeKind::LLVMPointerTypeKind => BasicTypeEnum::PointerType(PointerType::new(type_)),
            LLVMTypeKind::LLVMArrayTypeKind => BasicTypeEnum::ArrayType(ArrayType::new(type_)),
            LLVMTypeKind::LLVMVectorTypeKind => BasicTypeEnum::VectorType(VectorType::new(type_)),
            LLVMTypeKind::LLVMMetadataTypeKind => unreachable!("Unsupported type: Metadata"),
            LLVMTypeKind::LLVMX86_MMXTypeKind => unreachable!("Unsupported type: MMX"),
            LLVMTypeKind::LLVMLabelTypeKind => unreachable!("Unsupported type: Label"),
            LLVMTypeKind::LLVMVoidTypeKind => unreachable!("Unsupported type: VoidType"),
            LLVMTypeKind::LLVMFunctionTypeKind => unreachable!("Unsupported type: FunctionType"),
        }
    }
}
<|endoftext|>


<commit_before>#![cfg(feature = "integration")]

use std::env;
use std::ffi::OsStr;
use std::process::Command;

#[cfg_attr(feature = "integration", test)]
fn integration_test() {
    let repo_name = env::var("INTEGRATION").expect("`INTEGRATION` var not set");
    let repo_url = format!("https://github.com/{}", repo_name);
    let crate_name = repo_name
        .split('/')
        .nth(1)
        .expect("repo name should have format `<org>/<name>`");

    let mut repo_dir = tempfile::tempdir().expect("couldn't create temp dir").into_path();
    repo_dir.push(crate_name);

    let st = Command::new("git")
        .args(&[
            OsStr::new("clone"),
            OsStr::new("--depth=1"),
            OsStr::new(&repo_url),
            OsStr::new(&repo_dir),
        ])
        .status()
        .expect("unable to run git");
    assert!(st.success());

    let root_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
    let target_dir = std::path::Path::new(&root_dir).join("target");
    let clippy_binary = target_dir.join(env!("PROFILE")).join("cargo-clippy");

    let output = Command::new(clippy_binary)
        .current_dir(repo_dir)
        .env("RUST_BACKTRACE", "full")
        .env("CARGO_TARGET_DIR", target_dir)
        .args(&[
            "clippy",
            "--all-targets",
            "--all-features",
            "--",
            "--cap-lints",
            "warn",
            "-Wclippy::pedantic",
            "-Wclippy::nursery",
        ])
        .output()
        .expect("unable to run clippy");

    let stderr = String::from_utf8_lossy(&output.stderr);
    if stderr.contains("internal compiler error") {
        let backtrace_start = stderr
            .find("thread 'rustc' panicked at")
            .expect("start of backtrace not found");
        let backtrace_end = stderr
            .rfind("error: internal compiler error")
            .expect("end of backtrace not found");

        panic!(
            "internal compiler error\nBacktrace:\n\n{}",
            &stderr[backtrace_start..backtrace_end]
        );
    } else if stderr.contains("query stack during panic") {
        panic!("query stack during panic in the output");
    } else if stderr.contains("E0463") {
        panic!("error: E0463");
    } else if stderr.contains("E0514") {
        panic!("incompatible crate versions");
    } else if stderr.contains("failed to run `rustc` to learn about target-specific information") {
        panic!("couldn't find librustc_driver, consider setting `LD_LIBRARY_PATH`");
    }

    match output.status.code() {
        Some(0) => println!("Compilation successful"),
        Some(code) => eprintln!("Compilation failed. Exit code: {}", code),
        None => panic!("Process terminated by signal"),
    }
}
<commit_msg>Explain panic on `E0463` in integration tests<commit_after>#![cfg(feature = "integration")]

use std::env;
use std::ffi::OsStr;
use std::process::Command;

#[cfg_attr(feature = "integration", test)]
fn integration_test() {
    let repo_name = env::var("INTEGRATION").expect("`INTEGRATION` var not set");
    let repo_url = format!("https://github.com/{}", repo_name);
    let crate_name = repo_name
        .split('/')
        .nth(1)
        .expect("repo name should have format `<org>/<name>`");

    let mut repo_dir = tempfile::tempdir().expect("couldn't create temp dir").into_path();
    repo_dir.push(crate_name);

    let st = Command::new("git")
        .args(&[
            OsStr::new("clone"),
            OsStr::new("--depth=1"),
            OsStr::new(&repo_url),
            OsStr::new(&repo_dir),
        ])
        .status()
        .expect("unable to run git");
    assert!(st.success());

    let root_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
    let target_dir = std::path::Path::new(&root_dir).join("target");
    let clippy_binary = target_dir.join(env!("PROFILE")).join("cargo-clippy");

    let output = Command::new(clippy_binary)
        .current_dir(repo_dir)
        .env("RUST_BACKTRACE", "full")
        .env("CARGO_TARGET_DIR", target_dir)
        .args(&[
            "clippy",
            "--all-targets",
            "--all-features",
            "--",
            "--cap-lints",
            "warn",
            "-Wclippy::pedantic",
            "-Wclippy::nursery",
        ])
        .output()
        .expect("unable to run clippy");

    let stderr = String::from_utf8_lossy(&output.stderr);
    if stderr.contains("internal compiler error") {
        let backtrace_start = stderr
            .find("thread 'rustc' panicked at")
            .expect("start of backtrace not found");
        let backtrace_end = stderr
            .rfind("error: internal compiler error")
            .expect("end of backtrace not found");

        panic!(
            "internal compiler error\nBacktrace:\n\n{}",
            &stderr[backtrace_start..backtrace_end]
        );
    } else if stderr.contains("query stack during panic") {
        panic!("query stack during panic in the output");
    } else if stderr.contains("E0463") {
        // Encountering E0463 (can't find crate for `x`) did _not_ cause the build to fail in the
        // past. Even though it should have. That's why we explicitly panic here.
        // See PR #3552 and issue #3523 for more background.
        panic!("error: E0463");
    } else if stderr.contains("E0514") {
        panic!("incompatible crate versions");
    } else if stderr.contains("failed to run `rustc` to learn about target-specific information") {
        panic!("couldn't find librustc_driver, consider setting `LD_LIBRARY_PATH`");
    }

    match output.status.code() {
        Some(0) => println!("Compilation successful"),
        Some(code) => eprintln!("Compilation failed. Exit code: {}", code),
        None => panic!("Process terminated by signal"),
    }
}
<|endoftext|>