<commit_before>//! [Standard terms](https://en.wikipedia.org/wiki/Lambda_calculus#Standard_terms) and
//! [combinators](https://en.wikipedia.org/wiki/Combinatory_logic#Combinatory_calculi)
//!
//! * [SKI](https://en.wikipedia.org/wiki/SKI_combinator_calculus)
//! * [Iota](https://en.wikipedia.org/wiki/Iota_and_Jot)
//! * [BCKW](https://en.wikipedia.org/wiki/B,_C,_K,_W_system)
// //! * the recursion combinator U - needs more research
//! * the looping combinator ω
//! * the divergent combinator Ω
//! * [the fixed-point combinator Y](https://en.wikipedia.org/wiki/Fixed-point_combinator)

use term::*;
use term::Term::*;

/// I - the identity combinator.
///
/// I := λx.x = λ 1
///
/// # Example
/// ```
/// use lambda_calculus::combinators::i;
/// use lambda_calculus::arithmetic::zero;
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(i().app(zero())), zero());
/// ```
pub fn i() -> Term { abs(Var(1)) }

/// K - the constant / discarding combinator.
///
/// K := λxy.x = λ λ 2 = true
///
/// # Example
/// ```
/// use lambda_calculus::combinators::k;
/// use lambda_calculus::arithmetic::{zero, one};
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(k().app(zero()).app(one())), zero());
/// ```
pub fn k() -> Term { abs(abs(Var(2))) }

/// S - the substitution combinator.
///
/// S := λxyz.x z (y z) = λ λ λ 3 1 (2 1)
///
/// # Example
/// ```
/// use lambda_calculus::term::Term;
/// use lambda_calculus::combinators::s;
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(s().app(0.into()).app(1.into()).app(2.into())),
///            normalize(Term::from(0).app(2.into()).app(Term::from(1).app(2.into()))));
/// ```
pub fn s() -> Term {
    abs(abs(abs(
        Var(3)
        .app(Var(1))
        .app(Var(2).app(Var(1)))
    )))
}

/// Iota - the universal combinator.
///
/// ι := λx.x S K = λ 1 S K
///
/// # Example
/// ```
/// use lambda_calculus::combinators::{iota, i, k, s};
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(iota().app(iota())), i());
/// assert_eq!(normalize(iota().app(iota().app(iota().app(iota())))), k());
/// assert_eq!(normalize(iota().app(iota().app(iota().app(iota().app(iota()))))), s());
/// ```
pub fn iota() -> Term { abs(Var(1).app(s()).app(k())) }

/// B - the composition combinator.
///
/// B := λxyz.x (y z) = λ λ λ 3 (2 1)
///
/// # Example
/// ```
/// use lambda_calculus::term::Term;
/// use lambda_calculus::combinators::b;
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(b().app(0.into()).app(1.into()).app(2.into())),
///            normalize(Term::from(0).app(Term::from(1).app(2.into()))));
/// ```
pub fn b() -> Term {
    abs(abs(abs(
        Var(3)
        .app(Var(2).app(Var(1)))
    )))
}

/// C - the swapping combinator.
///
/// C := λxyz.x z y = λ λ λ 3 1 2
///
/// # Example
/// ```
/// use lambda_calculus::term::Term;
/// use lambda_calculus::combinators::c;
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(c().app(0.into()).app(1.into()).app(2.into())),
///            normalize(Term::from(0).app(2.into()).app(1.into())));
/// ```
pub fn c() -> Term {
    abs(abs(abs(
        Var(3)
        .app(Var(1))
        .app(Var(2))
    )))
}

/// W - the duplicating combinator.
///
/// W := λxy.x y y = λ λ 2 1 1
///
/// # Example
/// ```
/// use lambda_calculus::combinators::w;
/// use lambda_calculus::arithmetic::{zero, one};
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(w().app(zero()).app(one())),
///            normalize(zero().app(one()).app(one())));
/// ```
pub fn w() -> Term {
    abs(abs(
        Var(2)
        .app(Var(1))
        .app(Var(1))
    ))
}
/*
/// U - the recursion combinator.
///
/// U := λxy.y (x x y) = λ λ 1 (2 2 1)
pub fn u() -> Term { abs(abs(Var(1).app(Var(2).app(Var(2)).app(Var(1))))) }
*/
/// ω - the looping combinator.
///
/// ω := λx.x x
/// # Example
///
/// ```
/// use lambda_calculus::combinators::om;
/// use lambda_calculus::arithmetic::zero;
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(om().app(zero())), normalize(zero().app(zero())));
/// ```
pub fn om() -> Term { abs(Var(1).app(Var(1))) }

/// Ω - the divergent combinator.
///
/// Ω := ω ω
// TODO: add example
pub fn omm() -> Term { om().app(om()) }

/// Y - the fixed-point combinator.
///
/// Y := λg.(λx.g (x x)) (λx.g (x x)) = λ (λ 2 (1 1)) (λ 2 (1 1))
/// # Example
///
/// ```
/// use lambda_calculus::combinators::y;
/// use lambda_calculus::arithmetic::zero;
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(y().app(zero())), normalize(zero().app(y().app(zero()))));
/// ```
pub fn y() -> Term {
    abs(app(
        abs(Var(2).app(Var(1).app(Var(1)))),
        abs(Var(2).app(Var(1).app(Var(1))))
    ))
}
<commit_msg>Add an example and doc test for Ω<commit_after>//! [Standard terms](https://en.wikipedia.org/wiki/Lambda_calculus#Standard_terms) and
//! [combinators](https://en.wikipedia.org/wiki/Combinatory_logic#Combinatory_calculi)
//!
//! * [SKI](https://en.wikipedia.org/wiki/SKI_combinator_calculus)
//! * [Iota](https://en.wikipedia.org/wiki/Iota_and_Jot)
//! * [BCKW](https://en.wikipedia.org/wiki/B,_C,_K,_W_system)
// //! * the recursion combinator U - needs more research
//! * the looping combinator ω
//! * the divergent combinator Ω
//! * [the fixed-point combinator Y](https://en.wikipedia.org/wiki/Fixed-point_combinator)

use term::*;
use term::Term::*;

/// I - the identity combinator.
///
/// I := λx.x = λ 1
///
/// # Example
/// ```
/// use lambda_calculus::combinators::i;
/// use lambda_calculus::arithmetic::zero;
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(i().app(zero())), zero());
/// ```
pub fn i() -> Term { abs(Var(1)) }

/// K - the constant / discarding combinator.
///
/// K := λxy.x = λ λ 2 = true
///
/// # Example
/// ```
/// use lambda_calculus::combinators::k;
/// use lambda_calculus::arithmetic::{zero, one};
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(k().app(zero()).app(one())), zero());
/// ```
pub fn k() -> Term { abs(abs(Var(2))) }

/// S - the substitution combinator.
///
/// S := λxyz.x z (y z) = λ λ λ 3 1 (2 1)
///
/// # Example
/// ```
/// use lambda_calculus::term::Term;
/// use lambda_calculus::combinators::s;
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(s().app(0.into()).app(1.into()).app(2.into())),
///            normalize(Term::from(0).app(2.into()).app(Term::from(1).app(2.into()))));
/// ```
pub fn s() -> Term {
    abs(abs(abs(
        Var(3)
        .app(Var(1))
        .app(Var(2).app(Var(1)))
    )))
}

/// Iota - the universal combinator.
///
/// ι := λx.x S K = λ 1 S K
///
/// # Example
/// ```
/// use lambda_calculus::combinators::{iota, i, k, s};
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(iota().app(iota())), i());
/// assert_eq!(normalize(iota().app(iota().app(iota().app(iota())))), k());
/// assert_eq!(normalize(iota().app(iota().app(iota().app(iota().app(iota()))))), s());
/// ```
pub fn iota() -> Term { abs(Var(1).app(s()).app(k())) }

/// B - the composition combinator.
///
/// B := λxyz.x (y z) = λ λ λ 3 (2 1)
///
/// # Example
/// ```
/// use lambda_calculus::term::Term;
/// use lambda_calculus::combinators::b;
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(b().app(0.into()).app(1.into()).app(2.into())),
///            normalize(Term::from(0).app(Term::from(1).app(2.into()))));
/// ```
pub fn b() -> Term {
    abs(abs(abs(
        Var(3)
        .app(Var(2).app(Var(1)))
    )))
}

/// C - the swapping combinator.
///
/// C := λxyz.x z y = λ λ λ 3 1 2
///
/// # Example
/// ```
/// use lambda_calculus::term::Term;
/// use lambda_calculus::combinators::c;
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(c().app(0.into()).app(1.into()).app(2.into())),
///            normalize(Term::from(0).app(2.into()).app(1.into())));
/// ```
pub fn c() -> Term {
    abs(abs(abs(
        Var(3)
        .app(Var(1))
        .app(Var(2))
    )))
}

/// W - the duplicating combinator.
///
/// W := λxy.x y y = λ λ 2 1 1
///
/// # Example
/// ```
/// use lambda_calculus::combinators::w;
/// use lambda_calculus::arithmetic::{zero, one};
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(w().app(zero()).app(one())),
///            normalize(zero().app(one()).app(one())));
/// ```
pub fn w() -> Term {
    abs(abs(
        Var(2)
        .app(Var(1))
        .app(Var(1))
    ))
}
/*
/// U - the recursion combinator.
///
/// U := λxy.y (x x y) = λ λ 1 (2 2 1)
pub fn u() -> Term { abs(abs(Var(1).app(Var(2).app(Var(2)).app(Var(1))))) }
*/
/// ω - the looping combinator.
///
/// ω := λx.x x
/// # Example
///
/// ```
/// use lambda_calculus::combinators::om;
/// use lambda_calculus::arithmetic::zero;
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(om().app(zero())), normalize(zero().app(zero())));
/// ```
pub fn om() -> Term { abs(Var(1).app(Var(1))) }

/// Ω - the divergent combinator.
///
/// Ω := ω ω
///
/// # Example
///
/// ```
/// use lambda_calculus::combinators::omm;
/// use lambda_calculus::reduction::beta_reduce_once;
///
/// let mut doesnt_reduce = omm();
///
/// beta_reduce_once(&mut doesnt_reduce);
///
/// assert_eq!(doesnt_reduce, omm());
/// ```
pub fn omm() -> Term { om().app(om()) }

/// Y - the fixed-point combinator.
///
/// Y := λg.(λx.g (x x)) (λx.g (x x)) = λ (λ 2 (1 1)) (λ 2 (1 1))
/// # Example
///
/// ```
/// use lambda_calculus::combinators::y;
/// use lambda_calculus::arithmetic::zero;
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(y().app(zero())), normalize(zero().app(y().app(zero()))));
/// ```
pub fn y() -> Term {
    abs(app(
        abs(Var(2).app(Var(1).app(Var(1)))),
        abs(Var(2).app(Var(1).app(Var(1))))
    ))
}
<|endoftext|>


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

use std::fs::File;
use std::io::Read;
use std::time::Duration;
use yaml_rust::YamlLoader;

use crate::config::ServerConfig;
use crate::config::{DEFAULT_BATCH_SIZE, DEFAULT_STATUS_INTERVAL};
use crate::key::KmsProtection;
use crate::Error;

///
/// Read a Roughenough server configuration ([ServerConfig](trait.ServerConfig.html))
/// from a YAML file.
///
/// Example minimal config:
///
/// ```yaml
/// interface: 127.0.0.1
/// port: 8686
/// seed: f61075c988feb9cb700a4a6a3291bfbc9cab11b9c9eca8c802468eb38a43d7d3
/// ```
///
pub struct FileConfig {
    port: u16,
    interface: String,
    seed: Vec<u8>,
    batch_size: u8,
    status_interval: Duration,
    kms_protection: KmsProtection,
    health_check_port: Option<u16>,
    client_stats: bool,
    fault_percentage: u8,
}

impl FileConfig {
    pub fn new(config_file: &str) -> Result<Self, Error> {
        let mut infile = File::open(config_file).expect("failed to open config file");

        let mut contents = String::new();
        infile
            .read_to_string(&mut contents)
            .expect("could not read config file");

        let cfg = YamlLoader::load_from_str(&contents).expect("could not parse config file");

        if cfg.len() != 1 {
            return Err(Error::InvalidConfiguration(
                "Empty or malformed config file".to_string(),
            ));
        }

        let mut config = FileConfig {
            port: 0,
            interface: "".to_string(),
            seed: Vec::new(),
            batch_size: DEFAULT_BATCH_SIZE,
            status_interval: DEFAULT_STATUS_INTERVAL,
            kms_protection: KmsProtection::Plaintext,
            health_check_port: None,
            client_stats: false,
            fault_percentage: 0,
        };

        for (key, value) in cfg[0].as_hash().unwrap() {
            match key.as_str().unwrap() {
                "port" => config.port = value.as_i64().unwrap() as u16,
                "interface" => config.interface = value.as_str().unwrap().to_string(),
                "batch_size" => config.batch_size = value.as_i64().unwrap() as u8,
                "seed" => {
                    let val = value.as_str().unwrap().to_string();
                    config.seed = hex::decode(val)
                        .expect("seed value invalid; 'seed' must be a valid hex value");
                }
                "status_interval" => {
                    let val = value.as_i64().expect("status_interval value invalid");
                    config.status_interval = Duration::from_secs(val as u64)
                }
                "kms_protection" => {
                    let val =
                        value.as_str().unwrap().parse().unwrap_or_else(|_| {
                            panic!("invalid kms_protection value: {:?}", value)
                        });
                    config.kms_protection = val
                }
                "health_check_port" => {
                    let val = value.as_i64().unwrap() as u16;
                    config.health_check_port = Some(val);
                }
                "client_stats" => {
                    let val = value.as_str().unwrap().to_ascii_lowercase();
                    config.client_stats = val == "yes" || val == "on";
                }
                "fault_percentage" => {
                    let val = value.as_i64().unwrap() as u8;
                    config.fault_percentage = val;
                }
                unknown => {
                    return Err(Error::InvalidConfiguration(format!(
                        "unknown config key: {}",
                        unknown
                    )));
                }
            }
        }

        Ok(config)
    }
}

impl ServerConfig for FileConfig {
    fn interface(&self) -> &str {
        self.interface.as_ref()
    }

    fn port(&self) -> u16 {
        self.port
    }

    fn seed(&self) -> Vec<u8> {
        self.seed.clone()
    }

    fn batch_size(&self) -> u8 {
        self.batch_size
    }

    fn status_interval(&self) -> Duration {
        self.status_interval
    }

    fn kms_protection(&self) -> &KmsProtection {
        &self.kms_protection
    }

    fn health_check_port(&self) -> Option<u16> {
        self.health_check_port
    }

    fn client_stats_enabled(&self) -> bool {
        self.client_stats
    }

    fn fault_percentage(&self) -> u8 {
        self.fault_percentage
    }
}
<commit_msg>Improve FileConfig's error messages<commit_after>// Copyright 2017-2019 int08h LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::fs::File;
use std::io::Read;
use std::time::Duration;
use yaml_rust::YamlLoader;

use crate::config::ServerConfig;
use crate::config::{DEFAULT_BATCH_SIZE, DEFAULT_STATUS_INTERVAL};
use crate::key::KmsProtection;
use crate::Error;

///
/// Read a Roughenough server configuration ([ServerConfig](trait.ServerConfig.html))
/// from a YAML file.
///
/// Example minimal config:
///
/// ```yaml
/// interface: 127.0.0.1
/// port: 8686
/// seed: f61075c988feb9cb700a4a6a3291bfbc9cab11b9c9eca8c802468eb38a43d7d3
/// ```
///
pub struct FileConfig {
    port: u16,
    interface: String,
    seed: Vec<u8>,
    batch_size: u8,
    status_interval: Duration,
    kms_protection: KmsProtection,
    health_check_port: Option<u16>,
    client_stats: bool,
    fault_percentage: u8,
}

impl FileConfig {
    pub fn new(config_file: &str) -> Result<Self, Error> {
        let mut infile = File::open(config_file)
            .expect(&format!("failed to open config file '{}'", config_file));

        let mut contents = String::new();
        infile
            .read_to_string(&mut contents)
            .expect(&format!("could not read config file '{}'", config_file));

        let cfg = YamlLoader::load_from_str(&contents)
            .expect(&format!("could not parse config file '{}'", config_file));

        if cfg.len() != 1 {
            return Err(Error::InvalidConfiguration(
                format!("Empty or malformed config file '{}'", config_file),
            ));
        }

        let mut config = FileConfig {
            port: 0,
            interface: "".to_string(),
            seed: Vec::new(),
            batch_size: DEFAULT_BATCH_SIZE,
            status_interval: DEFAULT_STATUS_INTERVAL,
            kms_protection: KmsProtection::Plaintext,
            health_check_port: None,
            client_stats: false,
            fault_percentage: 0,
        };

        for (key, value) in cfg[0].as_hash().unwrap() {
            match key.as_str().unwrap() {
                "port" => config.port = value.as_i64().unwrap() as u16,
                "interface" => config.interface = value.as_str().unwrap().to_string(),
                "batch_size" => config.batch_size = value.as_i64().unwrap() as u8,
                "seed" => {
                    let val = value.as_str().unwrap().to_string();
                    config.seed = hex::decode(val)
                        .expect("seed value invalid; 'seed' must be a valid hex value");
                }
                "status_interval" => {
                    let val = value.as_i64().expect("status_interval value invalid");
                    config.status_interval = Duration::from_secs(val as u64)
                }
                "kms_protection" => {
                    let val = value.as_str().unwrap().parse().unwrap_or_else(|_| {
                        panic!("invalid kms_protection value: {:?}", value)
                    });
                    config.kms_protection = val
                }
                "health_check_port" => {
                    let val = value.as_i64().unwrap() as u16;
                    config.health_check_port = Some(val);
                }
                "client_stats" => {
                    let val = value.as_str().unwrap().to_ascii_lowercase();
                    config.client_stats = val == "yes" || val == "on";
                }
                "fault_percentage" => {
                    let val = value.as_i64().unwrap() as u8;
                    config.fault_percentage = val;
                }
                unknown => {
                    return Err(Error::InvalidConfiguration(format!(
                        "unknown config key: {}",
                        unknown
                    )));
                }
            }
        }

        Ok(config)
    }
}

impl ServerConfig for FileConfig {
    fn interface(&self) -> &str {
        self.interface.as_ref()
    }

    fn port(&self) -> u16 {
        self.port
    }

    fn seed(&self) -> Vec<u8> {
        self.seed.clone()
    }

    fn batch_size(&self) -> u8 {
        self.batch_size
    }

    fn status_interval(&self) -> Duration {
        self.status_interval
    }

    fn kms_protection(&self) -> &KmsProtection {
        &self.kms_protection
    }

    fn health_check_port(&self) -> Option<u16> {
        self.health_check_port
    }

    fn client_stats_enabled(&self) -> bool {
        self.client_stats
    }

    fn fault_percentage(&self) -> u8 {
        self.fault_percentage
    }
}
<|endoftext|>


<commit_before>use io::SystemFile;
use std::fs::{File, Metadata};
use std::path::Path;
use std::process;
use std::time::SystemTime;
use walkdir::{Iter, WalkDir};

///
///
///
pub struct Engine<'a> {

    path: &'a Path

}

impl<'a> Engine<'a> {

    ///
    ///
    ///
    pub fn new() -> Engine<'a> {
        Engine {
            path: Path::new("") // Defaults to the root directory of the current user's main disk
        }
    }

    ///
    ///
    ///
    pub fn from(path: &str) -> Engine {
        Engine {
            path: Path::new(path)
        }
    }

    ///
    ///
    ///
    pub fn do_scan(&self) {
        let cur_time: SystemTime = SystemTime::now();

        if !self.path.exists() {
            println!("Directory or file does not exist.");

            process::exit(1);
        }

        if self.path.is_dir() {
            let result = Engine::scan_dir(self.path).unwrap();
            println!("Total size: {}", SystemFile::human_readable_size(result.total_scan_size));
        } else {
            let result = Engine::scan_file(self.path).unwrap();
            println!("Total size: {}", SystemFile::human_readable_size(result.total_scan_size));
        }

        println!("Finished in {} seconds", SystemTime::now().duration_since(cur_time).unwrap().as_secs());
    }

    ///
    ///
    ///
    pub(self) fn scan_dir(dir: &Path) -> Option<ScanResult> {
        println!("Scanning dir: {}", dir.to_str().unwrap());

        let mut total_size: f64 = 0.0;
        let dir_iter: Iter = WalkDir::new(dir).into_iter();

        for entry in dir_iter.filter_map(|e| e.ok()) {
            let file: File = File::open(entry.path()).unwrap();
            let metadata: Metadata = file.metadata().unwrap();
            let file_path: String = String::from(entry.path().to_str().unwrap());
            let sys_file: SystemFile = SystemFile::from(file_path);

            total_size += metadata.len() as f64;

            println!("{}", sys_file);
        }

        Some(
            ScanResult {
                total_scan_size: total_size
            }
        )
    }

    ///
    ///
    ///
    pub(self) fn scan_file(file_path: &Path) -> Option<ScanResult> {
        println!("Scanning file: {}", file_path.to_str().unwrap());

        let file: File = File::open(file_path).unwrap();
        let metadata: Metadata = file.metadata().unwrap();
        let file_path_as_str: String = String::from(file_path.to_str().unwrap());
        let sys_file: SystemFile = SystemFile::from(file_path_as_str);

        println!("{}", sys_file);

        Some(
            ScanResult {
                total_scan_size: metadata.len() as f64
            }
        )
    }

}

pub struct ScanResult {

    pub total_scan_size: f64

}

#[allow(dead_code)]
pub struct FileType {

    extension: String,
    mime_type: String

}

pub trait FileTypeScan {

    ///
    ///
    ///
    fn get_file_type() -> FileType;

}<commit_msg>Use let binding with match instead of if/else block. Removes duplicate code.<commit_after>use io::SystemFile;
use std::fs::{File, Metadata};
use std::path::Path;
use std::process;
use std::time::SystemTime;
use walkdir::{Iter, WalkDir};

///
///
///
pub struct Engine<'a> {

    path: &'a Path

}

impl<'a> Engine<'a> {

    ///
    ///
    ///
    pub fn new() -> Engine<'a> {
        Engine {
            path: Path::new("") // Defaults to the root directory of the current user's main disk
        }
    }

    ///
    ///
    ///
    pub fn from(path: &str) -> Engine {
        Engine {
            path: Path::new(path)
        }
    }

    ///
    ///
    ///
    pub fn do_scan(&self) {
        let cur_time: SystemTime = SystemTime::now();

        if !self.path.exists() {
            println!("Directory or file does not exist.");

            process::exit(1);
        }

        let result: ScanResult = match self.path.is_dir() {
            true => Engine::scan_dir(self.path).unwrap(),
            false => Engine::scan_file(self.path).unwrap()
        };

        println!("Total size: {}", SystemFile::human_readable_size(result.total_scan_size));
        println!("Finished in {} seconds", SystemTime::now().duration_since(cur_time).unwrap().as_secs());
    }

    ///
    ///
    ///
    pub(self) fn scan_dir(dir: &Path) -> Option<ScanResult> {
        println!("Scanning dir: {}", dir.to_str().unwrap());

        let mut total_size: f64 = 0.0;
        let dir_iter: Iter = WalkDir::new(dir).into_iter();

        for entry in dir_iter.filter_map(|e| e.ok()) {
            let file: File = File::open(entry.path()).unwrap();
            let metadata: Metadata = file.metadata().unwrap();
            let file_path: String = String::from(entry.path().to_str().unwrap());
            let sys_file: SystemFile = SystemFile::from(file_path);

            total_size += metadata.len() as f64;

            println!("{}", sys_file);
        }

        Some(
            ScanResult {
                total_scan_size: total_size
            }
        )
    }

    ///
    ///
    ///
    pub(self) fn scan_file(file_path: &Path) -> Option<ScanResult> {
        println!("Scanning file: {}", file_path.to_str().unwrap());

        let file: File = File::open(file_path).unwrap();
        let metadata: Metadata = file.metadata().unwrap();
        let file_path_as_str: String = String::from(file_path.to_str().unwrap());
        let sys_file: SystemFile = SystemFile::from(file_path_as_str);

        println!("{}", sys_file);

        Some(
            ScanResult {
                total_scan_size: metadata.len() as f64
            }
        )
    }

}

pub struct ScanResult {

    pub total_scan_size: f64

}

#[allow(dead_code)]
pub struct FileType {

    extension: String,
    mime_type: String

}

pub trait FileTypeScan {

    ///
    ///
    ///
    fn get_file_type() -> FileType;

}<|endoftext|>


<commit_before>// Copyright (c) Carl-Erwin Griffith
//
// Permission is hereby granted, free of charge, to any
// person obtaining a copy of this software and associated
// documentation files (the "Software"), to deal in the
// Software without restriction, including without
// limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software
// is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice
// shall be included in all copies or substantial portions
// of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER

use std::sync::mpsc::Receiver;
use std::sync::mpsc::Sender;

use std::cell::RefCell;
use std::rc::Rc;

use core::document;
use core::editor::Editor;
use core::event::Event;
use core::event::Event::*;
use core::event::EventMessage;
use core::event::InputEvent;
use core::event::Key;

use core::view::{build_screen_layout, Id, View};

struct CoreState {
    keys: Vec<InputEvent>,
    quit: bool,
    status: String,
}

impl CoreState {
    fn new() -> Self {
        CoreState {
            keys: Vec::new(),
            quit: false,
            status: String::new(),
        }
    }
}

pub fn start(editor: &mut Editor, core_rx: &Receiver<EventMessage>, ui_tx: &Sender<EventMessage>) {
    let mut core_state = CoreState::new();

    let mut seq: usize = 0;

    fn get_next_seq(seq: &mut usize) -> usize {
        *seq = *seq + 1;
        *seq
    }

    while !core_state.quit {
        match core_rx.recv() {
            Ok(evt) => {
                match evt.event {
                    Event::ApplicationQuitEvent => {
                        break;
                    }

                    Event::RequestDocumentList => {
                        let mut list: Vec<(document::Id, String)> = vec![];
                        for e in &editor.document_map {
                            let name = &e.1.as_ref().borrow().name;
                            list.push((*e.0, name.to_string()));
                        }
                        let msg =
                            EventMessage::new(get_next_seq(&mut seq), Event::DocumentList { list });
                        ui_tx.send(msg).unwrap_or(());
                    }

                    Event::CreateView {
                        width,
                        height,
                        doc_id,
                    } => {
                        let vid = editor.view_map.len();
                        let doc = editor.document_map.get(&doc_id);
                        if let Some(doc) = doc {
                            let view =
                                View::new(vid as u64, 0 as u64, width, height, Some(doc.clone()));

                            editor.view_map.push((view.id, Rc::new(RefCell::new(view))));

                            let msg = EventMessage::new(
                                get_next_seq(&mut seq),
                                Event::ViewCreated {
                                    width,
                                    height,
                                    doc_id,
                                    view_id: vid as Id,
                                },
                            );
                            ui_tx.send(msg).unwrap_or(());
                        }
                    }

                    /*
                        <- createView : w, h , doc::id
                        -> viewCreate : view id, w, h, doc::id
                    */

                    /*
                        <- destroyView : w, h , doc::id
                        -> viewDestroyed : view id, w, h, doc::id
                    */
                    Event::RequestLayoutEvent {
                        view_id,
                        doc_id,
                        // start_offset
                        ref screen, // previous screen
                    } => {
                        let view_id = view_id as usize;
                        if view_id < editor.view_map.len() {
                            let mut view = editor.view_map[view_id].1.as_ref().borrow_mut();

                            // resize ?
                            if screen.width != view.screen.width
                                || screen.height != view.screen.height
                            {
                                view.screen = screen.clone();
                            }

                            fill_screen(&mut core_state, &mut view);

                            let msg = EventMessage::new(
                                get_next_seq(&mut seq),
                                BuildLayoutEvent {
                                    view_id: view_id as u64,
                                    doc_id,
                                    screen: view.screen.clone(),
                                },
                            );
                            ui_tx.send(msg).unwrap_or(());
                        }

                        // is there a view/screen ?
                        // with the correct size ?
                        // alloc/resize screen
                    }

                    Event::InputEvent { ev } => {
                        if !editor.view_map.is_empty() {
                            let view_id = 0 as usize;
                            let mut view = editor.view_map[view_id].1.as_ref().borrow_mut();

                            process_input_events(&mut core_state, &mut view, &ui_tx, &ev);

                            fill_screen(&mut core_state, &mut view);
                            let msg = EventMessage::new(
                                get_next_seq(&mut seq),
                                BuildLayoutEvent {
                                    view_id: view_id as u64,
                                    doc_id: 0,
                                    screen: view.screen.clone(),
                                },
                            );
                            ui_tx.send(msg).unwrap_or(());
                        }
                    }

                    _ => {}
                }
            }
            _ => {}
        }
    }

    let msg = EventMessage::new(get_next_seq(&mut seq), Event::ApplicationQuitEvent);
    ui_tx.send(msg).unwrap_or(());
}

fn fill_screen(_core_state: &mut CoreState, view: &mut View) {
    if let Some(ref _buf) = view.document {
        let mut screen = &mut view.screen;

        screen.clear();

        let mut data = vec![];
        let max_size = (screen.width * screen.height * 4) as usize;
        let doc = view.document.as_ref().unwrap().borrow_mut();
        doc.read(view.start_offset, max_size, &mut data);

        let max_offset = doc.buffer.size as u64;

        view.end_offset = build_screen_layout(&data, view.start_offset, max_offset, &mut screen);

        // core_state.last_offset = view.end_offset;

        // render marks

        // brute force for now
        for m in view.moving_marks.borrow().iter() {
            // TODO: screen.find_line_by_offset(m.offset) -> Option<&mut Line>
            if m.offset >= view.start_offset && m.offset <= view.end_offset {
                for l in 0..screen.height {
                    let line = screen.get_mut_line(l).unwrap();
                    for c in 0..line.nb_cells {
                        let cpi = line.get_mut_cpi(c).unwrap();

                        //if cpi.offset > m.offset {
                        //break;
                        //}

                        if cpi.offset == m.offset {
                            cpi.is_selected = true;
                            // core_state.mark_offset = m.offset;
                        }
                    }
                }
            }
        }
    }
}

fn process_input_events(
    core_state: &mut CoreState,
    view: &mut View,
    _ui_tx: &Sender<EventMessage>,
    ev: &InputEvent,
) {
    if *ev == ::core::event::InputEvent::NoInputEvent {
        // ignore no input event event :-)
        return;
    }

    core_state.keys.push(ev.clone());

    let mut clear_keys = true;
    match *ev {
        InputEvent::KeyPress {
            ctrl: true,
            alt: false,
            shift: false,
            key: Key::UNICODE('q'),
        } => {
            core_state.quit = true;
        }

        InputEvent::KeyPress {
            ctrl: true,
            alt: false,
            shift: false,
            key: Key::UNICODE('u'),
        } => {
            view.undo();
        }

        InputEvent::KeyPress {
            ctrl: true,
            alt: false,
            shift: false,
            key: Key::UNICODE('r'),
        } => {
            view.redo();
        }

        InputEvent::KeyPress {
            ctrl: true,
            alt: false,
            shift: false,
            key: Key::UNICODE('x'),
        } => {
            clear_keys = false;
        }

        // ctrl+a
        InputEvent::KeyPress {
            ctrl: true,
            alt: false,
            shift: false,
            key: Key::UNICODE('a'),
        }
        | InputEvent::KeyPress {
            ctrl: false,
            alt: false,
            shift: false,
            key: Key::Home,
        } => {
            view.move_marks_to_beginning_of_line();
        }

        // ctrl+e
        InputEvent::KeyPress {
            ctrl: true,
            alt: false,
            shift: false,
            key: Key::UNICODE('e'),
        }
        | InputEvent::KeyPress {
            ctrl: false,
            alt: false,
            shift: false,
            key: Key::End,
        } => {
            view.move_marks_to_end_of_line();
        }

        // ctrl+d
        InputEvent::KeyPress {
            ctrl: true,
            alt: false,
            shift: false,
            key: Key::UNICODE('d'),
        } => {
            view.remove_codepoint();
        }

        // ctrl+s
        InputEvent::KeyPress {
            ctrl: true,
            alt: false,
            shift: false,
            key: Key::UNICODE('s'),
        } => {
            view.save_document();
        }

        // ctrl+k
        InputEvent::KeyPress {
            ctrl: true,
            alt: false,
            shift: false,
            key: Key::UNICODE('k'),
        } => {
            view.cut_to_end_of_line();
        }

        // ctrl+y
        InputEvent::KeyPress {
            ctrl: true,
            alt: false,
            shift: false,
            key: Key::UNICODE('y'),
        } => {
            view.paste();
        }

        // ctrl+l
        InputEvent::KeyPress {
            ctrl: true,
            alt: false,
            shift: false,
            key: Key::UNICODE('l'),
        } => {
            view.center_arround_mark();
        }

        // ctrl+?
        InputEvent::KeyPress {
            ctrl: true,
            alt: false,
            shift: false,
            key: Key::UNICODE(c),
        } => {
            core_state.status = format!("ctrl+<{}>", c);
        }

        // left
        InputEvent::KeyPress {
            ctrl: false,
            alt: false,
            shift: false,
            key: Key::Left,
        } => {
            view.move_marks_backward();

            core_state.status = "<left>".to_owned();
        }

        // up
        InputEvent::KeyPress {
            ctrl: false,
            alt: false,
            shift: false,
            key: Key::Up,
        } => {
            view.move_marks_to_previous_line();

            core_state.status = "<up>".to_owned();
        }

        // down
        InputEvent::KeyPress {
            ctrl: false,
            alt: false,
            shift: false,
            key: Key::Down,
        } => {
            view.move_marks_to_next_line();

            core_state.status = "<down>".to_owned();
        }

        // right
        InputEvent::KeyPress {
            ctrl: false,
            alt: false,
            shift: false,
            key: Key::Right,
        } => {
            view.move_marks_forward();

            core_state.status = "<right>".to_owned();
        }

        // page_up
        InputEvent::KeyPress {
            ctrl: false,
            alt: false,
            shift: false,
            key: Key::PageUp,
        } => {
            view.scroll_to_previous_screen();
            core_state.status = "<page_up>".to_owned();
        }

        // page_down
        InputEvent::KeyPress {
            ctrl: false,
            alt: false,
            shift: false,
            key: Key::PageDown,
        } => {
            view.scroll_to_next_screen();
            core_state.status = "<page_down>".to_owned();
        }

        // alt+< goto beginning of file
        InputEvent::KeyPress {
            ctrl: false,
            alt: true,
            shift: false,
            key: Key::UNICODE('<'),
        } => {
            view.move_mark_to_beginning_of_file();
            core_state.status = "<move to beginning of file>".to_owned();
        }

        // alt+> goto end of file
        InputEvent::KeyPress {
            ctrl: false,
            alt: true,
            shift: false,
            key: Key::UNICODE('>'),
        } => {
            view.move_mark_to_end_of_file();
            core_state.status = "<move to end of file>".to_owned();
        }

        // delete
        InputEvent::KeyPress {
            ctrl: false,
            alt: false,
            shift: false,
            key: Key::Delete,
        } => {
            view.remove_codepoint();
            core_state.status = "<del>".to_owned();
        }

        // backspace
        InputEvent::KeyPress {
            ctrl: false,
            alt: false,
            shift: false,
            key: Key::BackSpace,
        } => {
            view.remove_previous_codepoint();
            core_state.status = "<backspace>".to_owned();
        }

        // insert text
        InputEvent::KeyPress {
            ctrl: false,
            alt: false,
            shift: false,
            key: Key::UNICODE(cp),
        } => {
            view.insert_codepoint(cp);
            core_state.status = format!("<insert [0x{:x}]>", cp as u32);
        }

        // mouse button pressed
        InputEvent::ButtonPress {
            ctrl: false,
            alt: false,
            shift: false,
            x,
            y,
            button,
        } => match button {
            0 | 1 => {
                view.button_press(button, x, y - 2);
                core_state.status = format!("<click({},@({},{}))]>", button, x, y - 2);
            }
            3 => {
                view.scroll_up(3);
                core_state.status = format!("<click({},@({},{}))]>", button, x, y - 2);
            }
            4 => {
                view.scroll_down(3);
                core_state.status = format!("<click({},@({},{}))]>", button, x, y - 2);
            }

            _ => {}
        },

        // mouse button released
        InputEvent::ButtonRelease {
            ctrl: false,
            alt: false,
            shift: false,
            x,
            y,
            button,
        } => {
            view.button_release(button, x, y);
            core_state.status = format!("<unclick({},@({},{}))]>", button, x, y);
        }

        _ => {}
    }

    if clear_keys {
        core_state.keys.clear();
    }
}
<commit_msg>core : do not generate layout if not asked to<commit_after>// Copyright (c) Carl-Erwin Griffith
//
// Permission is hereby granted, free of charge, to any
// person obtaining a copy of this software and associated
// documentation files (the "Software"), to deal in the
// Software without restriction, including without
// limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software
// is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice
// shall be included in all copies or substantial portions
// of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER

use std::sync::mpsc::Receiver;
use std::sync::mpsc::Sender;

use std::cell::RefCell;
use std::rc::Rc;

use core::document;
use core::editor::Editor;
use core::event::Event;
use core::event::Event::*;
use core::event::EventMessage;
use core::event::InputEvent;
use core::event::Key;

use core::view::{build_screen_layout, Id, View};

struct CoreState {
    keys: Vec<InputEvent>,
    quit: bool,
    status: String,
}

impl CoreState {
    fn new() -> Self {
        CoreState {
            keys: Vec::new(),
            quit: false,
            status: String::new(),
        }
    }
}

pub fn start(editor: &mut Editor, core_rx: &Receiver<EventMessage>, ui_tx: &Sender<EventMessage>) {
    let mut core_state = CoreState::new();

    let mut seq: usize = 0;

    fn get_next_seq(seq: &mut usize) -> usize {
        *seq = *seq + 1;
        *seq
    }

    while !core_state.quit {
        match core_rx.recv() {
            Ok(evt) => {
                match evt.event {
                    Event::ApplicationQuitEvent => {
                        break;
                    }

                    Event::RequestDocumentList => {
                        let mut list: Vec<(document::Id, String)> = vec![];
                        for e in &editor.document_map {
                            let name = &e.1.as_ref().borrow().name;
                            list.push((*e.0, name.to_string()));
                        }
                        let msg =
                            EventMessage::new(get_next_seq(&mut seq), Event::DocumentList { list });
                        ui_tx.send(msg).unwrap_or(());
                    }

                    Event::CreateView {
                        width,
                        height,
                        doc_id,
                    } => {
                        let vid = editor.view_map.len();
                        let doc = editor.document_map.get(&doc_id);
                        if let Some(doc) = doc {
                            let view =
                                View::new(vid as u64, 0 as u64, width, height, Some(doc.clone()));

                            editor.view_map.push((view.id, Rc::new(RefCell::new(view))));

                            let msg = EventMessage::new(
                                get_next_seq(&mut seq),
                                Event::ViewCreated {
                                    width,
                                    height,
                                    doc_id,
                                    view_id: vid as Id,
                                },
                            );
                            ui_tx.send(msg).unwrap_or(());
                        }
                    }

                    /*
                        <- createView : w, h , doc::id
                        -> viewCreate : view id, w, h, doc::id
                    */

                    /*
                        <- destroyView : w, h , doc::id
                        -> viewDestroyed : view id, w, h, doc::id
                    */
                    Event::RequestLayoutEvent {
                        view_id,
                        doc_id,
                        // start_offset
                        ref screen, // previous screen
                    } => {
                        let view_id = view_id as usize;
                        if view_id < editor.view_map.len() {
                            let mut view = editor.view_map[view_id].1.as_ref().borrow_mut();

                            // resize ?
                            if screen.width != view.screen.width
                                || screen.height != view.screen.height
                            {
                                view.screen = screen.clone();
                            }

                            fill_screen(&mut core_state, &mut view);

                            let msg = EventMessage::new(
                                get_next_seq(&mut seq),
                                BuildLayoutEvent {
                                    view_id: view_id as u64,
                                    doc_id,
                                    screen: view.screen.clone(),
                                },
                            );
                            ui_tx.send(msg).unwrap_or(());
                        }

                        // is there a view/screen ?
                        // with the correct size ?
                        // alloc/resize screen
                    }

                    Event::InputEvent { ev } => {
                        if !editor.view_map.is_empty() {
                            let view_id = 0 as usize;
                            let mut view = editor.view_map[view_id].1.as_ref().borrow_mut();
                            process_input_events(&mut core_state, &mut view, &ui_tx, &ev);
                        }
                    }

                    _ => {}
                }
            }
            _ => {}
        }
    }

    let msg = EventMessage::new(get_next_seq(&mut seq), Event::ApplicationQuitEvent);
    ui_tx.send(msg).unwrap_or(());
}

fn fill_screen(_core_state: &mut CoreState, view: &mut View) {
    if let Some(ref _buf) = view.document {
        let mut screen = &mut view.screen;

        screen.clear();

        let mut data = vec![];
        let max_size = (screen.width * screen.height * 4) as usize;
        let doc = view.document.as_ref().unwrap().borrow_mut();
        doc.read(view.start_offset, max_size, &mut data);

        let max_offset = doc.buffer.size as u64;

        view.end_offset = build_screen_layout(&data, view.start_offset, max_offset, &mut screen);

        // core_state.last_offset = view.end_offset;

        // render marks

        // brute force for now
        for m in view.moving_marks.borrow().iter() {
            // TODO: screen.find_line_by_offset(m.offset) -> Option<&mut Line>
            if m.offset >= view.start_offset && m.offset <= view.end_offset {
                for l in 0..screen.height {
                    let line = screen.get_mut_line(l).unwrap();
                    for c in 0..line.nb_cells {
                        let cpi = line.get_mut_cpi(c).unwrap();

                        //if cpi.offset > m.offset {
                        //break;
                        //}

                        if cpi.offset == m.offset {
                            cpi.is_selected = true;
                            // core_state.mark_offset = m.offset;
                        }
                    }
                }
            }
        }
    }
}

fn process_input_events(
    core_state: &mut CoreState,
    view: &mut View,
    _ui_tx: &Sender<EventMessage>,
    ev: &InputEvent,
) {
    if *ev == ::core::event::InputEvent::NoInputEvent {
        // ignore no input event event :-)
        return;
    }

    core_state.keys.push(ev.clone());

    let mut clear_keys = true;
    match *ev {
        InputEvent::KeyPress {
            ctrl: true,
            alt: false,
            shift: false,
            key: Key::UNICODE('q'),
        } => {
            core_state.quit = true;
        }

        InputEvent::KeyPress {
            ctrl: true,
            alt: false,
            shift: false,
            key: Key::UNICODE('u'),
        } => {
            view.undo();
        }

        InputEvent::KeyPress {
            ctrl: true,
            alt: false,
            shift: false,
            key: Key::UNICODE('r'),
        } => {
            view.redo();
        }

        InputEvent::KeyPress {
            ctrl: true,
            alt: false,
            shift: false,
            key: Key::UNICODE('x'),
        } => {
            clear_keys = false;
        }

        // ctrl+a
        InputEvent::KeyPress {
            ctrl: true,
            alt: false,
            shift: false,
            key: Key::UNICODE('a'),
        }
        | InputEvent::KeyPress {
            ctrl: false,
            alt: false,
            shift: false,
            key: Key::Home,
        } => {
            view.move_marks_to_beginning_of_line();
        }

        // ctrl+e
        InputEvent::KeyPress {
            ctrl: true,
            alt: false,
            shift: false,
            key: Key::UNICODE('e'),
        }
        | InputEvent::KeyPress {
            ctrl: false,
            alt: false,
            shift: false,
            key: Key::End,
        } => {
            view.move_marks_to_end_of_line();
        }

        // ctrl+d
        InputEvent::KeyPress {
            ctrl: true,
            alt: false,
            shift: false,
            key: Key::UNICODE('d'),
        } => {
            view.remove_codepoint();
        }

        // ctrl+s
        InputEvent::KeyPress {
            ctrl: true,
            alt: false,
            shift: false,
            key: Key::UNICODE('s'),
        } => {
            view.save_document();
        }

        // ctrl+k
        InputEvent::KeyPress {
            ctrl: true,
            alt: false,
            shift: false,
            key: Key::UNICODE('k'),
        } => {
            view.cut_to_end_of_line();
        }

        // ctrl+y
        InputEvent::KeyPress {
            ctrl: true,
            alt: false,
            shift: false,
            key: Key::UNICODE('y'),
        } => {
            view.paste();
        }

        // ctrl+l
        InputEvent::KeyPress {
            ctrl: true,
            alt: false,
            shift: false,
            key: Key::UNICODE('l'),
        } => {
            view.center_arround_mark();
        }

        // ctrl+?
        InputEvent::KeyPress {
            ctrl: true,
            alt: false,
            shift: false,
            key: Key::UNICODE(c),
        } => {
            core_state.status = format!("ctrl+<{}>", c);
        }

        // left
        InputEvent::KeyPress {
            ctrl: false,
            alt: false,
            shift: false,
            key: Key::Left,
        } => {
            view.move_marks_backward();

            core_state.status = "<left>".to_owned();
        }

        // up
        InputEvent::KeyPress {
            ctrl: false,
            alt: false,
            shift: false,
            key: Key::Up,
        } => {
            view.move_marks_to_previous_line();

            core_state.status = "<up>".to_owned();
        }

        // down
        InputEvent::KeyPress {
            ctrl: false,
            alt: false,
            shift: false,
            key: Key::Down,
        } => {
            view.move_marks_to_next_line();

            core_state.status = "<down>".to_owned();
        }

        // right
        InputEvent::KeyPress {
            ctrl: false,
            alt: false,
            shift: false,
            key: Key::Right,
        } => {
            view.move_marks_forward();

            core_state.status = "<right>".to_owned();
        }

        // page_up
        InputEvent::KeyPress {
            ctrl: false,
            alt: false,
            shift: false,
            key: Key::PageUp,
        } => {
            view.scroll_to_previous_screen();
            core_state.status = "<page_up>".to_owned();
        }

        // page_down
        InputEvent::KeyPress {
            ctrl: false,
            alt: false,
            shift: false,
            key: Key::PageDown,
        } => {
            view.scroll_to_next_screen();
            core_state.status = "<page_down>".to_owned();
        }

        // alt+< goto beginning of file
        InputEvent::KeyPress {
            ctrl: false,
            alt: true,
            shift: false,
            key: Key::UNICODE('<'),
        } => {
            view.move_mark_to_beginning_of_file();
            core_state.status = "<move to beginning of file>".to_owned();
        }

        // alt+> goto end of file
        InputEvent::KeyPress {
            ctrl: false,
            alt: true,
            shift: false,
            key: Key::UNICODE('>'),
        } => {
            view.move_mark_to_end_of_file();
            core_state.status = "<move to end of file>".to_owned();
        }

        // delete
        InputEvent::KeyPress {
            ctrl: false,
            alt: false,
            shift: false,
            key: Key::Delete,
        } => {
            view.remove_codepoint();
            core_state.status = "<del>".to_owned();
        }

        // backspace
        InputEvent::KeyPress {
            ctrl: false,
            alt: false,
            shift: false,
            key: Key::BackSpace,
        } => {
            view.remove_previous_codepoint();
            core_state.status = "<backspace>".to_owned();
        }

        // insert text
        InputEvent::KeyPress {
            ctrl: false,
            alt: false,
            shift: false,
            key: Key::UNICODE(cp),
        } => {
            view.insert_codepoint(cp);
            core_state.status = format!("<insert [0x{:x}]>", cp as u32);
        }

        // mouse button pressed
        InputEvent::ButtonPress {
            ctrl: false,
            alt: false,
            shift: false,
            x,
            y,
            button,
        } => match button {
            0 | 1 => {
                view.button_press(button, x, y - 2);
                core_state.status = format!("<click({},@({},{}))]>", button, x, y - 2);
            }
            3 => {
                view.scroll_up(3);
                core_state.status = format!("<click({},@({},{}))]>", button, x, y - 2);
            }
            4 => {
                view.scroll_down(3);
                core_state.status = format!("<click({},@({},{}))]>", button, x, y - 2);
            }

            _ => {}
        },

        // mouse button released
        InputEvent::ButtonRelease {
            ctrl: false,
            alt: false,
            shift: false,
            x,
            y,
            button,
        } => {
            view.button_release(button, x, y);
            core_state.status = format!("<unclick({},@({},{}))]>", button, x, y);
        }

        _ => {}
    }

    if clear_keys {
        core_state.keys.clear();
    }
}
<|endoftext|>


<commit_before>/**
    The layout task. Performs layout on the DOM, builds display lists and sends them to be
    rendered.
*/

use au = gfx::geometry;
use au::Au;
use content::content_task;
use core::dvec::DVec;
use newcss::Stylesheet;
use dl = gfx::display_list;
use dom::event::{Event, ReflowEvent};
use dom::node::{Node, LayoutData};
use geom::point::Point2D;
use geom::rect::Rect;
use geom::size::Size2D;
use gfx::display_list::DisplayList;
use gfx::render_task;
use gfx::render_layers::RenderLayer;
use layout::box::RenderBox;
use layout::box_builder::LayoutTreeBuilder;
use layout::context::LayoutContext;
use opt = core::option;
use render_task::RenderTask;
use resource::image_cache_task::{ImageCacheTask, ImageResponseMsg};
use resource::local_image_cache::LocalImageCache;
use servo_text::font_context::FontContext;
use servo_text::font_cache::FontCache;
use servo_text::font_matcher::FontMatcher;
use std::arc::ARC;
use std::net::url::Url;
use core::util::replace;
use util::time::time;
use std::cell::Cell;
use layout::traverse::*;
use comm::*;
use task::*;
use core::mutable::Mut;
use newcss::SelectCtx;

pub type LayoutTask = comm::Chan<Msg>;

pub enum LayoutQuery {
    ContentBox(Node)
}

pub type LayoutQueryResponse = Result<LayoutQueryResponse_, ()>;

enum LayoutQueryResponse_ {
    ContentSize(Size2D<int>)
}

pub enum Msg {
    AddStylesheet(Stylesheet),
    BuildMsg(BuildData),
    QueryMsg(LayoutQuery, comm::Chan<LayoutQueryResponse>),
    ExitMsg
}

struct BuildData {
    node: Node,
    url: Url,
    dom_event_chan: pipes::SharedChan<Event>,
    window_size: Size2D<uint>,
    content_join_chan: pipes::Chan<()>
}

fn LayoutTask(render_task: RenderTask,
              img_cache_task: ImageCacheTask) -> LayoutTask {
    do spawn_listener::<Msg> |from_content, move img_cache_task| {
        Layout(render_task, img_cache_task.clone(), from_content).start();
    }
}

struct Layout {
    render_task: RenderTask,
    image_cache_task: ImageCacheTask,
    local_image_cache: @LocalImageCache,
    from_content: comm::Port<Msg>,

    font_cache: @FontCache,
    font_matcher: @FontMatcher,
    // This is used to root auxilliary RCU reader data
    layout_refs: DVec<@LayoutData>,
    css_select_ctx: Mut<SelectCtx>,
}

fn Layout(render_task: RenderTask,
         image_cache_task: ImageCacheTask,
         from_content: comm::Port<Msg>) -> Layout {

    let fctx = @FontContext::new();

    Layout {
        render_task: render_task,
        image_cache_task: image_cache_task.clone(),
        local_image_cache: @LocalImageCache(move image_cache_task),
        from_content: from_content,
        font_matcher: @FontMatcher::new(fctx),
        font_cache: @FontCache::new(fctx),
        layout_refs: DVec(),
        css_select_ctx: Mut(SelectCtx::new())
    }
}

impl Layout {

    fn start() {
        while self.handle_request() {
            // loop indefinitely
        }
    }

    fn handle_request() -> bool {

        match self.from_content.recv() {
            AddStylesheet(move sheet) => {
                self.handle_add_stylesheet(move sheet);
            }
            BuildMsg(move data) => {
                let data = Cell(move data);

                do time("layout: performing layout") {
                    self.handle_build(data.take());
                }

            }
            QueryMsg(query, chan) => {
                do time("layout: querying layout") {
                    self.handle_query(query, chan)
                }
            }
            ExitMsg => {
                debug!("layout: ExitMsg received");
                return false
            }
        }

        true
    }

    fn handle_add_stylesheet(sheet: Stylesheet) {
        let sheet = Cell(move sheet);
        do self.css_select_ctx.borrow_mut |ctx| {
            ctx.append_sheet(sheet.take());
        }
    }

    fn handle_build(data: BuildData) {

        let node = &data.node;
        // FIXME: Bad copy
        let doc_url = copy data.url;
        // FIXME: Bad clone
        let dom_event_chan = data.dom_event_chan.clone();

        debug!("layout: received layout request for: %s", doc_url.to_str());
        debug!("layout: parsed Node tree");
        debug!("%?", node.dump());

        // Reset the image cache
        self.local_image_cache.next_round(self.make_on_image_available_cb(move dom_event_chan));

        let screen_size = Size2D(au::from_px(data.window_size.width as int),
                                 au::from_px(data.window_size.height as int));

        let layout_ctx = LayoutContext {
            image_cache: self.local_image_cache,
            font_cache: self.font_cache,
            doc_url: move doc_url,
            screen_size: Rect(Point2D(Au(0), Au(0)), screen_size)
        };

        let layout_root: @FlowContext = do time("layout: tree construction") {
            // TODO: this is dumb. we don't need 2 separate traversals.
            node.initialize_style_for_subtree(&self.layout_refs);
            do self.css_select_ctx.borrow_imm |ctx| {
                node.restyle_subtree(ctx);
            }

            let builder = LayoutTreeBuilder::new();
            let layout_root: @FlowContext = match builder.construct_trees(&layout_ctx,
                                                                          *node) {
                Ok(root) => root,
                Err(*) => fail ~"Root flow should always exist"
            };

            debug!("layout: constructed Flow tree");
            debug!("%?", layout_root.dump());

            layout_root
        };

        do time("layout: main layout") {
            /* perform layout passes over the flow tree */
            do layout_root.traverse_postorder |f| { f.bubble_widths(&layout_ctx) }
            do layout_root.traverse_preorder  |f| { f.assign_widths(&layout_ctx) }
            do layout_root.traverse_postorder |f| { f.assign_height(&layout_ctx) }
        }

        do time("layout: display list building") {
            let builder = dl::DisplayListBuilder {
                ctx: &layout_ctx,
            };
            let mut render_layer = RenderLayer {
                display_list: DisplayList::new(),
                size: Size2D(au::to_px(screen_size.width) as uint,
                             au::to_px(screen_size.height) as uint)
            };

            // TODO: set options on the builder before building
            // TODO: be smarter about what needs painting
            layout_root.build_display_list(&builder, &copy layout_root.d().position,
                                           &mut render_layer.display_list);
            self.render_task.send(render_task::RenderMsg(move render_layer));
        } // time(layout: display list building)

        // Tell content we're done
        data.content_join_chan.send(());

    }

    fn handle_query(query: LayoutQuery,
                    reply_chan: comm::Chan<LayoutQueryResponse>) {
        match query {
            ContentBox(node) => {
                let response = do node.aux |a| {
                    match a.flow {
                        None => Err(()),
                        Some(flow) => {
                            let start_val : Option<Rect<Au>> = None;
                            let rect = do flow.foldl_boxes_for_node(node, start_val) |acc, box| {
                                match acc {
                                    Some(acc) => Some(acc.union(&box.content_box())),
                                    None => Some(box.content_box())
                                }
                            };

                            match rect {
                                None => Err(()),
                                Some(rect) => {
                                    let size = Size2D(au::to_px(rect.size.width),
                                                      au::to_px(rect.size.height));
                                    Ok(ContentSize(move size))
                                }
                            }
                        }
                    }
                };

                reply_chan.send(response)
            }
        }
    }

    // When images can't be loaded in time to display they trigger
    // this callback in some task somewhere. This will send a message
    // to the content task, and ultimately cause the image to be
    // re-requested. We probably don't need to go all the way back to
    // the content task for this.
    fn make_on_image_available_cb(dom_event_chan: pipes::SharedChan<Event>) -> @fn() -> ~fn(ImageResponseMsg) {
        // This has a crazy signature because the image cache needs to
        // make multiple copies of the callback, and the dom event
        // channel is not a copyable type, so this is actually a
        // little factory to produce callbacks
        let f: @fn() -> ~fn(ImageResponseMsg) = |move dom_event_chan| {
            let dom_event_chan = dom_event_chan.clone();
            let f: ~fn(ImageResponseMsg) = |_msg, move dom_event_chan| {
                dom_event_chan.send(ReflowEvent)
            };
            move f
        };
        return f;
    }
}

<commit_msg>Time aux ptr initialization and selector matching separately<commit_after>/**
    The layout task. Performs layout on the DOM, builds display lists and sends them to be
    rendered.
*/

use au = gfx::geometry;
use au::Au;
use content::content_task;
use core::dvec::DVec;
use newcss::Stylesheet;
use dl = gfx::display_list;
use dom::event::{Event, ReflowEvent};
use dom::node::{Node, LayoutData};
use geom::point::Point2D;
use geom::rect::Rect;
use geom::size::Size2D;
use gfx::display_list::DisplayList;
use gfx::render_task;
use gfx::render_layers::RenderLayer;
use layout::box::RenderBox;
use layout::box_builder::LayoutTreeBuilder;
use layout::context::LayoutContext;
use opt = core::option;
use render_task::RenderTask;
use resource::image_cache_task::{ImageCacheTask, ImageResponseMsg};
use resource::local_image_cache::LocalImageCache;
use servo_text::font_context::FontContext;
use servo_text::font_cache::FontCache;
use servo_text::font_matcher::FontMatcher;
use std::arc::ARC;
use std::net::url::Url;
use core::util::replace;
use util::time::time;
use std::cell::Cell;
use layout::traverse::*;
use comm::*;
use task::*;
use core::mutable::Mut;
use newcss::SelectCtx;

pub type LayoutTask = comm::Chan<Msg>;

pub enum LayoutQuery {
    ContentBox(Node)
}

pub type LayoutQueryResponse = Result<LayoutQueryResponse_, ()>;

enum LayoutQueryResponse_ {
    ContentSize(Size2D<int>)
}

pub enum Msg {
    AddStylesheet(Stylesheet),
    BuildMsg(BuildData),
    QueryMsg(LayoutQuery, comm::Chan<LayoutQueryResponse>),
    ExitMsg
}

struct BuildData {
    node: Node,
    url: Url,
    dom_event_chan: pipes::SharedChan<Event>,
    window_size: Size2D<uint>,
    content_join_chan: pipes::Chan<()>
}

fn LayoutTask(render_task: RenderTask,
              img_cache_task: ImageCacheTask) -> LayoutTask {
    do spawn_listener::<Msg> |from_content, move img_cache_task| {
        Layout(render_task, img_cache_task.clone(), from_content).start();
    }
}

struct Layout {
    render_task: RenderTask,
    image_cache_task: ImageCacheTask,
    local_image_cache: @LocalImageCache,
    from_content: comm::Port<Msg>,

    font_cache: @FontCache,
    font_matcher: @FontMatcher,
    // This is used to root auxilliary RCU reader data
    layout_refs: DVec<@LayoutData>,
    css_select_ctx: Mut<SelectCtx>,
}

fn Layout(render_task: RenderTask,
         image_cache_task: ImageCacheTask,
         from_content: comm::Port<Msg>) -> Layout {

    let fctx = @FontContext::new();

    Layout {
        render_task: render_task,
        image_cache_task: image_cache_task.clone(),
        local_image_cache: @LocalImageCache(move image_cache_task),
        from_content: from_content,
        font_matcher: @FontMatcher::new(fctx),
        font_cache: @FontCache::new(fctx),
        layout_refs: DVec(),
        css_select_ctx: Mut(SelectCtx::new())
    }
}

impl Layout {

    fn start() {
        while self.handle_request() {
            // loop indefinitely
        }
    }

    fn handle_request() -> bool {

        match self.from_content.recv() {
            AddStylesheet(move sheet) => {
                self.handle_add_stylesheet(move sheet);
            }
            BuildMsg(move data) => {
                let data = Cell(move data);

                do time("layout: performing layout") {
                    self.handle_build(data.take());
                }

            }
            QueryMsg(query, chan) => {
                do time("layout: querying layout") {
                    self.handle_query(query, chan)
                }
            }
            ExitMsg => {
                debug!("layout: ExitMsg received");
                return false
            }
        }

        true
    }

    fn handle_add_stylesheet(sheet: Stylesheet) {
        let sheet = Cell(move sheet);
        do self.css_select_ctx.borrow_mut |ctx| {
            ctx.append_sheet(sheet.take());
        }
    }

    fn handle_build(data: BuildData) {

        let node = &data.node;
        // FIXME: Bad copy
        let doc_url = copy data.url;
        // FIXME: Bad clone
        let dom_event_chan = data.dom_event_chan.clone();

        debug!("layout: received layout request for: %s", doc_url.to_str());
        debug!("layout: parsed Node tree");
        debug!("%?", node.dump());

        // Reset the image cache
        self.local_image_cache.next_round(self.make_on_image_available_cb(move dom_event_chan));

        let screen_size = Size2D(au::from_px(data.window_size.width as int),
                                 au::from_px(data.window_size.height as int));

        let layout_ctx = LayoutContext {
            image_cache: self.local_image_cache,
            font_cache: self.font_cache,
            doc_url: move doc_url,
            screen_size: Rect(Point2D(Au(0), Au(0)), screen_size)
        };

        do time("layout: aux initialization") {
            // TODO: this is dumb. we don't need an entire traversal to do this
            node.initialize_style_for_subtree(&self.layout_refs);
        }

        do time("layout: selector matching") {
            do self.css_select_ctx.borrow_imm |ctx| {
                node.restyle_subtree(ctx);
            }
        }

        let layout_root: @FlowContext = do time("layout: tree construction") {
            let builder = LayoutTreeBuilder::new();
            let layout_root: @FlowContext = match builder.construct_trees(&layout_ctx,
                                                                          *node) {
                Ok(root) => root,
                Err(*) => fail ~"Root flow should always exist"
            };

            debug!("layout: constructed Flow tree");
            debug!("%?", layout_root.dump());

            layout_root
        };

        do time("layout: main layout") {
            /* perform layout passes over the flow tree */
            do layout_root.traverse_postorder |f| { f.bubble_widths(&layout_ctx) }
            do layout_root.traverse_preorder  |f| { f.assign_widths(&layout_ctx) }
            do layout_root.traverse_postorder |f| { f.assign_height(&layout_ctx) }
        }

        do time("layout: display list building") {
            let builder = dl::DisplayListBuilder {
                ctx: &layout_ctx,
            };
            let mut render_layer = RenderLayer {
                display_list: DisplayList::new(),
                size: Size2D(au::to_px(screen_size.width) as uint,
                             au::to_px(screen_size.height) as uint)
            };

            // TODO: set options on the builder before building
            // TODO: be smarter about what needs painting
            layout_root.build_display_list(&builder, &copy layout_root.d().position,
                                           &mut render_layer.display_list);
            self.render_task.send(render_task::RenderMsg(move render_layer));
        } // time(layout: display list building)

        // Tell content we're done
        data.content_join_chan.send(());
    }

    fn handle_query(query: LayoutQuery,
                    reply_chan: comm::Chan<LayoutQueryResponse>) {
        match query {
            ContentBox(node) => {
                let response = do node.aux |a| {
                    match a.flow {
                        None => Err(()),
                        Some(flow) => {
                            let start_val : Option<Rect<Au>> = None;
                            let rect = do flow.foldl_boxes_for_node(node, start_val) |acc, box| {
                                match acc {
                                    Some(acc) => Some(acc.union(&box.content_box())),
                                    None => Some(box.content_box())
                                }
                            };

                            match rect {
                                None => Err(()),
                                Some(rect) => {
                                    let size = Size2D(au::to_px(rect.size.width),
                                                      au::to_px(rect.size.height));
                                    Ok(ContentSize(move size))
                                }
                            }
                        }
                    }
                };

                reply_chan.send(response)
            }
        }
    }

    // When images can't be loaded in time to display they trigger
    // this callback in some task somewhere. This will send a message
    // to the content task, and ultimately cause the image to be
    // re-requested. We probably don't need to go all the way back to
    // the content task for this.
    fn make_on_image_available_cb(dom_event_chan: pipes::SharedChan<Event>) -> @fn() -> ~fn(ImageResponseMsg) {
        // This has a crazy signature because the image cache needs to
        // make multiple copies of the callback, and the dom event
        // channel is not a copyable type, so this is actually a
        // little factory to produce callbacks
        let f: @fn() -> ~fn(ImageResponseMsg) = |move dom_event_chan| {
            let dom_event_chan = dom_event_chan.clone();
            let f: ~fn(ImageResponseMsg) = |_msg, move dom_event_chan| {
                dom_event_chan.send(ReflowEvent)
            };
            move f
        };
        return f;
    }
}

<|endoftext|>


<commit_before>use super::{ffi, safe};
use std::{fmt, cmp};
use std::ffi::CStr;
use std::error::Error;

pub const MAX_DIAGNOSTIC_MESSAGE_SIZE: usize = 1024;

/// ODBC Diagnostic Record
///
/// The `description` method of the `std::error::Error` trait only returns the message. Use
/// `std::fmt::Display` to retrive status code and other information.
pub struct DiagnosticRecord {
    // All elements but the last one, may not be nul. The last one must be nul.
    state: [ffi::SQLCHAR; ffi::SQL_SQLSTATE_SIZE + 1],
    // Must at least contain one nul
    message: [ffi::SQLCHAR; MAX_DIAGNOSTIC_MESSAGE_SIZE],
    // The numbers of characters in message not nul
    message_length: ffi::SQLSMALLINT,
    native_error: ffi::SQLINTEGER,
    message_string: String,
}

impl DiagnosticRecord {
    /// get raw state string data.
    pub fn get_raw_state(&self) -> &[u8] {
        &self.state
    }
    /// get raw diagnostics message for avoiding encoding error.
    pub fn get_raw_message(&self) -> &[u8] {
        &self.message[0..self.message_length as usize]
    }
    /// get native odbc error number
    pub fn get_native_error(&self) -> i32 {
        self.native_error
    }
    /// constructs an empty diagnostics message.
    /// this is needed for errors where the driver doesn't return any diagnostics info.
    pub fn empty() -> DiagnosticRecord {
        let message = b"No SQL-driver error information available.";
        let mut rec = DiagnosticRecord {
            state: b"HY000\0".clone(),
            message: [0u8; MAX_DIAGNOSTIC_MESSAGE_SIZE],
            native_error: -1,
            message_length: message.len() as ffi::SQLSMALLINT,
            message_string: String::from(""),
        };
        rec.message[..message.len()].copy_from_slice(message);
        rec
    }
}

impl fmt::Display for DiagnosticRecord {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // Todo: replace unwrap with `?` in Rust 1.17
        let state = CStr::from_bytes_with_nul(&self.state).unwrap();

        write!(
            f,
            "State: {}, Native error: {}, Message: {}",
            state.to_str().unwrap(),
            self.native_error,
            self.message_string,
        )
    }
}

impl fmt::Debug for DiagnosticRecord {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(self, f)
    }
}

impl Error for DiagnosticRecord {
    fn description(&self) -> &str {
        &self.message_string
    }
    fn cause(&self) -> Option<&Error> {
        None
    }
}

/// Allows retriving a diagnostic record, describing errors (or lack thereof) during the last
/// operation.
pub trait GetDiagRec {
    /// Retrieves a diagnostic record
    ///
    /// `record_number` - Record numbers start at one. If you pass an number < 1 the function will
    /// panic. If no record is available for the number specified none is returned.
    fn get_diag_rec(&self, record_number: i16) -> Option<DiagnosticRecord>;
}

impl<D> GetDiagRec for D
where
    D: safe::Diagnostics,
{
    fn get_diag_rec(&self, record_number: i16) -> Option<(DiagnosticRecord)> {
        use safe::ReturnOption::*;
        let mut message = [0; MAX_DIAGNOSTIC_MESSAGE_SIZE];
        match self.diagnostics(record_number, &mut message) {
            Success(result) | Info(result) => {
                // The message could be larger than the supplied buffer, so we need to limit the message length to the buffer size.
                let mut message_length = cmp::min(result.text_length, MAX_DIAGNOSTIC_MESSAGE_SIZE as ffi::SQLSMALLINT - 1);
                // Some drivers pad the message with null-chars (which is still a valid C string, but not a valid Rust string).
                while message_length > 0 && message[(message_length - 1) as usize] == 0 {
                    message_length = message_length - 1;
                }
                Some(DiagnosticRecord {
                    state: result.state,
                    native_error: result.native_error,
                    message_length,
                    message,
                    message_string: unsafe { ::environment::OS_ENCODING.decode(&message[0..(message_length as usize + 1)]).0.into_owned()},
                })
            }
            NoData(()) => None,
            Error(()) => panic!("Diagnostics returned error for record number {}. Record numbers have to be at least 1.", record_number),
        }
    }
}

#[cfg(test)]
mod test {

    use super::*;

    impl DiagnosticRecord {
        fn new() -> DiagnosticRecord {
            DiagnosticRecord {
                state: [0u8; ffi::SQL_SQLSTATE_SIZE + 1],
                message: [0u8; MAX_DIAGNOSTIC_MESSAGE_SIZE],
                native_error: 0,
                message_length: 0,
                message_string: String::from(""),
            }
        }
    }

    #[test]
    fn formatting() {

        // build diagnostic record
        let message = b"[Microsoft][ODBC Driver Manager] Function sequence error\0";
        let mut rec = DiagnosticRecord::new();
        rec.state = b"HY010\0".clone();
        rec.message_length = 56;
        for i in 0..(rec.message_length as usize) {
            rec.message[i] = message[i];
        }

        // test formatting
        assert_eq!(
            format!("{}", rec),
            "State: HY010, Native error: 0, Message: [Microsoft][ODBC Driver Manager] \
             Function sequence error"
        );
    }
}
<commit_msg>Fix failing test<commit_after>use super::{ffi, safe};
use std::{fmt, cmp};
use std::ffi::CStr;
use std::error::Error;

pub const MAX_DIAGNOSTIC_MESSAGE_SIZE: usize = 1024;

/// ODBC Diagnostic Record
///
/// The `description` method of the `std::error::Error` trait only returns the message. Use
/// `std::fmt::Display` to retrive status code and other information.
pub struct DiagnosticRecord {
    // All elements but the last one, may not be nul. The last one must be nul.
    state: [ffi::SQLCHAR; ffi::SQL_SQLSTATE_SIZE + 1],
    // Must at least contain one nul
    message: [ffi::SQLCHAR; MAX_DIAGNOSTIC_MESSAGE_SIZE],
    // The numbers of characters in message not nul
    message_length: ffi::SQLSMALLINT,
    native_error: ffi::SQLINTEGER,
    message_string: String,
}

impl DiagnosticRecord {
    /// get raw state string data.
    pub fn get_raw_state(&self) -> &[u8] {
        &self.state
    }
    /// get raw diagnostics message for avoiding encoding error.
    pub fn get_raw_message(&self) -> &[u8] {
        &self.message[0..self.message_length as usize]
    }
    /// get native odbc error number
    pub fn get_native_error(&self) -> i32 {
        self.native_error
    }
    /// constructs an empty diagnostics message.
    /// this is needed for errors where the driver doesn't return any diagnostics info.
    pub fn empty() -> DiagnosticRecord {
        let message = b"No SQL-driver error information available.";
        let mut rec = DiagnosticRecord {
            state: b"HY000\0".clone(),
            message: [0u8; MAX_DIAGNOSTIC_MESSAGE_SIZE],
            native_error: -1,
            message_length: message.len() as ffi::SQLSMALLINT,
            message_string: String::from(""),
        };
        rec.message[..message.len()].copy_from_slice(message);
        rec
    }
}

impl fmt::Display for DiagnosticRecord {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // Todo: replace unwrap with `?` in Rust 1.17
        let state = CStr::from_bytes_with_nul(&self.state).unwrap();

        write!(
            f,
            "State: {}, Native error: {}, Message: {}",
            state.to_str().unwrap(),
            self.native_error,
            self.message_string,
        )
    }
}

impl fmt::Debug for DiagnosticRecord {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(self, f)
    }
}

impl Error for DiagnosticRecord {
    fn description(&self) -> &str {
        &self.message_string
    }
    fn cause(&self) -> Option<&Error> {
        None
    }
}

/// Allows retriving a diagnostic record, describing errors (or lack thereof) during the last
/// operation.
pub trait GetDiagRec {
    /// Retrieves a diagnostic record
    ///
    /// `record_number` - Record numbers start at one. If you pass an number < 1 the function will
    /// panic. If no record is available for the number specified none is returned.
    fn get_diag_rec(&self, record_number: i16) -> Option<DiagnosticRecord>;
}

impl<D> GetDiagRec for D
where
    D: safe::Diagnostics,
{
    fn get_diag_rec(&self, record_number: i16) -> Option<(DiagnosticRecord)> {
        use safe::ReturnOption::*;
        let mut message = [0; MAX_DIAGNOSTIC_MESSAGE_SIZE];
        match self.diagnostics(record_number, &mut message) {
            Success(result) | Info(result) => {
                // The message could be larger than the supplied buffer, so we need to limit the message length to the buffer size.
                let mut message_length = cmp::min(result.text_length, MAX_DIAGNOSTIC_MESSAGE_SIZE as ffi::SQLSMALLINT - 1);
                // Some drivers pad the message with null-chars (which is still a valid C string, but not a valid Rust string).
                while message_length > 0 && message[(message_length - 1) as usize] == 0 {
                    message_length = message_length - 1;
                }
                Some(DiagnosticRecord {
                    state: result.state,
                    native_error: result.native_error,
                    message_length,
                    message,
                    message_string: unsafe { ::environment::OS_ENCODING.decode(&message[0..(message_length as usize + 1)]).0.into_owned()},
                })
            }
            NoData(()) => None,
            Error(()) => panic!("Diagnostics returned error for record number {}. Record numbers have to be at least 1.", record_number),
        }
    }
}

#[cfg(test)]
mod test {

    use super::*;

    impl DiagnosticRecord {
        fn new() -> DiagnosticRecord {
            DiagnosticRecord {
                state: [0u8; ffi::SQL_SQLSTATE_SIZE + 1],
                message: [0u8; MAX_DIAGNOSTIC_MESSAGE_SIZE],
                native_error: 0,
                message_length: 0,
                message_string: String::from(""),
            }
        }
    }

    #[test]
    fn formatting() {

        // build diagnostic record
        let message = b"[Microsoft][ODBC Driver Manager] Function sequence error\0";
        let mut rec = DiagnosticRecord::new();
        rec.state = b"HY010\0".clone();
        rec.message_string = CStr::from_bytes_with_nul(message).unwrap().to_str().unwrap().to_owned();
        rec.message_length = 56;
        for i in 0..(rec.message_length as usize) {
            rec.message[i] = message[i];
        }

        // test formatting
        assert_eq!(
            format!("{}", rec),
            "State: HY010, Native error: 0, Message: [Microsoft][ODBC Driver Manager] \
             Function sequence error"
        );
    }
}
<|endoftext|>


<commit_before>use ffi::*;
use allegro::ffi::*;
use allegro::{Core, Color, Bitmap, BitmapLike};
use std::kinds::marker::NoSend;

use libc::*;
use std::option::Some;
use std::cast;
use std::mem;

pub enum FontAlignment
{
	AlignLeft,
	AlignCentre,
	AlignRight
}

impl FontAlignment
{
	fn get_allegro_flags(&self) -> c_int
	{
		match *self
		{
			AlignLeft => ALLEGRO_ALIGN_LEFT,
			AlignRight => ALLEGRO_ALIGN_RIGHT,
			AlignCentre => ALLEGRO_ALIGN_CENTRE,
		}
	}
}

pub trait FontDrawing
{
	fn draw_text(&self, font: &Font, color: Color, x: f32, y: f32, align: FontAlignment, text: &str);
	fn draw_justified_text(&self, font: &Font, color: Color, x1: f32, x2: f32, y: f32, diff: f32, align: FontAlignment, text: &str);
}

impl FontDrawing for Core
{
	fn draw_justified_text(&self, font: &Font, color: Color, x1: f32, x2: f32, y: f32, diff: f32, align: FontAlignment, text: &str)
	{
		unsafe
		{
			let mut info: ALLEGRO_USTR_INFO = mem::uninit();
			let ustr = al_ref_buffer(&mut info, text.as_ptr() as *i8, text.len() as size_t);

			al_draw_justified_ustr(cast::transmute(font.get_font()), *color, x1 as c_float,
			                       x2 as c_float, y as c_float, diff as c_float, align.get_allegro_flags(), ustr);
		}
	}

	fn draw_text(&self, font: &Font, color: Color, x: f32, y: f32, align: FontAlignment, text: &str)
	{
		unsafe
		{
			let mut info: ALLEGRO_USTR_INFO = mem::uninit();
			let ustr = al_ref_buffer(&mut info, text.as_ptr() as *i8, text.len() as size_t);

			al_draw_ustr(cast::transmute(font.get_font()), *color, x as c_float, y as c_float, align.get_allegro_flags(), ustr);
		}
	}
}

pub struct Font
{
	allegro_font: *mut ALLEGRO_FONT,
	no_send_marker: NoSend,
}

impl Font
{
	fn new(font: *mut ALLEGRO_FONT) -> Option
	{
		if font.is_null()
		{
			None
		}
		else
		{
			Some(Font{ allegro_font: font, no_send_marker: NoSend })
		}
	}

	pub fn get_font(&self) -> *mut ALLEGRO_FONT
	{
		self.allegro_font
	}

	pub fn get_text_width(&self, text: &str) -> i32
	{
		unsafe
		{
			let mut info: ALLEGRO_USTR_INFO = mem::uninit();
			let ustr = al_ref_buffer(&mut info, text.as_ptr() as *i8, text.len() as size_t);
			al_get_ustr_width(self.get_font() as *_, ustr) as i32
		}
	}

	pub fn get_line_height(&self) -> i32
	{
		unsafe
		{
			al_get_font_line_height(self.get_font() as *_) as i32
		}
	}

	pub fn get_ascent(&self) -> i32
	{
		unsafe
		{
			al_get_font_ascent(self.get_font() as *_) as i32
		}
	}

	pub fn get_descent(&self) -> i32
	{
		unsafe
		{
			al_get_font_descent(self.get_font() as *_) as i32
		}
	}

	pub fn get_text_dimensions(&self, text: &str) -> (i32, i32, i32, i32)
	{
		unsafe
		{
			let (mut x, mut y, mut w, mut h): (c_int, c_int, c_int, c_int) = mem::uninit();
			let mut info: ALLEGRO_USTR_INFO = mem::uninit();
			let ustr = al_ref_buffer(&mut info, text.as_ptr() as *i8, text.len() as size_t);
			al_get_ustr_dimensions(self.get_font() as *_, ustr, &mut x, &mut y, &mut w, &mut h);
			(x as i32, y as i32, w as i32, h as i32)
		}
	}
}

// Not Send just because of the marker
#[unsafe_destructor]
impl Drop for Font
{
	fn drop(&mut self)
	{
		unsafe
		{
			al_destroy_font(self.allegro_font);
		}
	}
}

impl ::addon::FontAddon
{
	pub fn create_builtin_font(&self) -> Option
	{
		Font::new(unsafe
		{
			al_create_builtin_font()
		})
	}

	pub fn load_bitmap_font(&self, filename: &str) -> Option
	{
		Font::new(unsafe
		{
			filename.with_c_str(|s|
			{
				al_load_bitmap_font(s)
			})
		})
	}

	pub fn load_font(&self, size: i32, filename: &str) -> Option
	{
		Font::new(unsafe
		{
			filename.with_c_str(|s|
			{
				al_load_font(s, size as c_int, 0)
			})
		})
	}

	pub fn grab_font_from_bitmap(&self, bmp: &Bitmap, ranges: &[(c_int, c_int)]) -> Option
	{
		Font::new(unsafe
		{
			al_grab_font_from_bitmap(bmp.get_bitmap(), (ranges.len() * 2) as c_int, ranges.as_ptr() as *c_int)
		})
	}
}
<commit_msg>Remove load_font as it is a silly API<commit_after>use ffi::*;
use allegro::ffi::*;
use allegro::{Core, Color, Bitmap, BitmapLike};
use std::kinds::marker::NoSend;

use libc::*;
use std::option::Some;
use std::cast;
use std::mem;

pub enum FontAlignment
{
	AlignLeft,
	AlignCentre,
	AlignRight
}

impl FontAlignment
{
	fn get_allegro_flags(&self) -> c_int
	{
		match *self
		{
			AlignLeft => ALLEGRO_ALIGN_LEFT,
			AlignRight => ALLEGRO_ALIGN_RIGHT,
			AlignCentre => ALLEGRO_ALIGN_CENTRE,
		}
	}
}

pub trait FontDrawing
{
	fn draw_text(&self, font: &Font, color: Color, x: f32, y: f32, align: FontAlignment, text: &str);
	fn draw_justified_text(&self, font: &Font, color: Color, x1: f32, x2: f32, y: f32, diff: f32, align: FontAlignment, text: &str);
}

impl FontDrawing for Core
{
	fn draw_justified_text(&self, font: &Font, color: Color, x1: f32, x2: f32, y: f32, diff: f32, align: FontAlignment, text: &str)
	{
		unsafe
		{
			let mut info: ALLEGRO_USTR_INFO = mem::uninit();
			let ustr = al_ref_buffer(&mut info, text.as_ptr() as *i8, text.len() as size_t);

			al_draw_justified_ustr(cast::transmute(font.get_font()), *color, x1 as c_float,
			                       x2 as c_float, y as c_float, diff as c_float, align.get_allegro_flags(), ustr);
		}
	}

	fn draw_text(&self, font: &Font, color: Color, x: f32, y: f32, align: FontAlignment, text: &str)
	{
		unsafe
		{
			let mut info: ALLEGRO_USTR_INFO = mem::uninit();
			let ustr = al_ref_buffer(&mut info, text.as_ptr() as *i8, text.len() as size_t);

			al_draw_ustr(cast::transmute(font.get_font()), *color, x as c_float, y as c_float, align.get_allegro_flags(), ustr);
		}
	}
}

pub struct Font
{
	allegro_font: *mut ALLEGRO_FONT,
	no_send_marker: NoSend,
}

impl Font
{
	fn new(font: *mut ALLEGRO_FONT) -> Option
	{
		if font.is_null()
		{
			None
		}
		else
		{
			Some(Font{ allegro_font: font, no_send_marker: NoSend })
		}
	}

	pub fn get_font(&self) -> *mut ALLEGRO_FONT
	{
		self.allegro_font
	}

	pub fn get_text_width(&self, text: &str) -> i32
	{
		unsafe
		{
			let mut info: ALLEGRO_USTR_INFO = mem::uninit();
			let ustr = al_ref_buffer(&mut info, text.as_ptr() as *i8, text.len() as size_t);
			al_get_ustr_width(self.get_font() as *_, ustr) as i32
		}
	}

	pub fn get_line_height(&self) -> i32
	{
		unsafe
		{
			al_get_font_line_height(self.get_font() as *_) as i32
		}
	}

	pub fn get_ascent(&self) -> i32
	{
		unsafe
		{
			al_get_font_ascent(self.get_font() as *_) as i32
		}
	}

	pub fn get_descent(&self) -> i32
	{
		unsafe
		{
			al_get_font_descent(self.get_font() as *_) as i32
		}
	}

	pub fn get_text_dimensions(&self, text: &str) -> (i32, i32, i32, i32)
	{
		unsafe
		{
			let (mut x, mut y, mut w, mut h): (c_int, c_int, c_int, c_int) = mem::uninit();
			let mut info: ALLEGRO_USTR_INFO = mem::uninit();
			let ustr = al_ref_buffer(&mut info, text.as_ptr() as *i8, text.len() as size_t);
			al_get_ustr_dimensions(self.get_font() as *_, ustr, &mut x, &mut y, &mut w, &mut h);
			(x as i32, y as i32, w as i32, h as i32)
		}
	}
}

// Not Send just because of the marker
#[unsafe_destructor]
impl Drop for Font
{
	fn drop(&mut self)
	{
		unsafe
		{
			al_destroy_font(self.allegro_font);
		}
	}
}

impl ::addon::FontAddon
{
	pub fn create_builtin_font(&self) -> Option
	{
		Font::new(unsafe
		{
			al_create_builtin_font()
		})
	}

	pub fn load_bitmap_font(&self, filename: &str) -> Option
	{
		Font::new(unsafe
		{
			filename.with_c_str(|s|
			{
				al_load_bitmap_font(s)
			})
		})
	}

	pub fn grab_font_from_bitmap(&self, bmp: &Bitmap, ranges: &[(c_int, c_int)]) -> Option
	{
		Font::new(unsafe
		{
			al_grab_font_from_bitmap(bmp.get_bitmap(), (ranges.len() * 2) as c_int, ranges.as_ptr() as *c_int)
		})
	}
}
<|endoftext|>