<commit_before>use crate::prelude::*;

pub fn clif_intcast(
    fx: &mut FunctionCx<'_, '_, impl Backend>,
    val: Value,
    to: Type,
    signed: bool,
) -> Value {
    let from = fx.bcx.func.dfg.value_type(val);
    match (from, to) {
        // equal
        (_, _) if from == to => val,

        // extend
        (_, types::I128) => {
            let wider = if from == types::I64 {
                val
            } else if signed {
                fx.bcx.ins().sextend(types::I64, val)
            } else {
                fx.bcx.ins().uextend(types::I64, val)
            };
            let zero = fx.bcx.ins().iconst(types::I64, 0);
            fx.bcx.ins().iconcat(wider, zero)
        }
        (_, _) if to.wider_or_equal(from) => {
            if signed {
                fx.bcx.ins().sextend(to, val)
            } else {
                fx.bcx.ins().uextend(to, val)
            }
        }

        // reduce
        (types::I128, _) => {
            let (lsb, _msb) = fx.bcx.ins().isplit(val);
            if to == types::I64 {
                lsb
            } else {
                fx.bcx.ins().ireduce(to, lsb)
            }
        }
        (_, _) => {
            fx.bcx.ins().ireduce(to, val)
        }
    }
}

pub fn clif_int_or_float_cast(
    fx: &mut FunctionCx<'_, '_, impl Backend>,
    from: Value,
    from_signed: bool,
    to_ty: Type,
    to_signed: bool,
) -> Value {
    let from_ty = fx.bcx.func.dfg.value_type(from);

    if from_ty.is_int() && to_ty.is_int() {
        // int-like -> int-like
        clif_intcast(
            fx,
            from,
            to_ty,
            from_signed, // FIXME is this correct?
        )
    } else if from_ty.is_int() && to_ty.is_float() {
        // int-like -> float
        if from_signed {
            fx.bcx.ins().fcvt_from_sint(to_ty, from)
        } else {
            fx.bcx.ins().fcvt_from_uint(to_ty, from)
        }
    } else if from_ty.is_float() && to_ty.is_int() {
        // float -> int-like
        if to_ty == types::I8 || to_ty == types::I16 {
            // FIXME implement fcvt_to_*int_sat.i8/i16
            let val = if to_signed {
                fx.bcx.ins().fcvt_to_sint_sat(types::I32, from)
            } else {
                fx.bcx.ins().fcvt_to_uint_sat(types::I32, from)
            };
            let (min, max) = type_min_max_value(to_ty, to_signed);
            let min_val = fx.bcx.ins().iconst(types::I32, min);
            let max_val = fx.bcx.ins().iconst(types::I32, max);

            let val = if to_signed {
                let has_underflow = fx.bcx.ins().icmp_imm(
                    IntCC::SignedLessThan,
                    val,
                    min,
                );
                let has_overflow = fx.bcx.ins().icmp_imm(
                    IntCC::SignedGreaterThan,
                    val,
                    max,
                );
                let bottom_capped = fx.bcx.ins().select(has_underflow, min_val, val);
                fx.bcx.ins().select(has_overflow, max_val, bottom_capped)
            } else {
                let has_overflow = fx.bcx.ins().icmp_imm(
                    IntCC::UnsignedGreaterThan,
                    val,
                    max,
                );
                fx.bcx.ins().select(has_overflow, max_val, val)
            };
            fx.bcx.ins().ireduce(to_ty, val)
        } else {
            if to_signed {
                fx.bcx.ins().fcvt_to_sint_sat(to_ty, from)
            } else {
                fx.bcx.ins().fcvt_to_uint_sat(to_ty, from)
            }
        }
    } else if from_ty.is_float() && to_ty.is_float() {
        // float -> float
        match (from_ty, to_ty) {
            (types::F32, types::F64) => {
                fx.bcx.ins().fpromote(types::F64, from)
            }
            (types::F64, types::F32) => {
                fx.bcx.ins().fdemote(types::F32, from)
            }
            _ => from,
        }
    } else {
        unreachable!("cast value from {:?} to {:?}", from_ty, to_ty);
    }
}
<commit_msg>Add unimpl! for cast between 128bit int and float<commit_after>use crate::prelude::*;

pub fn clif_intcast(
    fx: &mut FunctionCx<'_, '_, impl Backend>,
    val: Value,
    to: Type,
    signed: bool,
) -> Value {
    let from = fx.bcx.func.dfg.value_type(val);
    match (from, to) {
        // equal
        (_, _) if from == to => val,

        // extend
        (_, types::I128) => {
            let wider = if from == types::I64 {
                val
            } else if signed {
                fx.bcx.ins().sextend(types::I64, val)
            } else {
                fx.bcx.ins().uextend(types::I64, val)
            };
            let zero = fx.bcx.ins().iconst(types::I64, 0);
            fx.bcx.ins().iconcat(wider, zero)
        }
        (_, _) if to.wider_or_equal(from) => {
            if signed {
                fx.bcx.ins().sextend(to, val)
            } else {
                fx.bcx.ins().uextend(to, val)
            }
        }

        // reduce
        (types::I128, _) => {
            let (lsb, _msb) = fx.bcx.ins().isplit(val);
            if to == types::I64 {
                lsb
            } else {
                fx.bcx.ins().ireduce(to, lsb)
            }
        }
        (_, _) => {
            fx.bcx.ins().ireduce(to, val)
        }
    }
}

pub fn clif_int_or_float_cast(
    fx: &mut FunctionCx<'_, '_, impl Backend>,
    from: Value,
    from_signed: bool,
    to_ty: Type,
    to_signed: bool,
) -> Value {
    let from_ty = fx.bcx.func.dfg.value_type(from);

    if from_ty.is_int() && to_ty.is_int() {
        // int-like -> int-like
        clif_intcast(
            fx,
            from,
            to_ty,
            from_signed, // FIXME is this correct?
        )
    } else if from_ty.is_int() && to_ty.is_float() {
        if from_ty == types::I128 {
            unimpl!("u/i128 -> float");
        }

        // int-like -> float
        if from_signed {
            fx.bcx.ins().fcvt_from_sint(to_ty, from)
        } else {
            fx.bcx.ins().fcvt_from_uint(to_ty, from)
        }
    } else if from_ty.is_float() && to_ty.is_int() {
        if to_ty == types::I128 {
            unimpl!("float -> u/i128");
        }

        // float -> int-like
        if to_ty == types::I8 || to_ty == types::I16 {
            // FIXME implement fcvt_to_*int_sat.i8/i16
            let val = if to_signed {
                fx.bcx.ins().fcvt_to_sint_sat(types::I32, from)
            } else {
                fx.bcx.ins().fcvt_to_uint_sat(types::I32, from)
            };
            let (min, max) = type_min_max_value(to_ty, to_signed);
            let min_val = fx.bcx.ins().iconst(types::I32, min);
            let max_val = fx.bcx.ins().iconst(types::I32, max);

            let val = if to_signed {
                let has_underflow = fx.bcx.ins().icmp_imm(
                    IntCC::SignedLessThan,
                    val,
                    min,
                );
                let has_overflow = fx.bcx.ins().icmp_imm(
                    IntCC::SignedGreaterThan,
                    val,
                    max,
                );
                let bottom_capped = fx.bcx.ins().select(has_underflow, min_val, val);
                fx.bcx.ins().select(has_overflow, max_val, bottom_capped)
            } else {
                let has_overflow = fx.bcx.ins().icmp_imm(
                    IntCC::UnsignedGreaterThan,
                    val,
                    max,
                );
                fx.bcx.ins().select(has_overflow, max_val, val)
            };
            fx.bcx.ins().ireduce(to_ty, val)
        } else {
            if to_signed {
                fx.bcx.ins().fcvt_to_sint_sat(to_ty, from)
            } else {
                fx.bcx.ins().fcvt_to_uint_sat(to_ty, from)
            }
        }
    } else if from_ty.is_float() && to_ty.is_float() {
        // float -> float
        match (from_ty, to_ty) {
            (types::F32, types::F64) => {
                fx.bcx.ins().fpromote(types::F64, from)
            }
            (types::F64, types::F32) => {
                fx.bcx.ins().fdemote(types::F32, from)
            }
            _ => from,
        }
    } else {
        unreachable!("cast value from {:?} to {:?}", from_ty, to_ty);
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2020 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: Apache-2.0

use crate::firmware::tests::{
    create_fake_installation_set, create_fake_starup_callbacks, create_hook, device_attributes_dir,
    device_identity_dir, hardware_hook, product_uid_hook, version_hook,
};
use std::{any::Any, env, fs, io::Write, os::unix::fs::PermissionsExt, path::PathBuf};

pub use crate::{
    firmware::Metadata, runtime_settings::RuntimeSettings, settings::Settings,
    states::machine::SharedState,
};

pub struct TestEnvironment {
    pub firmware: Data<Metadata>,
    pub runtime_settings: Data<RuntimeSettings>,
    pub settings: Data<Settings>,
    pub binaries: Data<PathBuf>,
}

pub struct Data<T> {
    pub stored_path: PathBuf,
    #[allow(dead_code)]
    pub guard: Box<dyn Any>,
    pub data: T,
}

#[derive(Default)]
pub struct TestEnvironmentBuilder {
    disable_polling: bool,
    invalid_hardware: bool,
    extra_binaries: Vec<String>,
}

impl TestEnvironment {
    pub fn build() -> TestEnvironmentBuilder {
        TestEnvironmentBuilder::default()
    }

    pub fn gen_shared_state(&self) -> SharedState {
        SharedState {
            settings: self.settings.data.clone(),
            runtime_settings: self.runtime_settings.data.clone(),
            firmware: self.firmware.data.clone(),
        }
    }
}

impl TestEnvironmentBuilder {
    pub fn add_echo_binary(mut self, binary_name: &str) -> Self {
        self.extra_binaries.push(binary_name.to_owned());
        self
    }

    pub fn invalid_hardware(self) -> Self {
        TestEnvironmentBuilder { invalid_hardware: true, ..self }
    }

    pub fn disable_polling(self) -> Self {
        TestEnvironmentBuilder { disable_polling: true, ..self }
    }

    pub fn finish(self) -> TestEnvironment {
        let firmware = {
            let dir = tempfile::tempdir().unwrap();
            let dir_path = dir.path();

            // create fake hooks to be used to validate the load
            create_hook(
                product_uid_hook(dir_path),
                "#!/bin/sh\necho 229ffd7e08721d716163fc81a2dbaf6c90d449f0a3b009b6a2defe8a0b0d7381",
            );

            create_hook(version_hook(dir_path), "#!/bin/sh\necho 1.1");
            create_hook(
                hardware_hook(&dir_path),
                &format!(
                    "#!/bin/sh\necho {}",
                    match self.invalid_hardware {
                        false => "board",
                        true => "invalid",
                    }
                ),
            );
            create_hook(
                device_identity_dir(dir_path),
                "#!/bin/sh\necho id1=value1\necho id2=value2",
            );
            create_hook(
                device_attributes_dir(dir_path),
                "#!/bin/sh\necho attr1=attrvalue1\necho attr2=attrvalue2",
            );

            Data {
                data: Metadata::from_path(dir_path).unwrap(),
                stored_path: dir_path.to_owned(),
                guard: Box::new(dir),
            }
        };

        let binaries = {
            let bin_dir = tempfile::tempdir().unwrap();
            let bin_dir_path = bin_dir.path();
            let output_file = bin_dir_path.join("output");

            create_fake_installation_set(bin_dir_path, 0);
            // Startup callbacks will be stored in the firmware directory
            create_fake_starup_callbacks(&firmware.stored_path, &output_file);

            for bin in self.extra_binaries.into_iter() {
                let mut file = fs::File::create(&bin_dir_path.join(&bin)).unwrap();
                writeln!(file, "#!/bin/sh\necho $0 >> {}", output_file.to_string_lossy()).unwrap();
                let mut permissions = file.metadata().unwrap().permissions();
                permissions.set_mode(0o755);
                file.set_permissions(permissions).unwrap();
            }
            let curr_path = env::var("PATH").map(|s| ":".to_string() + &s).unwrap_or_default();
            env::set_var("PATH", format!("{}{}", bin_dir_path.to_string_lossy(), curr_path,));

            Data {
                data: output_file,
                stored_path: bin_dir_path.to_owned(),
                guard: Box::new(bin_dir),
            }
        };

        let runtime_settings = {
            let file = tempfile::NamedTempFile::new().unwrap();
            let file_path = file.path().to_owned();

            let mut runtime_settings = RuntimeSettings::default();
            runtime_settings.path = file_path.clone();

            Data { data: runtime_settings, stored_path: file_path, guard: Box::new(file) }
        };

        let settings = {
            let mut file = tempfile::NamedTempFile::new().unwrap();
            let file_path = file.path().to_owned();
            let download_dir = tempfile::tempdir().unwrap();

            write!(
                file,
                r#"[network]
server_address="https://api.updatehub.io"
listen_socket="localhost:8080"

[storage]
read_only=false
runtime_settings={runtime_settings}

[polling]
enabled={polling_enabled}
interval="1d"

[update]
download_dir={download_dir}
supported_install_modes=["copy", "tarball"]

[firmware]
metadata={metadata}"#,
                runtime_settings = toml::to_string(&runtime_settings.stored_path).unwrap(),
                polling_enabled = toml::to_string(&!self.disable_polling).unwrap(),
                download_dir = toml::to_string(download_dir.path()).unwrap(),
                metadata = toml::to_string(&firmware.stored_path).unwrap()
            )
            .unwrap();

            Data {
                data: Settings::load(&file_path).unwrap(),
                stored_path: file_path,
                guard: Box::new(download_dir),
            }
        };

        TestEnvironment { firmware, runtime_settings, settings, binaries }
    }
}
<commit_msg>updatehub: Add server_address and listen_socket to TestEnvironmentBuilder<commit_after>// Copyright (C) 2020 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: Apache-2.0

use crate::firmware::tests::{
    create_fake_installation_set, create_fake_starup_callbacks, create_hook, device_attributes_dir,
    device_identity_dir, hardware_hook, product_uid_hook, version_hook,
};
use std::{any::Any, env, fs, io::Write, os::unix::fs::PermissionsExt, path::PathBuf};

pub use crate::{
    firmware::Metadata, runtime_settings::RuntimeSettings, settings::Settings,
    states::machine::SharedState,
};

pub struct TestEnvironment {
    pub firmware: Data<Metadata>,
    pub runtime_settings: Data<RuntimeSettings>,
    pub settings: Data<Settings>,
    pub binaries: Data<PathBuf>,
}

pub struct Data<T> {
    pub stored_path: PathBuf,
    #[allow(dead_code)]
    pub guard: Box<dyn Any>,
    pub data: T,
}

#[derive(Default)]
pub struct TestEnvironmentBuilder {
    disable_polling: bool,
    invalid_hardware: bool,
    extra_binaries: Vec<String>,
    server_address: Option<String>,
    listen_socket: Option<String>,
}

impl TestEnvironment {
    pub fn build() -> TestEnvironmentBuilder {
        TestEnvironmentBuilder::default()
    }

    pub fn gen_shared_state(&self) -> SharedState {
        SharedState {
            settings: self.settings.data.clone(),
            runtime_settings: self.runtime_settings.data.clone(),
            firmware: self.firmware.data.clone(),
        }
    }
}

impl TestEnvironmentBuilder {
    pub fn add_echo_binary(mut self, binary_name: &str) -> Self {
        self.extra_binaries.push(binary_name.to_owned());
        self
    }

    pub fn invalid_hardware(self) -> Self {
        TestEnvironmentBuilder { invalid_hardware: true, ..self }
    }

    pub fn disable_polling(self) -> Self {
        TestEnvironmentBuilder { disable_polling: true, ..self }
    }

    pub fn listen_socket(self, s: String) -> Self {
        TestEnvironmentBuilder { listen_socket: Some(s), ..self }
    }

    pub fn server_address(self, s: String) -> Self {
        TestEnvironmentBuilder { server_address: Some(s), ..self }
    }

    pub fn finish(self) -> TestEnvironment {
        let firmware = {
            let dir = tempfile::tempdir().unwrap();
            let dir_path = dir.path();

            // create fake hooks to be used to validate the load
            create_hook(
                product_uid_hook(dir_path),
                "#!/bin/sh\necho 229ffd7e08721d716163fc81a2dbaf6c90d449f0a3b009b6a2defe8a0b0d7381",
            );

            create_hook(version_hook(dir_path), "#!/bin/sh\necho 1.1");
            create_hook(
                hardware_hook(&dir_path),
                &format!(
                    "#!/bin/sh\necho {}",
                    match self.invalid_hardware {
                        false => "board",
                        true => "invalid",
                    }
                ),
            );
            create_hook(
                device_identity_dir(dir_path),
                "#!/bin/sh\necho id1=value1\necho id2=value2",
            );
            create_hook(
                device_attributes_dir(dir_path),
                "#!/bin/sh\necho attr1=attrvalue1\necho attr2=attrvalue2",
            );

            Data {
                data: Metadata::from_path(dir_path).unwrap(),
                stored_path: dir_path.to_owned(),
                guard: Box::new(dir),
            }
        };

        let binaries = {
            let bin_dir = tempfile::tempdir().unwrap();
            let bin_dir_path = bin_dir.path();
            let output_file = bin_dir_path.join("output");

            create_fake_installation_set(bin_dir_path, 0);
            // Startup callbacks will be stored in the firmware directory
            create_fake_starup_callbacks(&firmware.stored_path, &output_file);

            for bin in self.extra_binaries.into_iter() {
                let mut file = fs::File::create(&bin_dir_path.join(&bin)).unwrap();
                writeln!(file, "#!/bin/sh\necho $0 >> {}", output_file.to_string_lossy()).unwrap();
                let mut permissions = file.metadata().unwrap().permissions();
                permissions.set_mode(0o755);
                file.set_permissions(permissions).unwrap();
            }
            let curr_path = env::var("PATH").map(|s| ":".to_string() + &s).unwrap_or_default();
            env::set_var("PATH", format!("{}{}", bin_dir_path.to_string_lossy(), curr_path,));

            Data {
                data: output_file,
                stored_path: bin_dir_path.to_owned(),
                guard: Box::new(bin_dir),
            }
        };

        let runtime_settings = {
            let file = tempfile::NamedTempFile::new().unwrap();
            let file_path = file.path().to_owned();

            let mut runtime_settings = RuntimeSettings::default();
            runtime_settings.path = file_path.clone();

            Data { data: runtime_settings, stored_path: file_path, guard: Box::new(file) }
        };

        let settings = {
            let mut file = tempfile::NamedTempFile::new().unwrap();
            let file_path = file.path().to_owned();
            let download_dir = tempfile::tempdir().unwrap();

            write!(
                file,
                r#"[network]
server_address={}
listen_socket={}

[storage]
read_only=false
runtime_settings={runtime_settings}

[polling]
enabled={polling_enabled}
interval="1d"

[update]
download_dir={download_dir}
supported_install_modes=["copy", "tarball"]

[firmware]
metadata={metadata}"#,
                server_address = toml::to_string(
                    self.server_address.as_deref().unwrap_or("https://api.updatehub.io")
                )
                .unwrap(),
                listen_socket =
                    toml::to_string(self.listen_socket.as_deref().unwrap_or("localhost:8080"))
                        .unwrap(),
                runtime_settings = toml::to_string(&runtime_settings.stored_path).unwrap(),
                polling_enabled = toml::to_string(&!self.disable_polling).unwrap(),
                download_dir = toml::to_string(download_dir.path()).unwrap(),
                metadata = toml::to_string(&firmware.stored_path).unwrap()
            )
            .unwrap();

            Data {
                data: Settings::load(&file_path).unwrap(),
                stored_path: file_path,
                guard: Box::new(download_dir),
            }
        };

        TestEnvironment { firmware, runtime_settings, settings, binaries }
    }
}
<|endoftext|>


<commit_before>use Module;
use socket::Socket;

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Unit {
    RAW,
    VOLTS,
}

impl ::std::convert::Into<String> for Unit {
    fn into(self) -> String {
        let s = match self {
            Unit::RAW => "RAW",
            Unit::VOLTS => "VOLTS",
        };

        String::from(s)
    }
}

impl ::std::str::FromStr for Unit  {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "RAW" => Ok(Unit::RAW),
            "VOLTS" => Ok(Unit::VOLTS),
            unit => Err(format!("Unknow unit '{}'", unit)),
        }
    }
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Format {
    FLOAT,
    ASCII,
}

impl ::std::convert::Into<String> for Format {
    fn into(self) -> String {
        let s = match self {
            Format::FLOAT => "FLOAT",
            Format::ASCII => "ASCII",
        };

        String::from(s)
    }
}

#[derive(Clone)]
pub struct Data {
    socket: ::std::cell::RefCell<Socket>,
}

impl ::Module for Data {
    fn get_socket<'a>(&'a self) -> ::std::cell::RefMut<'a, ::socket::Socket> {
        self.socket.borrow_mut()
    }
}

impl Data {
    pub fn new(socket: Socket) -> Self {
        Data {
            socket: ::std::cell::RefCell::new(socket),
        }
    }

    /**
     * Returns current position of write pointer.
     */
    pub fn get_write_pointer(&self) -> Result<u32, <u32 as ::std::str::FromStr>::Err> {
        self.send("ACQ:WPOS?");

        self.receive()
            .parse()
    }

    /**
     * Returns position where trigger event appeared.
     */
    pub fn get_trigger_position(&self) -> Result<u32, <u32 as ::std::str::FromStr>::Err> {
        self.send("ACQ:TPOS?");

        self.receive()
            .parse()
    }

    /**
     * Selects units in which acquired data will be returned.
     */
    pub fn set_units(&self, unit: Unit) {
        self.send(format!("ACQ:DATA:UNITS {}", Into::<String>::into(unit)));
    }

    /**
     * Get units in which acquired data will be returned.
     */
    pub fn get_units(&self) -> Result<Unit, String> {
        self.send("ACQ:DATA:UNITS?");

        self.receive()
            .parse()
    }

    /**
     * Selects format acquired data will be returned.
     */
    pub fn set_format(&self, format: Format) {
        self.send(format!("ACQ:DATA:FORMAT {}", Into::<String>::into(format)));
    }

    /**
     * Read samples from start to stop position.
     *
     * start = {0,1,...,16384}
     * stop_pos = {0,1,...16384}
     */
    pub fn read_slice(&self, source: ::acquire::Source, start: u16, end: u16) -> Vec<f64> {
        self.send(format!("ACQ:{}:DATA:STA:END? {},{}", Into::<String>::into(source), start, end));

        self.parse(self.receive())
    }

    /**
     * Read `m` samples from start position on.
     */
    pub fn read(&self, source: ::acquire::Source, start: u16, len: u32) -> Vec<f64> {
        self.send(format!("ACQ:{}:DATA:STA:N? {},{}", Into::<String>::into(source), start, len));

        self.parse(self.receive())
    }

    /**
     * Read full buf.
     *
     * Size starting from oldest sample in buffer (this is first sample after
     * trigger delay). Trigger delay by default is set to zero (in samples or
     * in seconds). If trigger delay is set to zero it will read full buf.
     * Size starting from trigger.
     */
    pub fn read_all(&self, source: ::acquire::Source) -> Vec<f64> {
        self.send(format!("ACQ:{}:DATA?", Into::<String>::into(source)));

        self.parse(self.receive())
    }

    fn parse(&self, data: String) -> Vec<f64> {
        data.trim_matches(|c: char| c == '{' || c == '}' || c == '!' || c.is_alphabetic())
            .split(",")
            .map(|s| {
                match s.parse::<f64>() {
                    Ok(f) => f,
                    Err(_) => {
                        error!("Invalid data '{}'", s);
                        0.0
                    },
                }
            }).collect()
    }

    /**
     * Read m samples after trigger delay, starting from oldest sample in buffer
     * (this is first sample after trigger delay).
     *
     * Trigger delay by default is set to zero (in samples or in seconds). If
     * trigger delay is set to zero it will read m samples starting from trigger.
     */
    pub fn read_oldest(&self, source: ::acquire::Source, len: u32) -> Vec<f64> {
        self.send(format!("ACQ:{}:DATA:OLD:N? {}", Into::<String>::into(source), len));

        self.parse(self.receive())
    }

    /**
     * Read ``m`` samples before trigger delay.
     *
     * Trigger delay by default is set to zero (in samples or in seconds). If
     * trigger delay is set to zero it will read m samples before trigger.
     */
    pub fn read_latest(&self, source: ::acquire::Source, len: u32) -> Vec<f64> {
        self.send(format!("ACQ:{}:DATA:LAT:N? {}", Into::<String>::into(source), len));

        self.parse(self.receive())
    }

    /**
     * Returns buffer size.
     */
    pub fn buffer_size(&self) -> Result<u32, <u32 as ::std::str::FromStr>::Err> {
        self.send("ACQ:BUF:SIZE?");

        self.receive()
            .parse()
    }
}

#[cfg(test)]
mod test {
    #[test]
    fn test_get_write_pointer() {
        let (_, data) = create_data();

        #[cfg(features = "mock")]
        assert_eq!(data.get_write_pointer(), Ok(1024));

        #[cfg(not(features = "mock"))]
        assert!(data.get_write_pointer().is_ok());
    }

    #[test]
    fn test_get_write_pointer_at_trigger() {
        let (_, data) = create_data();

        #[cfg(features = "mock")]
        assert_eq!(data.get_trigger_position(), Ok(512));

        #[cfg(not(features = "mock"))]
        assert!(data.get_trigger_position().is_ok());
    }

    #[test]
    fn test_units() {
        let (rx, data) = create_data();

        data.set_units(::data::Unit::RAW);
        assert_eq!("ACQ:DATA:UNITS RAW\r\n", rx.recv().unwrap());

        assert_eq!(data.get_units(), Ok(::data::Unit::RAW));
    }

    #[test]
    fn test_set_format() {
        let (rx, data) = create_data();

        data.set_format(::data::Format::BIN);
        assert_eq!("ACQ:DATA:FORMAT BIN\r\n", rx.recv().unwrap());

        data.set_format(::data::Format::ASCII);
    }

    #[test]
    fn test_read_slice() {
        acquire_start();

        let (_, data) = create_data();

        let vec = data.read_slice(::acquire::Source::IN1, 10, 13);

        #[cfg(features = "mock")]
        assert_eq!(vec, vec![123.0, 231.0, -231.0]);

        #[cfg(not(features = "mock"))]
        assert_eq!(vec.len(), 3);
    }

    #[test]
    fn test_read() {
        let (_, data) = create_data();

        let vec = data.read(::acquire::Source::IN1, 10, 3);

        #[cfg(features = "mock")]
        assert_eq!(vec, vec![1.2, 3.2, -1.2]);

        #[cfg(not(features = "mock"))]
        assert_eq!(vec.len(), 3);
    }

    #[test]
    fn test_read_all() {
        let (_, data) = create_data();

        let vec = data.read_all(::acquire::Source::IN1);

        #[cfg(features = "mock")]
        assert_eq!(vec, vec![]);

        #[cfg(not(features = "mock"))]
        assert!(vec.len() > 0);
    }

    #[test]
    fn test_read_oldest() {
        let (_, data) = create_data();

        let vec = data.read_oldest(::acquire::Source::IN1, 2);

        #[cfg(features = "mock")]
        assert_eq!(vec, vec![3.2, -1.2]);

        #[cfg(not(features = "mock"))]
        assert!(vec.len() > 0);
    }

    #[test]
    fn test_read_latest() {
        let (_, data) = create_data();

        let vec = data.read_latest(::acquire::Source::IN1, 2);

        #[cfg(features = "mock")]
        assert_eq!(vec, vec![1.2, 3.2]);

        #[cfg(not(features = "mock"))]
        assert!(vec.len() > 0);
    }

    #[test]
    fn test_buffer_size() {
        let (_, data) = create_data();

        assert_eq!(data.buffer_size(), Ok(16384));
    }

    fn create_data() -> (::std::sync::mpsc::Receiver<String>, ::data::Data) {
        let (addr, rx) = ::test::launch_server();
        let socket = ::socket::Socket::new(addr);

        (rx, ::data::Data::new(socket))
    }

    #[cfg(features = "mock")]
    fn acquire_start() {
    }

    #[cfg(not(features = "mock"))]
    fn acquire_start() {
        let (addr, _) = ::test::launch_server();
        let socket = ::socket::Socket::new(addr);

        let mut acquire = ::acquire::Acquire::new(socket);

        acquire.start();
    }
}
<commit_msg>Fix data format<commit_after>use Module;
use socket::Socket;

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Unit {
    RAW,
    VOLTS,
}

impl ::std::convert::Into<String> for Unit {
    fn into(self) -> String {
        let s = match self {
            Unit::RAW => "RAW",
            Unit::VOLTS => "VOLTS",
        };

        String::from(s)
    }
}

impl ::std::str::FromStr for Unit  {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "RAW" => Ok(Unit::RAW),
            "VOLTS" => Ok(Unit::VOLTS),
            unit => Err(format!("Unknow unit '{}'", unit)),
        }
    }
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Format {
    ASCII,
    BIN,
}

impl ::std::convert::Into<String> for Format {
    fn into(self) -> String {
        let s = match self {
            Format::ASCII => "ASCII",
            Format::BIN => "BIN",
        };

        String::from(s)
    }
}

#[derive(Clone)]
pub struct Data {
    socket: ::std::cell::RefCell<Socket>,
}

impl ::Module for Data {
    fn get_socket<'a>(&'a self) -> ::std::cell::RefMut<'a, ::socket::Socket> {
        self.socket.borrow_mut()
    }
}

impl Data {
    pub fn new(socket: Socket) -> Self {
        Data {
            socket: ::std::cell::RefCell::new(socket),
        }
    }

    /**
     * Returns current position of write pointer.
     */
    pub fn get_write_pointer(&self) -> Result<u32, <u32 as ::std::str::FromStr>::Err> {
        self.send("ACQ:WPOS?");

        self.receive()
            .parse()
    }

    /**
     * Returns position where trigger event appeared.
     */
    pub fn get_trigger_position(&self) -> Result<u32, <u32 as ::std::str::FromStr>::Err> {
        self.send("ACQ:TPOS?");

        self.receive()
            .parse()
    }

    /**
     * Selects units in which acquired data will be returned.
     */
    pub fn set_units(&self, unit: Unit) {
        self.send(format!("ACQ:DATA:UNITS {}", Into::<String>::into(unit)));
    }

    /**
     * Get units in which acquired data will be returned.
     */
    pub fn get_units(&self) -> Result<Unit, String> {
        self.send("ACQ:DATA:UNITS?");

        self.receive()
            .parse()
    }

    /**
     * Selects format acquired data will be returned.
     */
    pub fn set_format(&self, format: Format) {
        self.send(format!("ACQ:DATA:FORMAT {}", Into::<String>::into(format)));
    }

    /**
     * Read samples from start to stop position.
     *
     * start = {0,1,...,16384}
     * stop_pos = {0,1,...16384}
     */
    pub fn read_slice(&self, source: ::acquire::Source, start: u16, end: u16) -> Vec<f64> {
        self.send(format!("ACQ:{}:DATA:STA:END? {},{}", Into::<String>::into(source), start, end));

        self.parse(self.receive())
    }

    /**
     * Read `m` samples from start position on.
     */
    pub fn read(&self, source: ::acquire::Source, start: u16, len: u32) -> Vec<f64> {
        self.send(format!("ACQ:{}:DATA:STA:N? {},{}", Into::<String>::into(source), start, len));

        self.parse(self.receive())
    }

    /**
     * Read full buf.
     *
     * Size starting from oldest sample in buffer (this is first sample after
     * trigger delay). Trigger delay by default is set to zero (in samples or
     * in seconds). If trigger delay is set to zero it will read full buf.
     * Size starting from trigger.
     */
    pub fn read_all(&self, source: ::acquire::Source) -> Vec<f64> {
        self.send(format!("ACQ:{}:DATA?", Into::<String>::into(source)));

        self.parse(self.receive())
    }

    fn parse(&self, data: String) -> Vec<f64> {
        data.trim_matches(|c: char| c == '{' || c == '}' || c == '!' || c.is_alphabetic())
            .split(",")
            .map(|s| {
                match s.parse::<f64>() {
                    Ok(f) => f,
                    Err(_) => {
                        error!("Invalid data '{}'", s);
                        0.0
                    },
                }
            }).collect()
    }

    /**
     * Read m samples after trigger delay, starting from oldest sample in buffer
     * (this is first sample after trigger delay).
     *
     * Trigger delay by default is set to zero (in samples or in seconds). If
     * trigger delay is set to zero it will read m samples starting from trigger.
     */
    pub fn read_oldest(&self, source: ::acquire::Source, len: u32) -> Vec<f64> {
        self.send(format!("ACQ:{}:DATA:OLD:N? {}", Into::<String>::into(source), len));

        self.parse(self.receive())
    }

    /**
     * Read ``m`` samples before trigger delay.
     *
     * Trigger delay by default is set to zero (in samples or in seconds). If
     * trigger delay is set to zero it will read m samples before trigger.
     */
    pub fn read_latest(&self, source: ::acquire::Source, len: u32) -> Vec<f64> {
        self.send(format!("ACQ:{}:DATA:LAT:N? {}", Into::<String>::into(source), len));

        self.parse(self.receive())
    }

    /**
     * Returns buffer size.
     */
    pub fn buffer_size(&self) -> Result<u32, <u32 as ::std::str::FromStr>::Err> {
        self.send("ACQ:BUF:SIZE?");

        self.receive()
            .parse()
    }
}

#[cfg(test)]
mod test {
    #[test]
    fn test_get_write_pointer() {
        let (_, data) = create_data();

        #[cfg(features = "mock")]
        assert_eq!(data.get_write_pointer(), Ok(1024));

        #[cfg(not(features = "mock"))]
        assert!(data.get_write_pointer().is_ok());
    }

    #[test]
    fn test_get_write_pointer_at_trigger() {
        let (_, data) = create_data();

        #[cfg(features = "mock")]
        assert_eq!(data.get_trigger_position(), Ok(512));

        #[cfg(not(features = "mock"))]
        assert!(data.get_trigger_position().is_ok());
    }

    #[test]
    fn test_units() {
        let (rx, data) = create_data();

        data.set_units(::data::Unit::RAW);
        assert_eq!("ACQ:DATA:UNITS RAW\r\n", rx.recv().unwrap());

        assert_eq!(data.get_units(), Ok(::data::Unit::RAW));
    }

    #[test]
    fn test_set_format() {
        let (rx, data) = create_data();

        data.set_format(::data::Format::BIN);
        assert_eq!("ACQ:DATA:FORMAT BIN\r\n", rx.recv().unwrap());

        data.set_format(::data::Format::ASCII);
    }

    #[test]
    fn test_read_slice() {
        acquire_start();

        let (_, data) = create_data();

        let vec = data.read_slice(::acquire::Source::IN1, 10, 13);

        #[cfg(features = "mock")]
        assert_eq!(vec, vec![123.0, 231.0, -231.0]);

        #[cfg(not(features = "mock"))]
        assert_eq!(vec.len(), 3);
    }

    #[test]
    fn test_read() {
        let (_, data) = create_data();

        let vec = data.read(::acquire::Source::IN1, 10, 3);

        #[cfg(features = "mock")]
        assert_eq!(vec, vec![1.2, 3.2, -1.2]);

        #[cfg(not(features = "mock"))]
        assert_eq!(vec.len(), 3);
    }

    #[test]
    fn test_read_all() {
        let (_, data) = create_data();

        let vec = data.read_all(::acquire::Source::IN1);

        #[cfg(features = "mock")]
        assert_eq!(vec, vec![]);

        #[cfg(not(features = "mock"))]
        assert!(vec.len() > 0);
    }

    #[test]
    fn test_read_oldest() {
        let (_, data) = create_data();

        let vec = data.read_oldest(::acquire::Source::IN1, 2);

        #[cfg(features = "mock")]
        assert_eq!(vec, vec![3.2, -1.2]);

        #[cfg(not(features = "mock"))]
        assert!(vec.len() > 0);
    }

    #[test]
    fn test_read_latest() {
        let (_, data) = create_data();

        let vec = data.read_latest(::acquire::Source::IN1, 2);

        #[cfg(features = "mock")]
        assert_eq!(vec, vec![1.2, 3.2]);

        #[cfg(not(features = "mock"))]
        assert!(vec.len() > 0);
    }

    #[test]
    fn test_buffer_size() {
        let (_, data) = create_data();

        assert_eq!(data.buffer_size(), Ok(16384));
    }

    fn create_data() -> (::std::sync::mpsc::Receiver<String>, ::data::Data) {
        let (addr, rx) = ::test::launch_server();
        let socket = ::socket::Socket::new(addr);

        (rx, ::data::Data::new(socket))
    }

    #[cfg(features = "mock")]
    fn acquire_start() {
    }

    #[cfg(not(features = "mock"))]
    fn acquire_start() {
        let (addr, _) = ::test::launch_server();
        let socket = ::socket::Socket::new(addr);

        let mut acquire = ::acquire::Acquire::new(socket);

        acquire.start();
    }
}
<|endoftext|>


<commit_before>// failure-status: 101

// This is a repro test for an ICE in our pattern handling of constants.

const FOO: &&&u32 = &&&42;

fn main() {
    match unimplemented!() {
        &&&42 => {},
        FOO => {},
        _ => {},
    }
}
<commit_msg>Add 'rustc-env:RUST_BACKTRACE=0' to const-pat-ice test<commit_after>// failure-status: 101
// rustc-env:RUST_BACKTRACE=0

// This is a repro test for an ICE in our pattern handling of constants.

const FOO: &&&u32 = &&&42;

fn main() {
    match unimplemented!() {
        &&&42 => {},
        FOO => {},
        _ => {},
    }
}
<|endoftext|>


<commit_before>use std::sync::{Arc, Mutex};
use std::collections::HashMap;
use std::{fs, fmt, path};
use std::io::{self, Seek, SeekFrom, Write, Read};
use std::path::PathBuf;
use torrent::Info;
use slog::Logger;
use util::hash_to_id;
use ring::digest;
use amy;
use {handle, CONFIG};

const POLL_INT_MS: usize = 1000;

pub struct Disk {
    poll: amy::Poller,
    ch: handle::Handle<Request, Response>,
    l: Logger,
    files: FileCache,
}

#[derive(Clone)]
struct FileCache {
    files: Arc<Mutex<HashMap<path::PathBuf, fs::File>>>,
}

pub enum Request {
    Write {
        tid: usize,
        data: Box<[u8; 16384]>,
        locations: Vec<Location>,
    },
    Read {
        data: Box<[u8; 16384]>,
        locations: Vec<Location>,
        context: Ctx,
    },
    Serialize {
        tid: usize,
        data: Vec<u8>,
        hash: [u8; 20],
    },
    Delete { tid: usize, hash: [u8; 20] },
    Validate { tid: usize, info: Arc<Info> },
    Shutdown,
}

pub struct Ctx {
    pub pid: usize,
    pub tid: usize,
    pub idx: u32,
    pub begin: u32,
    pub length: u32,
}

impl Ctx {
    pub fn new(pid: usize, tid: usize, idx: u32, begin: u32, length: u32) -> Ctx {
        Ctx {
            pid,
            tid,
            idx,
            begin,
            length,
        }
    }
}

impl FileCache {
    pub fn new() -> FileCache {
        FileCache { files: Arc::new(Mutex::new(HashMap::new())) }
    }

    pub fn get_file<F: FnOnce(&mut fs::File) -> io::Result<()>>(
        &self,
        path: &path::Path,
        f: F,
    ) -> io::Result<()> {
        let mut d = self.files.lock().unwrap();
        if d.contains_key(path) {
            f(d.get_mut(path).unwrap())?;
        } else {
            let mut file = fs::OpenOptions::new()
                .write(true)
                .create(true)
                .read(true)
                .open(path)?;
            f(&mut file)?;
            d.insert(path.to_path_buf(), file);
        }
        Ok(())
    }
}

impl Request {
    pub fn write(tid: usize, data: Box<[u8; 16384]>, locations: Vec<Location>) -> Request {
        Request::Write {
            tid,
            data,
            locations,
        }
    }

    pub fn read(context: Ctx, data: Box<[u8; 16384]>, locations: Vec<Location>) -> Request {
        Request::Read {
            context,
            data,
            locations,
        }
    }

    pub fn serialize(tid: usize, data: Vec<u8>, hash: [u8; 20]) -> Request {
        Request::Serialize { tid, data, hash }
    }

    pub fn validate(tid: usize, info: Arc<Info>) -> Request {
        Request::Validate { tid, info }
    }

    pub fn delete(tid: usize, hash: [u8; 20]) -> Request {
        Request::Delete { tid, hash }
    }

    pub fn shutdown() -> Request {
        Request::Shutdown
    }

    fn execute(self, fc: FileCache) -> io::Result<Option<Response>> {
        let sd = &CONFIG.disk.session;
        let dd = &CONFIG.disk.directory;
        match self {
            Request::Write { data, locations, .. } => {
                let mut pb = path::PathBuf::from(dd);
                for loc in locations {
                    pb.push(&loc.file);
                    fc.get_file(&pb, |f| {
                        f.seek(SeekFrom::Start(loc.offset))?;
                        f.write(&data[loc.start..loc.end])?;
                        Ok(())
                    })?;
                    pb.pop();
                }
            }
            Request::Read {
                context,
                mut data,
                locations,
                ..
            } => {
                let mut pb = path::PathBuf::from(dd);
                for loc in locations {
                    pb.push(&loc.file);
                    fc.get_file(&pb, |f| {
                        f.seek(SeekFrom::Start(loc.offset))?;
                        f.read(&mut data[loc.start..loc.end])?;
                        Ok(())
                    })?;
                    pb.pop();
                }
                let data = Arc::new(data);
                return Ok(Some(Response::read(context, data)));
            }
            Request::Serialize { data, hash, .. } => {
                let mut pb = path::PathBuf::from(sd);
                pb.push(hash_to_id(&hash));
                let mut f = fs::OpenOptions::new().write(true).create(true).open(&pb)?;
                f.write(&data)?;
            }
            Request::Delete { hash, .. } => {
                let mut pb = path::PathBuf::from(sd);
                pb.push(hash_to_id(&hash));
                fs::remove_file(pb)?;
            }
            Request::Validate { tid, info } => {
                let mut invalid = Vec::new();
                let mut buf = vec![0u8; info.piece_len as usize];
                let mut pb = path::PathBuf::from(dd);

                let mut init_locs = info.piece_disk_locs(0);
                let mut cf = init_locs.remove(0).file;
                pb.push(&cf);
                let mut f = fs::OpenOptions::new().read(true).open(&pb)?;

                for i in 0..info.pieces() {
                    let mut ctx = digest::Context::new(&digest::SHA1);
                    let locs = info.piece_disk_locs(i);
                    for loc in locs {
                        if &loc.file != &cf {
                            pb.pop();
                            pb.push(&loc.file);
                            f = fs::OpenOptions::new().read(true).open(&pb)?;
                            cf = loc.file;
                        }
                        let amnt = f.read(&mut buf)?;
                        ctx.update(&buf[0..amnt]);
                    }
                    let digest = ctx.finish();
                    if digest.as_ref() != &info.hashes[i as usize][..] {
                        invalid.push(i);
                    }
                }
                return Ok(Some(Response::validation_complete(tid, invalid)));
            }
            Request::Shutdown => unreachable!(),
        }
        Ok(None)
    }

    pub fn tid(&self) -> usize {
        match *self {
            Request::Serialize { tid, .. } |
            Request::Validate { tid, .. } |
            Request::Delete { tid, .. } |
            Request::Write { tid, .. } => tid,
            Request::Read { ref context, .. } => context.tid,
            Request::Shutdown => unreachable!(),
        }
    }
}

impl fmt::Debug for Request {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "disk::Request")
    }
}

pub struct Location {
    pub file: PathBuf,
    pub offset: u64,
    pub start: usize,
    pub end: usize,
}

impl Location {
    pub fn new(file: PathBuf, offset: u64, start: usize, end: usize) -> Location {
        Location {
            file,
            offset,
            start,
            end,
        }
    }
}

pub enum Response {
    Read {
        context: Ctx,
        data: Arc<Box<[u8; 16384]>>,
    },
    ValidationComplete { tid: usize, invalid: Vec<u32> },
    Error { tid: usize, err: io::Error },
}

impl Response {
    pub fn read(context: Ctx, data: Arc<Box<[u8; 16384]>>) -> Response {
        Response::Read { context, data }
    }

    pub fn error(tid: usize, err: io::Error) -> Response {
        Response::Error { tid, err }
    }

    pub fn validation_complete(tid: usize, invalid: Vec<u32>) -> Response {
        Response::ValidationComplete { tid, invalid }
    }

    pub fn tid(&self) -> usize {
        match *self {
            Response::Read { ref context, .. } => context.tid,
            Response::ValidationComplete { tid, .. } |
            Response::Error { tid, .. } => tid,
        }
    }
}

impl fmt::Debug for Response {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "disk::Response")
    }
}

impl Disk {
    pub fn new(poll: amy::Poller, ch: handle::Handle<Request, Response>, l: Logger) -> Disk {
        Disk {
            poll,
            ch,
            l,
            files: FileCache::new(),
        }
    }

    pub fn run(&mut self) {
        let sd = &CONFIG.disk.session;
        fs::create_dir_all(sd).unwrap();

        loop {
            match self.poll.wait(POLL_INT_MS) {
                Ok(_) => {
                    if self.handle_events() {
                        break;
                    }
                }
                Err(e) => {
                    warn!(self.l, "Failed to poll for events: {:?}", e);
                }
            }
        }

    }

    pub fn handle_events(&mut self) -> bool {
        loop {
            match self.ch.recv() {
                Ok(Request::Shutdown) => {
                    return true;
                }
                Ok(r) => {
                    trace!(self.l, "Handling disk job!");
                    let tid = r.tid();
                    match r.execute(self.files.clone()) {
                        Ok(Some(r)) => {
                            self.ch.send(r).unwrap();
                        }
                        Ok(None) => {}
                        Err(e) => {
                            self.ch.send(Response::error(tid, e)).unwrap();
                        }
                    }
                }
                _ => break,
            }
        }
        false
    }
}

pub fn start(creg: &mut amy::Registrar) -> io::Result<handle::Handle<Response, Request>> {
    let poll = amy::Poller::new()?;
    let mut reg = poll.get_registrar()?;
    let (ch, dh) = handle::Handle::new(creg, &mut reg)?;
    dh.run("disk", move |h, l| Disk::new(poll, h, l).run());
    Ok(ch)
}
<commit_msg>Enforce max open file limit<commit_after>use std::sync::{Arc, Mutex};
use std::collections::HashMap;
use std::{fs, fmt, path};
use std::io::{self, Seek, SeekFrom, Write, Read};
use std::path::PathBuf;
use torrent::Info;
use slog::Logger;
use util::hash_to_id;
use ring::digest;
use amy;
use {handle, CONFIG};

const POLL_INT_MS: usize = 1000;

pub struct Disk {
    poll: amy::Poller,
    ch: handle::Handle<Request, Response>,
    l: Logger,
    files: FileCache,
}

#[derive(Clone)]
struct FileCache {
    files: Arc<Mutex<HashMap<path::PathBuf, fs::File>>>,
}

pub enum Request {
    Write {
        tid: usize,
        data: Box<[u8; 16384]>,
        locations: Vec<Location>,
    },
    Read {
        data: Box<[u8; 16384]>,
        locations: Vec<Location>,
        context: Ctx,
    },
    Serialize {
        tid: usize,
        data: Vec<u8>,
        hash: [u8; 20],
    },
    Delete { tid: usize, hash: [u8; 20] },
    Validate { tid: usize, info: Arc<Info> },
    Shutdown,
}

pub struct Ctx {
    pub pid: usize,
    pub tid: usize,
    pub idx: u32,
    pub begin: u32,
    pub length: u32,
}

impl Ctx {
    pub fn new(pid: usize, tid: usize, idx: u32, begin: u32, length: u32) -> Ctx {
        Ctx {
            pid,
            tid,
            idx,
            begin,
            length,
        }
    }
}

impl FileCache {
    pub fn new() -> FileCache {
        FileCache { files: Arc::new(Mutex::new(HashMap::new())) }
    }

    pub fn get_file<F: FnOnce(&mut fs::File) -> io::Result<()>>(
        &self,
        path: &path::Path,
        f: F,
    ) -> io::Result<()> {
        let mut d = self.files.lock().unwrap();
        if d.contains_key(path) {
            f(d.get_mut(path).unwrap())?;
        } else {
            // TODO: LRU maybe?
            if d.len() >= CONFIG.net.max_open_files {
                let removal = d.iter().map(|(id, _)| id.clone()).next().unwrap();
                d.remove(&removal);
            }
            let mut file = fs::OpenOptions::new()
                .write(true)
                .create(true)
                .read(true)
                .open(path)?;
            f(&mut file)?;
            d.insert(path.to_path_buf(), file);
        }
        Ok(())
    }
}

impl Request {
    pub fn write(tid: usize, data: Box<[u8; 16384]>, locations: Vec<Location>) -> Request {
        Request::Write {
            tid,
            data,
            locations,
        }
    }

    pub fn read(context: Ctx, data: Box<[u8; 16384]>, locations: Vec<Location>) -> Request {
        Request::Read {
            context,
            data,
            locations,
        }
    }

    pub fn serialize(tid: usize, data: Vec<u8>, hash: [u8; 20]) -> Request {
        Request::Serialize { tid, data, hash }
    }

    pub fn validate(tid: usize, info: Arc<Info>) -> Request {
        Request::Validate { tid, info }
    }

    pub fn delete(tid: usize, hash: [u8; 20]) -> Request {
        Request::Delete { tid, hash }
    }

    pub fn shutdown() -> Request {
        Request::Shutdown
    }

    fn execute(self, fc: FileCache) -> io::Result<Option<Response>> {
        let sd = &CONFIG.disk.session;
        let dd = &CONFIG.disk.directory;
        match self {
            Request::Write { data, locations, .. } => {
                let mut pb = path::PathBuf::from(dd);
                for loc in locations {
                    pb.push(&loc.file);
                    fc.get_file(&pb, |f| {
                        f.seek(SeekFrom::Start(loc.offset))?;
                        f.write(&data[loc.start..loc.end])?;
                        Ok(())
                    })?;
                    pb.pop();
                }
            }
            Request::Read {
                context,
                mut data,
                locations,
                ..
            } => {
                let mut pb = path::PathBuf::from(dd);
                for loc in locations {
                    pb.push(&loc.file);
                    fc.get_file(&pb, |f| {
                        f.seek(SeekFrom::Start(loc.offset))?;
                        f.read(&mut data[loc.start..loc.end])?;
                        Ok(())
                    })?;
                    pb.pop();
                }
                let data = Arc::new(data);
                return Ok(Some(Response::read(context, data)));
            }
            Request::Serialize { data, hash, .. } => {
                let mut pb = path::PathBuf::from(sd);
                pb.push(hash_to_id(&hash));
                let mut f = fs::OpenOptions::new().write(true).create(true).open(&pb)?;
                f.write(&data)?;
            }
            Request::Delete { hash, .. } => {
                let mut pb = path::PathBuf::from(sd);
                pb.push(hash_to_id(&hash));
                fs::remove_file(pb)?;
            }
            Request::Validate { tid, info } => {
                let mut invalid = Vec::new();
                let mut buf = vec![0u8; info.piece_len as usize];
                let mut pb = path::PathBuf::from(dd);

                let mut init_locs = info.piece_disk_locs(0);
                let mut cf = init_locs.remove(0).file;
                pb.push(&cf);
                let mut f = fs::OpenOptions::new().read(true).open(&pb)?;

                for i in 0..info.pieces() {
                    let mut ctx = digest::Context::new(&digest::SHA1);
                    let locs = info.piece_disk_locs(i);
                    for loc in locs {
                        if &loc.file != &cf {
                            pb.pop();
                            pb.push(&loc.file);
                            f = fs::OpenOptions::new().read(true).open(&pb)?;
                            cf = loc.file;
                        }
                        let amnt = f.read(&mut buf)?;
                        ctx.update(&buf[0..amnt]);
                    }
                    let digest = ctx.finish();
                    if digest.as_ref() != &info.hashes[i as usize][..] {
                        invalid.push(i);
                    }
                }
                return Ok(Some(Response::validation_complete(tid, invalid)));
            }
            Request::Shutdown => unreachable!(),
        }
        Ok(None)
    }

    pub fn tid(&self) -> usize {
        match *self {
            Request::Serialize { tid, .. } |
            Request::Validate { tid, .. } |
            Request::Delete { tid, .. } |
            Request::Write { tid, .. } => tid,
            Request::Read { ref context, .. } => context.tid,
            Request::Shutdown => unreachable!(),
        }
    }
}

impl fmt::Debug for Request {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "disk::Request")
    }
}

pub struct Location {
    pub file: PathBuf,
    pub offset: u64,
    pub start: usize,
    pub end: usize,
}

impl Location {
    pub fn new(file: PathBuf, offset: u64, start: usize, end: usize) -> Location {
        Location {
            file,
            offset,
            start,
            end,
        }
    }
}

pub enum Response {
    Read {
        context: Ctx,
        data: Arc<Box<[u8; 16384]>>,
    },
    ValidationComplete { tid: usize, invalid: Vec<u32> },
    Error { tid: usize, err: io::Error },
}

impl Response {
    pub fn read(context: Ctx, data: Arc<Box<[u8; 16384]>>) -> Response {
        Response::Read { context, data }
    }

    pub fn error(tid: usize, err: io::Error) -> Response {
        Response::Error { tid, err }
    }

    pub fn validation_complete(tid: usize, invalid: Vec<u32>) -> Response {
        Response::ValidationComplete { tid, invalid }
    }

    pub fn tid(&self) -> usize {
        match *self {
            Response::Read { ref context, .. } => context.tid,
            Response::ValidationComplete { tid, .. } |
            Response::Error { tid, .. } => tid,
        }
    }
}

impl fmt::Debug for Response {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "disk::Response")
    }
}

impl Disk {
    pub fn new(poll: amy::Poller, ch: handle::Handle<Request, Response>, l: Logger) -> Disk {
        Disk {
            poll,
            ch,
            l,
            files: FileCache::new(),
        }
    }

    pub fn run(&mut self) {
        let sd = &CONFIG.disk.session;
        fs::create_dir_all(sd).unwrap();

        loop {
            match self.poll.wait(POLL_INT_MS) {
                Ok(_) => {
                    if self.handle_events() {
                        break;
                    }
                }
                Err(e) => {
                    warn!(self.l, "Failed to poll for events: {:?}", e);
                }
            }
        }

    }

    pub fn handle_events(&mut self) -> bool {
        loop {
            match self.ch.recv() {
                Ok(Request::Shutdown) => {
                    return true;
                }
                Ok(r) => {
                    trace!(self.l, "Handling disk job!");
                    let tid = r.tid();
                    match r.execute(self.files.clone()) {
                        Ok(Some(r)) => {
                            self.ch.send(r).unwrap();
                        }
                        Ok(None) => {}
                        Err(e) => {
                            self.ch.send(Response::error(tid, e)).unwrap();
                        }
                    }
                }
                _ => break,
            }
        }
        false
    }
}

pub fn start(creg: &mut amy::Registrar) -> io::Result<handle::Handle<Response, Request>> {
    let poll = amy::Poller::new()?;
    let mut reg = poll.get_registrar()?;
    let (ch, dh) = handle::Handle::new(creg, &mut reg)?;
    dh.run("disk", move |h, l| Disk::new(poll, h, l).run());
    Ok(ch)
}
<|endoftext|>


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

//! 2D geometric primitives.

use std::cmp;
use std::f64;
use std::fmt;

// external
use usvg::{
    FuzzyEq
};
pub use usvg::{
    Line,
    Point,
    Rect,
    Size,
};

pub(crate) use usvg::{
    f64_bound,
};

// self
use utils;

/// A 2D screen size representation.
#[allow(missing_docs)]
#[derive(Clone, Copy, PartialEq)]
pub struct ScreenSize {
    pub width: u32,
    pub height: u32,
}

impl ScreenSize {
    /// Creates a new `ScreenSize` from values.
    pub fn new(width: u32, height: u32) -> Self {
        ScreenSize { width, height }
    }

    /// Scales current size to specified size.
    pub fn scale_to(&self, to: Self) -> Self {
        size_scale(*self, to, false)
    }

    /// Expands current size to specified size.
    pub fn expand_to(&self, to: ScreenSize) -> ScreenSize {
        size_scale(*self, to, true)
    }

    /// Converts the current `ScreenSize` to `Size`.
    pub fn to_size(&self) -> Size {
        Size::new(self.width as f64, self.height as f64)
    }
}

impl From<(u32, u32)> for ScreenSize {
    fn from(v: (u32, u32)) -> Self {
        ScreenSize::new(v.0, v.1)
    }
}

impl fmt::Debug for ScreenSize {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "ScreenSize({} {})", self.width, self.height)
    }
}

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

/// Additional `Size` methods.
pub trait SizeExt {
    /// Converts `Size` to `ScreenSize`.
    fn to_screen_size(&self) -> ScreenSize;
}

impl SizeExt for Size {
    fn to_screen_size(&self) -> ScreenSize {
        ScreenSize::new(self.width.round() as u32, self.height.round() as u32)
    }
}

fn size_scale(s1: ScreenSize, s2: ScreenSize, expand: bool) -> ScreenSize {
    let rw = (s2.height as f64 * s1.width as f64 / s1.height as f64).ceil() as u32;
    let with_h = if expand { rw <= s2.width } else { rw >= s2.width };
    if !with_h {
        ScreenSize::new(rw, s2.height)
    } else {
        let h = (s2.width as f64 * s1.height as f64 / s1.width as f64).ceil() as u32;
        ScreenSize::new(s2.width, h)
    }
}

/// Additional `Rect` methods.
pub trait RectExt: Sized {
    /// Creates a new `Rect` for bounding box calculation.
    ///
    /// Shorthand for `Rect::new(f64::MAX, f64::MAX, 1.0, 1.0)`.
    fn new_bbox() -> Self;

    /// Expands the `Rect` to the provided size.
    fn expand(&mut self, r: Rect);

    /// Transforms the `Rect` using the provided `bbox`.
    fn bbox_transform(&self, bbox: Rect) -> Option<Self>;

    /// Transforms the `Rect` using the provided `Transform`.
    ///
    /// This method is expensive.
    fn transform(&self, ts: &usvg::Transform) -> Self;

    /// Returns rect's size in screen units.
    fn to_screen_size(&self) -> ScreenSize;

    /// Returns rect in screen units.
    fn to_screen_rect(&self) -> ScreenRect;
}

impl RectExt for Rect {
    fn new_bbox() -> Self {
        (f64::MAX, f64::MAX, 1.0, 1.0).into()
    }

    fn expand(&mut self, r: Rect) {
        if !r.is_valid() {
            return;
        }

        if self.fuzzy_eq(&Rect::new_bbox()) {
            *self = r;
        } else {
            let x1 = f64_min(self.x, r.x);
            let y1 = f64_min(self.y, r.y);

            let x2 = f64_max(self.right(), r.right());
            let y2 = f64_max(self.bottom(), r.bottom());

            self.x = x1;
            self.y = y1;
            self.width = x2 - x1;
            self.height = y2 - y1;
        }
    }

    fn bbox_transform(&self, bbox: Rect) -> Option<Self> {
        if bbox.is_valid() {
            let x = self.x * bbox.width + bbox.x;
            let y = self.y * bbox.height + bbox.y;
            let w = self.width * bbox.width;
            let h = self.height * bbox.height;

            Some(Self::new(x, y, w, h))
        } else {
            None
        }
    }

    fn transform(&self, ts: &usvg::Transform) -> Self {
        if !ts.is_default() {
            let path = &[
                usvg::PathSegment::MoveTo {
                    x: self.x, y: self.y
                },
                usvg::PathSegment::LineTo {
                    x: self.right(), y: self.y
                },
                usvg::PathSegment::LineTo {
                    x: self.right(), y: self.bottom()
                },
                usvg::PathSegment::LineTo {
                    x: self.x, y: self.bottom()
                },
                usvg::PathSegment::ClosePath,
            ];

            utils::path_bbox(path, None, ts)
        } else {
            *self
        }
    }

    fn to_screen_size(&self) -> ScreenSize {
        self.size().to_screen_size()
    }

    fn to_screen_rect(&self) -> ScreenRect {
        ScreenRect::new(self.x as i32, self.y as i32,
                        cmp::max(0, self.width as i32) as u32,
                        cmp::max(0, self.height as i32) as u32)
    }
}

/// A 2D screen rect representation.
#[allow(missing_docs)]
#[derive(Clone, Copy, PartialEq)]
pub struct ScreenRect {
    pub x: i32,
    pub y: i32,
    pub width: u32,
    pub height: u32,
}

impl ScreenRect {
    /// Creates a new `Rect` from values.
    pub fn new(x: i32, y: i32, width: u32, height: u32) -> Self {
        ScreenRect { x, y, width, height }
    }

    /// Returns rect's size.
    pub fn size(&self) -> ScreenSize {
        ScreenSize::new(self.width, self.height)
    }

    /// Returns rect's left edge position.
    pub fn left(&self) -> i32 {
        self.x
    }

    /// Returns rect's right edge position.
    pub fn right(&self) -> i32 {
        self.x + self.width as i32
    }

    /// Returns rect's top edge position.
    pub fn top(&self) -> i32 {
        self.y
    }

    /// Returns rect's bottom edge position.
    pub fn bottom(&self) -> i32 {
        self.y + self.height as i32
    }

    /// Checks that rect contains a point.
    pub fn contains(&self, x: i32, y: i32) -> bool {
        if x < self.x || x > self.x + self.width as i32 - 1 {
            return false;
        }

        if y < self.y || y > self.y + self.height as i32 - 1 {
            return false;
        }

        true
    }

    /// Fits the current rect into the specified bounds.
    pub fn fit_to_rect(&self, bounds: ScreenRect) -> Self {
        let mut r = *self;

        if r.x < 0 { r.x = 0; }
        if r.y < 0 { r.y = 0; }

        if r.right() > bounds.width as i32 {
            r.width = cmp::max(0, bounds.width as i32 - r.x) as u32;
        }

        if r.bottom() > bounds.height as i32 {
            r.height = cmp::max(0, bounds.height as i32 - r.y) as u32;
        }

        r
    }

    /// Converts into `Rect`.
    pub fn to_rect(&self) -> Rect {
        Rect::new(self.x as f64, self.y as f64, self.width as f64, self.height as f64)
    }

    /// Checks that the rect has a valid size.
    pub fn is_valid(&self) -> bool {
        self.width > 0 && self.height > 0
    }
}

impl fmt::Debug for ScreenRect {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "ScreenRect({} {} {} {})", self.x, self.y, self.width, self.height)
    }
}

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

impl From<(i32, i32, u32, u32)> for ScreenRect {
    fn from(v: (i32, i32, u32, u32)) -> Self {
        Self::new(v.0, v.1, v.2, v.3)
    }
}

#[inline]
fn f64_min(v1: f64, v2: f64) -> f64 {
    if v1 < v2 { v1 } else { v2 }
}

#[inline]
fn f64_max(v1: f64, v2: f64) -> f64 {
    if v1 > v2 { v1 } else { v2 }
}

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

    #[test]
    fn bbox_transform_1() {
        let r = Rect::new(10.0, 20.0, 30.0, 40.0);
        assert!(r.bbox_transform(Rect::new(0.2, 0.3, 0.4, 0.5)).unwrap()
                 .fuzzy_eq(&Rect::new(4.2, 10.3, 12.0, 20.0)));
    }
}
<commit_msg>Fixed build with an old Rust version.<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

//! 2D geometric primitives.

use std::cmp;
use std::f64;
use std::fmt;

// external
use usvg::{
    self,
    FuzzyEq,
};
pub use usvg::{
    Line,
    Point,
    Rect,
    Size,
};

pub(crate) use usvg::{
    f64_bound,
};

// self
use utils;

/// A 2D screen size representation.
#[allow(missing_docs)]
#[derive(Clone, Copy, PartialEq)]
pub struct ScreenSize {
    pub width: u32,
    pub height: u32,
}

impl ScreenSize {
    /// Creates a new `ScreenSize` from values.
    pub fn new(width: u32, height: u32) -> Self {
        ScreenSize { width, height }
    }

    /// Scales current size to specified size.
    pub fn scale_to(&self, to: Self) -> Self {
        size_scale(*self, to, false)
    }

    /// Expands current size to specified size.
    pub fn expand_to(&self, to: ScreenSize) -> ScreenSize {
        size_scale(*self, to, true)
    }

    /// Converts the current `ScreenSize` to `Size`.
    pub fn to_size(&self) -> Size {
        Size::new(self.width as f64, self.height as f64)
    }
}

impl From<(u32, u32)> for ScreenSize {
    fn from(v: (u32, u32)) -> Self {
        ScreenSize::new(v.0, v.1)
    }
}

impl fmt::Debug for ScreenSize {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "ScreenSize({} {})", self.width, self.height)
    }
}

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

/// Additional `Size` methods.
pub trait SizeExt {
    /// Converts `Size` to `ScreenSize`.
    fn to_screen_size(&self) -> ScreenSize;
}

impl SizeExt for Size {
    fn to_screen_size(&self) -> ScreenSize {
        ScreenSize::new(self.width.round() as u32, self.height.round() as u32)
    }
}

fn size_scale(s1: ScreenSize, s2: ScreenSize, expand: bool) -> ScreenSize {
    let rw = (s2.height as f64 * s1.width as f64 / s1.height as f64).ceil() as u32;
    let with_h = if expand { rw <= s2.width } else { rw >= s2.width };
    if !with_h {
        ScreenSize::new(rw, s2.height)
    } else {
        let h = (s2.width as f64 * s1.height as f64 / s1.width as f64).ceil() as u32;
        ScreenSize::new(s2.width, h)
    }
}

/// Additional `Rect` methods.
pub trait RectExt: Sized {
    /// Creates a new `Rect` for bounding box calculation.
    ///
    /// Shorthand for `Rect::new(f64::MAX, f64::MAX, 1.0, 1.0)`.
    fn new_bbox() -> Self;

    /// Expands the `Rect` to the provided size.
    fn expand(&mut self, r: Rect);

    /// Transforms the `Rect` using the provided `bbox`.
    fn bbox_transform(&self, bbox: Rect) -> Option<Self>;

    /// Transforms the `Rect` using the provided `Transform`.
    ///
    /// This method is expensive.
    fn transform(&self, ts: &usvg::Transform) -> Self;

    /// Returns rect's size in screen units.
    fn to_screen_size(&self) -> ScreenSize;

    /// Returns rect in screen units.
    fn to_screen_rect(&self) -> ScreenRect;
}

impl RectExt for Rect {
    fn new_bbox() -> Self {
        (f64::MAX, f64::MAX, 1.0, 1.0).into()
    }

    fn expand(&mut self, r: Rect) {
        if !r.is_valid() {
            return;
        }

        if self.fuzzy_eq(&Rect::new_bbox()) {
            *self = r;
        } else {
            let x1 = f64_min(self.x, r.x);
            let y1 = f64_min(self.y, r.y);

            let x2 = f64_max(self.right(), r.right());
            let y2 = f64_max(self.bottom(), r.bottom());

            self.x = x1;
            self.y = y1;
            self.width = x2 - x1;
            self.height = y2 - y1;
        }
    }

    fn bbox_transform(&self, bbox: Rect) -> Option<Self> {
        if bbox.is_valid() {
            let x = self.x * bbox.width + bbox.x;
            let y = self.y * bbox.height + bbox.y;
            let w = self.width * bbox.width;
            let h = self.height * bbox.height;

            Some(Self::new(x, y, w, h))
        } else {
            None
        }
    }

    fn transform(&self, ts: &usvg::Transform) -> Self {
        if !ts.is_default() {
            let path = &[
                usvg::PathSegment::MoveTo {
                    x: self.x, y: self.y
                },
                usvg::PathSegment::LineTo {
                    x: self.right(), y: self.y
                },
                usvg::PathSegment::LineTo {
                    x: self.right(), y: self.bottom()
                },
                usvg::PathSegment::LineTo {
                    x: self.x, y: self.bottom()
                },
                usvg::PathSegment::ClosePath,
            ];

            utils::path_bbox(path, None, ts)
        } else {
            *self
        }
    }

    fn to_screen_size(&self) -> ScreenSize {
        self.size().to_screen_size()
    }

    fn to_screen_rect(&self) -> ScreenRect {
        ScreenRect::new(self.x as i32, self.y as i32,
                        cmp::max(0, self.width as i32) as u32,
                        cmp::max(0, self.height as i32) as u32)
    }
}

/// A 2D screen rect representation.
#[allow(missing_docs)]
#[derive(Clone, Copy, PartialEq)]
pub struct ScreenRect {
    pub x: i32,
    pub y: i32,
    pub width: u32,
    pub height: u32,
}

impl ScreenRect {
    /// Creates a new `Rect` from values.
    pub fn new(x: i32, y: i32, width: u32, height: u32) -> Self {
        ScreenRect { x, y, width, height }
    }

    /// Returns rect's size.
    pub fn size(&self) -> ScreenSize {
        ScreenSize::new(self.width, self.height)
    }

    /// Returns rect's left edge position.
    pub fn left(&self) -> i32 {
        self.x
    }

    /// Returns rect's right edge position.
    pub fn right(&self) -> i32 {
        self.x + self.width as i32
    }

    /// Returns rect's top edge position.
    pub fn top(&self) -> i32 {
        self.y
    }

    /// Returns rect's bottom edge position.
    pub fn bottom(&self) -> i32 {
        self.y + self.height as i32
    }

    /// Checks that rect contains a point.
    pub fn contains(&self, x: i32, y: i32) -> bool {
        if x < self.x || x > self.x + self.width as i32 - 1 {
            return false;
        }

        if y < self.y || y > self.y + self.height as i32 - 1 {
            return false;
        }

        true
    }

    /// Fits the current rect into the specified bounds.
    pub fn fit_to_rect(&self, bounds: ScreenRect) -> Self {
        let mut r = *self;

        if r.x < 0 { r.x = 0; }
        if r.y < 0 { r.y = 0; }

        if r.right() > bounds.width as i32 {
            r.width = cmp::max(0, bounds.width as i32 - r.x) as u32;
        }

        if r.bottom() > bounds.height as i32 {
            r.height = cmp::max(0, bounds.height as i32 - r.y) as u32;
        }

        r
    }

    /// Converts into `Rect`.
    pub fn to_rect(&self) -> Rect {
        Rect::new(self.x as f64, self.y as f64, self.width as f64, self.height as f64)
    }

    /// Checks that the rect has a valid size.
    pub fn is_valid(&self) -> bool {
        self.width > 0 && self.height > 0
    }
}

impl fmt::Debug for ScreenRect {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "ScreenRect({} {} {} {})", self.x, self.y, self.width, self.height)
    }
}

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

impl From<(i32, i32, u32, u32)> for ScreenRect {
    fn from(v: (i32, i32, u32, u32)) -> Self {
        Self::new(v.0, v.1, v.2, v.3)
    }
}

#[inline]
fn f64_min(v1: f64, v2: f64) -> f64 {
    if v1 < v2 { v1 } else { v2 }
}

#[inline]
fn f64_max(v1: f64, v2: f64) -> f64 {
    if v1 > v2 { v1 } else { v2 }
}

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

    #[test]
    fn bbox_transform_1() {
        let r = Rect::new(10.0, 20.0, 30.0, 40.0);
        assert!(r.bbox_transform(Rect::new(0.2, 0.3, 0.4, 0.5)).unwrap()
                 .fuzzy_eq(&Rect::new(4.2, 10.3, 12.0, 20.0)));
    }
}
<|endoftext|>