<commit_before>use super::{
    device::{Device, DeviceState, SensorKind},
    devices_manager::{mk_device_state_key, DevicesState},
    events::{Message, TxEventChannel},
    rule::{Action, Actions, Routine, RoutineId, RoutinesConfig, Rule, SensorRuleState},
};
use std::collections::HashSet;

pub struct RulesEngine {
    config: RoutinesConfig,
    sender: TxEventChannel,
}

impl RulesEngine {
    pub fn new(config: RoutinesConfig, sender: TxEventChannel) -> Self {
        RulesEngine { config, sender }
    }

    pub fn handle_device_update(
        &self,
        old_state: DevicesState,
        new_state: DevicesState,
        old: Option<Device>,
        new: Device,
    ) {
        match old {
            Some(old) => {
                println!("device_updated {:?} (was: {:?})", new, old);

                let matching_actions = self.find_matching_actions(old_state, new_state);

                for action in matching_actions {
                    self.run_action(&action);
                }
            }
            None => {}
        }
    }

    fn run_action(&self, action: &Action) {
        match action {
            Action::ActivateScene(action) => {
                self.sender
                    .send(Message::ActivateScene(action.clone()))
                    .unwrap();
            }
        }
    }

    fn find_matching_actions(&self, old_state: DevicesState, new_state: DevicesState) -> Actions {
        let prev_triggered_routine_ids: HashSet<RoutineId> = self
            .config
            .clone()
            .into_iter()
            .filter(|(_, routine)| is_routine_triggered(&old_state, routine).unwrap())
            .map(|(routine_id, _)| routine_id)
            .collect();

        let new_triggered_routine_ids: HashSet<RoutineId> = self
            .config
            .clone()
            .into_iter()
            .filter(|(_, routine)| is_routine_triggered(&new_state, routine).unwrap())
            .map(|(routine_id, _)| routine_id)
            .collect();

        let triggered_routine_ids =
            new_triggered_routine_ids.difference(&prev_triggered_routine_ids);

        triggered_routine_ids
            .map(|id| {
                let routine = self.config.get(id).unwrap();
                routine.actions.clone()
            })
            .flatten()
            .collect()
    }
}

fn is_routine_triggered(state: &DevicesState, routine: &Routine) -> Result<bool, String> {
    Ok(routine
        .rules
        .iter()
        // FIXME: unsafe .unwrap()
        .all(|rule| is_rule_triggered(state, rule).unwrap()))
}

fn get_device_sensor_kind(device: &Device) -> Option<SensorKind> {
    match device.state {
        DeviceState::Sensor(sensor_kind) => Some(sensor_kind),
        _ => None,
    }
}

fn compare_rule_device_state(rule: &Rule, device: &Device) -> Result<bool, String> {
    let sensor_kind = get_device_sensor_kind(device);

    // FIXME: there must be a better way
    match (rule.state.clone(), sensor_kind) {
        (
            SensorRuleState::OnOffSensor { value: rule_value },
            Some(SensorKind::OnOffSensor {
                value: sensor_value,
            }),
        ) => Ok(rule_value == sensor_value),
        (
            SensorRuleState::DimmerSwitch {
                on: Some(rule_on),
                up: _,
                down: _,
                off: _,
            },
            Some(SensorKind::DimmerSwitch {
                on: sensor_on,
                up: _,
                down: _,
                off: _,
            }),
        ) => Ok(rule_on == sensor_on),
        (
            SensorRuleState::DimmerSwitch {
                on: _,
                up: Some(rule_up),
                down: _,
                off: _,
            },
            Some(SensorKind::DimmerSwitch {
                on: _,
                up: sensor_up,
                down: _,
                off: _,
            }),
        ) => Ok(rule_up == sensor_up),
        (
            SensorRuleState::DimmerSwitch {
                on: _,
                up: _,
                down: Some(rule_down),
                off: _,
            },
            Some(SensorKind::DimmerSwitch {
                on: _,
                up: _,
                down: sensor_down,
                off: _,
            }),
        ) => Ok(rule_down == sensor_down),
        (
            SensorRuleState::DimmerSwitch {
                on: _,
                up: _,
                down: _,
                off: Some(rule_off),
            },
            Some(SensorKind::DimmerSwitch {
                on: _,
                up: _,
                down: _,
                off: sensor_off,
            }),
        ) => Ok(rule_off == sensor_off),
        (rule, sensor) => Err(format!(
            "Unknown sensor states encountered when processing rule {:?}. (sensor: {:?})",
            rule, sensor,
        )),
    }
}

fn is_rule_triggered(state: &DevicesState, rule: &Rule) -> Result<bool, String> {
    let device = state
        .get(&mk_device_state_key(&rule.integration_id, &rule.device_id))
        .ok_or(format!(
            "Could not find device: {} / {}",
            rule.integration_id, rule.device_id
        ))?;

    let triggered = compare_rule_device_state(rule, device)?;

    Ok(triggered)
}
<commit_msg>fix panic when evaluating rules before discovery is done<commit_after>use super::{
    device::{Device, DeviceState, SensorKind},
    devices_manager::{mk_device_state_key, DevicesState},
    events::{Message, TxEventChannel},
    rule::{Action, Actions, Routine, RoutineId, RoutinesConfig, Rule, SensorRuleState},
};
use std::collections::HashSet;

pub struct RulesEngine {
    config: RoutinesConfig,
    sender: TxEventChannel,
}

impl RulesEngine {
    pub fn new(config: RoutinesConfig, sender: TxEventChannel) -> Self {
        RulesEngine { config, sender }
    }

    pub fn handle_device_update(
        &self,
        old_state: DevicesState,
        new_state: DevicesState,
        old: Option<Device>,
        new: Device,
    ) {
        match old {
            Some(old) => {
                println!("device_updated {:?} (was: {:?})", new, old);

                let matching_actions = self.find_matching_actions(old_state, new_state);

                for action in matching_actions {
                    self.run_action(&action);
                }
            }
            None => {}
        }
    }

    fn run_action(&self, action: &Action) {
        match action {
            Action::ActivateScene(action) => {
                self.sender
                    .send(Message::ActivateScene(action.clone()))
                    .unwrap();
            }
        }
    }

    fn find_matching_actions(&self, old_state: DevicesState, new_state: DevicesState) -> Actions {
        // if states are equal we can bail out early
        if old_state == new_state {
            return vec![];
        }

        let prev_triggered_routine_ids = get_triggered_routine_ids(&self.config, &old_state);
        let new_triggered_routine_ids = get_triggered_routine_ids(&self.config, &new_state);

        let triggered_routine_ids =
            new_triggered_routine_ids.difference(&prev_triggered_routine_ids);

        triggered_routine_ids
            .map(|id| {
                // .unwrap() should be safe here because triggered_routine_ids
                // contains only existing routine_ids
                let routine = self.config.get(id).unwrap();
                routine.actions.clone()
            })
            .flatten()
            .collect()
    }
}

fn get_triggered_routine_ids(
    routines: &RoutinesConfig,
    state: &DevicesState,
) -> HashSet<RoutineId> {
    let triggered_routine_ids: HashSet<RoutineId> = routines
        .iter()
        .filter(|(_, routine)| match is_routine_triggered(state, routine) {
            Ok(triggered) => triggered,
            Err(e) => {
                println!("Error while checking routine {:?} rules: {}", routine, e);
                false
            }
        })
        .map(|(routine_id, _)| routine_id.clone())
        .collect();

    triggered_routine_ids
}

fn is_routine_triggered(state: &DevicesState, routine: &Routine) -> Result<bool, String> {
    let result = routine
        .rules
        .iter()
        .map(|rule| is_rule_triggered(state, rule))
        .all(|result| result == Ok(true));

    Ok(result)
}

fn get_device_sensor_kind(device: &Device) -> Option<SensorKind> {
    match device.state {
        DeviceState::Sensor(sensor_kind) => Some(sensor_kind),
        _ => None,
    }
}

fn compare_rule_device_state(rule: &Rule, device: &Device) -> Result<bool, String> {
    let sensor_kind = get_device_sensor_kind(device);

    // FIXME: there must be a better way
    match (rule.state.clone(), sensor_kind) {
        (
            SensorRuleState::OnOffSensor { value: rule_value },
            Some(SensorKind::OnOffSensor {
                value: sensor_value,
            }),
        ) => Ok(rule_value == sensor_value),
        (
            SensorRuleState::DimmerSwitch {
                on: Some(rule_on),
                up: _,
                down: _,
                off: _,
            },
            Some(SensorKind::DimmerSwitch {
                on: sensor_on,
                up: _,
                down: _,
                off: _,
            }),
        ) => Ok(rule_on == sensor_on),
        (
            SensorRuleState::DimmerSwitch {
                on: _,
                up: Some(rule_up),
                down: _,
                off: _,
            },
            Some(SensorKind::DimmerSwitch {
                on: _,
                up: sensor_up,
                down: _,
                off: _,
            }),
        ) => Ok(rule_up == sensor_up),
        (
            SensorRuleState::DimmerSwitch {
                on: _,
                up: _,
                down: Some(rule_down),
                off: _,
            },
            Some(SensorKind::DimmerSwitch {
                on: _,
                up: _,
                down: sensor_down,
                off: _,
            }),
        ) => Ok(rule_down == sensor_down),
        (
            SensorRuleState::DimmerSwitch {
                on: _,
                up: _,
                down: _,
                off: Some(rule_off),
            },
            Some(SensorKind::DimmerSwitch {
                on: _,
                up: _,
                down: _,
                off: sensor_off,
            }),
        ) => Ok(rule_off == sensor_off),
        (rule, sensor) => Err(format!(
            "Unknown sensor states encountered when processing rule {:?}. (sensor: {:?})",
            rule, sensor,
        )),
    }
}

fn is_rule_triggered(state: &DevicesState, rule: &Rule) -> Result<bool, String> {
    let device = state
        .get(&mk_device_state_key(&rule.integration_id, &rule.device_id))
        .ok_or(format!(
            "Could not find device: {} / {}",
            rule.integration_id, rule.device_id
        ))?;

    let triggered = compare_rule_device_state(rule, device)?;

    Ok(triggered)
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use crate::errors::BuildProjectError;
use log::info;
use serde::{Serialize, Serializer};
use std::fs::{create_dir_all, File};
use std::io;
use std::io::prelude::*;
use std::{path::PathBuf, sync::Mutex};

type BuildProjectResult = Result<(), BuildProjectError>;

pub trait ArtifactWriter {
    fn write_if_changed(&self, path: PathBuf, content: Vec<u8>) -> BuildProjectResult;
    fn remove(&self, path: PathBuf) -> BuildProjectResult;
    fn finalize(&self) -> crate::errors::Result<()>;
}

type SourceControlFn = fn(&Mutex<Vec<PathBuf>>, &Mutex<Vec<PathBuf>>) -> crate::errors::Result<()>;
pub struct ArtifactFileWriter {
    added: Mutex<Vec<PathBuf>>,
    removed: Mutex<Vec<PathBuf>>,
    source_control_fn: SourceControlFn,
}

impl Default for ArtifactFileWriter {
    fn default() -> Self {
        Self {
            added: Default::default(),
            removed: Default::default(),
            source_control_fn: |_, _| Ok(()),
        }
    }
}

impl ArtifactFileWriter {
    pub fn new(source_control_fn: SourceControlFn) -> Self {
        Self {
            added: Default::default(),
            removed: Default::default(),
            source_control_fn,
        }
    }

    fn write_file(&self, path: &PathBuf, content: &[u8]) -> io::Result<()> {
        let mut should_add = false;
        if path.exists() {
            let existing_content = std::fs::read(path)?;
            if existing_content == content {
                return Ok(());
            }
        } else {
            should_add = true;
            ensure_file_directory_exists(path)?;
        }

        let mut file = File::create(path)?;
        file.write_all(&content)?;
        if should_add {
            self.added.lock().unwrap().push(path.clone());
        }
        Ok(())
    }
}
impl ArtifactWriter for ArtifactFileWriter {
    fn write_if_changed(&self, path: PathBuf, content: Vec<u8>) -> BuildProjectResult {
        self.write_file(&path, &content)
            .map_err(|error| BuildProjectError::WriteFileError {
                file: path,
                source: error,
            })
    }

    fn remove(&self, path: PathBuf) -> BuildProjectResult {
        match std::fs::remove_file(&path) {
            Ok(_) => {
                self.removed.lock().unwrap().push(path);
            }
            _ => info!("tried to delete already deleted file: {:?}", path),
        }
        Ok(())
    }

    fn finalize(&self) -> crate::errors::Result<()> {
        (self.source_control_fn)(&self.added, &self.removed)
    }
}

#[derive(Serialize)]
struct CodegenRecords {
    pub removed: Vec<ArtifactDeletionRecord>,
    pub changed: Vec<ArtifactUpdateRecord>,
}

#[derive(Serialize)]
struct ArtifactDeletionRecord {
    pub path: PathBuf,
}

#[derive(Serialize)]
struct ArtifactUpdateRecord {
    pub path: PathBuf,
    #[serde(serialize_with = "from_utf8")]
    pub data: Vec<u8>,
}

fn from_utf8<S>(slice: &Vec<u8>, s: S) -> Result<S::Ok, S::Error>
where
    S: Serializer,
{
    s.serialize_str(std::str::from_utf8(slice).unwrap())
}

pub struct ArtifactDifferenceWriter {
    codegen_records: Mutex<CodegenRecords>,
    codegen_filepath: PathBuf,
    verify_changes_against_filesystem: bool,
}

impl ArtifactDifferenceWriter {
    pub fn new(
        codegen_filepath: PathBuf,
        verify_changes_against_filesystem: bool,
    ) -> ArtifactDifferenceWriter {
        ArtifactDifferenceWriter {
            codegen_filepath,
            codegen_records: Mutex::new(CodegenRecords {
                changed: Vec::new(),
                removed: Vec::new(),
            }),
            verify_changes_against_filesystem,
        }
    }
}

impl ArtifactWriter for ArtifactDifferenceWriter {
    fn write_if_changed(&self, path: PathBuf, content: Vec<u8>) -> BuildProjectResult {
        let should_include_artifact_in_codegen = !self.verify_changes_against_filesystem
            || !content_is_same(&path, &content).map_err(|error| {
                BuildProjectError::WriteFileError {
                    file: path.clone(),
                    source: error,
                }
            })?;
        if should_include_artifact_in_codegen {
            self.codegen_records
                .lock()
                .unwrap()
                .changed
                .push(ArtifactUpdateRecord {
                    path,
                    data: content,
                });
        }
        Ok(())
    }

    fn remove(&self, path: PathBuf) -> BuildProjectResult {
        if path.exists() {
            self.codegen_records
                .lock()
                .unwrap()
                .removed
                .push(ArtifactDeletionRecord { path });
        }
        Ok(())
    }

    fn finalize(&self) -> crate::errors::Result<()> {
        (|| {
            let mut file = File::create(&self.codegen_filepath)?;
            file.write_all(&serde_json::to_string(&self.codegen_records)?.as_bytes())
        })()
        .map_err(|error| crate::errors::Error::WriteFileError {
            file: self.codegen_filepath.clone(),
            source: error,
        })
    }
}

fn ensure_file_directory_exists(file_path: &PathBuf) -> io::Result<()> {
    if let Some(file_directory) = file_path.parent() {
        if !file_directory.exists() {
            create_dir_all(file_directory)?;
        }
    }

    Ok(())
}

fn content_is_same(path: &PathBuf, content: &Vec<u8>) -> io::Result<bool> {
    if path.exists() {
        let existing_content = std::fs::read(path)?;
        Ok(&existing_content == content)
    } else {
        Ok(false)
    }
}
<commit_msg>Make artifact_writer accept an Option<SourceControlFn><commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use crate::errors::BuildProjectError;
use log::info;
use serde::{Serialize, Serializer};
use std::fs::{create_dir_all, File};
use std::io;
use std::io::prelude::*;
use std::{path::PathBuf, sync::Mutex};

type BuildProjectResult = Result<(), BuildProjectError>;

pub trait ArtifactWriter {
    fn write_if_changed(&self, path: PathBuf, content: Vec<u8>) -> BuildProjectResult;
    fn remove(&self, path: PathBuf) -> BuildProjectResult;
    fn finalize(&self) -> crate::errors::Result<()>;
}

type SourceControlFn = fn(&Mutex<Vec<PathBuf>>, &Mutex<Vec<PathBuf>>) -> crate::errors::Result<()>;
pub struct ArtifactFileWriter {
    added: Mutex<Vec<PathBuf>>,
    removed: Mutex<Vec<PathBuf>>,
    source_control_fn: Option<SourceControlFn>,
}

impl Default for ArtifactFileWriter {
    fn default() -> Self {
        Self {
            added: Default::default(),
            removed: Default::default(),
            source_control_fn: None,
        }
    }
}

impl ArtifactFileWriter {
    pub fn new(source_control_fn: Option<SourceControlFn>) -> Self {
        Self {
            added: Default::default(),
            removed: Default::default(),
            source_control_fn,
        }
    }

    fn write_file(&self, path: &PathBuf, content: &[u8]) -> io::Result<()> {
        let mut should_add = false;
        if path.exists() {
            let existing_content = std::fs::read(path)?;
            if existing_content == content {
                return Ok(());
            }
        } else {
            should_add = true;
            ensure_file_directory_exists(path)?;
        }

        let mut file = File::create(path)?;
        file.write_all(&content)?;
        if should_add {
            self.added.lock().unwrap().push(path.clone());
        }
        Ok(())
    }
}
impl ArtifactWriter for ArtifactFileWriter {
    fn write_if_changed(&self, path: PathBuf, content: Vec<u8>) -> BuildProjectResult {
        self.write_file(&path, &content)
            .map_err(|error| BuildProjectError::WriteFileError {
                file: path,
                source: error,
            })
    }

    fn remove(&self, path: PathBuf) -> BuildProjectResult {
        match std::fs::remove_file(&path) {
            Ok(_) => {
                self.removed.lock().unwrap().push(path);
            }
            _ => info!("tried to delete already deleted file: {:?}", path),
        }
        Ok(())
    }

    fn finalize(&self) -> crate::errors::Result<()> {
        if let Some(source_control_fn) = self.source_control_fn {
            (source_control_fn)(&self.added, &self.removed)
        } else {
            Ok(())
        }
    }
}

#[derive(Serialize)]
struct CodegenRecords {
    pub removed: Vec<ArtifactDeletionRecord>,
    pub changed: Vec<ArtifactUpdateRecord>,
}

#[derive(Serialize)]
struct ArtifactDeletionRecord {
    pub path: PathBuf,
}

#[derive(Serialize)]
struct ArtifactUpdateRecord {
    pub path: PathBuf,
    #[serde(serialize_with = "from_utf8")]
    pub data: Vec<u8>,
}

fn from_utf8<S>(slice: &Vec<u8>, s: S) -> Result<S::Ok, S::Error>
where
    S: Serializer,
{
    s.serialize_str(std::str::from_utf8(slice).unwrap())
}

pub struct ArtifactDifferenceWriter {
    codegen_records: Mutex<CodegenRecords>,
    codegen_filepath: PathBuf,
    verify_changes_against_filesystem: bool,
}

impl ArtifactDifferenceWriter {
    pub fn new(
        codegen_filepath: PathBuf,
        verify_changes_against_filesystem: bool,
    ) -> ArtifactDifferenceWriter {
        ArtifactDifferenceWriter {
            codegen_filepath,
            codegen_records: Mutex::new(CodegenRecords {
                changed: Vec::new(),
                removed: Vec::new(),
            }),
            verify_changes_against_filesystem,
        }
    }
}

impl ArtifactWriter for ArtifactDifferenceWriter {
    fn write_if_changed(&self, path: PathBuf, content: Vec<u8>) -> BuildProjectResult {
        let should_include_artifact_in_codegen = !self.verify_changes_against_filesystem
            || !content_is_same(&path, &content).map_err(|error| {
                BuildProjectError::WriteFileError {
                    file: path.clone(),
                    source: error,
                }
            })?;
        if should_include_artifact_in_codegen {
            self.codegen_records
                .lock()
                .unwrap()
                .changed
                .push(ArtifactUpdateRecord {
                    path,
                    data: content,
                });
        }
        Ok(())
    }

    fn remove(&self, path: PathBuf) -> BuildProjectResult {
        if path.exists() {
            self.codegen_records
                .lock()
                .unwrap()
                .removed
                .push(ArtifactDeletionRecord { path });
        }
        Ok(())
    }

    fn finalize(&self) -> crate::errors::Result<()> {
        (|| {
            let mut file = File::create(&self.codegen_filepath)?;
            file.write_all(&serde_json::to_string(&self.codegen_records)?.as_bytes())
        })()
        .map_err(|error| crate::errors::Error::WriteFileError {
            file: self.codegen_filepath.clone(),
            source: error,
        })
    }
}

fn ensure_file_directory_exists(file_path: &PathBuf) -> io::Result<()> {
    if let Some(file_directory) = file_path.parent() {
        if !file_directory.exists() {
            create_dir_all(file_directory)?;
        }
    }

    Ok(())
}

fn content_is_same(path: &PathBuf, content: &Vec<u8>) -> io::Result<bool> {
    if path.exists() {
        let existing_content = std::fs::read(path)?;
        Ok(&existing_content == content)
    } else {
        Ok(false)
    }
}
<|endoftext|>


<commit_before>/// This function is where the kernel sets up IRQ handlers
/// It is increcibly unsafe, and should be minimal in nature
/// It must create the IDT with the correct entries, those entries are
/// defined in other files inside of the `arch` module

use core::{mem, slice};
use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering};

use crate::allocator;
#[cfg(feature = "acpi")]
use crate::acpi;
#[cfg(feature = "graphical_debug")]
use arch::x86_64::graphical_debug;
use crate::arch::x86_64::pti;
use crate::device;
use crate::gdt;
use crate::idt;
use crate::interrupt;
use crate::log;
use crate::memory;
use crate::paging;

/// Test of zero values in BSS.
static BSS_TEST_ZERO: usize = 0;
/// Test of non-zero values in data.
static DATA_TEST_NONZERO: usize = 0xFFFF_FFFF_FFFF_FFFF;
/// Test of zero values in thread BSS
#[thread_local]
static mut TBSS_TEST_ZERO: usize = 0;
/// Test of non-zero values in thread data.
#[thread_local]
static mut TDATA_TEST_NONZERO: usize = 0xFFFF_FFFF_FFFF_FFFF;

pub static KERNEL_BASE: AtomicUsize = AtomicUsize::new(0);
pub static KERNEL_SIZE: AtomicUsize = AtomicUsize::new(0);
pub static CPU_COUNT: AtomicUsize = AtomicUsize::new(0);
pub static AP_READY: AtomicBool = AtomicBool::new(false);
static BSP_READY: AtomicBool = AtomicBool::new(false);

#[repr(packed)]
pub struct KernelArgs {
    kernel_base: u64,
    kernel_size: u64,
    stack_base: u64,
    stack_size: u64,
    env_base: u64,
    env_size: u64,
}

/// Extended kernel args.
///
/// While the base kernel args are sufficient for basic initialization of most things, information
/// like the memory map and the ACPI RSDPS (on UEFI), might have to be passed som other way.
///
/// If the envs begin with b"\x7f=V2", the pointer to `KernelArgs` can be assumed to also point to a
/// complete `KernelArgsExt`.
#[repr(packed)]
pub struct KernelArgsExt {
    /// The base compatible kernel args.
    base: KernelArgs,
    /// The revision of the KernelArgsExt struct. Only 0 at the moment.
    proto_rev: u16,
    /// The total length of the kernel args struct.
    length: u16,
    /// Some flags. All flags are currently reserved and shall be 0.
    flags: u32,
    /// The base 64-bit pointer to an array of saved RSDPs. It's up to the kernel (and possibly
    /// userspace), to decide which RSDP to use. The buffer will be a linked list containing a
    /// 32-bit relative (to this field) next, and the actual struct afterwards.
    ///
    /// This field can be NULL, and if so, the system has not booted with UEFI or in some other way
    /// retrieved the RSDPs. The kernel or a userspace driver will thus try searching the BIOS
    /// memory instead. On UEFI systems, this is not guaranteed to actually work.
    acpi_rsdps_base: u64,
    /// The size of the RSDPs region.
    acpi_rsdps_size: u64,
    // TODO: Include things like memory map
    // TODO: Generalized tag structure, like with GRUB.
}

/// The entry to Rust, all things must be initialized
#[no_mangle]
pub unsafe extern fn kstart(args_ptr: *const KernelArgs) -> ! {
    let env = {
        let args = &*args_ptr;

        let kernel_base = args.kernel_base as usize;
        let kernel_size = args.kernel_size as usize;
        let stack_base = args.stack_base as usize;
        let stack_size = args.stack_size as usize;
        let env_base = args.env_base as usize;
        let env_size = args.env_size as usize;

        // BSS should already be zero
        {
            assert_eq!(BSS_TEST_ZERO, 0);
            assert_eq!(DATA_TEST_NONZERO, 0xFFFF_FFFF_FFFF_FFFF);
        }

        KERNEL_BASE.store(kernel_base, Ordering::SeqCst);
        KERNEL_SIZE.store(kernel_size, Ordering::SeqCst);

        println!("Kernel: {:X}:{:X}", kernel_base, kernel_base + kernel_size);
        println!("Stack: {:X}:{:X}", stack_base, stack_base + stack_size);
        println!("Env: {:X}:{:X}", env_base, env_base + env_size);

        let mut env = slice::from_raw_parts(env_base as *const u8, env_size);

        // This is kind of a hack, only used for an extended KernelArgs struct.
        let extended_kargs = if &env[..4] == b"\x7f=V2" {
            println!("Using EXT kernel args.");
            env = &env[4..];
            let ext_kargs = &*(args_ptr as *const KernelArgsExt);

            if (ext_kargs.length as usize) < mem::size_of::<KernelArgsExt>() {
                None
            } else {
                Some(ext_kargs)
            }
        } else { None };

        let ext_mem_ranges = if let Some(ref xargs) = extended_kargs {
            Some([(xargs.acpi_rsdps_base as usize, xargs.acpi_rsdps_size as usize)])
        } else {
            None
        };

        // Set up GDT before paging
        gdt::init();

        // Set up IDT before paging
        idt::init();

        // Initialize memory management
        memory::init(0, kernel_base + ((kernel_size + 4095)/4096) * 4096);

        // Initialize paging
        let (mut active_table, tcb_offset) = paging::init(0, kernel_base, kernel_base + kernel_size, stack_base, stack_base + stack_size, ext_mem_ranges.as_ref().map(|arr| &arr[..]).unwrap_or(&[]));

        // Set up GDT after paging with TLS
        gdt::init_paging(tcb_offset, stack_base + stack_size);

        // Set up IDT
        idt::init_paging();

        // Set up syscall instruction
        interrupt::syscall::init();

        // Test tdata and tbss
        {
            assert_eq!(TBSS_TEST_ZERO, 0);
            TBSS_TEST_ZERO += 1;
            assert_eq!(TBSS_TEST_ZERO, 1);
            assert_eq!(TDATA_TEST_NONZERO, 0xFFFF_FFFF_FFFF_FFFF);
            TDATA_TEST_NONZERO -= 1;
            assert_eq!(TDATA_TEST_NONZERO, 0xFFFF_FFFF_FFFF_FFFE);
        }

        // Reset AP variables
        CPU_COUNT.store(1, Ordering::SeqCst);
        AP_READY.store(false, Ordering::SeqCst);
        BSP_READY.store(false, Ordering::SeqCst);

        // Setup kernel heap
        allocator::init(&mut active_table);

        // Activate memory logging
        log::init();

        // Use graphical debug
        #[cfg(feature="graphical_debug")]
        graphical_debug::init(&mut active_table);

        // Initialize devices
        device::init(&mut active_table);

        // Read ACPI tables, starts APs
        #[cfg(feature = "acpi")]
        {
            acpi::init(&mut active_table, extended_kargs.as_ref().map(|kargs| (kargs.acpi_rsdps_base, kargs.acpi_rsdps_size)));
            device::init_after_acpi(&mut active_table);
        }

        // Initialize all of the non-core devices not otherwise needed to complete initialization
        device::init_noncore();

        // Initialize memory functions after core has loaded
        memory::init_noncore();

        // Stop graphical debug
        #[cfg(feature="graphical_debug")]
        graphical_debug::fini(&mut active_table);

        BSP_READY.store(true, Ordering::SeqCst);

        env
    };

    crate::kmain(CPU_COUNT.load(Ordering::SeqCst), env);
}

#[repr(packed)]
pub struct KernelArgsAp {
    cpu_id: u64,
    page_table: u64,
    stack_start: u64,
    stack_end: u64,
}

/// Entry to rust for an AP
pub unsafe extern fn kstart_ap(args_ptr: *const KernelArgsAp) -> ! {
    let cpu_id = {
        let args = &*args_ptr;
        let cpu_id = args.cpu_id as usize;
        let bsp_table = args.page_table as usize;
        let stack_start = args.stack_start as usize;
        let stack_end = args.stack_end as usize;

        assert_eq!(BSS_TEST_ZERO, 0);
        assert_eq!(DATA_TEST_NONZERO, 0xFFFF_FFFF_FFFF_FFFF);

        // Set up GDT before paging
        gdt::init();

        // Set up IDT before paging
        idt::init();

        // Initialize paging
        let tcb_offset = paging::init_ap(cpu_id, bsp_table, stack_start, stack_end);

        // Set up GDT with TLS
        gdt::init_paging(tcb_offset, stack_end);

        // Set up IDT for AP
        idt::init_paging();

        // Set up syscall instruction
        interrupt::syscall::init();

        // Test tdata and tbss
        {
            assert_eq!(TBSS_TEST_ZERO, 0);
            TBSS_TEST_ZERO += 1;
            assert_eq!(TBSS_TEST_ZERO, 1);
            assert_eq!(TDATA_TEST_NONZERO, 0xFFFF_FFFF_FFFF_FFFF);
            TDATA_TEST_NONZERO -= 1;
            assert_eq!(TDATA_TEST_NONZERO, 0xFFFF_FFFF_FFFF_FFFE);
        }

        // Initialize devices (for AP)
        device::init_ap();

        AP_READY.store(true, Ordering::SeqCst);

        cpu_id
    };

    while ! BSP_READY.load(Ordering::SeqCst) {
        interrupt::pause();
    }

    crate::kmain_ap(cpu_id);
}

#[naked]
pub unsafe fn usermode(ip: usize, sp: usize, arg: usize) -> ! {
    asm!("push r10
          push r11
          push r12
          push r13
          push r14
          push r15"
          : // No output
          :   "{r10}"(gdt::GDT_USER_DATA << 3 | 3), // Data segment
              "{r11}"(sp), // Stack pointer
              "{r12}"(1 << 9), // Flags - Set interrupt enable flag
              "{r13}"(gdt::GDT_USER_CODE << 3 | 3), // Code segment
              "{r14}"(ip), // IP
              "{r15}"(arg) // Argument
          : // No clobbers
          : "intel", "volatile");

    // Unmap kernel
    pti::unmap();

    // Go to usermode
    asm!("mov ds, r14d
         mov es, r14d
         mov fs, r15d
         mov gs, r14d
         xor rax, rax
         xor rbx, rbx
         xor rcx, rcx
         xor rdx, rdx
         xor rsi, rsi
         xor rdi, rdi
         xor rbp, rbp
         xor r8, r8
         xor r9, r9
         xor r10, r10
         xor r11, r11
         xor r12, r12
         xor r13, r13
         xor r14, r14
         xor r15, r15
         fninit
         pop rdi
         iretq"
         : // No output because it never returns
         :   "{r14}"(gdt::GDT_USER_DATA << 3 | 3), // Data segment
             "{r15}"(gdt::GDT_USER_TLS << 3 | 3) // TLS segment
         : // No clobbers because it never returns
         : "intel", "volatile");
    unreachable!();
}
<commit_msg>Remove unnecessary kernel args.<commit_after>/// This function is where the kernel sets up IRQ handlers
/// It is increcibly unsafe, and should be minimal in nature
/// It must create the IDT with the correct entries, those entries are
/// defined in other files inside of the `arch` module

use core::{mem, slice};
use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering};

use crate::allocator;
#[cfg(feature = "acpi")]
use crate::acpi;
#[cfg(feature = "graphical_debug")]
use arch::x86_64::graphical_debug;
use crate::arch::x86_64::pti;
use crate::device;
use crate::gdt;
use crate::idt;
use crate::interrupt;
use crate::log;
use crate::memory;
use crate::paging;

/// Test of zero values in BSS.
static BSS_TEST_ZERO: usize = 0;
/// Test of non-zero values in data.
static DATA_TEST_NONZERO: usize = 0xFFFF_FFFF_FFFF_FFFF;
/// Test of zero values in thread BSS
#[thread_local]
static mut TBSS_TEST_ZERO: usize = 0;
/// Test of non-zero values in thread data.
#[thread_local]
static mut TDATA_TEST_NONZERO: usize = 0xFFFF_FFFF_FFFF_FFFF;

pub static KERNEL_BASE: AtomicUsize = AtomicUsize::new(0);
pub static KERNEL_SIZE: AtomicUsize = AtomicUsize::new(0);
pub static CPU_COUNT: AtomicUsize = AtomicUsize::new(0);
pub static AP_READY: AtomicBool = AtomicBool::new(false);
static BSP_READY: AtomicBool = AtomicBool::new(false);

#[repr(packed)]
pub struct KernelArgs {
    kernel_base: u64,
    kernel_size: u64,
    stack_base: u64,
    stack_size: u64,
    env_base: u64,
    env_size: u64,

    /// The base 64-bit pointer to an array of saved RSDPs. It's up to the kernel (and possibly
    /// userspace), to decide which RSDP to use. The buffer will be a linked list containing a
    /// 32-bit relative (to this field) next, and the actual struct afterwards.
    ///
    /// This field can be NULL, and if so, the system has not booted with UEFI or in some other way
    /// retrieved the RSDPs. The kernel or a userspace driver will thus try searching the BIOS
    /// memory instead. On UEFI systems, searching is not guaranteed to actually work though.
    acpi_rsdps_base: u64,
    /// The size of the RSDPs region.
    acpi_rsdps_size: u64,
}

/// The entry to Rust, all things must be initialized
#[no_mangle]
pub unsafe extern fn kstart(args_ptr: *const KernelArgs) -> ! {
    let env = {
        let args = &*args_ptr;

        let kernel_base = args.kernel_base as usize;
        let kernel_size = args.kernel_size as usize;
        let stack_base = args.stack_base as usize;
        let stack_size = args.stack_size as usize;
        let env_base = args.env_base as usize;
        let env_size = args.env_size as usize;

        // BSS should already be zero
        {
            assert_eq!(BSS_TEST_ZERO, 0);
            assert_eq!(DATA_TEST_NONZERO, 0xFFFF_FFFF_FFFF_FFFF);
        }

        KERNEL_BASE.store(kernel_base, Ordering::SeqCst);
        KERNEL_SIZE.store(kernel_size, Ordering::SeqCst);

        println!("Kernel: {:X}:{:X}", kernel_base, kernel_base + kernel_size);
        println!("Stack: {:X}:{:X}", stack_base, stack_base + stack_size);
        println!("Env: {:X}:{:X}", env_base, env_base + env_size);
        println!("RSDPs: {:X}:{:X}", args.acpi_rsdps_base, args.acpi_rsdps_base + args.acpi_rsdps_size);

        let ext_mem_ranges = if args.acpi_rsdps_base != 0 && args.acpi_rsdps_size > 0 {
            Some([(args.acpi_rsdps_base as usize, args.acpi_rsdps_size as usize)])
        } else {
            None
        };

        // Set up GDT before paging
        gdt::init();

        // Set up IDT before paging
        idt::init();

        // Initialize memory management
        memory::init(0, kernel_base + ((kernel_size + 4095)/4096) * 4096);

        // Initialize paging
        let (mut active_table, tcb_offset) = paging::init(0, kernel_base, kernel_base + kernel_size, stack_base, stack_base + stack_size, ext_mem_ranges.as_ref().map(|arr| &arr[..]).unwrap_or(&[]));

        // Set up GDT after paging with TLS
        gdt::init_paging(tcb_offset, stack_base + stack_size);

        // Set up IDT
        idt::init_paging();

        // Set up syscall instruction
        interrupt::syscall::init();

        // Test tdata and tbss
        {
            assert_eq!(TBSS_TEST_ZERO, 0);
            TBSS_TEST_ZERO += 1;
            assert_eq!(TBSS_TEST_ZERO, 1);
            assert_eq!(TDATA_TEST_NONZERO, 0xFFFF_FFFF_FFFF_FFFF);
            TDATA_TEST_NONZERO -= 1;
            assert_eq!(TDATA_TEST_NONZERO, 0xFFFF_FFFF_FFFF_FFFE);
        }

        // Reset AP variables
        CPU_COUNT.store(1, Ordering::SeqCst);
        AP_READY.store(false, Ordering::SeqCst);
        BSP_READY.store(false, Ordering::SeqCst);

        // Setup kernel heap
        allocator::init(&mut active_table);

        // Activate memory logging
        log::init();

        // Use graphical debug
        #[cfg(feature="graphical_debug")]
        graphical_debug::init(&mut active_table);

        // Initialize devices
        device::init(&mut active_table);

        // Read ACPI tables, starts APs
        #[cfg(feature = "acpi")]
        {
            acpi::init(&mut active_table, if args.acpi_rsdps_base != 0 && args.acpi_rsdps_size > 0 { Some((args.acpi_rsdps_base, args.acpi_rsdps_size)) } else { None });
            device::init_after_acpi(&mut active_table);
        }

        // Initialize all of the non-core devices not otherwise needed to complete initialization
        device::init_noncore();

        // Initialize memory functions after core has loaded
        memory::init_noncore();

        // Stop graphical debug
        #[cfg(feature="graphical_debug")]
        graphical_debug::fini(&mut active_table);

        BSP_READY.store(true, Ordering::SeqCst);

        slice::from_raw_parts(env_base as *const u8, env_size)
    };

    crate::kmain(CPU_COUNT.load(Ordering::SeqCst), env);
}

#[repr(packed)]
pub struct KernelArgsAp {
    cpu_id: u64,
    page_table: u64,
    stack_start: u64,
    stack_end: u64,
}

/// Entry to rust for an AP
pub unsafe extern fn kstart_ap(args_ptr: *const KernelArgsAp) -> ! {
    let cpu_id = {
        let args = &*args_ptr;
        let cpu_id = args.cpu_id as usize;
        let bsp_table = args.page_table as usize;
        let stack_start = args.stack_start as usize;
        let stack_end = args.stack_end as usize;

        assert_eq!(BSS_TEST_ZERO, 0);
        assert_eq!(DATA_TEST_NONZERO, 0xFFFF_FFFF_FFFF_FFFF);

        // Set up GDT before paging
        gdt::init();

        // Set up IDT before paging
        idt::init();

        // Initialize paging
        let tcb_offset = paging::init_ap(cpu_id, bsp_table, stack_start, stack_end);

        // Set up GDT with TLS
        gdt::init_paging(tcb_offset, stack_end);

        // Set up IDT for AP
        idt::init_paging();

        // Set up syscall instruction
        interrupt::syscall::init();

        // Test tdata and tbss
        {
            assert_eq!(TBSS_TEST_ZERO, 0);
            TBSS_TEST_ZERO += 1;
            assert_eq!(TBSS_TEST_ZERO, 1);
            assert_eq!(TDATA_TEST_NONZERO, 0xFFFF_FFFF_FFFF_FFFF);
            TDATA_TEST_NONZERO -= 1;
            assert_eq!(TDATA_TEST_NONZERO, 0xFFFF_FFFF_FFFF_FFFE);
        }

        // Initialize devices (for AP)
        device::init_ap();

        AP_READY.store(true, Ordering::SeqCst);

        cpu_id
    };

    while ! BSP_READY.load(Ordering::SeqCst) {
        interrupt::pause();
    }

    crate::kmain_ap(cpu_id);
}

#[naked]
pub unsafe fn usermode(ip: usize, sp: usize, arg: usize) -> ! {
    asm!("push r10
          push r11
          push r12
          push r13
          push r14
          push r15"
          : // No output
          :   "{r10}"(gdt::GDT_USER_DATA << 3 | 3), // Data segment
              "{r11}"(sp), // Stack pointer
              "{r12}"(1 << 9), // Flags - Set interrupt enable flag
              "{r13}"(gdt::GDT_USER_CODE << 3 | 3), // Code segment
              "{r14}"(ip), // IP
              "{r15}"(arg) // Argument
          : // No clobbers
          : "intel", "volatile");

    // Unmap kernel
    pti::unmap();

    // Go to usermode
    asm!("mov ds, r14d
         mov es, r14d
         mov fs, r15d
         mov gs, r14d
         xor rax, rax
         xor rbx, rbx
         xor rcx, rcx
         xor rdx, rdx
         xor rsi, rsi
         xor rdi, rdi
         xor rbp, rbp
         xor r8, r8
         xor r9, r9
         xor r10, r10
         xor r11, r11
         xor r12, r12
         xor r13, r13
         xor r14, r14
         xor r15, r15
         fninit
         pop rdi
         iretq"
         : // No output because it never returns
         :   "{r14}"(gdt::GDT_USER_DATA << 3 | 3), // Data segment
             "{r15}"(gdt::GDT_USER_TLS << 3 | 3) // TLS segment
         : // No clobbers because it never returns
         : "intel", "volatile");
    unreachable!();
}
<|endoftext|>


<commit_before><commit_msg>Fix doc tests of proc-macro-nested<commit_after><|endoftext|>


<commit_before>// Zinc, the bare metal stack for rust.
// Copyright 2014 Vladimir "farcaller" Pouzanov <farcaller@gmail.com>
//
// 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.

/*!
Driver for C12332 LCD.

C12332 is black&white LCD, the only supported color value is `1`. The LCD is
buffered in driver memory.

The driver uses SPI bus for output only, it never reads back from SPI, which
might be an issue for any other peripheral sharing the same SPI bus.
*/

use std::cell;
use std::slice::ImmutableVector;

use super::font_small_7;
use super::LCD;
use drivers::chario::CharIO;
use hal::timer::Timer;
use hal::gpio::GPIOConf;
use hal::spi::SPI;

pub struct C12332<'a, S, T> {
  spi: &'a S,
  timer: &'a T,

  dc:    GPIOConf,
  cs:    GPIOConf,
  reset: GPIOConf,

  videobuf: [cell::Cell<u8>, ..512],

  font: &'static [u8],
  char_x: cell::Cell<u32>,
  char_y: cell::Cell<u32>,
}

impl<'a, S: SPI, T: Timer> C12332<'a, S, T> {
  pub fn new(spi: &'a S, timer: &'a T, dc: GPIOConf, cs: GPIOConf,
      reset: GPIOConf) -> C12332<'a, S, T> {
    let lcd = C12332 {
      spi:   spi,
      timer: timer,
      dc:    *dc.setup(),
      cs:    *cs.setup(),
      reset: *reset.setup(),

      videobuf: [cell::Cell::new(0), ..512],

      font: font_small_7::FONT,
      char_x: cell::Cell::new(0),
      char_y: cell::Cell::new(0),
    };

    lcd.configure();

    lcd
  }

  fn configure(&self) {
    self.dc.set_low();
    self.cs.set_high();
    self.reset.set_low();
    self.timer.wait_us(50);
    self.reset.set_high();
    self.timer.wait_ms(5);

    self.wr_cmd(0xAE);   //  display off
    self.wr_cmd(0xA2);   //  bias voltage

    self.wr_cmd(0xA0);
    self.wr_cmd(0xC8);   //  colum normal

    self.wr_cmd(0x22);   //  voltage resistor ratio
    self.wr_cmd(0x2F);   //  power on
    //self.wr_cmd(0xA4);   //  LCD display ram
    self.wr_cmd(0x40);   // start line = 0
    self.wr_cmd(0xAF);     // display ON

    self.wr_cmd(0x81);   //  set contrast
    self.wr_cmd(0x17);   //  set contrast

    self.wr_cmd(0xA6);     // display normal

    (self as &LCD).flush();
  }

  fn wr_cmd(&self, cmd: u8) {
    self.dc.set_low();
    self.cs.set_low();
    self.spi.write(cmd);
    self.cs.set_high();
  }

  fn wr_dat(&self, cmd: u8) {
    self.dc.set_high();
    self.cs.set_low();
    self.spi.write(cmd);
    self.cs.set_high();
  }

  pub fn set_pixel(&self, x: i32, y: i32, color: u16) {
    if x > 127 || y > 31 || x < 0 || y < 0 {
      return
    }

    let index = x + (y/8) * 128;
    if color == 0 {
      self.videobuf[index as uint].set(
        self.videobuf[index as uint].get() & !(1 << (y%8) as u8));
    } else {
      self.videobuf[index as uint].set(
        self.videobuf[index as uint].get() | (1 << (y%8)));
    }
  }

  pub fn character(&self, x: i32, y: i32, c: u8) {
    let hor: u8;
    let vert: u8;
    let offset: u8;
    let bpl: u8;
    let mut j: u8;
    let mut i: u8;
    let mut b: u8;
    let zeichen: &[u8];
    let mut z: u8;
    let w: u8;
    let width: u32 = 128;
    let height: u32 = 32;

    if (c < 31) || (c > 127) {
      return;
    }

    // read font parameter from start of array
    offset = self.font[0];                    // bytes / char
    hor = self.font[1];                       // get hor size of font
    vert = self.font[2];                      // get vert size of font
    bpl = self.font[3];                       // bytes per line

    let mut char_x: u32 = self.char_x.get();
    let mut char_y: u32 = self.char_y.get();

    if char_x + hor as u32 > width {
      char_x = 0;
      char_y = char_y + vert as u32;
      if char_y >= height - self.font[2] as u32 {
        char_y = 0;
      }
    }

    let start: uint = ((c - 32) as uint * offset as uint) + 4;
    let end: uint = start + offset as uint;
    zeichen = self.font.slice(start, end);
    // zeichen = &self.font[]; // start of char bitmap
    w = zeichen[0];                          // width of actual char
    // construct the char into the buffer
    j = 0;
    while j < vert {
      i = 0;
      while i < hor {
        z =  zeichen[(bpl * i + ((j & 0xF8) >> 3)+1) as uint];
        b = 1 << (j & 0x07);
        if ( z & b ) == 0x00 {
          self.set_pixel(x+i as i32, y+j as i32, 0);
        } else {
          self.set_pixel(x+i as i32, y+j as i32, 1);
        }
        i += 1;
      }
      j += 1;
    }

    char_x += w as u32;

    self.char_x.set(char_x);
    self.char_y.set(char_y);
  }
}

impl<'a, S: SPI, T: Timer> LCD for C12332<'a, S, T> {
  fn flush(&self) {
    let mut i: uint = 0;

    //page 0
    self.wr_cmd(0x00);      // set column low nibble 0
    self.wr_cmd(0x10);      // set column hi  nibble 0
    self.wr_cmd(0xB0);      // set page address  0
    self.dc.set_high();
    while i < 128 {
      self.wr_dat(self.videobuf[i].get());
      i += 1;
    }

    // page 1
    self.wr_cmd(0x00);      // set column low nibble 0
    self.wr_cmd(0x10);      // set column hi  nibble 0
    self.wr_cmd(0xB1);      // set page address  1
    self.dc.set_high();
    while i < 256 {
      self.wr_dat(self.videobuf[i].get());
      i += 1;
    }

    //page 2
    self.wr_cmd(0x00);      // set column low nibble 0
    self.wr_cmd(0x10);      // set column hi  nibble 0
    self.wr_cmd(0xB2);      // set page address  2
    self.dc.set_high();
    while i < 384 {
      self.wr_dat(self.videobuf[i].get());
      i += 1;
    }

    //page 3
    self.wr_cmd(0x00);      // set column low nibble 0
    self.wr_cmd(0x10);      // set column hi  nibble 0
    self.wr_cmd(0xB3);      // set page address  3
    self.dc.set_high();
    while i < 512 {
      self.wr_dat(self.videobuf[i].get());
      i += 1;
    }
  }

  fn clear(&self) {
    let mut i = 0;
    while i < 512 {
      self.videobuf[i].set(0);
      i += 1;
    }
  }

  fn pixel(&self, x: i32, y: i32, color: u16) {
    self.set_pixel(x, y, color);
  }
}

impl<'a, S: SPI, T: Timer> CharIO for C12332<'a, S, T> {
  fn putc(&self, value: char) {
    let height: u32 = 32;
    if value == '\n' {
      self.char_x.set(0);
      self.char_y.set(self.char_y.get() + self.font[2] as u32);
      if self.char_y.get() >= height - self.font[2] as u32 {
          self.char_y.set(0);
      }
    } else {
      self.character(self.char_x.get() as i32, self.char_y.get() as i32, value as u8);
    }
  }
}
<commit_msg>Can't copy Cell of std, so using init() instead.<commit_after>// Zinc, the bare metal stack for rust.
// Copyright 2014 Vladimir "farcaller" Pouzanov <farcaller@gmail.com>
//
// 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.

/*!
Driver for C12332 LCD.

C12332 is black&white LCD, the only supported color value is `1`. The LCD is
buffered in driver memory.

The driver uses SPI bus for output only, it never reads back from SPI, which
might be an issue for any other peripheral sharing the same SPI bus.
*/

use std::cell;
use std::slice::ImmutableVector;
use std::mem::init;

use super::font_small_7;
use super::LCD;
use drivers::chario::CharIO;
use hal::timer::Timer;
use hal::gpio::GPIOConf;
use hal::spi::SPI;

pub struct C12332<'a, S, T> {
  spi: &'a S,
  timer: &'a T,

  dc:    GPIOConf,
  cs:    GPIOConf,
  reset: GPIOConf,

  videobuf: [cell::Cell<u8>, ..512],

  font: &'static [u8],
  char_x: cell::Cell<u32>,
  char_y: cell::Cell<u32>,
}

impl<'a, S: SPI, T: Timer> C12332<'a, S, T> {
  pub fn new(spi: &'a S, timer: &'a T, dc: GPIOConf, cs: GPIOConf,
      reset: GPIOConf) -> C12332<'a, S, T> {
    let lcd = C12332 {
      spi:   spi,
      timer: timer,
      dc:    *dc.setup(),
      cs:    *cs.setup(),
      reset: *reset.setup(),

      videobuf: unsafe { init() },

      font: font_small_7::FONT,
      char_x: cell::Cell::new(0),
      char_y: cell::Cell::new(0),
    };

    lcd.configure();

    lcd
  }

  fn configure(&self) {
    self.dc.set_low();
    self.cs.set_high();
    self.reset.set_low();
    self.timer.wait_us(50);
    self.reset.set_high();
    self.timer.wait_ms(5);

    self.wr_cmd(0xAE);   //  display off
    self.wr_cmd(0xA2);   //  bias voltage

    self.wr_cmd(0xA0);
    self.wr_cmd(0xC8);   //  colum normal

    self.wr_cmd(0x22);   //  voltage resistor ratio
    self.wr_cmd(0x2F);   //  power on
    //self.wr_cmd(0xA4);   //  LCD display ram
    self.wr_cmd(0x40);   // start line = 0
    self.wr_cmd(0xAF);     // display ON

    self.wr_cmd(0x81);   //  set contrast
    self.wr_cmd(0x17);   //  set contrast

    self.wr_cmd(0xA6);     // display normal

    (self as &LCD).flush();
  }

  fn wr_cmd(&self, cmd: u8) {
    self.dc.set_low();
    self.cs.set_low();
    self.spi.write(cmd);
    self.cs.set_high();
  }

  fn wr_dat(&self, cmd: u8) {
    self.dc.set_high();
    self.cs.set_low();
    self.spi.write(cmd);
    self.cs.set_high();
  }

  pub fn set_pixel(&self, x: i32, y: i32, color: u16) {
    if x > 127 || y > 31 || x < 0 || y < 0 {
      return
    }

    let index = x + (y/8) * 128;
    if color == 0 {
      self.videobuf[index as uint].set(
        self.videobuf[index as uint].get() & !(1 << (y%8) as u8));
    } else {
      self.videobuf[index as uint].set(
        self.videobuf[index as uint].get() | (1 << (y%8)));
    }
  }

  pub fn character(&self, x: i32, y: i32, c: u8) {
    let hor: u8;
    let vert: u8;
    let offset: u8;
    let bpl: u8;
    let mut j: u8;
    let mut i: u8;
    let mut b: u8;
    let zeichen: &[u8];
    let mut z: u8;
    let w: u8;
    let width: u32 = 128;
    let height: u32 = 32;

    if (c < 31) || (c > 127) {
      return;
    }

    // read font parameter from start of array
    offset = self.font[0];                    // bytes / char
    hor = self.font[1];                       // get hor size of font
    vert = self.font[2];                      // get vert size of font
    bpl = self.font[3];                       // bytes per line

    let mut char_x: u32 = self.char_x.get();
    let mut char_y: u32 = self.char_y.get();

    if char_x + hor as u32 > width {
      char_x = 0;
      char_y = char_y + vert as u32;
      if char_y >= height - self.font[2] as u32 {
        char_y = 0;
      }
    }

    let start: uint = ((c - 32) as uint * offset as uint) + 4;
    let end: uint = start + offset as uint;
    zeichen = self.font.slice(start, end);
    // zeichen = &self.font[]; // start of char bitmap
    w = zeichen[0];                          // width of actual char
    // construct the char into the buffer
    j = 0;
    while j < vert {
      i = 0;
      while i < hor {
        z =  zeichen[(bpl * i + ((j & 0xF8) >> 3)+1) as uint];
        b = 1 << (j & 0x07);
        if ( z & b ) == 0x00 {
          self.set_pixel(x+i as i32, y+j as i32, 0);
        } else {
          self.set_pixel(x+i as i32, y+j as i32, 1);
        }
        i += 1;
      }
      j += 1;
    }

    char_x += w as u32;

    self.char_x.set(char_x);
    self.char_y.set(char_y);
  }
}

impl<'a, S: SPI, T: Timer> LCD for C12332<'a, S, T> {
  fn flush(&self) {
    let mut i: uint = 0;

    //page 0
    self.wr_cmd(0x00);      // set column low nibble 0
    self.wr_cmd(0x10);      // set column hi  nibble 0
    self.wr_cmd(0xB0);      // set page address  0
    self.dc.set_high();
    while i < 128 {
      self.wr_dat(self.videobuf[i].get());
      i += 1;
    }

    // page 1
    self.wr_cmd(0x00);      // set column low nibble 0
    self.wr_cmd(0x10);      // set column hi  nibble 0
    self.wr_cmd(0xB1);      // set page address  1
    self.dc.set_high();
    while i < 256 {
      self.wr_dat(self.videobuf[i].get());
      i += 1;
    }

    //page 2
    self.wr_cmd(0x00);      // set column low nibble 0
    self.wr_cmd(0x10);      // set column hi  nibble 0
    self.wr_cmd(0xB2);      // set page address  2
    self.dc.set_high();
    while i < 384 {
      self.wr_dat(self.videobuf[i].get());
      i += 1;
    }

    //page 3
    self.wr_cmd(0x00);      // set column low nibble 0
    self.wr_cmd(0x10);      // set column hi  nibble 0
    self.wr_cmd(0xB3);      // set page address  3
    self.dc.set_high();
    while i < 512 {
      self.wr_dat(self.videobuf[i].get());
      i += 1;
    }
  }

  fn clear(&self) {
    let mut i = 0;
    while i < 512 {
      self.videobuf[i].set(0);
      i += 1;
    }
  }

  fn pixel(&self, x: i32, y: i32, color: u16) {
    self.set_pixel(x, y, color);
  }
}

impl<'a, S: SPI, T: Timer> CharIO for C12332<'a, S, T> {
  fn putc(&self, value: char) {
    let height: u32 = 32;
    if value == '\n' {
      self.char_x.set(0);
      self.char_y.set(self.char_y.get() + self.font[2] as u32);
      if self.char_y.get() >= height - self.font[2] as u32 {
          self.char_y.set(0);
      }
    } else {
      self.character(self.char_x.get() as i32, self.char_y.get() as i32, value as u8);
    }
  }
}
<|endoftext|>


<commit_before>#![cfg(test)]
#![allow(non_upper_case_globals)]
#![allow(dead_code)]
use std::fs::File;
extern crate core;
extern crate brotli_decompressor;
use brotli_decompressor::{CustomRead, CustomWrite};
use super::brotli::BrotliResult;
use super::brotli::BrotliState;
use super::brotli::enc::BrotliEncoderParams;
use super::brotli::concat::BroCatli;
use brotli::BrotliDecompressStream;
use std::io::{Read, Write};
use super::integration_tests::{Buffer, UnlimitedBuffer};
static RANDOM_THEN_UNICODE : &'static [u8] = include_bytes!("../../testdata/random_then_unicode");
static ALICE: &'static[u8]  = include_bytes!("../../testdata/alice29.txt");
static UKKONOOA: &'static[u8]  = include_bytes!("../../testdata/ukkonooa");
static ASYOULIKE: &'static[u8] = include_bytes!("../../testdata/asyoulik.txt");
static BACKWARD65536: &'static [u8] = include_bytes!("../../testdata/backward65536");
static DICTWORD: &'static [u8] = include_bytes!("../../testdata/ends_with_truncated_dictionary");
static RANDOM10K: &'static [u8] = include_bytes!("../../testdata/random_org_10k.bin");
static RANDOMTHENUNICODE: &'static [u8] = include_bytes!("../../testdata/random_then_unicode");
static QUICKFOX: &'static [u8] = include_bytes!("../../testdata/quickfox_repeated");
static EMPTY: &'static [u8] = &[];

fn concat(files:&mut [UnlimitedBuffer],
          brotli_files:&mut [UnlimitedBuffer],
          window_override:Option<u8>,
          bs: usize) {
  let mut obuffer = vec![0u8; bs];
  let mut ibuffer = vec![0u8; bs];
  let mut ooffset = 0usize;
  let mut ioffset = 0usize;
  let mut uboutput = UnlimitedBuffer::new(&[]);
  {
    let mut output = super::IoWriterWrapper(&mut uboutput);
    let mut bro_cat_li = match window_override {
      Some(ws) => BroCatli::new_with_window_size(ws),
      None => BroCatli::new(),
    };
    for (index, brotli) in brotli_files.iter_mut().enumerate() {
        {
            let dfn = index.to_string();

            let mut debug_file = File::create("/tmp/".to_owned() + &dfn).unwrap();
            debug_file.write_all(brotli.data());
        }

        bro_cat_li.new_brotli_file();
        {
            let mut input = super::IoReaderWrapper(brotli);
            loop {
                ioffset = 0;
                match input.read(&mut ibuffer[..]) {
                    Err(e) => panic!(e),
                    Ok(cur_read) => {
                        if cur_read == 0 {
                            break;
                        }
                        loop {
                            match bro_cat_li.stream(&ibuffer[..cur_read], &mut ioffset,
                                                    &mut obuffer[..], &mut ooffset) {
                                BrotliResult::ResultFailure => {
                                    panic!(index);
                },
                BrotliResult::NeedsMoreOutput => {
                  match output.write(&obuffer[..ooffset]) {
                    Err(why) => panic!("couldn't write: {:}", why),
                    Ok(count) => {assert_eq!(count, ooffset);},
                  }
                  ooffset = 0;
                },
                BrotliResult::NeedsMoreInput => {
                  break;
                },
                BrotliResult::ResultSuccess => {
                  panic!("Unexpected state: Success when streaming before finish");
                }
              }
            }
          }
        }
      }
        }
      brotli.reset_read();
    }
    loop {
      match bro_cat_li.finish(&mut obuffer[..], &mut ooffset) {
        BrotliResult::NeedsMoreOutput => {
          match output.write(&obuffer[..ooffset]) {
            Err(why) => panic!("couldn't write\n{:}", why),
            Ok(count) => {assert_eq!(count, ooffset);},
          }
          ooffset = 0;
        },
        BrotliResult::NeedsMoreInput => {
          panic!("Unexpected EOF");
        },
        BrotliResult::ResultSuccess => {
          if ooffset != 0 {
            match output.write(&obuffer[..ooffset]) {
              Err(why) => panic!("couldn't write\n{:}", why),
              Ok(count) => {assert_eq!(count, ooffset);},
            }
          }
          break;
        }
        BrotliResult::ResultFailure => {
          panic!("Failed to terminate concatenation")
        }
      }
    }
  }
    let mut rt = UnlimitedBuffer::new(&[]);
    {
        let mut debug_file = File::create("/tmp/concatted".to_owned() + &files.len().to_string()+&".br".to_owned()).unwrap();
        debug_file.write_all(uboutput.data());
    }
  match super::decompress(&mut uboutput, &mut rt, 65536) {
    Ok(_) => {},
    Err(e) => panic!("Error {:?}", e),
  }
  let mut offset = 0;
  for file in files {
    assert_eq!(&rt.data()[offset..offset+file.data().len()],
               file.data());
    offset += file.data().len();
  }
  assert_eq!(offset, rt.data().len());
}

fn concat_many_subsets(files:&mut [UnlimitedBuffer],
                       brotli_files:&mut [UnlimitedBuffer],
                       window_override:Option<u8>) {
  let test_plans:[(usize,usize);4] = [(brotli_files.len(), 4096 * 1024), (4, 1), (3, 3),  (2, 4096)];
  for plan_bs in test_plans.iter() {
    let files_len = files.len();
    for index in 0..(brotli_files.len() - core::cmp::min((plan_bs.0 - 1), files_len)) {
      let file_subset = &mut files[index..core::cmp::min((index+plan_bs.0), files_len)];
      let brotli_subset = &mut brotli_files[index..core::cmp::min((index+plan_bs.0), files_len)];
      concat(file_subset, brotli_subset, window_override, plan_bs.1);
    }
  }
}

#[cfg(debug_assertions)]
fn light_debug_test(params: &mut BrotliEncoderParams) {
    params.quality = 5;
}

#[cfg(not(debug_assertions))]
fn light_debug_test(params: &mut BrotliEncoderParams) {
}

#[test]
#[should_panic]
fn test_appendonly_twice_fails() {
  let mut files = [
    UnlimitedBuffer::new(UKKONOOA),
    UnlimitedBuffer::new(QUICKFOX),
  ];
  let mut ufiles = [
    UnlimitedBuffer::new(&[]),
    UnlimitedBuffer::new(&[]),
  ];
  for (src, dst) in files.iter_mut().zip(ufiles.iter_mut()) {
    let mut params0 = BrotliEncoderParams::default();
    params0.appendable = true;
    super::compress(src, dst, 4096, &params0).unwrap();
  }
  concat(&mut files[..], &mut ufiles[..], None, 2);
}

#[test]
fn test_append_then_cat_works() {
  let mut files = [
    UnlimitedBuffer::new(UKKONOOA),
    UnlimitedBuffer::new(QUICKFOX),
  ];
  let mut ufiles = [
    UnlimitedBuffer::new(&[]),
    UnlimitedBuffer::new(&[]),
  ];
  let mut first = true;
  for (src, dst) in files.iter_mut().zip(ufiles.iter_mut()) {
    let mut params0 = BrotliEncoderParams::default();
    params0.appendable = first;
    params0.catable = !first;
    super::compress(src, dst, 4096, &params0).unwrap();
    first = false;
  }
  concat(&mut files[..], &mut ufiles[..], None, 2);
}

#[test]
fn test_concat() {
    let mut files = [
      /*  UnlimitedBuffer::new(ALICE),
      UnlimitedBuffer::new(RANDOM_THEN_UNICODE),*/

        UnlimitedBuffer::new(UKKONOOA),
        //UnlimitedBuffer::new(ASYOULIKE),
        UnlimitedBuffer::new(BACKWARD65536),
        UnlimitedBuffer::new(DICTWORD),/*
        UnlimitedBuffer::new(RANDOM10K),
        UnlimitedBuffer::new(RANDOMTHENUNICODE),
        UnlimitedBuffer::new(QUICKFOX),
        UnlimitedBuffer::new(EMPTY),*/
    ];
    let mut params0 = BrotliEncoderParams::default();
    light_debug_test(&mut params0);
    let mut params1 = params0.clone();
    params1.quality = 9;
    params1.q9_5 = true;
    params1.lgwin=22;
    params1.magic_number = true;
    let mut params2 = params0.clone();
    params2.quality = 9;
    params2.lgwin=19;
    let mut params3 = params0.clone();
    params3.quality = 9;
    params3.lgwin = 16;
    params3.magic_number = true;
    let mut params4 = params0.clone();
    params4.quality = 8;
    params4.lgwin = 14;
    let mut params4 = params0.clone();
    params4.quality = 1;
    params4.lgwin = 10;
    let mut params5 = params0.clone();
    params5.quality = 0;
    params5.lgwin = 10;
    params5.magic_number = true;
    params0.lgwin = 23;
    //params0.large_window = true; (FIXME: turn this challenge back on)

    let mut options = [
        params0,
        params1,
        params2,
        params3,
        params4,
        params5,
        ];
    for option in options.iter_mut() {
        let mut ufiles = [
            UnlimitedBuffer::new(&[]),
            UnlimitedBuffer::new(&[]),
            UnlimitedBuffer::new(&[]),
            /*UnlimitedBuffer::new(&[]),
            UnlimitedBuffer::new(&[]),
            UnlimitedBuffer::new(&[]),
            UnlimitedBuffer::new(&[]),
            UnlimitedBuffer::new(&[]),
            UnlimitedBuffer::new(&[]),
            UnlimitedBuffer::new(&[]),*/
        ];
        let mut first = true;
        for (src, dst) in files.iter_mut().zip(ufiles.iter_mut()) {
            if first {
                option.appendable = true;
            } else {
                option.appendable = false;
                option.catable = true;
            }
            super::compress(src, dst, 4096, option).unwrap();
            src.reset_read();
            first = false;
        }
        concat_many_subsets(&mut files[..], &mut ufiles[..], None);
    }
    let mut ufiles = [
      UnlimitedBuffer::new(&[]),
      UnlimitedBuffer::new(&[]),
      UnlimitedBuffer::new(&[]),/*
      UnlimitedBuffer::new(&[]),
      UnlimitedBuffer::new(&[]),
      UnlimitedBuffer::new(&[]),
      UnlimitedBuffer::new(&[]),
      UnlimitedBuffer::new(&[]),
      UnlimitedBuffer::new(&[]),
      UnlimitedBuffer::new(&[]),*/
    ];
    let options_len = options.len();
    for (index, (src, dst)) in files.iter_mut().zip(ufiles.iter_mut()).enumerate() {
      options[core::cmp::min(index, options_len - 1)].catable = true;
      options[core::cmp::min(index, options_len - 1)].appendable = false;
      options[core::cmp::min(index, options_len - 1)].quality = core::cmp::max(
        2, options[core::cmp::min(index, options_len - 1)].quality);
      // ^^^ there's an artificial limitation of using 18 as the minimum window size for quality 0,1
      // since this test depends on different window sizes for each stream, exclude q={0,1}
      super::compress(src, dst, 4096, &options[core::cmp::min(index, options_len - 1)]).unwrap();
      src.reset_read();
    }
    concat_many_subsets(&mut files[..], &mut ufiles[..], None);
    concat_many_subsets(&mut files[..], &mut ufiles[..], Some(24)); // FIXME: make this 28
}
<commit_msg>broadening the test set... alice at front seems to cause issues still<commit_after>#![cfg(test)]
#![allow(non_upper_case_globals)]
#![allow(dead_code)]
use std::fs::File;
extern crate core;
extern crate brotli_decompressor;
use brotli_decompressor::{CustomRead, CustomWrite};
use super::brotli::BrotliResult;
use super::brotli::BrotliState;
use super::brotli::enc::BrotliEncoderParams;
use super::brotli::concat::BroCatli;
use brotli::BrotliDecompressStream;
use std::io::{Read, Write};
use super::integration_tests::{Buffer, UnlimitedBuffer};
static RANDOM_THEN_UNICODE : &'static [u8] = include_bytes!("../../testdata/random_then_unicode");
static ALICE: &'static[u8]  = include_bytes!("../../testdata/alice29.txt");
static UKKONOOA: &'static[u8]  = include_bytes!("../../testdata/ukkonooa");
static ASYOULIKE: &'static[u8] = include_bytes!("../../testdata/asyoulik.txt");
static BACKWARD65536: &'static [u8] = include_bytes!("../../testdata/backward65536");
static DICTWORD: &'static [u8] = include_bytes!("../../testdata/ends_with_truncated_dictionary");
static RANDOM10K: &'static [u8] = include_bytes!("../../testdata/random_org_10k.bin");
static RANDOMTHENUNICODE: &'static [u8] = include_bytes!("../../testdata/random_then_unicode");
static QUICKFOX: &'static [u8] = include_bytes!("../../testdata/quickfox_repeated");
static EMPTY: &'static [u8] = &[];

fn concat(files:&mut [UnlimitedBuffer],
          brotli_files:&mut [UnlimitedBuffer],
          window_override:Option<u8>,
          bs: usize) {
  let mut obuffer = vec![0u8; bs];
  let mut ibuffer = vec![0u8; bs];
  let mut ooffset = 0usize;
  let mut ioffset = 0usize;
  let mut uboutput = UnlimitedBuffer::new(&[]);
  {
    let mut output = super::IoWriterWrapper(&mut uboutput);
    let mut bro_cat_li = match window_override {
      Some(ws) => BroCatli::new_with_window_size(ws),
      None => BroCatli::new(),
    };
    for (index, brotli) in brotli_files.iter_mut().enumerate() {
        {
            let dfn = index.to_string();

            let mut debug_file = File::create("/tmp/".to_owned() + &dfn).unwrap();
            debug_file.write_all(brotli.data());
        }

        bro_cat_li.new_brotli_file();
        {
            let mut input = super::IoReaderWrapper(brotli);
            loop {
                ioffset = 0;
                match input.read(&mut ibuffer[..]) {
                    Err(e) => panic!(e),
                    Ok(cur_read) => {
                        if cur_read == 0 {
                            break;
                        }
                        loop {
                            match bro_cat_li.stream(&ibuffer[..cur_read], &mut ioffset,
                                                    &mut obuffer[..], &mut ooffset) {
                                BrotliResult::ResultFailure => {
                                    panic!(index);
                },
                BrotliResult::NeedsMoreOutput => {
                  match output.write(&obuffer[..ooffset]) {
                    Err(why) => panic!("couldn't write: {:}", why),
                    Ok(count) => {assert_eq!(count, ooffset);},
                  }
                  ooffset = 0;
                },
                BrotliResult::NeedsMoreInput => {
                  break;
                },
                BrotliResult::ResultSuccess => {
                  panic!("Unexpected state: Success when streaming before finish");
                }
              }
            }
          }
        }
      }
        }
      brotli.reset_read();
    }
    loop {
      match bro_cat_li.finish(&mut obuffer[..], &mut ooffset) {
        BrotliResult::NeedsMoreOutput => {
          match output.write(&obuffer[..ooffset]) {
            Err(why) => panic!("couldn't write\n{:}", why),
            Ok(count) => {assert_eq!(count, ooffset);},
          }
          ooffset = 0;
        },
        BrotliResult::NeedsMoreInput => {
          panic!("Unexpected EOF");
        },
        BrotliResult::ResultSuccess => {
          if ooffset != 0 {
            match output.write(&obuffer[..ooffset]) {
              Err(why) => panic!("couldn't write\n{:}", why),
              Ok(count) => {assert_eq!(count, ooffset);},
            }
          }
          break;
        }
        BrotliResult::ResultFailure => {
          panic!("Failed to terminate concatenation")
        }
      }
    }
  }
    let mut rt = UnlimitedBuffer::new(&[]);
    {
        let mut debug_file = File::create("/tmp/concatted".to_owned() + &files.len().to_string()+&".br".to_owned()).unwrap();
        debug_file.write_all(uboutput.data());
    }
  match super::decompress(&mut uboutput, &mut rt, 65536) {
    Ok(_) => {},
    Err(e) => panic!("Error {:?}", e),
  }
  let mut offset = 0;
  for file in files {
    assert_eq!(&rt.data()[offset..offset+file.data().len()],
               file.data());
    offset += file.data().len();
  }
  assert_eq!(offset, rt.data().len());
}

fn concat_many_subsets(files:&mut [UnlimitedBuffer],
                       brotli_files:&mut [UnlimitedBuffer],
                       window_override:Option<u8>) {
  let test_plans:[(usize,usize);4] = [(brotli_files.len(), 4096 * 1024), (4, 1), (3, 3),  (2, 4096)];
  for plan_bs in test_plans.iter() {
    let files_len = files.len();
    for index in 0..(brotli_files.len() - core::cmp::min((plan_bs.0 - 1), files_len)) {
      let file_subset = &mut files[index..core::cmp::min((index+plan_bs.0), files_len)];
      let brotli_subset = &mut brotli_files[index..core::cmp::min((index+plan_bs.0), files_len)];
      concat(file_subset, brotli_subset, window_override, plan_bs.1);
    }
  }
}

#[cfg(debug_assertions)]
fn light_debug_test(params: &mut BrotliEncoderParams) {
    params.quality = 5;
}

#[cfg(not(debug_assertions))]
fn light_debug_test(params: &mut BrotliEncoderParams) {
}

#[cfg(debug_assertions)]
fn medium_debug_test(params: &mut BrotliEncoderParams) {
    params.quality = 9;
    params.q9_5 = false;
}

#[cfg(not(debug_assertions))]
fn medium_debug_test(params: &mut BrotliEncoderParams) {
}

#[test]
#[should_panic]
fn test_appendonly_twice_fails() {
  let mut files = [
    UnlimitedBuffer::new(UKKONOOA),
    UnlimitedBuffer::new(QUICKFOX),
  ];
  let mut ufiles = [
    UnlimitedBuffer::new(&[]),
    UnlimitedBuffer::new(&[]),
  ];
  for (src, dst) in files.iter_mut().zip(ufiles.iter_mut()) {
    let mut params0 = BrotliEncoderParams::default();
    params0.appendable = true;
    super::compress(src, dst, 4096, &params0).unwrap();
  }
  concat(&mut files[..], &mut ufiles[..], None, 2);
}

#[test]
fn test_append_then_cat_works() {
  let mut files = [
    UnlimitedBuffer::new(UKKONOOA),
    UnlimitedBuffer::new(QUICKFOX),
  ];
  let mut ufiles = [
    UnlimitedBuffer::new(&[]),
    UnlimitedBuffer::new(&[]),
  ];
  let mut first = true;
  for (src, dst) in files.iter_mut().zip(ufiles.iter_mut()) {
    let mut params0 = BrotliEncoderParams::default();
    params0.appendable = first;
    params0.catable = !first;
    super::compress(src, dst, 4096, &params0).unwrap();
    first = false;
  }
  concat(&mut files[..], &mut ufiles[..], None, 2);
}

#[test]
fn test_concat() {
    let mut files = [
//        UnlimitedBuffer::new(ALICE),
        UnlimitedBuffer::new(UKKONOOA),
        UnlimitedBuffer::new(ASYOULIKE),
        UnlimitedBuffer::new(BACKWARD65536),
        UnlimitedBuffer::new(DICTWORD),
        UnlimitedBuffer::new(RANDOM10K),
        UnlimitedBuffer::new(RANDOMTHENUNICODE),
        UnlimitedBuffer::new(QUICKFOX),/*
        UnlimitedBuffer::new(EMPTY),*/
    ];
    let mut params0 = BrotliEncoderParams::default();
    light_debug_test(&mut params0);
    let mut params1 = params0.clone();
    params1.quality = 9;
    params1.q9_5 = true;
    params1.lgwin=22;
    params1.magic_number = true;
    medium_debug_test(&mut params1);
    let mut params2 = params0.clone();
    params2.quality = if params1.q9_5 || params1.quality > 9 {9} else {8};
    params2.lgwin=19;
    let mut params3 = params0.clone();
    params3.quality = 8;
    params3.lgwin = 16;
    params3.magic_number = true;
    let mut params4 = params0.clone();
    params4.quality = 7;
    params4.lgwin = 14;
    let mut params4 = params0.clone();
    params4.quality = 1;
    params4.lgwin = 10;
    let mut params5 = params0.clone();
    params5.quality = 0;
    params5.lgwin = 10;
    params5.magic_number = true;
    params0.lgwin = 23;
    //params0.large_window = true; (FIXME: turn this challenge back on)

    let mut options = [
        params0,
        params1,
        params2,
        params3,
        params4,
        params5,
        ];
    for option in options.iter_mut() {
        let mut ufiles = [
            UnlimitedBuffer::new(&[]),
            UnlimitedBuffer::new(&[]),
            UnlimitedBuffer::new(&[]),
            UnlimitedBuffer::new(&[]),
            UnlimitedBuffer::new(&[]),
            UnlimitedBuffer::new(&[]),
            UnlimitedBuffer::new(&[]),/*
            UnlimitedBuffer::new(&[]),
            UnlimitedBuffer::new(&[]),*/
        ];
        let mut first = true;
        for (src, dst) in files.iter_mut().zip(ufiles.iter_mut()) {
            if first {
                option.appendable = true;
            } else {
                option.appendable = false;
                option.catable = true;
            }
            super::compress(src, dst, 4096, option).unwrap();
            src.reset_read();
            first = false;
        }
        concat_many_subsets(&mut files[..], &mut ufiles[..], None);
    }
    let mut ufiles = [
      UnlimitedBuffer::new(&[]),
      UnlimitedBuffer::new(&[]),
      UnlimitedBuffer::new(&[]),
      UnlimitedBuffer::new(&[]),
      UnlimitedBuffer::new(&[]),
      UnlimitedBuffer::new(&[]),
      UnlimitedBuffer::new(&[]),/*
      UnlimitedBuffer::new(&[]),
      UnlimitedBuffer::new(&[]),*/
    ];
    let options_len = options.len();
    for (index, (src, dst)) in files.iter_mut().zip(ufiles.iter_mut()).enumerate() {
      options[core::cmp::min(index, options_len - 1)].catable = true;
      options[core::cmp::min(index, options_len - 1)].appendable = false;
      options[core::cmp::min(index, options_len - 1)].quality = core::cmp::max(
        2, options[core::cmp::min(index, options_len - 1)].quality);
      // ^^^ there's an artificial limitation of using 18 as the minimum window size for quality 0,1
      // since this test depends on different window sizes for each stream, exclude q={0,1}
      super::compress(src, dst, 4096, &options[core::cmp::min(index, options_len - 1)]).unwrap();
      src.reset_read();
    }
    concat_many_subsets(&mut files[..], &mut ufiles[..], None);
    concat_many_subsets(&mut files[..], &mut ufiles[..], Some(24)); // FIXME: make this 28
}
<|endoftext|>


<commit_before>//! Handlers for the server.

use std::collections::BTreeMap;

use rustc_serialize::json::{Json, ToJson};
use iron::prelude::*;
use iron::{status, headers, middleware};
use iron::modifiers::Header;
use router::Router;

use urlencoded;

use ::api;
use ::api::optional::Optional;
use ::datastore;
use ::sensors;

#[derive(Debug)]
struct ErrorResponse {
    reason: String,
}

impl ToJson for ErrorResponse {
    /// Serialize an ErrorResponse object into a proper JSON structure.
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("status".to_string(), "error".to_json());
        d.insert("reason".to_string(), self.reason.to_json());
        Json::Object(d)
    }
}

pub struct ReadHandler {
    status: api::Status,
    datastore: datastore::SafeDataStore,
    sensor_specs: sensors::SafeSensorSpecs,
}

impl ReadHandler {
    pub fn new(status: api::Status, datastore: datastore::SafeDataStore, sensor_specs: sensors::SafeSensorSpecs) -> ReadHandler {
        ReadHandler {
            status: status,
            datastore: datastore,
            sensor_specs: sensor_specs,
        }
    }

    fn build_response_json(&self) -> Json {

        // Create a mutable copy of the status struct
        let mut status_copy = self.status.clone();

        // Process registered sensors
        for sensor_spec in self.sensor_specs.lock().unwrap().iter() {
            sensor_spec.get_sensor_value(self.datastore.clone()).map(|value| {
                if status_copy.sensors.is_absent() {
                    status_copy.sensors = Optional::Value(api::Sensors {
                        people_now_present: Optional::Absent,
                        temperature: Optional::Absent,
                    });
                }
                sensor_spec.template.to_sensor(&value, &mut status_copy.sensors.as_mut().unwrap());
            });
        }

        // Update state depending on number of people present
        let people_now_present: Option<u64> = status_copy.sensors.as_ref()
            .and_then(|sensors| sensors.people_now_present.as_ref())
            .map(|people_now_present| people_now_present[0].value)
            .into();
        if let Some(count) = people_now_present {
            status_copy.state.open = Some(count > 0);
            if count == 1 {
                status_copy.state.message = Optional::Value(format!("{} person here right now", count));
            } else if count > 1 {
                status_copy.state.message = Optional::Value(format!("{} people here right now", count));
            }
        }

        // Serialize to JSON
        status_copy.to_json()
    }
}

impl middleware::Handler for ReadHandler {

    /// Return the current status JSON.
    fn handle(&self, req: &mut Request) -> IronResult<Response> {

        info!("{} /{} from {}", req.method, req.url.path[0], req.remote_addr);

        // Get response body
        let body = self.build_response_json().to_string();

        // Create response
        let response = Response::with((status::Ok, body))
            // Set headers
            .set(Header(headers::ContentType("application/json; charset=utf-8".parse().unwrap())))
            .set(Header(headers::CacheControl(vec![headers::CacheDirective::NoCache])))
            .set(Header(headers::AccessControlAllowOrigin::Any));

        Ok(response)
    }

}

pub struct UpdateHandler {
    datastore: datastore::SafeDataStore,
    sensor_specs: sensors::SafeSensorSpecs,
}

error_type! {
    #[derive(Debug)]
    pub enum UpdateHandlerError {
        UnknownSensor(String) {
            desc (sensor) &sensor;
        },
        DataStoreError(datastore::DataStoreError) {
            cause;
        }
    }
}

impl UpdateHandler {
    pub fn new(datastore: datastore::SafeDataStore, sensor_specs: sensors::SafeSensorSpecs) -> UpdateHandler {
        UpdateHandler {
            datastore: datastore,
            sensor_specs: sensor_specs,
        }
    }

    /// Update sensor value in the `DataStore`
    fn update_sensor(&self, sensor: &str, value: &str) -> Result<(), UpdateHandlerError> {
        // Validate sensor
        try!(self.sensor_specs.lock().unwrap().iter()
                              .find(|&spec| spec.data_key == sensor)
                              .ok_or(UpdateHandlerError::UnknownSensor(sensor.to_string())));

        // Store data to datastore
        let datastore_ref = self.datastore.clone();
        let mut datastore_lock = datastore_ref.lock().unwrap();
        datastore_lock.store(sensor, value)
                      .map(|_| ()).map_err(|e| {
                          error!("Could not update sensor value in datastore: {:?}", e);
                          UpdateHandlerError::DataStoreError(e)
                      })
    }

    /// Build an OK response with the `HTTP 204 No Content` status code.
    fn ok_response(&self) -> Response {
        Response::with((status::NoContent))
            // Set headers
            .set(Header(headers::ContentType("application/json; charset=utf-8".parse().unwrap())))
            .set(Header(headers::CacheControl(vec![headers::CacheDirective::NoCache])))
            .set(Header(headers::AccessControlAllowOrigin::Any))
    }

    /// Build an error response with the specified `error_code` and the specified `reason` text.
    fn err_response(&self, error_code: status::Status, reason: &str) -> Response {
        let error = ErrorResponse { reason: reason.to_string() };
        Response::with((error_code, error.to_json().to_string()))
            // Set headers
            .set(Header(headers::ContentType("application/json; charset=utf-8".parse().unwrap())))
            .set(Header(headers::CacheControl(vec![headers::CacheDirective::NoCache])))
            .set(Header(headers::AccessControlAllowOrigin::Any))
    }

}

impl middleware::Handler for UpdateHandler {

    /// Update the sensor, return correct status code.
    fn handle(&self, req: &mut Request) -> IronResult<Response> {

        // TODO: create macro for these info! invocations.
        info!("{} /{} from {}", req.method, req.url.path[0], req.remote_addr);

        // Get sensor name
        let sensor_name;
        {
            // TODO: Properly propagate errors
            let params = req.extensions.get::<Router>().unwrap();
            sensor_name = params.find("sensor").unwrap().to_string();
        }

        // Get sensor value
        let sensor_value;
        {
            let params = req.get_ref::<urlencoded::UrlEncodedBody>().unwrap();
            sensor_value = match params.get("value") {
                Some(ref values) =>  match values.len() {
                    1 => values[0].to_string(),
                    _ => return Ok(self.err_response(status::BadRequest, "Too many values specified")),
                },
                None => return Ok(self.err_response(status::BadRequest, "\"value\" parameter not specified")),
            }
        }

        // Update values in datastore
        if let Err(e) = self.update_sensor(&sensor_name, &sensor_value) {
            error!("update_sensor() failed: {:?}", e);
            let response = match e {
                UpdateHandlerError::UnknownSensor(sensor) =>
                    self.err_response(status::BadRequest, &format!("Unknown sensor: {}", sensor)),
                UpdateHandlerError::DataStoreError(_) =>
                    self.err_response(status::InternalServerError, "Updating values in datastore failed"),
            };
            return Ok(response)
        };

        // Create response
        Ok(self.ok_response())
    }

}
<commit_msg>Add StatusHandler<commit_after>//! Handlers for the server.

use std::collections::BTreeMap;
use std::any::Any;

use rustc_serialize::json::{Json, ToJson};
use iron::prelude::*;
use iron::{status, headers, middleware};
use iron::modifiers::Header;
use router::Router;

use urlencoded;

use ::api;
use ::api::optional::Optional;
use ::datastore;
use ::sensors;

#[derive(Debug)]
struct ErrorResponse {
    reason: String,
}

impl ToJson for ErrorResponse {
    /// Serialize an ErrorResponse object into a proper JSON structure.
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("status".to_string(), "error".to_json());
        d.insert("reason".to_string(), self.reason.to_json());
        Json::Object(d)
    }
}

/// `StatusHandler`s are used to modify the status
pub trait StatusHandler: Send + Sync + Any {
    /// Called after all registered sensors are read
    fn handle(&self, status: &mut api::Status);
}

pub struct ReadHandler {
    status: api::Status,
    datastore: datastore::SafeDataStore,
    sensor_specs: sensors::SafeSensorSpecs,
    status_handlers: Vec<Box<StatusHandler>>,
}

impl ReadHandler {
    pub fn new(status: api::Status, datastore: datastore::SafeDataStore, sensor_specs: sensors::SafeSensorSpecs) -> ReadHandler {
        ReadHandler {
            status: status,
            datastore: datastore,
            sensor_specs: sensor_specs,
            status_handlers: vec![],
        }
    }

    fn build_response_json(&self) -> Json {

        // Create a mutable copy of the status struct
        let mut status_copy = self.status.clone();

        // Process registered sensors
        for sensor_spec in self.sensor_specs.lock().unwrap().iter() {
            sensor_spec.get_sensor_value(self.datastore.clone()).map(|value| {
                if status_copy.sensors.is_absent() {
                    status_copy.sensors = Optional::Value(api::Sensors {
                        people_now_present: Optional::Absent,
                        temperature: Optional::Absent,
                    });
                }
                sensor_spec.template.to_sensor(&value, &mut status_copy.sensors.as_mut().unwrap());
            });
        }

        // Update state depending on number of people present
        let people_now_present: Option<u64> = status_copy.sensors.as_ref()
            .and_then(|sensors| sensors.people_now_present.as_ref())
            .map(|people_now_present| people_now_present[0].value)
            .into();
        if let Some(count) = people_now_present {
            status_copy.state.open = Some(count > 0);
            if count == 1 {
                status_copy.state.message = Optional::Value(format!("{} person here right now", count));
            } else if count > 1 {
                status_copy.state.message = Optional::Value(format!("{} people here right now", count));
            }
        }

        // Serialize to JSON
        status_copy.to_json()
    }
}

impl middleware::Handler for ReadHandler {

    /// Return the current status JSON.
    fn handle(&self, req: &mut Request) -> IronResult<Response> {

        info!("{} /{} from {}", req.method, req.url.path[0], req.remote_addr);

        // Get response body
        let body = self.build_response_json().to_string();

        // Create response
        let response = Response::with((status::Ok, body))
            // Set headers
            .set(Header(headers::ContentType("application/json; charset=utf-8".parse().unwrap())))
            .set(Header(headers::CacheControl(vec![headers::CacheDirective::NoCache])))
            .set(Header(headers::AccessControlAllowOrigin::Any));

        Ok(response)
    }

}

pub struct UpdateHandler {
    datastore: datastore::SafeDataStore,
    sensor_specs: sensors::SafeSensorSpecs,
}

error_type! {
    #[derive(Debug)]
    pub enum UpdateHandlerError {
        UnknownSensor(String) {
            desc (sensor) &sensor;
        },
        DataStoreError(datastore::DataStoreError) {
            cause;
        }
    }
}

impl UpdateHandler {
    pub fn new(datastore: datastore::SafeDataStore, sensor_specs: sensors::SafeSensorSpecs) -> UpdateHandler {
        UpdateHandler {
            datastore: datastore,
            sensor_specs: sensor_specs,
        }
    }

    /// Update sensor value in the `DataStore`
    fn update_sensor(&self, sensor: &str, value: &str) -> Result<(), UpdateHandlerError> {
        // Validate sensor
        try!(self.sensor_specs.lock().unwrap().iter()
                              .find(|&spec| spec.data_key == sensor)
                              .ok_or(UpdateHandlerError::UnknownSensor(sensor.to_string())));

        // Store data to datastore
        let datastore_ref = self.datastore.clone();
        let mut datastore_lock = datastore_ref.lock().unwrap();
        datastore_lock.store(sensor, value)
                      .map(|_| ()).map_err(|e| {
                          error!("Could not update sensor value in datastore: {:?}", e);
                          UpdateHandlerError::DataStoreError(e)
                      })
    }

    /// Build an OK response with the `HTTP 204 No Content` status code.
    fn ok_response(&self) -> Response {
        Response::with((status::NoContent))
            // Set headers
            .set(Header(headers::ContentType("application/json; charset=utf-8".parse().unwrap())))
            .set(Header(headers::CacheControl(vec![headers::CacheDirective::NoCache])))
            .set(Header(headers::AccessControlAllowOrigin::Any))
    }

    /// Build an error response with the specified `error_code` and the specified `reason` text.
    fn err_response(&self, error_code: status::Status, reason: &str) -> Response {
        let error = ErrorResponse { reason: reason.to_string() };
        Response::with((error_code, error.to_json().to_string()))
            // Set headers
            .set(Header(headers::ContentType("application/json; charset=utf-8".parse().unwrap())))
            .set(Header(headers::CacheControl(vec![headers::CacheDirective::NoCache])))
            .set(Header(headers::AccessControlAllowOrigin::Any))
    }

}

impl middleware::Handler for UpdateHandler {

    /// Update the sensor, return correct status code.
    fn handle(&self, req: &mut Request) -> IronResult<Response> {

        // TODO: create macro for these info! invocations.
        info!("{} /{} from {}", req.method, req.url.path[0], req.remote_addr);

        // Get sensor name
        let sensor_name;
        {
            // TODO: Properly propagate errors
            let params = req.extensions.get::<Router>().unwrap();
            sensor_name = params.find("sensor").unwrap().to_string();
        }

        // Get sensor value
        let sensor_value;
        {
            let params = req.get_ref::<urlencoded::UrlEncodedBody>().unwrap();
            sensor_value = match params.get("value") {
                Some(ref values) =>  match values.len() {
                    1 => values[0].to_string(),
                    _ => return Ok(self.err_response(status::BadRequest, "Too many values specified")),
                },
                None => return Ok(self.err_response(status::BadRequest, "\"value\" parameter not specified")),
            }
        }

        // Update values in datastore
        if let Err(e) = self.update_sensor(&sensor_name, &sensor_value) {
            error!("update_sensor() failed: {:?}", e);
            let response = match e {
                UpdateHandlerError::UnknownSensor(sensor) =>
                    self.err_response(status::BadRequest, &format!("Unknown sensor: {}", sensor)),
                UpdateHandlerError::DataStoreError(_) =>
                    self.err_response(status::InternalServerError, "Updating values in datastore failed"),
            };
            return Ok(response)
        };

        // Create response
        Ok(self.ok_response())
    }

}
<|endoftext|>