<commit_before>#![allow(clippy::upper_case_acronyms)]

use anyhow::{anyhow, Result};
use clap::clap_app;
use log::{debug, error, info};

use lancelot::{
    analysis::{
        cfg::{InstructionIndex, CFG},
        dis,
        dis::zydis,
    },
    aspace::AddressSpace,
    loader::pe::PE,
    util,
    workspace::{formatter::Formatter, PEWorkspace},
    RVA, VA,
};

fn handle_functions(ws: &PEWorkspace) -> Result<()> {
    info!("found {} functions", ws.analysis.functions.len());
    for va in ws.analysis.functions.keys() {
        println!("{:#x}", va);
    }

    Ok(())
}

fn handle_disassemble(ws: &PEWorkspace, va: VA) -> Result<()> {
    let mut blocks = ws.cfg.get_reachable_blocks(va).collect::<Vec<_>>();
    blocks.sort_unstable_by_key(|&bb| bb.address);
    info!("found {} basic blocks", blocks.len());

    let decoder = dis::get_disassembler(&ws.pe.module).unwrap();
    let fmt = Formatter::new().with_colors(true).build();

    for bb in blocks.into_iter() {
        // need to over-read the bb buffer, to account for the final instructions.
        let buf = ws
            .pe
            .module
            .address_space
            .read_bytes(bb.address, bb.length as usize + 0x10)?;
        for (offset, insn) in dis::linear_disassemble(&decoder, &buf) {
            // because we over-read the bb buffer,
            // discard the instructions found after it.
            if offset >= bb.length as usize {
                break;
            }

            if let Ok(Some(insn)) = insn {
                let va = bb.address + offset as RVA;
                println!("{}", fmt.format_instruction(ws, &insn, va)?);
            }
        }
        println!();
    }

    Ok(())
}

fn parse_va(s: &str) -> Result<VA> {
    if s.starts_with("0x") {
        let without_prefix = s.trim_start_matches("0x");
        Ok(u64::from_str_radix(without_prefix, 16)?)
    } else {
        Ok(s.parse()?)
    }
}

fn _main() -> Result<()> {
    better_panic::install();

    let matches = clap::clap_app!(lancelot =>
        (author: "Willi Ballenthin <william.ballenthin@mandiant.com>")
        (about: "Binary analysis framework")
        (@arg verbose: -v --verbose +multiple "log verbose messages")
        (@arg quiet: -q --quiet "disable informational messages")
        (@subcommand functions =>
            (about: "find functions")
            (@arg input: +required "path to file to analyze"))
        (@subcommand disassemble =>
            (about: "disassemble function")
            (@arg input: +required "path to file to analyze")
            (@arg va: +required "VA of function")))
    .get_matches();

    // --quiet overrides --verbose
    let log_level = if matches.is_present("quiet") {
        log::LevelFilter::Error
    } else {
        match matches.occurrences_of("verbose") {
            0 => log::LevelFilter::Info,
            1 => log::LevelFilter::Debug,
            2 => log::LevelFilter::Trace,
            _ => log::LevelFilter::Trace,
        }
    };

    fern::Dispatch::new()
        .format(move |out, message, record| {
            out.finish(format_args!(
                "{} [{:5}] {} {}",
                chrono::Local::now().format("%Y-%m-%d %H:%M:%S"),
                record.level(),
                if log_level == log::LevelFilter::Trace {
                    record.target()
                } else {
                    ""
                },
                message
            ))
        })
        .level(log_level)
        .chain(std::io::stderr())
        .filter(|metadata| !metadata.target().starts_with("goblin::pe"))
        .apply()
        .expect("failed to configure logging");

    // Enable ANSI support for Windows
    // via: https://github.com/sharkdp/hexyl/blob/d1ae68585fe743d225bb39361bd383cb925b61f7/src/bin/hexyl.rs#L261
    #[cfg(windows)]
    let _ = ansi_term::enable_ansi_support();

    if let Some(matches) = matches.subcommand_matches("functions") {
        debug!("mode: find functions");

        let filename = matches.value_of("input").unwrap();
        debug!("input: {}", filename);

        let buf = util::read_file(filename)?;
        let pe = PE::from_bytes(&buf)?;
        let ws = PEWorkspace::from_pe(pe)?;

        handle_functions(&ws)
    } else if let Some(matches) = matches.subcommand_matches("disassemble") {
        debug!("mode: disassemble");

        let filename = matches.value_of("input").unwrap();
        debug!("input: {}", filename);

        let va = parse_va(matches.value_of("va").unwrap())?;

        let buf = util::read_file(filename)?;
        let pe = PE::from_bytes(&buf)?;
        let ws = PEWorkspace::from_pe(pe)?;

        handle_disassemble(&ws, va)
    } else {
        Err(anyhow!("SUBCOMMAND required"))
    }
}

fn main() {
    if let Err(e) = _main() {
        #[cfg(debug_assertions)]
        error!("{:?}", e);
        #[cfg(not(debug_assertions))]
        error!("{:}", e);
    }
}
<commit_msg>clippy<commit_after>#![allow(clippy::upper_case_acronyms)]

use anyhow::{anyhow, Result};
use clap::clap_app;
use log::{debug, error, info};

use lancelot::{
    analysis::dis,
    aspace::AddressSpace,
    loader::pe::PE,
    util,
    workspace::{formatter::Formatter, PEWorkspace},
    RVA, VA,
};

fn handle_functions(ws: &PEWorkspace) -> Result<()> {
    info!("found {} functions", ws.analysis.functions.len());
    for va in ws.analysis.functions.keys() {
        println!("{:#x}", va);
    }

    Ok(())
}

fn handle_disassemble(ws: &PEWorkspace, va: VA) -> Result<()> {
    let mut blocks = ws.cfg.get_reachable_blocks(va).collect::<Vec<_>>();
    blocks.sort_unstable_by_key(|&bb| bb.address);
    info!("found {} basic blocks", blocks.len());

    let decoder = dis::get_disassembler(&ws.pe.module).unwrap();
    let fmt = Formatter::new().with_colors(true).build();

    for bb in blocks.into_iter() {
        // need to over-read the bb buffer, to account for the final instructions.
        let buf = ws
            .pe
            .module
            .address_space
            .read_bytes(bb.address, bb.length as usize + 0x10)?;
        for (offset, insn) in dis::linear_disassemble(&decoder, &buf) {
            // because we over-read the bb buffer,
            // discard the instructions found after it.
            if offset >= bb.length as usize {
                break;
            }

            if let Ok(Some(insn)) = insn {
                let va = bb.address + offset as RVA;
                println!("{}", fmt.format_instruction(ws, &insn, va)?);
            }
        }
        println!();
    }

    Ok(())
}

fn parse_va(s: &str) -> Result<VA> {
    if s.starts_with("0x") {
        let without_prefix = s.trim_start_matches("0x");
        Ok(u64::from_str_radix(without_prefix, 16)?)
    } else {
        Ok(s.parse()?)
    }
}

fn _main() -> Result<()> {
    better_panic::install();

    let matches = clap::clap_app!(lancelot =>
        (author: "Willi Ballenthin <william.ballenthin@mandiant.com>")
        (about: "Binary analysis framework")
        (@arg verbose: -v --verbose +multiple "log verbose messages")
        (@arg quiet: -q --quiet "disable informational messages")
        (@subcommand functions =>
            (about: "find functions")
            (@arg input: +required "path to file to analyze"))
        (@subcommand disassemble =>
            (about: "disassemble function")
            (@arg input: +required "path to file to analyze")
            (@arg va: +required "VA of function")))
    .get_matches();

    // --quiet overrides --verbose
    let log_level = if matches.is_present("quiet") {
        log::LevelFilter::Error
    } else {
        match matches.occurrences_of("verbose") {
            0 => log::LevelFilter::Info,
            1 => log::LevelFilter::Debug,
            2 => log::LevelFilter::Trace,
            _ => log::LevelFilter::Trace,
        }
    };

    fern::Dispatch::new()
        .format(move |out, message, record| {
            out.finish(format_args!(
                "{} [{:5}] {} {}",
                chrono::Local::now().format("%Y-%m-%d %H:%M:%S"),
                record.level(),
                if log_level == log::LevelFilter::Trace {
                    record.target()
                } else {
                    ""
                },
                message
            ))
        })
        .level(log_level)
        .chain(std::io::stderr())
        .filter(|metadata| !metadata.target().starts_with("goblin::pe"))
        .apply()
        .expect("failed to configure logging");

    // Enable ANSI support for Windows
    // via: https://github.com/sharkdp/hexyl/blob/d1ae68585fe743d225bb39361bd383cb925b61f7/src/bin/hexyl.rs#L261
    #[cfg(windows)]
    let _ = ansi_term::enable_ansi_support();

    if let Some(matches) = matches.subcommand_matches("functions") {
        debug!("mode: find functions");

        let filename = matches.value_of("input").unwrap();
        debug!("input: {}", filename);

        let buf = util::read_file(filename)?;
        let pe = PE::from_bytes(&buf)?;
        let ws = PEWorkspace::from_pe(pe)?;

        handle_functions(&ws)
    } else if let Some(matches) = matches.subcommand_matches("disassemble") {
        debug!("mode: disassemble");

        let filename = matches.value_of("input").unwrap();
        debug!("input: {}", filename);

        let va = parse_va(matches.value_of("va").unwrap())?;

        let buf = util::read_file(filename)?;
        let pe = PE::from_bytes(&buf)?;
        let ws = PEWorkspace::from_pe(pe)?;

        handle_disassemble(&ws, va)
    } else {
        Err(anyhow!("SUBCOMMAND required"))
    }
}

fn main() {
    if let Err(e) = _main() {
        #[cfg(debug_assertions)]
        error!("{:?}", e);
        #[cfg(not(debug_assertions))]
        error!("{:}", e);
    }
}
<|endoftext|>


<commit_before>//
// Copyright 2022 The Project Oak Authors
//
// 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 crate::fw_cfg::FwCfg;
use core::{
    ffi::CStr,
    mem::{size_of, MaybeUninit},
};
use oak_linux_boot_params::{BootE820Entry, BootParams};

#[link_section = ".boot.zero_page"]
static mut BOOT_ZERO_PAGE: MaybeUninit<BootParams> = MaybeUninit::uninit();

pub fn init_zero_page(fw_cfg: &mut FwCfg) -> &'static mut BootParams {
    let mut zero_page = unsafe { BOOT_ZERO_PAGE.write(core::mem::zeroed()) };

    // Magic constants.
    // See https://www.kernel.org/doc/html/latest/x86/boot.html#the-real-mode-kernel-header for more details.
    zero_page.hdr.type_of_loader = 0xFF; // loader type undefined
    zero_page.hdr.boot_flag = 0xAA55; // magic number
    zero_page.hdr.header = 0x53726448; // Magic "HdrS" string
    zero_page.hdr.kernel_alignment = 0x1000000; // Magic number from crosvm source.

    // Load the E820 table from fw_cfg.
    // Safety: BootE820Entry has the same structure as what qemu uses, and we're limiting
    // ourselves to up to 128 entries.
    let len_bytes = unsafe {
        fw_cfg.read_file_by_name(
            CStr::from_bytes_with_nul(b"etc/e820\0").unwrap(),
            &mut zero_page.e820_table,
        )
    }
    .unwrap();
    zero_page.e820_entries = (len_bytes / size_of::<BootE820Entry>()) as u8;

    for entry in zero_page.e820_table() {
        log::debug!(
            "early E820 entry: start {:#018x}, len {}, type {}",
            entry.addr(),
            entry.size(),
            entry.entry_type().unwrap()
        );
    }

    zero_page
}

/// Returns a mutable reference to the zero page, which we assume is initialized.
///
/// # Safety
///
/// This assumes the VMM has set up the zero page for us. Calling this function without the memory
/// set up correctly is undefined behaviour.
pub unsafe fn get_zero_page() -> &'static mut BootParams {
    BOOT_ZERO_PAGE.assume_init_mut()
}
<commit_msg>Sort E820 entries by address in stage0.<commit_after>//
// Copyright 2022 The Project Oak Authors
//
// 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 crate::fw_cfg::FwCfg;
use core::{
    ffi::CStr,
    mem::{size_of, MaybeUninit},
};
use oak_linux_boot_params::{BootE820Entry, BootParams};

#[link_section = ".boot.zero_page"]
static mut BOOT_ZERO_PAGE: MaybeUninit<BootParams> = MaybeUninit::uninit();

pub fn init_zero_page(fw_cfg: &mut FwCfg) -> &'static mut BootParams {
    let mut zero_page = unsafe { BOOT_ZERO_PAGE.write(core::mem::zeroed()) };

    // Magic constants.
    // See https://www.kernel.org/doc/html/latest/x86/boot.html#the-real-mode-kernel-header for more details.
    zero_page.hdr.type_of_loader = 0xFF; // loader type undefined
    zero_page.hdr.boot_flag = 0xAA55; // magic number
    zero_page.hdr.header = 0x53726448; // Magic "HdrS" string
    zero_page.hdr.kernel_alignment = 0x1000000; // Magic number from crosvm source.

    // Load the E820 table from fw_cfg.
    // Safety: BootE820Entry has the same structure as what qemu uses, and we're limiting
    // ourselves to up to 128 entries.
    let len_bytes = unsafe {
        fw_cfg.read_file_by_name(
            CStr::from_bytes_with_nul(b"etc/e820\0").unwrap(),
            &mut zero_page.e820_table,
        )
    }
    .unwrap();
    zero_page.e820_entries = (len_bytes / size_of::<BootE820Entry>()) as u8;
    zero_page.e820_table[..(zero_page.e820_entries as usize)].sort_unstable_by_key(|x| x.addr());
    for entry in zero_page.e820_table() {
        log::debug!(
            "early E820 entry: [{:#018x}-{:#018x}), len {}, type {}",
            entry.addr(),
            entry.addr() + entry.size(),
            entry.size(),
            entry.entry_type().unwrap()
        );
    }

    zero_page
}

/// Returns a mutable reference to the zero page, which we assume is initialized.
///
/// # Safety
///
/// This assumes the VMM has set up the zero page for us. Calling this function without the memory
/// set up correctly is undefined behaviour.
pub unsafe fn get_zero_page() -> &'static mut BootParams {
    BOOT_ZERO_PAGE.assume_init_mut()
}
<|endoftext|>


<commit_before>use events;
use events::Event;
use pipeline::chain::{ChainedElement,PipelineElement};
use serde;

pub struct FixedPropertyEnricher {
    name: &'static str,
    value: String
}

impl FixedPropertyEnricher {
    pub fn new<T: serde::ser::Serialize>(name: &'static str, value: &T) -> FixedPropertyEnricher {
        FixedPropertyEnricher { name: name, value: events::capture_property_value(value) }
    }
}

impl PipelineElement for FixedPropertyEnricher {
    fn emit(&self, event: Event<'static>, next: &ChainedElement) {
        let mut e = event;
        e.add_or_update_property(self.name, self.value.clone());
        next.emit(e);
    }
}
<commit_msg>Tiny advancement - remove static bound on FixedPropertyEnricher property name (#12)<commit_after>use events;
use events::Event;
use pipeline::chain::{ChainedElement,PipelineElement};
use serde;

pub struct FixedPropertyEnricher<'a> {
    name: &'a str,
    value: String
}

impl<'a> FixedPropertyEnricher<'a> {
    pub fn new<T: serde::ser::Serialize>(name: &'a str, value: &T) -> FixedPropertyEnricher<'a> {
        FixedPropertyEnricher { name: name, value: events::capture_property_value(value) }
    }
}

impl PipelineElement for FixedPropertyEnricher<'static> {
    fn emit(&self, event: Event<'static>, next: &ChainedElement) {
        let mut e = event;
        e.add_or_update_property(self.name, self.value.clone());
        next.emit(e);
    }
}
<|endoftext|>


<commit_before>use crate::calculate::*;
use std::path::PathBuf;
use std::io;
#[cfg(test)]
use std::path::Path;
use thiserror::Error;

#[derive(Debug, Error)]
pub enum IOError {
    #[error("ReadErr: The file cannot be read.\nFilepath: {}\nOriginating Exception:{}", .0.to_string_lossy().into_owned(), .1.as_ref().map_or("None".to_owned(), |e| format!("{}", e)))]
    ReadErr(PathBuf, Option<io::Error>),
    #[error("MissingFilenameErr: The path provided does not specify a file.\nFilepath: {}", .0.to_string_lossy().into_owned())]
    MissingFilenameErr(PathBuf),
    #[error("FilenameNotUnicodeErr: The filename is not expressible in unicode. Consider renaming the file.\nFilepath: {}", .0.to_string_lossy().into_owned())]
    FilenameNotUnicodeErr(PathBuf),
    #[error("BadFileContentsErr: Check that the file exists and is readable.\nFilepath: {}\nOriginating Exception:{}", .0.to_string_lossy().into_owned(), .1.as_ref().map_or("None".to_owned(), |e| format!("{}", e)))]
    BadFileContentsErr(PathBuf, Option<io::Error>),
    #[error("CommandErr: System command failed to run.\nOriginating Exception: {}", .0.as_ref().map_or("None".to_owned(), |e| format!("{}", e)))]
    CommandErr(Option<io::Error>),
}

#[derive(Debug, Error)]
pub enum CalculateError {
    #[error("BadJSONErr: JSON in file cannot be deserialized as expected.\nFilepath: {}\nOriginating Exception:{}", .0.to_string_lossy().into_owned(), .1.as_ref().map_or("None".to_owned(), |e| format!("{}", e)))]
    BadJSONErr(PathBuf, Option<serde_json::Error>),
    #[error("{}", .0)]
    CalculateIOError(IOError),
    #[error("NoResultsErr: The results directory has no json files in it.\nFilepath: {}", .0.to_string_lossy().into_owned())]
    NoResultsErr(PathBuf),
    #[error("OddResultsCountErr: The results directory has an odd number of results in it. Expected an even number.\nFile Count: {}\nFilepath: {}", .0, .1.to_string_lossy().into_owned())]
    OddResultsCountErr(usize, PathBuf),
    #[error("BadGroupSizeErr: Expected two results per group, one for each branch-project pair.\nCount: {}\nGroup: {:?}", .0, .1.into_iter().map(|group| (&group.version[..], &group.run[..])).collect::<Vec<(&str, &str)>>())]
    BadGroupSizeErr(usize, Vec<MeasurementGroup>),
    #[error("BadBranchNameErr: Branch names must be 'baseline' and 'dev'.\nFound: {}, {}", .0, .1)]
    BadBranchNameErr(String, String),
}

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

    #[test]
    fn test_io_error_messages() {
        let pairs = vec![
            (
                IOError::ReadErr(Path::new("dummy/path/file.json").to_path_buf(), None),
                r#"ReadErr: The file cannot be read.
Filepath: dummy/path/file.json
Originating Exception:None"#
            ),
            (
                IOError::MissingFilenameErr(Path::new("dummy/path/no_file/").to_path_buf()),
                r#"MissingFilenameErr: The path provided does not specify a file.
Filepath: dummy/path/no_file/"#
            ),
            (
                IOError::FilenameNotUnicodeErr(Path::new("dummy/path/no_file/").to_path_buf()),
                r#"FilenameNotUnicodeErr: The filename is not expressible in unicode. Consider renaming the file.
Filepath: dummy/path/no_file/"#
            ),
            (
                IOError::BadFileContentsErr(Path::new("dummy/path/filenotexist.json").to_path_buf(), None),
                r#"BadFileContentsErr: Check that the file exists and is readable.
Filepath: dummy/path/filenotexist.json
Originating Exception:None"#
            ),
            (
                IOError::CommandErr(None),
                r#"CommandErr: System command failed to run.
Originating Exception: None"#
            ),
        ];

        for (err, msg) in pairs {
            assert_eq!(format!("{}", err), msg)
        }
    }

    #[test]
    fn test_calculate_error_messages() {
        let pairs = vec![
            (
                CalculateError::BadJSONErr(Path::new("dummy/path/file.json").to_path_buf(), None),
                r#"BadJSONErr: JSON in file cannot be deserialized as expected.
Filepath: dummy/path/file.json
Originating Exception:None"#
            ),
            (
                CalculateError::BadJSONErr(Path::new("dummy/path/file.json").to_path_buf(), None),
                r#"BadJSONErr: JSON in file cannot be deserialized as expected.
Filepath: dummy/path/file.json
Originating Exception:None"#
            ),
            (
                CalculateError::NoResultsErr(Path::new("dummy/path/no_file/").to_path_buf()),
                r#"NoResultsErr: The results directory has no json files in it.
Filepath: dummy/path/no_file/"#
            ),
            (
                CalculateError::OddResultsCountErr(3, Path::new("dummy/path/no_file/").to_path_buf()),
                r#"OddResultsCountErr: The results directory has an odd number of results in it. Expected an even number.
File Count: 3
Filepath: dummy/path/no_file/"#
            ),
            (
                CalculateError::BadGroupSizeErr(1, vec![MeasurementGroup {
                    version: "dev".to_owned(),
                    run: "some command".to_owned(),
                    measurement: Measurement {
                        command: "some command".to_owned(),
                        mean: 1.0,
                        stddev: 1.0,
                        median: 1.0,
                        user: 1.0,
                        system: 1.0,
                        min: 1.0,
                        max: 1.0,
                        times: vec![1.0, 1.1, 0.9, 1.0, 1.1, 0.9, 1.1],
                    }
                }]),
                r#"BadGroupSizeErr: Expected two results per group, one for each branch-project pair.
Count: 1
Group: [("dev", "some command")]"#
            ),
            (
                CalculateError::BadBranchNameErr("boop".to_owned(), "noop".to_owned()),
                r#"BadBranchNameErr: Branch names must be 'baseline' and 'dev'.
Found: boop, noop"#
            ),
        ];

        for (err, msg) in pairs {
            assert_eq!(format!("{}", err), msg)
        }
    }

}
<commit_msg>fix spacing<commit_after>use crate::calculate::*;
use std::path::PathBuf;
use std::io;
#[cfg(test)]
use std::path::Path;
use thiserror::Error;

#[derive(Debug, Error)]
pub enum IOError {
    #[error("ReadErr: The file cannot be read.\nFilepath: {}\nOriginating Exception: {}", .0.to_string_lossy().into_owned(), .1.as_ref().map_or("None".to_owned(), |e| format!("{}", e)))]
    ReadErr(PathBuf, Option<io::Error>),
    #[error("MissingFilenameErr: The path provided does not specify a file.\nFilepath: {}", .0.to_string_lossy().into_owned())]
    MissingFilenameErr(PathBuf),
    #[error("FilenameNotUnicodeErr: The filename is not expressible in unicode. Consider renaming the file.\nFilepath: {}", .0.to_string_lossy().into_owned())]
    FilenameNotUnicodeErr(PathBuf),
    #[error("BadFileContentsErr: Check that the file exists and is readable.\nFilepath: {}\nOriginating Exception: {}", .0.to_string_lossy().into_owned(), .1.as_ref().map_or("None".to_owned(), |e| format!("{}", e)))]
    BadFileContentsErr(PathBuf, Option<io::Error>),
    #[error("CommandErr: System command failed to run.\nOriginating Exception: {}", .0.as_ref().map_or("None".to_owned(), |e| format!("{}", e)))]
    CommandErr(Option<io::Error>),
}

#[derive(Debug, Error)]
pub enum CalculateError {
    #[error("BadJSONErr: JSON in file cannot be deserialized as expected.\nFilepath: {}\nOriginating Exception: {}", .0.to_string_lossy().into_owned(), .1.as_ref().map_or("None".to_owned(), |e| format!("{}", e)))]
    BadJSONErr(PathBuf, Option<serde_json::Error>),
    #[error("{}", .0)]
    CalculateIOError(IOError),
    #[error("NoResultsErr: The results directory has no json files in it.\nFilepath: {}", .0.to_string_lossy().into_owned())]
    NoResultsErr(PathBuf),
    #[error("OddResultsCountErr: The results directory has an odd number of results in it. Expected an even number.\nFile Count: {}\nFilepath: {}", .0, .1.to_string_lossy().into_owned())]
    OddResultsCountErr(usize, PathBuf),
    #[error("BadGroupSizeErr: Expected two results per group, one for each branch-project pair.\nCount: {}\nGroup: {:?}", .0, .1.into_iter().map(|group| (&group.version[..], &group.run[..])).collect::<Vec<(&str, &str)>>())]
    BadGroupSizeErr(usize, Vec<MeasurementGroup>),
    #[error("BadBranchNameErr: Branch names must be 'baseline' and 'dev'.\nFound: {}, {}", .0, .1)]
    BadBranchNameErr(String, String),
}

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

    #[test]
    fn test_io_error_messages() {
        let pairs = vec![
            (
                IOError::ReadErr(Path::new("dummy/path/file.json").to_path_buf(), None),
                r#"ReadErr: The file cannot be read.
Filepath: dummy/path/file.json
Originating Exception: None"#
            ),
            (
                IOError::MissingFilenameErr(Path::new("dummy/path/no_file/").to_path_buf()),
                r#"MissingFilenameErr: The path provided does not specify a file.
Filepath: dummy/path/no_file/"#
            ),
            (
                IOError::FilenameNotUnicodeErr(Path::new("dummy/path/no_file/").to_path_buf()),
                r#"FilenameNotUnicodeErr: The filename is not expressible in unicode. Consider renaming the file.
Filepath: dummy/path/no_file/"#
            ),
            (
                IOError::BadFileContentsErr(Path::new("dummy/path/filenotexist.json").to_path_buf(), None),
                r#"BadFileContentsErr: Check that the file exists and is readable.
Filepath: dummy/path/filenotexist.json
Originating Exception: None"#
            ),
            (
                IOError::CommandErr(None),
                r#"CommandErr: System command failed to run.
Originating Exception: None"#
            ),
        ];

        for (err, msg) in pairs {
            assert_eq!(format!("{}", err), msg)
        }
    }

    #[test]
    fn test_calculate_error_messages() {
        let pairs = vec![
            (
                CalculateError::BadJSONErr(Path::new("dummy/path/file.json").to_path_buf(), None),
                r#"BadJSONErr: JSON in file cannot be deserialized as expected.
Filepath: dummy/path/file.json
Originating Exception: None"#
            ),
            (
                CalculateError::BadJSONErr(Path::new("dummy/path/file.json").to_path_buf(), None),
                r#"BadJSONErr: JSON in file cannot be deserialized as expected.
Filepath: dummy/path/file.json
Originating Exception: None"#
            ),
            (
                CalculateError::NoResultsErr(Path::new("dummy/path/no_file/").to_path_buf()),
                r#"NoResultsErr: The results directory has no json files in it.
Filepath: dummy/path/no_file/"#
            ),
            (
                CalculateError::OddResultsCountErr(3, Path::new("dummy/path/no_file/").to_path_buf()),
                r#"OddResultsCountErr: The results directory has an odd number of results in it. Expected an even number.
File Count: 3
Filepath: dummy/path/no_file/"#
            ),
            (
                CalculateError::BadGroupSizeErr(1, vec![MeasurementGroup {
                    version: "dev".to_owned(),
                    run: "some command".to_owned(),
                    measurement: Measurement {
                        command: "some command".to_owned(),
                        mean: 1.0,
                        stddev: 1.0,
                        median: 1.0,
                        user: 1.0,
                        system: 1.0,
                        min: 1.0,
                        max: 1.0,
                        times: vec![1.0, 1.1, 0.9, 1.0, 1.1, 0.9, 1.1],
                    }
                }]),
                r#"BadGroupSizeErr: Expected two results per group, one for each branch-project pair.
Count: 1
Group: [("dev", "some command")]"#
            ),
            (
                CalculateError::BadBranchNameErr("boop".to_owned(), "noop".to_owned()),
                r#"BadBranchNameErr: Branch names must be 'baseline' and 'dev'.
Found: boop, noop"#
            ),
        ];

        for (err, msg) in pairs {
            assert_eq!(format!("{}", err), msg)
        }
    }

}
<|endoftext|>


<commit_before>//!
//! Masked Enzyme Context with strand specific behaviour - kmer can have masked positions
//!

use std::collections::VecDeque;
use super::{EnzContext, KmerIndex};
use seqtable::SeqTableParams;

// Strand Specific Masked version
pub struct EnzContextMaskedStrandSpecific {
    kmer_length: usize,
    unmasked_count: u32,
    buf: VecDeque<u8>,
    mask_plus: Vec<bool>,
    mask_minus: Vec<bool>,
}

impl EnzContextMaskedStrandSpecific {
    pub fn new(params: &SeqTableParams) -> EnzContextMaskedStrandSpecific {
        let mut rev_mask = params.mask.as_ref().unwrap().clone();
        rev_mask.reverse();
        EnzContextMaskedStrandSpecific {
            kmer_length: params.kmer_length as usize,
            unmasked_count: params.unmasked_count as u32,
            buf: VecDeque::with_capacity(params.unmasked_count as usize),
            mask_plus: params.mask.as_ref().unwrap().clone(),
            mask_minus: rev_mask,
        }
    }

    fn nmer_index(&self) -> KmerIndex {
        let mut idx_plus = 0;
        let mut idx_minus = 0;
        let mut plus_is_some = true;
        let mut minus_is_some = true;
        let mut mult = 4u64.pow(self.unmasked_count - 1);

        // compute plus kmer
        for (base, flag) in self.buf.iter().zip(&self.mask_plus) {
            if *flag {
                if *base == 4 { plus_is_some = false; break } // N in a non-masked position

                idx_plus = idx_plus + *base as u64 * mult;
                mult = mult / 4;
            }
        }
        // compute minus kmer - reverse complement
        mult = 1;
        for (base, flag) in self.buf.iter().zip(&self.mask_minus) {
            if *flag {
                if *base == 4 { minus_is_some = false; break } // N in a non-masked position

                idx_minus = idx_minus + ( 3 - *base ) as u64 * mult;
                mult = mult * 4;
            }
        }
        KmerIndex {
            plus: if plus_is_some { Some(idx_plus as u32) } else { None },
            minus: if minus_is_some { Some(idx_minus as u32) } else { None }
        }
    }
}

impl EnzContext for EnzContextMaskedStrandSpecific {
    fn sequence_change(&mut self) {
        self.buf.clear();
    }

    fn add_base(&mut self, base: u8) -> KmerIndex {
        if self.buf.len() == self.kmer_length { self.buf.pop_front(); }
        self.buf.push_back(base);
        if self.buf.len() == self.kmer_length {
            self.nmer_index()
        } else {
            KmerIndex{ plus: None, minus: None }
        }
    }
}
<commit_msg>Add minimal tests to stranded masked<commit_after>//!
//! Masked Enzyme Context with strand specific behaviour - kmer can have masked positions
//!

use std::collections::VecDeque;
use super::{EnzContext, KmerIndex};
use seqtable::SeqTableParams;

// Strand Specific Masked version
pub struct EnzContextMaskedStrandSpecific {
    kmer_length: usize,
    unmasked_count: u32,
    buf: VecDeque<u8>,
    mask_plus: Vec<bool>,
    mask_minus: Vec<bool>,
}

impl EnzContextMaskedStrandSpecific {
    pub fn new(params: &SeqTableParams) -> EnzContextMaskedStrandSpecific {
        let mut rev_mask = params.mask.as_ref().unwrap().clone();
        rev_mask.reverse();
        EnzContextMaskedStrandSpecific {
            kmer_length: params.kmer_length as usize,
            unmasked_count: params.unmasked_count as u32,
            buf: VecDeque::with_capacity(params.unmasked_count as usize),
            mask_plus: params.mask.as_ref().unwrap().clone(),
            mask_minus: rev_mask,
        }
    }

    fn nmer_index(&self) -> KmerIndex {
        let mut idx_plus = 0;
        let mut idx_minus = 0;
        let mut plus_is_some = true;
        let mut minus_is_some = true;
        let mut mult = 4u64.pow(self.unmasked_count - 1);

        // compute plus kmer
        for (base, flag) in self.buf.iter().zip(&self.mask_plus) {
            if *flag {
                if *base == 4 { plus_is_some = false; break } // N in a non-masked position

                idx_plus = idx_plus + *base as u64 * mult;
                mult = mult / 4;
            }
        }
        // compute minus kmer - reverse complement
        mult = 1;
        for (base, flag) in self.buf.iter().zip(&self.mask_minus) {
            if *flag {
                if *base == 4 { minus_is_some = false; break } // N in a non-masked position

                idx_minus = idx_minus + ( 3 - *base ) as u64 * mult;
                mult = mult * 4;
            }
        }
        KmerIndex {
            plus: if plus_is_some { Some(idx_plus as u32) } else { None },
            minus: if minus_is_some { Some(idx_minus as u32) } else { None }
        }
    }
}

impl EnzContext for EnzContextMaskedStrandSpecific {
    fn sequence_change(&mut self) {
        self.buf.clear();
    }

    fn add_base(&mut self, base: u8) -> KmerIndex {
        if self.buf.len() == self.kmer_length { self.buf.pop_front(); }
        self.buf.push_back(base);
        if self.buf.len() == self.kmer_length {
            self.nmer_index()
        } else {
            KmerIndex{ plus: None, minus: None }
        }
    }
}

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

    // AA 0   CA 4   GA 8   TA 12
    // AC     CC     GC     TC
    // AG     CG     GG     TG
    // AT     CT     GT     TT 15

    fn kmer_value(bases: Vec<DNABases>) -> Option<u32> {
        let mut res = 0;
        for base in bases {
            if base == DNABases::N {
                return None;
            }
            res *= 4;
            res += base as u32;
        }
        Some(res)
    }

    fn simple_params( kmer_size: u8 ) -> SeqTableParams {
        SeqTableParams::new( kmer_size, 0, 0, 0, &Some("NXN".to_string()), true)
    }

    #[test]
    fn kmer_value_ok() {
        assert_eq!( Some(6), kmer_value(vec![DNABases::C, DNABases::G]));
        assert_eq!( Some(12), kmer_value(vec![DNABases::T, DNABases::A]));
        assert_eq!( None, kmer_value(vec![DNABases::C, DNABases::N]));
    }

    #[test]
    fn valid_first_reverse_complement_index() {
        println!("{:?}", simple_params(2));
        let mut simple = EnzContextMaskedStrandSpecific::new(&simple_params(2));
        assert_eq!( KmerIndex { plus: None, minus: None }, simple.add_base( fasta::DNABases::C as u8 ) );
        assert_eq!( KmerIndex { plus: None, minus: None }, simple.add_base( fasta::DNABases::C as u8 ) ); // masked position
        assert_eq!( KmerIndex {
            plus: kmer_value(vec![DNABases::C, DNABases::T]), // CT
            minus: kmer_value(vec![DNABases::A, DNABases::G]) // AG
        }, simple.add_base( fasta::DNABases::T as u8 ) );
    }

    #[test]
    fn valid_second_reverse_complement_index() {
        let mut simple = EnzContextMaskedStrandSpecific::new(&simple_params(2));
        simple.add_base( fasta::DNABases::C as u8 );
        simple.add_base( fasta::DNABases::G as u8 );
        simple.add_base( fasta::DNABases::C as u8 ); // position masked in second index
        assert_eq!( KmerIndex {
            plus: kmer_value(vec![DNABases::G, DNABases::T]), // GT
            minus: kmer_value(vec![DNABases::A, DNABases::C]) // AC
        }, simple.add_base( fasta::DNABases::T as u8 ) );

    }
}<|endoftext|>


<commit_before>//! DNS Resolution used by the `HttpConnector`.
//!
//! This module contains:
//!
//! - A [`GaiResolver`](GaiResolver) that is the default resolver for the
//!   `HttpConnector`.
//! - The `Name` type used as an argument to custom resolvers.
//!
//! # Resolvers are `Service`s
//!
//! A resolver is just a
//! `Service<Name, Response = impl Iterator<Item = SocketAddr>>`.
//!
//! A simple resolver that ignores the name and always returns a specific
//! address:
//!
//! ```rust,ignore
//! use std::{convert::Infallible, iter, net::SocketAddr};
//!
//! let resolver = tower::service_fn(|_name| async {
//!     Ok::<_, Infallible>(iter::once(SocketAddr::from(([127, 0, 0, 1], 8080))))
//! });
//! ```
use std::error::Error;
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr};
use std::str::FromStr;
use std::{fmt, vec};

/// A domain name to resolve into IP addresses.
#[derive(Clone, Hash, Eq, PartialEq)]
pub struct Name {
    host: Box<str>,
}

/// A resolver using blocking `getaddrinfo` calls in a threadpool.
#[derive(Clone)]
pub struct GaiResolver {
    _priv: (),
}

/// An iterator of IP addresses returned from `getaddrinfo`.
pub struct GaiAddrs {
    inner: SocketAddrs,
}

impl Name {
    pub(super) fn new(host: Box<str>) -> Name {
        Name { host }
    }

    /// View the hostname as a string slice.
    pub fn as_str(&self) -> &str {
        &self.host
    }
}

impl fmt::Debug for Name {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Debug::fmt(&self.host, f)
    }
}

impl fmt::Display for Name {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(&self.host, f)
    }
}

impl FromStr for Name {
    type Err = InvalidNameError;

    fn from_str(host: &str) -> Result<Self, Self::Err> {
        // Possibly add validation later
        Ok(Name::new(host.into()))
    }
}

/// Error indicating a given string was not a valid domain name.
#[derive(Debug)]
pub struct InvalidNameError(());

impl fmt::Display for InvalidNameError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str("Not a valid domain name")
    }
}

impl Error for InvalidNameError {}

impl GaiResolver {
    /// Construct a new `GaiResolver`.
    pub fn new() -> Self {
        GaiResolver { _priv: () }
    }
}

impl fmt::Debug for GaiResolver {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.pad("GaiResolver")
    }
}

impl Iterator for GaiAddrs {
    type Item = SocketAddr;

    fn next(&mut self) -> Option<Self::Item> {
        self.inner.next()
    }
}

impl fmt::Debug for GaiAddrs {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.pad("GaiAddrs")
    }
}

pub(super) struct SocketAddrs {
    iter: vec::IntoIter<SocketAddr>,
}

impl SocketAddrs {
    pub(super) fn new(addrs: Vec<SocketAddr>) -> Self {
        SocketAddrs {
            iter: addrs.into_iter(),
        }
    }

    #[inline]
    fn filter(self, predicate: impl FnMut(&SocketAddr) -> bool) -> SocketAddrs {
        SocketAddrs::new(self.iter.filter(predicate).collect())
    }

    pub(super) fn split_by_preference(
        self,
        local_addr_ipv4: Option<Ipv4Addr>,
        local_addr_ipv6: Option<Ipv6Addr>,
    ) -> (SocketAddrs, SocketAddrs) {
        match (local_addr_ipv4, local_addr_ipv6) {
            (Some(_), None) => (self.filter(SocketAddr::is_ipv4), SocketAddrs::new(vec![])),
            (None, Some(_)) => (self.filter(SocketAddr::is_ipv6), SocketAddrs::new(vec![])),
            _ => {
                let preferring_v6 = self
                    .iter
                    .as_slice()
                    .first()
                    .map(SocketAddr::is_ipv6)
                    .unwrap_or(false);

                let (preferred, fallback) = self
                    .iter
                    .partition::<Vec<_>, _>(|addr| addr.is_ipv6() == preferring_v6);

                (SocketAddrs::new(preferred), SocketAddrs::new(fallback))
            }
        }
    }

    pub(super) fn is_empty(&self) -> bool {
        self.iter.as_slice().is_empty()
    }
}

impl Iterator for SocketAddrs {
    type Item = SocketAddr;
    #[inline]
    fn next(&mut self) -> Option<SocketAddr> {
        self.iter.next()
    }
}

/*
/// A resolver using `getaddrinfo` calls via the `tokio_executor::threadpool::blocking` API.
///
/// Unlike the `GaiResolver` this will not spawn dedicated threads, but only works when running on the
/// multi-threaded Tokio runtime.
#[cfg(feature = "runtime")]
#[derive(Clone, Debug)]
pub struct TokioThreadpoolGaiResolver(());

/// The future returned by `TokioThreadpoolGaiResolver`.
#[cfg(feature = "runtime")]
#[derive(Debug)]
pub struct TokioThreadpoolGaiFuture {
    name: Name,
}

#[cfg(feature = "runtime")]
impl TokioThreadpoolGaiResolver {
    /// Creates a new DNS resolver that will use tokio threadpool's blocking
    /// feature.
    ///
    /// **Requires** its futures to be run on the threadpool runtime.
    pub fn new() -> Self {
        TokioThreadpoolGaiResolver(())
    }
}

#[cfg(feature = "runtime")]
impl Service<Name> for TokioThreadpoolGaiResolver {
    type Response = GaiAddrs;
    type Error = io::Error;
    type Future = TokioThreadpoolGaiFuture;

    fn poll_ready(&mut self, _cx: &mut task::Context<'_>) -> Poll<Result<(), io::Error>> {
        Poll::Ready(Ok(()))
    }

    fn call(&mut self, name: Name) -> Self::Future {
        TokioThreadpoolGaiFuture { name }
    }
}

#[cfg(feature = "runtime")]
impl Future for TokioThreadpoolGaiFuture {
    type Output = Result<GaiAddrs, io::Error>;

    fn poll(self: Pin<&mut Self>, _cx: &mut task::Context<'_>) -> Poll<Self::Output> {
        match ready!(tokio_executor::threadpool::blocking(|| (
            self.name.as_str(),
            0
        )
            .to_socket_addrs()))
        {
            Ok(Ok(iter)) => Poll::Ready(Ok(GaiAddrs {
                inner: IpAddrs { iter },
            })),
            Ok(Err(e)) => Poll::Ready(Err(e)),
            // a BlockingError, meaning not on a tokio_executor::threadpool :(
            Err(e) => Poll::Ready(Err(io::Error::new(io::ErrorKind::Other, e))),
        }
    }
}
*/

mod sealed {
    use super::{Name, SocketAddr};
    use crate::common::{task, Future, Poll};
    use tower_service::Service;

    // "Trait alias" for `Service<Name, Response = Addrs>`
    pub(crate) trait Resolve {
        type Addrs: Iterator<Item = SocketAddr>;
        type Error: Into<Box<dyn std::error::Error + Send + Sync>>;
        type Future: Future<Output = Result<Self::Addrs, Self::Error>>;

        fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll<Result<(), Self::Error>>;
        fn resolve(&mut self, name: Name) -> Self::Future;
    }

    impl<S> Resolve for S
    where
        S: Service<Name>,
        S::Response: Iterator<Item = SocketAddr>,
        S::Error: Into<Box<dyn std::error::Error + Send + Sync>>,
    {
        type Addrs = S::Response;
        type Error = S::Error;
        type Future = S::Future;

        fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll<Result<(), Self::Error>> {
            Service::poll_ready(self, cx)
        }

        fn resolve(&mut self, name: Name) -> Self::Future {
            Service::call(self, name)
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::net::{Ipv4Addr, Ipv6Addr};

    #[test]
    fn test_ip_addrs_split_by_preference() {
        let ip_v4 = Ipv4Addr::new(127, 0, 0, 1);
        let ip_v6 = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
        let v4_addr = (ip_v4, 80).into();
        let v6_addr = (ip_v6, 80).into();

        let (mut preferred, mut fallback) = SocketAddrs {
            iter: vec![v4_addr, v6_addr].into_iter(),
        }
        .split_by_preference(None, None);
        assert!(preferred.next().unwrap().is_ipv4());
        assert!(fallback.next().unwrap().is_ipv6());

        let (mut preferred, mut fallback) = SocketAddrs {
            iter: vec![v6_addr, v4_addr].into_iter(),
        }
        .split_by_preference(None, None);
        assert!(preferred.next().unwrap().is_ipv6());
        assert!(fallback.next().unwrap().is_ipv4());

        let (mut preferred, mut fallback) = SocketAddrs {
            iter: vec![v4_addr, v6_addr].into_iter(),
        }
        .split_by_preference(Some(ip_v4), Some(ip_v6));
        assert!(preferred.next().unwrap().is_ipv4());
        assert!(fallback.next().unwrap().is_ipv6());

        let (mut preferred, mut fallback) = SocketAddrs {
            iter: vec![v6_addr, v4_addr].into_iter(),
        }
        .split_by_preference(Some(ip_v4), Some(ip_v6));
        assert!(preferred.next().unwrap().is_ipv6());
        assert!(fallback.next().unwrap().is_ipv4());

        let (mut preferred, fallback) = SocketAddrs {
            iter: vec![v4_addr, v6_addr].into_iter(),
        }
        .split_by_preference(Some(ip_v4), None);
        assert!(preferred.next().unwrap().is_ipv4());
        assert!(fallback.is_empty());

        let (mut preferred, fallback) = SocketAddrs {
            iter: vec![v4_addr, v6_addr].into_iter(),
        }
        .split_by_preference(None, Some(ip_v6));
        assert!(preferred.next().unwrap().is_ipv6());
        assert!(fallback.is_empty());
    }

    #[test]
    fn test_name_from_str() {
        const DOMAIN: &str = "test.example.com";
        let name = Name::from_str(DOMAIN).expect("Should be a valid domain");
        assert_eq!(name.as_str(), DOMAIN);
        assert_eq!(name.to_string(), DOMAIN);
    }
}
<commit_msg>refactor(client): clean up unused lint warnings in dns module (#2931)<commit_after>//! DNS Resolution used by the `HttpConnector`.
//!
//! This module contains:
//!
//! - A [`GaiResolver`](GaiResolver) that is the default resolver for the
//!   `HttpConnector`.
//! - The `Name` type used as an argument to custom resolvers.
//!
//! # Resolvers are `Service`s
//!
//! A resolver is just a
//! `Service<Name, Response = impl Iterator<Item = SocketAddr>>`.
//!
//! A simple resolver that ignores the name and always returns a specific
//! address:
//!
//! ```rust,ignore
//! use std::{convert::Infallible, iter, net::SocketAddr};
//!
//! let resolver = tower::service_fn(|_name| async {
//!     Ok::<_, Infallible>(iter::once(SocketAddr::from(([127, 0, 0, 1], 8080))))
//! });
//! ```
use std::error::Error;
use std::net::{SocketAddr};
use std::str::FromStr;
use std::{fmt, vec};

/// A domain name to resolve into IP addresses.
#[derive(Clone, Hash, Eq, PartialEq)]
pub struct Name {
    host: Box<str>,
}

/// A resolver using blocking `getaddrinfo` calls in a threadpool.
#[derive(Clone)]
pub struct GaiResolver {
    _priv: (),
}

/// An iterator of IP addresses returned from `getaddrinfo`.
pub struct GaiAddrs {
    inner: SocketAddrs,
}

impl Name {
    pub(super) fn new(host: Box<str>) -> Name {
        Name { host }
    }

    /// View the hostname as a string slice.
    pub fn as_str(&self) -> &str {
        &self.host
    }
}

impl fmt::Debug for Name {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Debug::fmt(&self.host, f)
    }
}

impl fmt::Display for Name {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(&self.host, f)
    }
}

impl FromStr for Name {
    type Err = InvalidNameError;

    fn from_str(host: &str) -> Result<Self, Self::Err> {
        // Possibly add validation later
        Ok(Name::new(host.into()))
    }
}

/// Error indicating a given string was not a valid domain name.
#[derive(Debug)]
pub struct InvalidNameError(());

impl fmt::Display for InvalidNameError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str("Not a valid domain name")
    }
}

impl Error for InvalidNameError {}

impl GaiResolver {
    /// Construct a new `GaiResolver`.
    pub fn new() -> Self {
        GaiResolver { _priv: () }
    }
}

impl fmt::Debug for GaiResolver {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.pad("GaiResolver")
    }
}

impl Iterator for GaiAddrs {
    type Item = SocketAddr;

    fn next(&mut self) -> Option<Self::Item> {
        self.inner.next()
    }
}

impl fmt::Debug for GaiAddrs {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.pad("GaiAddrs")
    }
}

pub(super) struct SocketAddrs {
    iter: vec::IntoIter<SocketAddr>,
}

impl Iterator for SocketAddrs {
    type Item = SocketAddr;
    #[inline]
    fn next(&mut self) -> Option<SocketAddr> {
        self.iter.next()
    }
}

/*
/// A resolver using `getaddrinfo` calls via the `tokio_executor::threadpool::blocking` API.
///
/// Unlike the `GaiResolver` this will not spawn dedicated threads, but only works when running on the
/// multi-threaded Tokio runtime.
#[cfg(feature = "runtime")]
#[derive(Clone, Debug)]
pub struct TokioThreadpoolGaiResolver(());

/// The future returned by `TokioThreadpoolGaiResolver`.
#[cfg(feature = "runtime")]
#[derive(Debug)]
pub struct TokioThreadpoolGaiFuture {
    name: Name,
}

#[cfg(feature = "runtime")]
impl TokioThreadpoolGaiResolver {
    /// Creates a new DNS resolver that will use tokio threadpool's blocking
    /// feature.
    ///
    /// **Requires** its futures to be run on the threadpool runtime.
    pub fn new() -> Self {
        TokioThreadpoolGaiResolver(())
    }
}

#[cfg(feature = "runtime")]
impl Service<Name> for TokioThreadpoolGaiResolver {
    type Response = GaiAddrs;
    type Error = io::Error;
    type Future = TokioThreadpoolGaiFuture;

    fn poll_ready(&mut self, _cx: &mut task::Context<'_>) -> Poll<Result<(), io::Error>> {
        Poll::Ready(Ok(()))
    }

    fn call(&mut self, name: Name) -> Self::Future {
        TokioThreadpoolGaiFuture { name }
    }
}

#[cfg(feature = "runtime")]
impl Future for TokioThreadpoolGaiFuture {
    type Output = Result<GaiAddrs, io::Error>;

    fn poll(self: Pin<&mut Self>, _cx: &mut task::Context<'_>) -> Poll<Self::Output> {
        match ready!(tokio_executor::threadpool::blocking(|| (
            self.name.as_str(),
            0
        )
            .to_socket_addrs()))
        {
            Ok(Ok(iter)) => Poll::Ready(Ok(GaiAddrs {
                inner: IpAddrs { iter },
            })),
            Ok(Err(e)) => Poll::Ready(Err(e)),
            // a BlockingError, meaning not on a tokio_executor::threadpool :(
            Err(e) => Poll::Ready(Err(io::Error::new(io::ErrorKind::Other, e))),
        }
    }
}
*/

mod sealed {
    use super::{Name, SocketAddr};
    use crate::common::{task, Future, Poll};
    use tower_service::Service;

    // "Trait alias" for `Service<Name, Response = Addrs>`
    pub(crate) trait Resolve {
        type Addrs: Iterator<Item = SocketAddr>;
        type Error: Into<Box<dyn std::error::Error + Send + Sync>>;
        type Future: Future<Output = Result<Self::Addrs, Self::Error>>;

        fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll<Result<(), Self::Error>>;
        fn resolve(&mut self, name: Name) -> Self::Future;
    }

    impl<S> Resolve for S
    where
        S: Service<Name>,
        S::Response: Iterator<Item = SocketAddr>,
        S::Error: Into<Box<dyn std::error::Error + Send + Sync>>,
    {
        type Addrs = S::Response;
        type Error = S::Error;
        type Future = S::Future;

        fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll<Result<(), Self::Error>> {
            Service::poll_ready(self, cx)
        }

        fn resolve(&mut self, name: Name) -> Self::Future {
            Service::call(self, name)
        }
    }
}

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

    #[test]
    fn test_name_from_str() {
        const DOMAIN: &str = "test.example.com";
        let name = Name::from_str(DOMAIN).expect("Should be a valid domain");
        assert_eq!(name.as_str(), DOMAIN);
        assert_eq!(name.to_string(), DOMAIN);
    }
}
<|endoftext|>


<commit_before>// https://leetcode.com/problems/longest-uploaded-prefix/
struct LUPrefix {}

impl LUPrefix {
    fn new(n: i32) -> Self {
        todo!()
    }

    fn upload(&self, video: i32) {
        todo!()
    }

    fn longest(&self) -> i32 {
        todo!()
    }
}

fn main() {
    let server = LUPrefix::new(4);
    server.upload(3);
    println!("{}", server.longest()); // 0
    server.upload(1);
    println!("{}", server.longest()); // 1.
    server.upload(2);
    println!("{}", server.longest()); // 3
}
<commit_msg>Update problem 2424<commit_after>use std::collections::BTreeSet;
use std::ops::Bound::Included;

// https://leetcode.com/problems/longest-uploaded-prefix/
struct LUPrefix {}

impl LUPrefix {
    fn new(n: i32) -> Self {
        LUPrefix {}
    }

    fn upload(&mut self, video: i32) {
        todo!()
    }

    fn longest(&self) -> i32 {
        todo!()
    }
}

fn main() {
    let mut server = LUPrefix::new(4);
    server.upload(3);
    println!("{}", server.longest()); // 0
    server.upload(1);
    println!("{}", server.longest()); // 1
    server.upload(2);
    println!("{}", server.longest()); // 3
}
<|endoftext|>


<commit_before>//! Signed Church-encoded numerals

use term::{Term, abs, app};
use term::Term::*;
use data::num::church;
use data::pair::swap;
use combinators::Z;

/// Applied to a Church-encoded numeral it produces a pair representing a signed Church-encoded
/// integer.
///
/// TO_SIGNED ≡ λx.PAIR x ZERO ≡ λ PAIR 1 ZERO
///
/// # Example
/// ```
/// use lambda_calculus::data::signed::church::to_signed;
/// use lambda_calculus::*;
///
/// assert_eq!(beta(app(to_signed(), 1.into_church()), NOR, 0), (1, 0).into_church());
/// ```
pub fn to_signed() -> Term {
    abs!(2, app!(Var(1), Var(2), church::zero()))
}

/// Applied to a pair representing a signed Church-encoded integer it flips the sign.
///
/// NEGATE ≡ SWAP
///
/// # Example
/// ```
/// use lambda_calculus::data::signed::church::negate;
/// use lambda_calculus::*;
///
/// assert_eq!(beta(app(negate(), (1, 0).into_church()), NOR, 0), (0, 1).into_church());
/// ```
pub fn negate() -> Term {
    swap()
}

/// Applied to a pair of two Church-encoded numerals representing a signed integer, ensure that at
/// least one element of the pair is equal to 0.
///
/// NORMALIZE ≡ Z (λz.λx.IS_ZERO (FST x) (λy.x) (λy.IS_ZERO (SND x) x (z (PAIR (PRED (FST x))
/// (PRED (SND x))))) I) ≡
/// Z (λ λ IS_ZERO (FST 1) (λ 2) (λ IS_ZERO (SND 2) 2 (3 (PAIR (PRED (FST 2)) (PRED (SND 2))))) I)
///
/// # Example
/// ```
/// use lambda_calculus::data::signed::church::normalize;
/// use lambda_calculus::*;
///
/// assert_eq!(beta(app(normalize(), (3, 0).into_church()), NOR, 0), (3, 0).into_church());
/// assert_eq!(beta(app(normalize(), (0, 3).into_church()), NOR, 0), (0, 3).into_church());
/// assert_eq!(beta(app(normalize(), (4, 1).into_church()), NOR, 0), (3, 0).into_church());
/// ```
pub fn normalize() -> Term {
    app(
        Z(),
        abs!(2, app!(
            Var(1),
            abs!(2, Var(2)),
            abs!(3, Var(1)),
            abs!(2, Var(2)),
            abs(Var(2)),
            abs(app!(
                Var(2),
                abs!(2, Var(1)),
                abs!(3, Var(1)),
                abs!(2, Var(2)),
                Var(2),
                app!(
                    Var(3),
                    abs(app!(
                        Var(1),
                        abs!(2, app!(
                            Var(5),
                            abs!(2, Var(2)),
                            abs!(2, app!(
                                Var(1),
                                app(Var(2), Var(4))
                            )),
                            abs(Var(2)),
                            abs(Var(1))
                        )),
                        abs!(2, app!(
                            Var(5),
                            abs!(2, Var(1)),
                            abs!(2, app!(
                                Var(1),
                                app(Var(2), Var(4))
                            )),
                            abs(Var(2)),
                            abs(Var(1))
                        ))
                    ))
                )
            )),
            abs(Var(1))
        ))
    )
}

/// Applied to a pair representing a signed Church-encoded integer it returns its absolute
/// value as a Church numeral.
///
/// ABSOLUTE_VALUE ≡ λx.(λy.IS_ZERO (FST y) (SND y) (FST y)) (NORMALIZE x) ≡
/// λ (λ IS_ZERO (FST 1) (SND 1) (FST 1)) (NORMALIZE 1)
///
/// # Example
/// ```
/// use lambda_calculus::data::signed::church::{to_signed, negate, absolute_value};
/// use lambda_calculus::*;
///
/// let one = app(to_signed(), 1.into_church());
/// let neg_one = app(negate(), one.clone());
///
/// assert_eq!(beta(app(absolute_value(), one.clone()), NOR, 0), 1.into_church());
/// assert_eq!(beta(app(absolute_value(), neg_one.clone()), NOR, 0), 1.into_church());
/// ```
pub fn absolute_value() -> Term {
    abs(app(
        abs(app!(
            Var(1),
            abs!(2, Var(2)),
            abs!(3, Var(1)),
            abs!(2, Var(2)),
            app(Var(1), abs!(2, Var(1))),
            app(Var(1), abs!(2, Var(2)))
        )),
        app(normalize(), Var(1))
    ))
}

/// Applied to a pair of two Church-encoded numerals representing a signed integer it returns a
/// normalized pair representing their sum.
///
/// SIGNED_ADD ≡ λa.λb.NORMALIZE (PAIR (ADD (FST a) (FST b)) (ADD (SND a) (SND b))) ≡
/// λ λ NORMALIZE (PAIR (ADD (FST 1) (FST 2)) (ADD (SND 1) (SND 2)))
///
/// # Example
/// ```
/// use lambda_calculus::data::signed::church::{to_signed, negate, signed_add};
/// use lambda_calculus::*;
///
/// let two = app(to_signed(), 2.into_church());
/// let three = app(to_signed(), 3.into_church());
/// let neg_one = app(negate(), app(to_signed(), 1.into_church()));
///
/// assert_eq!(
///     beta(app!(signed_add(), neg_one.clone(), three.clone()), NOR, 0),
///     beta(two.clone(), NOR, 0)
/// );
/// ```
pub fn signed_add() -> Term {
    abs!(2, app(
        normalize(),
        abs(app!(
            Var(1),
            app!(
                Var(2),
                abs!(2, Var(2)),
                abs!(3, app(
                    Var(2),
                    app!(Var(3), Var(2), Var(1))
                )),
                app(Var(3), abs!(2, Var(2)))
            ),
            app!(
                Var(2),
                abs!(2, Var(1)),
                abs!(3, app(
                    Var(2),
                    app!(Var(3), Var(2), Var(1))
                )),
                app(Var(3), abs!(2, Var(1)))
            )
        ))
    ))
}

/// Applied to a pair of two Church-encoded numerals representing a signed integer it returns a
/// normalized pair representing their difference.
///
/// SIGNED_SUB ≡ λa.λb.NORMALIZE (PAIR (ADD (FST a) (SND b)) (ADD (SND a) (FST b))) ≡
/// λ λ NORMALIZE (PAIR (ADD (FST 1) (SND 2)) (ADD (SND 1) (FST 2)))
///
/// # Example
/// ```
/// use lambda_calculus::data::signed::church::{to_signed, negate, signed_sub};
/// use lambda_calculus::*;
///
/// let two = app(to_signed(), 2.into_church());
/// let three = app(to_signed(), 3.into_church());
/// let neg_one = app(negate(), app(to_signed(), 1.into_church()));
///
/// assert_eq!(
///     beta(app!(signed_sub(), two.clone(), three.clone()), NOR, 0),
///     beta(neg_one.clone(), NOR, 0)
/// );
/// ```
pub fn signed_sub() -> Term {
    abs!(2, app(
        normalize(),
        abs(app!(
            Var(1),
            app!(
                Var(2),
                abs!(2, Var(1)),
                abs!(3, app(
                    Var(2),
                    app!(Var(3), Var(2), Var(1))
                )),
                app(Var(3), abs!(2, Var(2)))
            ),
            app!(
                Var(2),
                abs!(2, Var(2)),
                abs!(3, app(
                    Var(2),
                    app!(Var(3), Var(2), Var(1))
                )),
                app(Var(3), abs!(2, Var(1)))
            )
        ))
    ))
}
<commit_msg>make functions match definitions<commit_after>//! Signed Church-encoded numerals

use term::{Term, abs, app};
use term::Term::*;
use data::num::church;
use data::pair::{fst, snd, pair, swap};
use combinators::Z;

/// Applied to a Church-encoded numeral it produces a pair representing a signed Church-encoded
/// integer.
///
/// TO_SIGNED ≡ λx.PAIR x ZERO ≡ λ PAIR 1 ZERO
///
/// # Example
/// ```
/// use lambda_calculus::data::signed::church::to_signed;
/// use lambda_calculus::*;
///
/// assert_eq!(beta(app(to_signed(), 1.into_church()), NOR, 0), (1, 0).into_church());
/// ```
pub fn to_signed() -> Term {
    abs(app!(pair(), Var(1), church::zero()))
}

/// Applied to a pair representing a signed Church-encoded integer it flips the sign.
///
/// NEGATE ≡ SWAP
///
/// # Example
/// ```
/// use lambda_calculus::data::signed::church::negate;
/// use lambda_calculus::*;
///
/// assert_eq!(beta(app(negate(), (1, 0).into_church()), NOR, 0), (0, 1).into_church());
/// ```
pub fn negate() -> Term {
    swap()
}

/// Applied to a pair of two Church-encoded numerals representing a signed integer, ensure that at
/// least one element of the pair is equal to 0.
///
/// NORMALIZE ≡ Z (λz.λx.IS_ZERO (FST x) (λy.x) (λy.IS_ZERO (SND x) x (z (PAIR (PRED (FST x))
/// (PRED (SND x))))) I) ≡
/// Z (λ λ IS_ZERO (FST 1) (λ 2) (λ IS_ZERO (SND 2) 2 (3 (PAIR (PRED (FST 2)) (PRED (SND 2))))) I)
///
/// # Example
/// ```
/// use lambda_calculus::data::signed::church::normalize;
/// use lambda_calculus::*;
///
/// assert_eq!(beta(app(normalize(), (3, 0).into_church()), NOR, 0), (3, 0).into_church());
/// assert_eq!(beta(app(normalize(), (0, 3).into_church()), NOR, 0), (0, 3).into_church());
/// assert_eq!(beta(app(normalize(), (4, 1).into_church()), NOR, 0), (3, 0).into_church());
/// ```
pub fn normalize() -> Term {
    app(
        Z(),
        abs!(2, app!(
            Var(1),
            abs!(2, Var(2)),
            abs!(3, Var(1)),
            abs!(2, Var(2)),
            abs(Var(2)),
            abs(app!(
                Var(2),
                abs!(2, Var(1)),
                abs!(3, Var(1)),
                abs!(2, Var(2)),
                Var(2),
                app!(
                    Var(3),
                    abs(app!(
                        Var(1),
                        abs!(2, app!(
                            Var(5),
                            abs!(2, Var(2)),
                            abs!(2, app!(
                                Var(1),
                                app(Var(2), Var(4))
                            )),
                            abs(Var(2)),
                            abs(Var(1))
                        )),
                        abs!(2, app!(
                            Var(5),
                            abs!(2, Var(1)),
                            abs!(2, app!(
                                Var(1),
                                app(Var(2), Var(4))
                            )),
                            abs(Var(2)),
                            abs(Var(1))
                        ))
                    ))
                )
            )),
            abs(Var(1))
        ))
    )
}

/// Applied to a pair representing a signed Church-encoded integer it returns its absolute
/// value as a Church numeral.
///
/// ABSOLUTE_VALUE ≡ λx.(λy.IS_ZERO (FST y) (SND y) (FST y)) (NORMALIZE x) ≡
/// λ (λ IS_ZERO (FST 1) (SND 1) (FST 1)) (NORMALIZE 1)
///
/// # Example
/// ```
/// use lambda_calculus::data::signed::church::{to_signed, negate, absolute_value};
/// use lambda_calculus::*;
///
/// let one = app(to_signed(), 1.into_church());
/// let neg_one = app(negate(), one.clone());
///
/// assert_eq!(beta(app(absolute_value(), one.clone()), NOR, 0), 1.into_church());
/// assert_eq!(beta(app(absolute_value(), neg_one.clone()), NOR, 0), 1.into_church());
/// ```
pub fn absolute_value() -> Term {
    abs(app(
        abs(app!(
            church::is_zero(),
            app(fst(), Var(1)),
            app(snd(), Var(1)),
            app(fst(), Var(1))
        )),
        app(normalize(), Var(1))
    ))
}

/// Applied to a pair of two Church-encoded numerals representing a signed integer it returns a
/// normalized pair representing their sum.
///
/// SIGNED_ADD ≡ λa.λb.NORMALIZE (PAIR (ADD (FST a) (FST b)) (ADD (SND a) (SND b))) ≡
/// λ λ NORMALIZE (PAIR (ADD (FST 2) (FST 1)) (ADD (SND 2) (SND 1)))
///
/// # Example
/// ```
/// use lambda_calculus::data::signed::church::{to_signed, negate, signed_add};
/// use lambda_calculus::*;
///
/// let two = app(to_signed(), 2.into_church());
/// let three = app(to_signed(), 3.into_church());
/// let neg_one = app(negate(), app(to_signed(), 1.into_church()));
///
/// assert_eq!(
///     beta(app!(signed_add(), neg_one.clone(), three.clone()), NOR, 0),
///     beta(two.clone(), NOR, 0)
/// );
/// ```
pub fn signed_add() -> Term {
    abs!(2, app(
        normalize(),
        app!(
            pair(),
            app!(
                church::add(),
                app(fst(), Var(2)),
                app(fst(), Var(1))
            ),
            app!(
                church::add(),
                app(snd(), Var(2)),
                app(snd(), Var(1))
            )
        )
    ))
}

/// Applied to a pair of two Church-encoded numerals representing a signed integer it returns a
/// normalized pair representing their difference.
///
/// SIGNED_SUB ≡ λa.λb.NORMALIZE (PAIR (ADD (FST a) (SND b)) (ADD (SND a) (FST b))) ≡
/// λ λ NORMALIZE (PAIR (ADD (FST 2) (SND 1)) (ADD (SND 2) (FST 1)))
///
/// # Example
/// ```
/// use lambda_calculus::data::signed::church::{to_signed, negate, signed_sub};
/// use lambda_calculus::*;
///
/// let two = app(to_signed(), 2.into_church());
/// let three = app(to_signed(), 3.into_church());
/// let neg_one = app(negate(), app(to_signed(), 1.into_church()));
///
/// assert_eq!(
///     beta(app!(signed_sub(), two.clone(), three.clone()), NOR, 0),
///     beta(neg_one.clone(), NOR, 0)
/// );
/// ```
pub fn signed_sub() -> Term {
    abs!(2, app(
        normalize(),
        app!(
            pair(),
            app!(
                church::add(),
                app(fst(), Var(2)),
                app(snd(), Var(1))
            ),
            app!(
                church::add(),
                app(snd(), Var(2)),
                app(fst(), Var(1))
            )
        )
    ))
}
<|endoftext|>


<commit_before>use cssparser::{Parser, ParserInput};
use std::collections::hash_map::Entry;
use std::collections::{HashMap, HashSet};
use std::ptr;
use std::str::{self, FromStr};

use libc;
use url::Url;

use glib::translate::*;
use glib_sys::{gboolean, gpointer, GList};

use crate::allowed_url::AllowedUrl;
use crate::attributes::Attribute;
use crate::croco::*;
use crate::error::LoadingError;
use crate::io::{self, BinaryData};
use crate::properties::{parse_attribute_value_into_parsed_property, Declaration, SpecifiedValues};
use crate::util::utf8_cstr;

// Maps property_name -> Declaration
type DeclarationList = HashMap<Attribute, Declaration>;

type Selector = String;

/// Contains all the mappings of selectors to style declarations
/// that result from loading an SVG document.
pub struct CssRules {
    selectors_to_declarations: HashMap<Selector, DeclarationList>,
}

impl CssRules {
    pub fn new() -> CssRules {
        CssRules {
            selectors_to_declarations: HashMap::new(),
        }
    }

    pub fn parse(&mut self, base_url: Option<&Url>, buf: &str) {
        if buf.len() == 0 {
            return; // libcroco doesn't like empty strings :(
        }

        unsafe {
            let mut handler_data = DocHandlerData {
                base_url,
                css_rules: self,
                selector: ptr::null_mut(),
            };

            let doc_handler = cr_doc_handler_new();
            init_cr_doc_handler(&mut *doc_handler);

            (*doc_handler).app_data = &mut handler_data as *mut _ as gpointer;

            let buf_ptr = buf.as_ptr() as *mut _;
            let buf_len = buf.len() as libc::c_ulong;

            let parser = cr_parser_new_from_buf(buf_ptr, buf_len, CR_UTF_8, false.to_glib());
            if parser.is_null() {
                cr_doc_handler_unref(doc_handler);
                return;
            }

            cr_parser_set_sac_handler(parser, doc_handler);
            cr_doc_handler_unref(doc_handler);

            cr_parser_set_use_core_grammar(parser, false.to_glib());
            cr_parser_parse(parser);

            cr_parser_destroy(parser);
        }
    }

    pub fn load_css(&mut self, aurl: &AllowedUrl) -> Result<(), LoadingError> {
        io::acquire_data(aurl, None)
            .and_then(|data| {
                let BinaryData {
                    data: bytes,
                    content_type,
                } = data;

                if content_type.as_ref().map(String::as_ref) == Some("text/css") {
                    Ok(bytes)
                } else {
                    rsvg_log!("\"{}\" is not of type text/css; ignoring", aurl);
                    Err(LoadingError::BadCss)
                }
            })
            .and_then(|bytes| {
                String::from_utf8(bytes).map_err(|_| {
                    rsvg_log!(
                        "\"{}\" does not contain valid UTF-8 CSS data; ignoring",
                        aurl
                    );
                    LoadingError::BadCss
                })
            })
            .and_then(|utf8| {
                self.parse(Some(&aurl), &utf8);
                Ok(()) // FIXME: return CSS parsing errors
            })
    }

    fn add_declaration(&mut self, selector: &str, declaration: Declaration) {
        let decl_list = self
            .selectors_to_declarations
            .entry(selector.to_string())
            .or_insert_with(|| DeclarationList::new());

        match decl_list.entry(declaration.attribute) {
            Entry::Occupied(mut e) => {
                let decl = e.get_mut();

                if !decl.important {
                    *decl = declaration;
                }
            }

            Entry::Vacant(v) => {
                v.insert(declaration);
            }
        }
    }

    /// Takes CSS rules which match the given `selector` name and applies them
    /// to the `values`.
    pub fn lookup_apply(
        &self,
        selector: &str,
        values: &mut SpecifiedValues,
        important_styles: &mut HashSet<Attribute>,
    ) -> bool {
        if let Some(decl_list) = self.selectors_to_declarations.get(selector) {
            for (_, declaration) in decl_list.iter() {
                values.set_property_from_declaration(declaration, important_styles);
            }

            true
        } else {
            false
        }
    }
}

struct DocHandlerData<'a> {
    base_url: Option<&'a Url>,
    css_rules: &'a mut CssRules,
    selector: *mut CRSelector,
}

macro_rules! get_doc_handler_data {
    ($doc_handler:expr) => {
        &mut *((*$doc_handler).app_data as *mut DocHandlerData)
    };
}

fn init_cr_doc_handler(handler: &mut CRDocHandler) {
    handler.import_style = Some(css_import_style);
    handler.start_selector = Some(css_start_selector);
    handler.end_selector = Some(css_end_selector);
    handler.property = Some(css_property);
    handler.error = Some(css_error);
    handler.unrecoverable_error = Some(css_unrecoverable_error);
}

unsafe extern "C" fn css_import_style(
    a_this: *mut CRDocHandler,
    _a_media_list: *mut GList,
    a_uri: CRString,
    _a_uri_default_ns: CRString,
    _a_location: CRParsingLocation,
) {
    let handler_data = get_doc_handler_data!(a_this);

    if a_uri.is_null() {
        return;
    }

    let raw_uri = cr_string_peek_raw_str(a_uri);
    let uri = utf8_cstr(raw_uri);

    if let Ok(aurl) = AllowedUrl::from_href(uri, handler_data.base_url) {
        // FIXME: handle CSS errors
        let _ = handler_data.css_rules.load_css(&aurl);
    } else {
        rsvg_log!("disallowed URL \"{}\" for importing CSS", uri);
    }
}

unsafe extern "C" fn css_start_selector(
    a_this: *mut CRDocHandler,
    a_selector_list: *mut CRSelector,
) {
    let handler_data = get_doc_handler_data!(a_this);

    cr_selector_ref(a_selector_list);
    handler_data.selector = a_selector_list;
}

unsafe extern "C" fn css_end_selector(
    a_this: *mut CRDocHandler,
    _a_selector_list: *mut CRSelector,
) {
    let handler_data = get_doc_handler_data!(a_this);

    cr_selector_unref(handler_data.selector);
    handler_data.selector = ptr::null_mut();
}

unsafe extern "C" fn css_property(
    a_this: *mut CRDocHandler,
    a_name: CRString,
    a_expression: CRTerm,
    a_is_important: gboolean,
) {
    let handler_data = get_doc_handler_data!(a_this);

    if a_name.is_null() || a_expression.is_null() || handler_data.selector.is_null() {
        return;
    }

    let mut cur_sel = handler_data.selector;
    while !cur_sel.is_null() {
        let simple_sel = (*cur_sel).simple_sel;

        if !simple_sel.is_null() {
            let raw_selector_name = cr_simple_sel_to_string(simple_sel) as *mut libc::c_char;

            if !raw_selector_name.is_null() {
                let raw_prop_name = cr_string_peek_raw_str(a_name);
                let prop_name = utf8_cstr(raw_prop_name);

                let prop_value =
                    <String as FromGlibPtrFull<_>>::from_glib_full(cr_term_to_string(a_expression));

                let selector_name =
                    <String as FromGlibPtrFull<_>>::from_glib_full(raw_selector_name);

                let important = from_glib(a_is_important);

                if let Ok(attribute) = Attribute::from_str(prop_name) {
                    let mut input = ParserInput::new(&prop_value);
                    let mut parser = Parser::new(&mut input);

                    match parse_attribute_value_into_parsed_property(attribute, &mut parser, true) {
                        Ok(property) => {
                            let declaration = Declaration {
                                attribute,
                                property,
                                important,
                            };

                            handler_data
                                .css_rules
                                .add_declaration(&selector_name, declaration);
                        }
                        Err(_) => (), // invalid property name or invalid value; ignore
                    }
                }
                // else unknown property name; ignore
            }
        }

        cur_sel = (*cur_sel).next;
    }
}

unsafe extern "C" fn css_error(_a_this: *mut CRDocHandler) {
    println!("CSS parsing error");
}

unsafe extern "C" fn css_unrecoverable_error(_a_this: *mut CRDocHandler) {
    println!("CSS unrecoverable error");
}
<commit_msg>Make DeclarationList a real type, so we can change it later<commit_after>use cssparser::{Parser, ParserInput};
use std::collections::hash_map::Entry;
use std::collections::{HashMap, HashSet};
use std::ptr;
use std::str::{self, FromStr};

use libc;
use url::Url;

use glib::translate::*;
use glib_sys::{gboolean, gpointer, GList};

use crate::allowed_url::AllowedUrl;
use crate::attributes::Attribute;
use crate::croco::*;
use crate::error::LoadingError;
use crate::io::{self, BinaryData};
use crate::properties::{parse_attribute_value_into_parsed_property, Declaration, SpecifiedValues};
use crate::util::utf8_cstr;

pub struct DeclarationList {
    // Maps property_name -> Declaration
    declarations: HashMap<Attribute, Declaration>,
}

type Selector = String;

/// Contains all the mappings of selectors to style declarations
/// that result from loading an SVG document.
pub struct CssRules {
    selectors_to_declarations: HashMap<Selector, DeclarationList>,
}

impl DeclarationList {
    fn new() -> DeclarationList {
        DeclarationList {
            declarations: HashMap::new(),
        }
    }

    fn add_declaration(&mut self, declaration: Declaration) {
        match self.declarations.entry(declaration.attribute) {
            Entry::Occupied(mut e) => {
                let decl = e.get_mut();

                if !decl.important {
                    *decl = declaration;
                }
            }

            Entry::Vacant(v) => {
                v.insert(declaration);
            }
        }
    }
}

impl CssRules {
    pub fn new() -> CssRules {
        CssRules {
            selectors_to_declarations: HashMap::new(),
        }
    }

    pub fn parse(&mut self, base_url: Option<&Url>, buf: &str) {
        if buf.len() == 0 {
            return; // libcroco doesn't like empty strings :(
        }

        unsafe {
            let mut handler_data = DocHandlerData {
                base_url,
                css_rules: self,
                selector: ptr::null_mut(),
            };

            let doc_handler = cr_doc_handler_new();
            init_cr_doc_handler(&mut *doc_handler);

            (*doc_handler).app_data = &mut handler_data as *mut _ as gpointer;

            let buf_ptr = buf.as_ptr() as *mut _;
            let buf_len = buf.len() as libc::c_ulong;

            let parser = cr_parser_new_from_buf(buf_ptr, buf_len, CR_UTF_8, false.to_glib());
            if parser.is_null() {
                cr_doc_handler_unref(doc_handler);
                return;
            }

            cr_parser_set_sac_handler(parser, doc_handler);
            cr_doc_handler_unref(doc_handler);

            cr_parser_set_use_core_grammar(parser, false.to_glib());
            cr_parser_parse(parser);

            cr_parser_destroy(parser);
        }
    }

    pub fn load_css(&mut self, aurl: &AllowedUrl) -> Result<(), LoadingError> {
        io::acquire_data(aurl, None)
            .and_then(|data| {
                let BinaryData {
                    data: bytes,
                    content_type,
                } = data;

                if content_type.as_ref().map(String::as_ref) == Some("text/css") {
                    Ok(bytes)
                } else {
                    rsvg_log!("\"{}\" is not of type text/css; ignoring", aurl);
                    Err(LoadingError::BadCss)
                }
            })
            .and_then(|bytes| {
                String::from_utf8(bytes).map_err(|_| {
                    rsvg_log!(
                        "\"{}\" does not contain valid UTF-8 CSS data; ignoring",
                        aurl
                    );
                    LoadingError::BadCss
                })
            })
            .and_then(|utf8| {
                self.parse(Some(&aurl), &utf8);
                Ok(()) // FIXME: return CSS parsing errors
            })
    }

    fn add_declaration(&mut self, selector: &str, declaration: Declaration) {
        let decl_list = self
            .selectors_to_declarations
            .entry(selector.to_string())
            .or_insert_with(|| DeclarationList::new());

        decl_list.add_declaration(declaration);
    }

    /// Takes CSS rules which match the given `selector` name and applies them
    /// to the `values`.
    pub fn lookup_apply(
        &self,
        selector: &str,
        values: &mut SpecifiedValues,
        important_styles: &mut HashSet<Attribute>,
    ) -> bool {
        if let Some(decl_list) = self.selectors_to_declarations.get(selector) {
            for (_, declaration) in decl_list.declarations.iter() {
                values.set_property_from_declaration(declaration, important_styles);
            }

            true
        } else {
            false
        }
    }
}

struct DocHandlerData<'a> {
    base_url: Option<&'a Url>,
    css_rules: &'a mut CssRules,
    selector: *mut CRSelector,
}

macro_rules! get_doc_handler_data {
    ($doc_handler:expr) => {
        &mut *((*$doc_handler).app_data as *mut DocHandlerData)
    };
}

fn init_cr_doc_handler(handler: &mut CRDocHandler) {
    handler.import_style = Some(css_import_style);
    handler.start_selector = Some(css_start_selector);
    handler.end_selector = Some(css_end_selector);
    handler.property = Some(css_property);
    handler.error = Some(css_error);
    handler.unrecoverable_error = Some(css_unrecoverable_error);
}

unsafe extern "C" fn css_import_style(
    a_this: *mut CRDocHandler,
    _a_media_list: *mut GList,
    a_uri: CRString,
    _a_uri_default_ns: CRString,
    _a_location: CRParsingLocation,
) {
    let handler_data = get_doc_handler_data!(a_this);

    if a_uri.is_null() {
        return;
    }

    let raw_uri = cr_string_peek_raw_str(a_uri);
    let uri = utf8_cstr(raw_uri);

    if let Ok(aurl) = AllowedUrl::from_href(uri, handler_data.base_url) {
        // FIXME: handle CSS errors
        let _ = handler_data.css_rules.load_css(&aurl);
    } else {
        rsvg_log!("disallowed URL \"{}\" for importing CSS", uri);
    }
}

unsafe extern "C" fn css_start_selector(
    a_this: *mut CRDocHandler,
    a_selector_list: *mut CRSelector,
) {
    let handler_data = get_doc_handler_data!(a_this);

    cr_selector_ref(a_selector_list);
    handler_data.selector = a_selector_list;
}

unsafe extern "C" fn css_end_selector(
    a_this: *mut CRDocHandler,
    _a_selector_list: *mut CRSelector,
) {
    let handler_data = get_doc_handler_data!(a_this);

    cr_selector_unref(handler_data.selector);
    handler_data.selector = ptr::null_mut();
}

unsafe extern "C" fn css_property(
    a_this: *mut CRDocHandler,
    a_name: CRString,
    a_expression: CRTerm,
    a_is_important: gboolean,
) {
    let handler_data = get_doc_handler_data!(a_this);

    if a_name.is_null() || a_expression.is_null() || handler_data.selector.is_null() {
        return;
    }

    let mut cur_sel = handler_data.selector;
    while !cur_sel.is_null() {
        let simple_sel = (*cur_sel).simple_sel;

        if !simple_sel.is_null() {
            let raw_selector_name = cr_simple_sel_to_string(simple_sel) as *mut libc::c_char;

            if !raw_selector_name.is_null() {
                let raw_prop_name = cr_string_peek_raw_str(a_name);
                let prop_name = utf8_cstr(raw_prop_name);

                let prop_value =
                    <String as FromGlibPtrFull<_>>::from_glib_full(cr_term_to_string(a_expression));

                let selector_name =
                    <String as FromGlibPtrFull<_>>::from_glib_full(raw_selector_name);

                let important = from_glib(a_is_important);

                if let Ok(attribute) = Attribute::from_str(prop_name) {
                    let mut input = ParserInput::new(&prop_value);
                    let mut parser = Parser::new(&mut input);

                    match parse_attribute_value_into_parsed_property(attribute, &mut parser, true) {
                        Ok(property) => {
                            let declaration = Declaration {
                                attribute,
                                property,
                                important,
                            };

                            handler_data
                                .css_rules
                                .add_declaration(&selector_name, declaration);
                        }
                        Err(_) => (), // invalid property name or invalid value; ignore
                    }
                }
                // else unknown property name; ignore
            }
        }

        cur_sel = (*cur_sel).next;
    }
}

unsafe extern "C" fn css_error(_a_this: *mut CRDocHandler) {
    println!("CSS parsing error");
}

unsafe extern "C" fn css_unrecoverable_error(_a_this: *mut CRDocHandler) {
    println!("CSS unrecoverable error");
}
<|endoftext|>


<commit_before>
struct median_filter_t {
    window: u8,
    input: usize,
    hole: i64,
    max: i64,
}

fn main() {
    println!("Hello, world!");
}
<commit_msg>modify struct definition for pointers<commit_after>
struct median_filter_t<'a> {
    window: &'a mut u8,
    input: &'a mut usize,
    hole: &'a mut i64,
    max: &'a mut i64,
}

fn median_init(f: median_filter_t, w_size: isize) -> i64 {
    *f.max = 0;
    *f.hole = 0;

    return 0;
}

fn main() {
    println!("Hello, world!");
}
<|endoftext|>


<commit_before>
use bsp::i2c;

const TSL2561_I2C_ADDR: u8 = 0xaa;

const CONTROL_REG_ADDR: u8 = 0x00 | 0x80 | 0x10;
const TIMING_REG_ADDR: u8 = 0x01 | 0x80 | 0x10;
const DATA_REG_ADDR: u8 = 0x0c | 0x80 | 0x10;
const DATA_BYTE_NUM: usize = 4;

#[derive(Clone, Copy)]
#[repr(u8)]
pub enum State {
    On = 0x03,
    Off = 0x00,
}

#[derive(Clone, Copy)]
#[repr(u8)]
pub enum Gain {
    Gain1x = 0x10,
    Gain16x = 0x00,
}

impl Gain {
    fn get_scaling_factor(&self) -> f32 {
        match *self {
            Gain::Gain1x => 1.0,
            Gain::Gain16x => 16.0,
        }
    }
}

#[allow(non_camel_case_types)]
#[derive(Clone, Copy)]
#[repr(u8)]
pub enum IntegrationTime {
    Time13_7ms = 0x00,
    Time101ms = 0x01,
    Time402ms = 0x10,
}

impl IntegrationTime {
    fn get_scaling_factor(&self) -> f32 {
        match *self {
            IntegrationTime::Time13_7ms => 0.034,
            IntegrationTime::Time101ms => 0.252,
            IntegrationTime::Time402ms => 1.0,
        }
    }
}

pub struct Tsl2561 {
    dev_addr: u8,
    i2c_bus: i2c::Peripheral,
    gain: Gain,
    integ_time: IntegrationTime,
    state: State,
}

impl Tsl2561 {
    pub fn new(periph: i2c::Peripheral) -> Tsl2561 {
        Tsl2561 {
            dev_addr: TSL2561_I2C_ADDR,
            i2c_bus: periph,
            gain: Gain::Gain1x,
            integ_time: IntegrationTime::Time402ms,
            state: State::Off,
        }
    }

    pub fn set_state(&mut self, new_state: State) -> Result<(), ()> {
        let mut state_cmd = [CONTROL_REG_ADDR, new_state as u8];

        self.i2c_bus
            .run_transaction(TSL2561_I2C_ADDR, &mut [i2c::Step::Write(&mut state_cmd)])
            .and_then(|_| {
                self.state = new_state;
                Ok(())
            })
    }

    pub fn set_gain_and_integ_time(
        &mut self,
        new_gain: Gain,
        new_integ_time: IntegrationTime,
    ) -> Result<(), ()> {
        let mut g_it_cmd = [TIMING_REG_ADDR, (new_gain as u8) | (new_integ_time as u8)];

        self.i2c_bus
            .run_transaction(TSL2561_I2C_ADDR, &mut [i2c::Step::Write(&mut g_it_cmd)])
            .and_then(|_| {
                self.gain = new_gain;
                self.integ_time = new_integ_time;
                Ok(())
            })
    }

    fn get_raw_data(&self) -> Result<(u16, u16), ()> {
        let mut data_addr_cmd = [DATA_REG_ADDR];
        let mut data_buf = [0; DATA_BYTE_NUM];

        let res = self.i2c_bus.run_transaction(
            TSL2561_I2C_ADDR,
            &mut [
                i2c::Step::Write(&mut data_addr_cmd),
                i2c::Step::Read(&mut data_buf),
            ],
        );

        res.map(|_| {
            (
                ((data_buf[1] as u16) << 8) | (data_buf[0] as u16),
                ((data_buf[3] as u16) << 8) | (data_buf[2] as u16),
            )
        })
    }

    pub fn measure(&mut self) -> Result<f32, ()> {
        let (raw_ch0, raw_ch1) = self.get_raw_data()?;
        if raw_ch0 == 0 {
            return Ok(0.0);
        }

        let ch0 = (raw_ch0 as f32) / self.gain.get_scaling_factor() /
            self.integ_time.get_scaling_factor();

        let ch1 = (raw_ch1 as f32) / self.gain.get_scaling_factor() /
            self.integ_time.get_scaling_factor();

        match ch1 / ch0 {
            x if 0.0 <= x && x < 0.125 => Ok(0.0304 * ch0 - 0.0272 * ch1),
            x if 0.125 <= x && x < 0.25 => Ok(0.0325 * ch0 - 0.0440 * ch1),
            x if 0.25 <= x && x < 0.375 => Ok(0.0351 * ch0 - 0.0544 * ch1),
            x if 0.375 <= x && x < 0.50 => Ok(0.0381 * ch0 - 0.0624 * ch1),
            x if 0.50 <= x && x < 0.61 => Ok(0.0224 * ch0 - 0.0310 * ch1),
            x if 0.61 <= x && x < 0.80 => Ok(0.0128 * ch0 - 0.0153 * ch1),
            x if 0.80 <= x && x < 1.30 => Ok(0.00146 * ch0 - 0.00112 * ch1),
            x if 1.30 <= x => Ok(0.0),
            _ => Err(()),
        }
    }
}
<commit_msg>Fixed TSL2561 I2C protocol bug<commit_after>
use bsp::i2c;

const TSL2561_I2C_ADDR: u8 = 0x29;

const CONTROL_REG_ADDR: u8 = 0x00 | 0x80 | 0x10;
const TIMING_REG_ADDR: u8 = 0x01 | 0x80 | 0x10;
const DATA_REG_ADDR: u8 = 0x0b | 0x80 | 0x10;
const DATA_BYTE_NUM: usize = 5;

#[derive(Clone, Copy)]
#[repr(u8)]
pub enum State {
    On = 0x03,
    Off = 0x00,
}

#[derive(Clone, Copy)]
#[repr(u8)]
pub enum Gain {
    Gain1x = 0x10,
    Gain16x = 0x00,
}

impl Gain {
    fn get_scaling_factor(&self) -> f32 {
        match *self {
            Gain::Gain1x => 1.0,
            Gain::Gain16x => 16.0,
        }
    }
}

#[allow(non_camel_case_types)]
#[derive(Clone, Copy)]
#[repr(u8)]
pub enum IntegrationTime {
    Time13_7ms = 0x00,
    Time101ms = 0x01,
    Time402ms = 0x10,
}

impl IntegrationTime {
    fn get_scaling_factor(&self) -> f32 {
        match *self {
            IntegrationTime::Time13_7ms => 0.034,
            IntegrationTime::Time101ms => 0.252,
            IntegrationTime::Time402ms => 1.0,
        }
    }
}

pub struct Tsl2561 {
    dev_addr: u8,
    i2c_bus: i2c::Peripheral,
    gain: Gain,
    integ_time: IntegrationTime,
    state: State,
}

impl Tsl2561 {
    pub fn new(periph: i2c::Peripheral) -> Tsl2561 {
        Tsl2561 {
            dev_addr: TSL2561_I2C_ADDR,
            i2c_bus: periph,
            gain: Gain::Gain1x,
            integ_time: IntegrationTime::Time402ms,
            state: State::Off,
        }
    }

    pub fn set_state(&mut self, new_state: State) -> Result<(), ()> {
        let mut state_cmd = [CONTROL_REG_ADDR, 0x01, new_state as u8];

        self.i2c_bus
            .run_transaction(TSL2561_I2C_ADDR, &mut [i2c::Step::Write(&mut state_cmd)])
            .and_then(|_| {
                self.state = new_state;
                Ok(())
            })
    }

    pub fn set_gain_and_integ_time(
        &mut self,
        new_gain: Gain,
        new_integ_time: IntegrationTime,
    ) -> Result<(), ()> {
        let mut g_it_cmd = [TIMING_REG_ADDR, 0x01, (new_gain as u8) | (new_integ_time as u8)];

        self.i2c_bus
            .run_transaction(TSL2561_I2C_ADDR, &mut [i2c::Step::Write(&mut g_it_cmd)])
            .and_then(|_| {
                self.gain = new_gain;
                self.integ_time = new_integ_time;
                Ok(())
            })
    }

    fn get_raw_data(&self) -> Result<(u16, u16), ()> {
        let mut data_addr_cmd = [DATA_REG_ADDR];
        let mut data_buf = [0; DATA_BYTE_NUM];

        let res = self.i2c_bus.run_transaction(
            TSL2561_I2C_ADDR,
            &mut [
                i2c::Step::Write(&mut data_addr_cmd),
                i2c::Step::Read(&mut data_buf),
            ],
        );

        res.map(|_| {
            (
                ((data_buf[2] as u16) << 8) | (data_buf[1] as u16),
                ((data_buf[4] as u16) << 8) | (data_buf[3] as u16),
            )
        })
    }

    pub fn measure(&mut self) -> Result<f32, ()> {
        let (raw_ch0, raw_ch1) = self.get_raw_data()?;
        if raw_ch0 == 0 {
            return Ok(0.0);
        }

        let ch0 = (raw_ch0 as f32) / self.gain.get_scaling_factor() /
            self.integ_time.get_scaling_factor();

        let ch1 = (raw_ch1 as f32) / self.gain.get_scaling_factor() /
            self.integ_time.get_scaling_factor();

        match ch1 / ch0 {
            x if 0.0 <= x && x < 0.125 => Ok(0.0304 * ch0 - 0.0272 * ch1),
            x if 0.125 <= x && x < 0.25 => Ok(0.0325 * ch0 - 0.0440 * ch1),
            x if 0.25 <= x && x < 0.375 => Ok(0.0351 * ch0 - 0.0544 * ch1),
            x if 0.375 <= x && x < 0.50 => Ok(0.0381 * ch0 - 0.0624 * ch1),
            x if 0.50 <= x && x < 0.61 => Ok(0.0224 * ch0 - 0.0310 * ch1),
            x if 0.61 <= x && x < 0.80 => Ok(0.0128 * ch0 - 0.0153 * ch1),
            x if 0.80 <= x && x < 1.30 => Ok(0.00146 * ch0 - 0.00112 * ch1),
            x if 1.30 <= x => Ok(0.0),
            _ => Err(()),
        }
    }
}
<|endoftext|>