<commit_before>//! Atoms and atomic traits.

use std::{char, u8, u16, u32, u64, usize};
use std::{ascii, cmp};
use std::ops::Range;
use std::fmt::{self, Debug};

use super::{Anchor, Class, Element, Sequence, Repetition, Union};

use util::set::{self, Contains, IsSubsetOf};

/// Trait-bounds requirements for atomic values in a pattern.
pub trait Atom: Debug + Copy + Clone + Eq + Ord + Distance + Step {}
impl<T> Atom for T where T: Debug + Copy + Clone + Eq + Ord + Distance + Step {}

// ----------------------------------------------------------------
// set::IsSubsetOf

impl<T: Atom> set::IsSubsetOf<T> for T {
    #[inline(always)]
    fn is_subset_of(&self, other: &T) -> bool {
        self == other
    }
}
impl<T: Atom> set::IsSubsetOf<Anchor<T>> for T {
    /// An atom is never a subset of an anchor.
    #[inline(always)]
    fn is_subset_of(&self, _: &Anchor<T>) -> bool {
        false
    }
}

impl<T: Atom> set::IsSubsetOf<Class<T>> for T {
    #[inline(always)]
    fn is_subset_of(&self, class: &Class<T>) -> bool {
        class.contains(*self)
    }
}

impl<T: Atom> set::IsSubsetOf<Union<T>> for T {
    #[inline]
    fn is_subset_of(&self, union: &Union<T>) -> bool {
        union.iter().any(|m| self.is_subset_of(m))
    }
}

impl<T: Atom> set::IsSubsetOf<Sequence<T>> for T {
    #[inline]
    fn is_subset_of(&self, seq: &Sequence<T>) -> bool {
        seq.len() == 1 && self.is_subset_of(&seq[0])
    }
}

impl<T: Atom> set::IsSubsetOf<Repetition<T>> for T {
    #[inline]
    fn is_subset_of(&self, rep: &Repetition<T>) -> bool {
        self.is_subset_of(rep.element()) && rep.count().contains(1)
    }
}

impl<T: Atom> set::IsSubsetOf<Element<T>> for T {
    fn is_subset_of(&self, elt: &Element<T>) -> bool {
        match elt {
            &Element::Wildcard => true,
            &Element::Atom(a) => self.is_subset_of(&a),

            &Element::Class(ref class) => self.is_subset_of(class),
            &Element::Union(ref union) => self.is_subset_of(union),
            &Element::Repeat(ref rep) => self.is_subset_of(rep),
            &Element::Tagged{ref element, ..} => self.is_subset_of(&**element),

            &Element::Sequence(ref seq) => self.is_subset_of(seq),
            &Element::Anchor(ref anch) => self.is_subset_of(anch)
        }
    }
}

// ----------------------------------------------------------------
// set::Difference

impl<T: Atom, U> set::Difference<U> for T
    where T: set::IsSubsetOf<U> {
    type Output = Element<T>;
    fn difference(self, other: &U) -> Self::Output {
        if self.is_subset_of(other) {
            Element::empty()
        } else {
            Element::Atom(self)
        }
    }
}

// ----------------------------------------------------------------

/// Trait for types whose values can be stepped through by increment/decrement
/// operatons
pub trait Step: PartialEq<Self> {
    ///  Fetch the next value after the one provided in the positive direction.
    ///  If the supplied value is already at its maximum, return it.
    fn increment(&self) -> Self;

    ///  Fetch the next value after the one provided in the negative direction.
    ///  If the supplied value is already at its minimum, return it.
    fn decrement(&self) -> Self;
}

/// Trait used to determine the distance between two atoms.
pub trait Distance {
    /// Calculate the distance between `self` and the given value, returning
    /// the number of `Self`-sized steps between them.
    fn distance(&self, b: &Self) -> usize;
}

macro_rules! impl_step_distance_for_primitives {
    ($first: tt, $($rest:tt),+) => (
        impl_step_distance_for_primitives!($first);
        impl_step_distance_for_primitives!($($rest),+);
    );
    ($tp: tt) => (
        impl Step for $tp {
            fn increment(&self) -> Self {
                if *self >= $tp::MAX { *self }
                else { ((*self) + 1) as $tp }
            }
            fn decrement(&self) -> Self {
                if *self == 0 { *self }
                else { (*self - 1) as $tp }
            }
        }
        impl Distance for $tp {
            fn distance(&self, b: &Self) -> usize {
                if *self > *b { (*self - *b) as usize }
                else { (*b - *self) as usize }
            }
        }
    );
}

impl_step_distance_for_primitives!(u8, u16, u32, u64, usize);

const SURROGATE_RANGE: Range<u32> = 0xD800..0xE000;

impl Distance for char {
    fn distance(&self, b: &Self) -> usize {
        let (a, b) = (cmp::min(*self, *b) as u32, cmp::max(*self, *b) as u32);
        let a_surrogate = SURROGATE_RANGE.contains(a);
        let b_surrogate = SURROGATE_RANGE.contains(b);

        if a_surrogate && b_surrogate { 0 }
        else if a_surrogate { b as usize }
        else if b_surrogate { a as usize }
        else if (a < SURROGATE_RANGE.start && b < SURROGATE_RANGE.start) || (a >= SURROGATE_RANGE.end && b >= SURROGATE_RANGE.end) {
            (b - a) as usize
        } else {
            (b - SURROGATE_RANGE.end + SURROGATE_RANGE.start - a) as usize
        }
    }
}

impl Step for char {
    fn increment(&self) -> Self {
        if *self >= char::MAX {
            *self
        } else {
            let mut o = *self as u32 + 1;
            if SURROGATE_RANGE.contains(o) {
                o += SURROGATE_RANGE.len() as u32;
            }

            // We've manually skipped the surrogate range and done range
            // checking above, so this *should* actually be safe.
            unsafe { char::from_u32_unchecked(o) }
        }
    }

    fn decrement(&self) -> Self {
        if *self == '\0' {
            *self
        } else {
            let mut o = *self as u32 - 1;
            if SURROGATE_RANGE.contains(o) {
                o -= SURROGATE_RANGE.len() as u32;
            }

            // We've manually skipped the surrogate range and done range
            // checking above, so this *should* actually be safe.
            unsafe { char::from_u32_unchecked(o) }
        }
    }
}

/// Atom type for use with mixed binary/text data.
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Hash)]
pub enum ByteOrChar {
    /// Single byte
    Byte(u8),
    /// Character
    Char(char)
}

impl From<u8> for ByteOrChar {
    fn from(byte: u8) -> Self {
        ByteOrChar::Byte(byte)
    }
}

impl From<char> for ByteOrChar {
    fn from(c: char) -> Self {
        ByteOrChar::Char(c)
    }
}

impl Distance for ByteOrChar {
    fn distance(&self, b: &Self) -> usize {
        Distance::distance(&Into::<char>::into(*self), &Into::<char>::into(*b))
    }
}

impl Step for ByteOrChar {
    fn increment(&self) -> Self {
        match self {
            &ByteOrChar::Byte(b) => ByteOrChar::Byte(b.increment()),
            &ByteOrChar::Char(c) => ByteOrChar::Char(c.increment()),
        }
    }
    fn decrement(&self) -> Self {
        match self {
            &ByteOrChar::Byte(b) => ByteOrChar::Byte(b.increment()),
            &ByteOrChar::Char(c) => ByteOrChar::Char(c.increment()),
        }
    }
}

impl Into<char> for ByteOrChar {
    fn into(self) -> char {
        match self {
            ByteOrChar::Byte(b) => b as char,
            ByteOrChar::Char(c) => c,
        }
    }
}

macro_rules! BoC_ascii_ext_forward {
    ($slf: ident, $name: ident) => (match $slf {
        &ByteOrChar::Byte(b) => b.$name(),
        &ByteOrChar::Char(c) => c.$name()
    });
    (mut $slf: ident, $name: ident) => (match *$slf {
        ByteOrChar::Byte(ref mut b) => b.$name(),
        ByteOrChar::Char(ref mut c) => c.$name()
    });
    ($slf: ident, $name: ident -> $conv: ident) => (match $slf {
        &ByteOrChar::Byte(b) => b.$name().$conv(),
        &ByteOrChar::Char(c) => c.$name().$conv()
    });
}

impl ascii::AsciiExt for ByteOrChar {
    type Owned = ByteOrChar;
    #[inline]
    fn is_ascii(&self) -> bool { BoC_ascii_ext_forward!(self, is_ascii) }
    #[inline]
    fn to_ascii_uppercase(&self) -> Self::Owned { BoC_ascii_ext_forward!(self, to_ascii_uppercase -> into) }
    #[inline]
    fn to_ascii_lowercase(&self) -> Self::Owned { BoC_ascii_ext_forward!(self, to_ascii_uppercase -> into) }
    #[inline]
    fn make_ascii_uppercase(&mut self) { BoC_ascii_ext_forward!(mut self, make_ascii_uppercase) }
    #[inline]
    fn make_ascii_lowercase(&mut self) { BoC_ascii_ext_forward!(mut self, make_ascii_lowercase) }

    #[inline]
    fn eq_ignore_ascii_case(&self, other: &Self) -> bool {
        match self {
            &ByteOrChar::Byte(b1) => match other {
                &ByteOrChar::Byte(b2) => b1.eq_ignore_ascii_case(&b2),
                _ => false },
            &ByteOrChar::Char(c1) => match other {
                &ByteOrChar::Char(c2) => c1.eq_ignore_ascii_case(&c2),
                _ => false }
        }
    }
}
<commit_msg>Revert "pattern/atom: added blanket impl of `set::Difference`"<commit_after>//! Atoms and atomic traits.

use std::{char, u8, u16, u32, u64, usize};
use std::{ascii, cmp};
use std::ops::Range;
use std::fmt::{self, Debug};

use super::{Anchor, Class, Element, Sequence, Repetition, Union};

use util::set::{self, Contains, IsSubsetOf};

/// Trait-bounds requirements for atomic values in a pattern.
pub trait Atom: Debug + Copy + Clone + Eq + Ord + Distance + Step {}
impl<T> Atom for T where T: Debug + Copy + Clone + Eq + Ord + Distance + Step {}

impl<T: Atom> set::IsSubsetOf<T> for T {
    #[inline(always)]
    fn is_subset_of(&self, other: &T) -> bool {
        self == other
    }
}
impl<T: Atom> set::IsSubsetOf<Anchor<T>> for T {
    /// An atom is never a subset of an anchor.
    #[inline(always)]
    fn is_subset_of(&self, _: &Anchor<T>) -> bool {
        false
    }
}

impl<T: Atom> set::IsSubsetOf<Class<T>> for T {
    #[inline(always)]
    fn is_subset_of(&self, class: &Class<T>) -> bool {
        class.contains(*self)
    }
}

impl<T: Atom> set::IsSubsetOf<Union<T>> for T {
    #[inline]
    fn is_subset_of(&self, union: &Union<T>) -> bool {
        union.iter().any(|m| self.is_subset_of(m))
    }
}

impl<T: Atom> set::IsSubsetOf<Sequence<T>> for T {
    #[inline]
    fn is_subset_of(&self, seq: &Sequence<T>) -> bool {
        seq.len() == 1 && self.is_subset_of(&seq[0])
    }
}

impl<T: Atom> set::IsSubsetOf<Repetition<T>> for T {
    #[inline]
    fn is_subset_of(&self, rep: &Repetition<T>) -> bool {
        self.is_subset_of(rep.element()) && rep.count().contains(1)
    }
}

impl<T: Atom> set::IsSubsetOf<Element<T>> for T {
    fn is_subset_of(&self, elt: &Element<T>) -> bool {
        match elt {
            &Element::Wildcard => true,
            &Element::Atom(a) => self.is_subset_of(&a),

            &Element::Class(ref class) => self.is_subset_of(class),
            &Element::Union(ref union) => self.is_subset_of(union),
            &Element::Repeat(ref rep) => self.is_subset_of(rep),
            &Element::Tagged{ref element, ..} => self.is_subset_of(&**element),

            &Element::Sequence(ref seq) => self.is_subset_of(seq),
            &Element::Anchor(ref anch) => self.is_subset_of(anch)
        }
    }
}

/// Trait for types whose values can be stepped through by increment/decrement
/// operatons
pub trait Step: PartialEq<Self> {
    ///  Fetch the next value after the one provided in the positive direction.
    ///  If the supplied value is already at its maximum, return it.
    fn increment(&self) -> Self;

    ///  Fetch the next value after the one provided in the negative direction.
    ///  If the supplied value is already at its minimum, return it.
    fn decrement(&self) -> Self;
}

/// Trait used to determine the distance between two atoms.
pub trait Distance {
    /// Calculate the distance between `self` and the given value, returning
    /// the number of `Self`-sized steps between them.
    fn distance(&self, b: &Self) -> usize;
}

macro_rules! impl_step_distance_for_primitives {
    ($first: tt, $($rest:tt),+) => (
        impl_step_distance_for_primitives!($first);
        impl_step_distance_for_primitives!($($rest),+);
    );
    ($tp: tt) => (
        impl Step for $tp {
            fn increment(&self) -> Self {
                if *self >= $tp::MAX { *self }
                else { ((*self) + 1) as $tp }
            }
            fn decrement(&self) -> Self {
                if *self == 0 { *self }
                else { (*self - 1) as $tp }
            }
        }
        impl Distance for $tp {
            fn distance(&self, b: &Self) -> usize {
                if *self > *b { (*self - *b) as usize }
                else { (*b - *self) as usize }
            }
        }
    );
}

impl_step_distance_for_primitives!(u8, u16, u32, u64, usize);

const SURROGATE_RANGE: Range<u32> = 0xD800..0xE000;

impl Distance for char {
    fn distance(&self, b: &Self) -> usize {
        let (a, b) = (cmp::min(*self, *b) as u32, cmp::max(*self, *b) as u32);
        let a_surrogate = SURROGATE_RANGE.contains(a);
        let b_surrogate = SURROGATE_RANGE.contains(b);

        if a_surrogate && b_surrogate { 0 }
        else if a_surrogate { b as usize }
        else if b_surrogate { a as usize }
        else if (a < SURROGATE_RANGE.start && b < SURROGATE_RANGE.start) || (a >= SURROGATE_RANGE.end && b >= SURROGATE_RANGE.end) {
            (b - a) as usize
        } else {
            (b - SURROGATE_RANGE.end + SURROGATE_RANGE.start - a) as usize
        }
    }
}

impl Step for char {
    fn increment(&self) -> Self {
        if *self >= char::MAX {
            *self
        } else {
            let mut o = *self as u32 + 1;
            if SURROGATE_RANGE.contains(o) {
                o += SURROGATE_RANGE.len() as u32;
            }

            // We've manually skipped the surrogate range and done range
            // checking above, so this *should* actually be safe.
            unsafe { char::from_u32_unchecked(o) }
        }
    }

    fn decrement(&self) -> Self {
        if *self == '\0' {
            *self
        } else {
            let mut o = *self as u32 - 1;
            if SURROGATE_RANGE.contains(o) {
                o -= SURROGATE_RANGE.len() as u32;
            }

            // We've manually skipped the surrogate range and done range
            // checking above, so this *should* actually be safe.
            unsafe { char::from_u32_unchecked(o) }
        }
    }
}

/// Atom type for use with mixed binary/text data.
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Hash)]
pub enum ByteOrChar {
    /// Single byte
    Byte(u8),
    /// Character
    Char(char)
}

impl From<u8> for ByteOrChar {
    fn from(byte: u8) -> Self {
        ByteOrChar::Byte(byte)
    }
}

impl From<char> for ByteOrChar {
    fn from(c: char) -> Self {
        ByteOrChar::Char(c)
    }
}

impl Distance for ByteOrChar {
    fn distance(&self, b: &Self) -> usize {
        Distance::distance(&Into::<char>::into(*self), &Into::<char>::into(*b))
    }
}

impl Step for ByteOrChar {
    fn increment(&self) -> Self {
        match self {
            &ByteOrChar::Byte(b) => ByteOrChar::Byte(b.increment()),
            &ByteOrChar::Char(c) => ByteOrChar::Char(c.increment()),
        }
    }
    fn decrement(&self) -> Self {
        match self {
            &ByteOrChar::Byte(b) => ByteOrChar::Byte(b.increment()),
            &ByteOrChar::Char(c) => ByteOrChar::Char(c.increment()),
        }
    }
}

impl Into<char> for ByteOrChar {
    fn into(self) -> char {
        match self {
            ByteOrChar::Byte(b) => b as char,
            ByteOrChar::Char(c) => c,
        }
    }
}

macro_rules! BoC_ascii_ext_forward {
    ($slf: ident, $name: ident) => (match $slf {
        &ByteOrChar::Byte(b) => b.$name(),
        &ByteOrChar::Char(c) => c.$name()
    });
    (mut $slf: ident, $name: ident) => (match *$slf {
        ByteOrChar::Byte(ref mut b) => b.$name(),
        ByteOrChar::Char(ref mut c) => c.$name()
    });
    ($slf: ident, $name: ident -> $conv: ident) => (match $slf {
        &ByteOrChar::Byte(b) => b.$name().$conv(),
        &ByteOrChar::Char(c) => c.$name().$conv()
    });
}

impl ascii::AsciiExt for ByteOrChar {
    type Owned = ByteOrChar;
    #[inline]
    fn is_ascii(&self) -> bool { BoC_ascii_ext_forward!(self, is_ascii) }
    #[inline]
    fn to_ascii_uppercase(&self) -> Self::Owned { BoC_ascii_ext_forward!(self, to_ascii_uppercase -> into) }
    #[inline]
    fn to_ascii_lowercase(&self) -> Self::Owned { BoC_ascii_ext_forward!(self, to_ascii_uppercase -> into) }
    #[inline]
    fn make_ascii_uppercase(&mut self) { BoC_ascii_ext_forward!(mut self, make_ascii_uppercase) }
    #[inline]
    fn make_ascii_lowercase(&mut self) { BoC_ascii_ext_forward!(mut self, make_ascii_lowercase) }

    #[inline]
    fn eq_ignore_ascii_case(&self, other: &Self) -> bool {
        match self {
            &ByteOrChar::Byte(b1) => match other {
                &ByteOrChar::Byte(b2) => b1.eq_ignore_ascii_case(&b2),
                _ => false },
            &ByteOrChar::Char(c1) => match other {
                &ByteOrChar::Char(c2) => c1.eq_ignore_ascii_case(&c2),
                _ => false }
        }
    }
}
<|endoftext|>


<commit_before>use render::Texture;
use types::OutputHandle;

use wlroots_sys::{wlr_backend, wlr_gles2_renderer_create, wlr_render_texture_create,
                  wlr_render_with_matrix, wlr_renderer, wlr_renderer_begin, wlr_renderer_destroy,
                  wlr_renderer_end};

/// Holds the state necessary to start rendering for GLES2.
pub struct GLES2 {
    renderer: *mut wlr_renderer
}

/// Renderer for GLES2
pub struct GLES2Renderer<'output> {
    renderer: *mut wlr_renderer,
    output: &'output mut OutputHandle
}

impl GLES2 {
    pub(crate) unsafe fn new(backend: *mut wlr_backend) -> Option<Self> {
        if backend.is_null() {
            wlr_log!(L_ERROR, "Backend was null");
            return None;
        }
        let renderer = wlr_gles2_renderer_create(backend);
        if renderer.is_null() {
            wlr_log!(L_ERROR, "Could not construct GLES2 renderer");
            None
        } else {
            Some(GLES2 { renderer })
        }
    }

    // TODO This should probably make a wrapper type or something
    // Because you shouldn't be able to call these methods otherwise.
    // Make this a GLES2
    // Make the thing in the callback a GLES2Renderer

    pub fn render<'output>(&mut self, output: &'output mut OutputHandle) -> GLES2Renderer<'output> {
        output.make_current();
        unsafe {
            wlr_renderer_begin(self.renderer, output.to_ptr());
        }
        GLES2Renderer {
            renderer: self.renderer,
            output
        }
    }

    pub fn create_texture(&mut self) -> Option<Texture> {
        unsafe { create_texture(self.renderer) }
    }
}

impl<'output> GLES2Renderer<'output> {
    pub fn render_with_matrix(&mut self, texture: &Texture, matrix: &[f32; 16]) -> bool {
        unsafe { wlr_render_with_matrix(self.renderer, texture.to_ptr(), matrix) }
    }

    /// Create a texture using the GLES2 backend.
    pub fn create_texture(&mut self) -> Option<Texture> {
        unsafe { create_texture(self.renderer) }
    }
}

impl<'output> Drop for GLES2Renderer<'output> {
    fn drop(&mut self) {
        unsafe {
            wlr_renderer_end(self.renderer);
        }
        self.output.swap_buffers()
    }
}

impl Drop for GLES2 {
    fn drop(&mut self) {
        unsafe { wlr_renderer_destroy(self.renderer) }
    }
}

unsafe fn create_texture(renderer: *mut wlr_renderer) -> Option<Texture> {
    let texture = wlr_render_texture_create(renderer);
    if texture.is_null() {
        wlr_log!(L_ERROR, "Could not create texture");
        None
    } else {
        Some(Texture::from_ptr(texture))
    }
}
<commit_msg>Removed out-dated TODO<commit_after>use render::Texture;
use types::OutputHandle;

use wlroots_sys::{wlr_backend, wlr_gles2_renderer_create, wlr_render_texture_create,
                  wlr_render_with_matrix, wlr_renderer, wlr_renderer_begin, wlr_renderer_destroy,
                  wlr_renderer_end};

/// Holds the state necessary to start rendering for GLES2.
pub struct GLES2 {
    renderer: *mut wlr_renderer
}

/// Renderer for GLES2
pub struct GLES2Renderer<'output> {
    renderer: *mut wlr_renderer,
    output: &'output mut OutputHandle
}

impl GLES2 {
    pub(crate) unsafe fn new(backend: *mut wlr_backend) -> Option<Self> {
        if backend.is_null() {
            wlr_log!(L_ERROR, "Backend was null");
            return None;
        }
        let renderer = wlr_gles2_renderer_create(backend);
        if renderer.is_null() {
            wlr_log!(L_ERROR, "Could not construct GLES2 renderer");
            None
        } else {
            Some(GLES2 { renderer })
        }
    }

    pub fn render<'output>(&mut self, output: &'output mut OutputHandle) -> GLES2Renderer<'output> {
        output.make_current();
        unsafe {
            wlr_renderer_begin(self.renderer, output.to_ptr());
        }
        GLES2Renderer {
            renderer: self.renderer,
            output
        }
    }

    pub fn create_texture(&mut self) -> Option<Texture> {
        unsafe { create_texture(self.renderer) }
    }
}

impl<'output> GLES2Renderer<'output> {
    pub fn render_with_matrix(&mut self, texture: &Texture, matrix: &[f32; 16]) -> bool {
        unsafe { wlr_render_with_matrix(self.renderer, texture.to_ptr(), matrix) }
    }

    /// Create a texture using the GLES2 backend.
    pub fn create_texture(&mut self) -> Option<Texture> {
        unsafe { create_texture(self.renderer) }
    }
}

impl<'output> Drop for GLES2Renderer<'output> {
    fn drop(&mut self) {
        unsafe {
            wlr_renderer_end(self.renderer);
        }
        self.output.swap_buffers()
    }
}

impl Drop for GLES2 {
    fn drop(&mut self) {
        unsafe { wlr_renderer_destroy(self.renderer) }
    }
}

unsafe fn create_texture(renderer: *mut wlr_renderer) -> Option<Texture> {
    let texture = wlr_render_texture_create(renderer);
    if texture.is_null() {
        wlr_log!(L_ERROR, "Could not create texture");
        None
    } else {
        Some(Texture::from_ptr(texture))
    }
}
<|endoftext|>


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

// Prevent warning when casting u32 as i64
#![allow(clippy::cast_lossless)]
#![allow(dead_code)]

use std::ptr;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::mpsc::{self, Receiver, Sender};
use std::sync::Arc;
use std::thread;
use std::time::Duration;

use libc::{
    self, c_long, sched_param, time_t, timespec, CLOCK_MONOTONIC, PR_SET_TIMERSLACK, SCHED_RR,
};

use super::{Error, GpioState, Result};

// Only call sleep_ns() if we have enough time remaining
const SLEEP_THRESHOLD: i64 = 250_000;
// Reserve some time for busy waiting
const BUSYWAIT_MAX: i64 = 200_000;
// Subtract from the remaining busy wait time to account for get_time_ns() overhead
const BUSYWAIT_REMAINDER: i64 = 100;

static mut MSG_WAITING: AtomicBool = AtomicBool::new(false);

#[derive(Debug)]
enum Msg {
    Reconfigure(Duration, Duration),
    Stop,
}

#[derive(Debug)]
pub(crate) struct SoftPwm {
    pwm_thread: Option<thread::JoinHandle<Result<()>>>,
    sender: Sender<Msg>,
}

impl SoftPwm {
    pub(crate) fn new(
        pin: u8,
        gpio_state: Arc<GpioState>,
        period: Duration,
        pulse_width: Duration,
    ) -> SoftPwm {
        let (sender, receiver): (Sender<Msg>, Receiver<Msg>) = mpsc::channel();

        let pwm_thread = thread::spawn(move || -> Result<()> {
            // Set the scheduling policy to real-time round robin at the highest priority. This
            // will silently fail if we're not running as root.
            #[cfg(target_env = "gnu")]
            let params = sched_param {
                sched_priority: unsafe { libc::sched_get_priority_max(SCHED_RR) },
            };

            #[cfg(target_env = "musl")]
            let params = sched_param {
                sched_priority: unsafe { libc::sched_get_priority_max(SCHED_RR) },
                sched_ss_low_priority: 0,
                sched_ss_repl_period: timespec {
                    tv_sec: 0,
                    tv_nsec: 0,
                },
                sched_ss_init_budget: timespec {
                    tv_sec: 0,
                    tv_nsec: 0,
                },
                sched_ss_max_repl: 0,
            };

            unsafe {
                libc::sched_setscheduler(0, SCHED_RR, &params);
            }

            // Set timer slack to 1 ns (default = 50 µs). This is only relevant if we're unable
            // to set a real-time scheduling policy.
            unsafe {
                libc::prctl(PR_SET_TIMERSLACK, 1);
            }

            let mut period_ns =
                (period.as_secs() as i64 * 1_000_000_000) + period.subsec_nanos() as i64;

            let mut pulse_width_ns =
                (pulse_width.as_secs() as i64 * 1_000_000_000) + pulse_width.subsec_nanos() as i64;

            let mut start_ns = get_time_ns();

            loop {
                // PWM active
                if pulse_width_ns > 0 {
                    gpio_state.gpio_mem.set_high(pin);
                }

                // Sleep if we have enough time remaining, while reserving some time
                // for busy waiting to compensate for sleep taking longer than needed.
                if pulse_width_ns >= SLEEP_THRESHOLD {
                    sleep_ns(pulse_width_ns - BUSYWAIT_MAX);
                }

                // Busy-wait for the remaining active time, minus BUSYWAIT_REMAINDER
                // to account for get_time_ns() overhead
                loop {
                    if (pulse_width_ns - (get_time_ns() - start_ns)) <= BUSYWAIT_REMAINDER {
                        break;
                    }
                }

                // PWM inactive
                gpio_state.gpio_mem.set_low(pin);

                // This is slightly faster than directly checking try_recv()
                if unsafe { MSG_WAITING.compare_and_swap(true, false, Ordering::AcqRel) } {
                    while let Ok(msg) = receiver.try_recv() {
                        match msg {
                            Msg::Reconfigure(period, pulse_width) => {
                                // Reconfigure period and pulse width
                                pulse_width_ns = (pulse_width.as_secs() as i64 * 1_000_000_000)
                                    + pulse_width.subsec_nanos() as i64;

                                period_ns = (period.as_secs() as i64 * 1_000_000_000)
                                    + period.subsec_nanos() as i64;

                                if pulse_width_ns > period_ns {
                                    pulse_width_ns = period_ns;
                                }
                            }
                            Msg::Stop => {
                                // The main thread asked us to stop
                                return Ok(());
                            }
                        }
                    }
                }

                let remaining_ns = period_ns - (get_time_ns() - start_ns);

                // Sleep if we have enough time remaining, while reserving some time
                // for busy waiting to compensate for sleep taking longer than needed.
                if remaining_ns >= SLEEP_THRESHOLD {
                    sleep_ns(remaining_ns - BUSYWAIT_MAX);
                }

                // Busy-wait for the remaining inactive time, minus BUSYWAIT_REMAINDER
                // to account for get_time_ns() overhead
                loop {
                    let current_ns = get_time_ns();
                    if (period_ns - (current_ns - start_ns)) <= BUSYWAIT_REMAINDER {
                        start_ns = current_ns;
                        break;
                    }
                }
            }
        });

        SoftPwm {
            pwm_thread: Some(pwm_thread),
            sender,
        }
    }

    pub(crate) fn reconfigure(&mut self, period: Duration, pulse_width: Duration) {
        let _ = self.sender.send(Msg::Reconfigure(period, pulse_width));
        unsafe {
            MSG_WAITING.store(true, Ordering::Release);
        }
    }

    pub(crate) fn stop(&mut self) -> Result<()> {
        let _ = self.sender.send(Msg::Stop);
        unsafe {
            MSG_WAITING.store(true, Ordering::Release);
        }

        if let Some(pwm_thread) = self.pwm_thread.take() {
            match pwm_thread.join() {
                Ok(r) => return r,
                Err(_) => return Err(Error::ThreadPanic),
            }
        }

        Ok(())
    }
}

impl Drop for SoftPwm {
    fn drop(&mut self) {
        // Don't wait for the pwm thread to exit if the main thread is panicking,
        // because we could potentially block indefinitely while unwinding if the
        // pwm thread doesn't respond to the Stop message for some reason.
        if !thread::panicking() {
            let _ = self.stop();
        }
    }
}

#[inline(always)]
fn get_time_ns() -> i64 {
    let mut ts = timespec {
        tv_sec: 0,
        tv_nsec: 0,
    };

    unsafe {
        libc::clock_gettime(CLOCK_MONOTONIC, &mut ts);
    }

    (ts.tv_sec as i64 * 1_000_000_000) + ts.tv_nsec as i64
}

#[inline(always)]
fn sleep_ns(ns: i64) {
    let ts = timespec {
        tv_sec: (ns / 1_000_000_000) as time_t,
        tv_nsec: (ns % 1_000_000_000) as c_long,
    };

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

// Prevent warning when casting u32 as i64
#![allow(clippy::cast_lossless)]
#![allow(dead_code)]

use std::ptr;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::mpsc::{self, Receiver, Sender};
use std::sync::Arc;
use std::thread;
use std::time::Duration;

use libc::{
    self, c_long, sched_param, time_t, timespec, CLOCK_MONOTONIC, PR_SET_TIMERSLACK, SCHED_RR,
};

use super::{Error, GpioState, Result};

// Only call sleep_ns() if we have enough time remaining
const SLEEP_THRESHOLD: i64 = 250_000;
// Reserve some time for busy waiting
const BUSYWAIT_MAX: i64 = 200_000;
// Subtract from the remaining busy wait time to account for get_time_ns() overhead
const BUSYWAIT_REMAINDER: i64 = 100;

static mut MSG_WAITING: AtomicBool = AtomicBool::new(false);

#[derive(Debug)]
enum Msg {
    Reconfigure(Duration, Duration),
    Stop,
}

#[derive(Debug)]
pub(crate) struct SoftPwm {
    pwm_thread: Option<thread::JoinHandle<Result<()>>>,
    sender: Sender<Msg>,
}

impl SoftPwm {
    pub(crate) fn new(
        pin: u8,
        gpio_state: Arc<GpioState>,
        period: Duration,
        pulse_width: Duration,
    ) -> SoftPwm {
        let (sender, receiver): (Sender<Msg>, Receiver<Msg>) = mpsc::channel();

        let pwm_thread = thread::spawn(move || -> Result<()> {
            // Set the scheduling policy to real-time round robin at the highest priority. This
            // will silently fail if we're not running as root.
            #[cfg(target_env = "gnu")]
            let params = sched_param {
                sched_priority: unsafe { libc::sched_get_priority_max(SCHED_RR) },
            };

            #[cfg(target_env = "musl")]
            let params = sched_param {
                sched_priority: unsafe { libc::sched_get_priority_max(SCHED_RR) },
                sched_ss_low_priority: 0,
                sched_ss_repl_period: timespec {
                    tv_sec: 0,
                    tv_nsec: 0,
                },
                sched_ss_init_budget: timespec {
                    tv_sec: 0,
                    tv_nsec: 0,
                },
                sched_ss_max_repl: 0,
            };

            unsafe {
                libc::sched_setscheduler(0, SCHED_RR, &params);
            }

            // Set timer slack to 1 ns (default = 50 µs). This is only relevant if we're unable
            // to set a real-time scheduling policy.
            unsafe {
                libc::prctl(PR_SET_TIMERSLACK, 1);
            }

            let mut period_ns =
                (period.as_secs() as i64 * 1_000_000_000) + period.subsec_nanos() as i64;

            let mut pulse_width_ns =
                (pulse_width.as_secs() as i64 * 1_000_000_000) + pulse_width.subsec_nanos() as i64;

            let mut start_ns = get_time_ns();

            loop {
                // PWM active
                if pulse_width_ns > 0 {
                    gpio_state.gpio_mem.set_high(pin);
                }

                // Sleep if we have enough time remaining, while reserving some time
                // for busy waiting to compensate for sleep taking longer than needed.
                if pulse_width_ns >= SLEEP_THRESHOLD {
                    sleep_ns(pulse_width_ns - BUSYWAIT_MAX);
                }

                // Busy-wait for the remaining active time, minus BUSYWAIT_REMAINDER
                // to account for get_time_ns() overhead
                loop {
                    if (pulse_width_ns - (get_time_ns() - start_ns)) <= BUSYWAIT_REMAINDER {
                        break;
                    }
                }

                // PWM inactive
                gpio_state.gpio_mem.set_low(pin);

                // This is slightly faster than directly checking try_recv()
                if unsafe { MSG_WAITING.compare_and_swap(true, false, Ordering::AcqRel) } {
                    while let Ok(msg) = receiver.try_recv() {
                        match msg {
                            Msg::Reconfigure(period, pulse_width) => {
                                // Reconfigure period and pulse width
                                pulse_width_ns = (pulse_width.as_secs() as i64 * 1_000_000_000)
                                    + pulse_width.subsec_nanos() as i64;

                                period_ns = (period.as_secs() as i64 * 1_000_000_000)
                                    + period.subsec_nanos() as i64;

                                if pulse_width_ns > period_ns {
                                    pulse_width_ns = period_ns;
                                }
                            }
                            Msg::Stop => {
                                // The main thread asked us to stop
                                return Ok(());
                            }
                        }
                    }
                }

                let remaining_ns = period_ns - (get_time_ns() - start_ns);

                // Sleep if we have enough time remaining, while reserving some time
                // for busy waiting to compensate for sleep taking longer than needed.
                if remaining_ns >= SLEEP_THRESHOLD {
                    sleep_ns(remaining_ns - BUSYWAIT_MAX);
                }

                // Busy-wait for the remaining inactive time, minus BUSYWAIT_REMAINDER
                // to account for get_time_ns() overhead
                loop {
                    let current_ns = get_time_ns();
                    if (period_ns - (current_ns - start_ns)) <= BUSYWAIT_REMAINDER {
                        start_ns = current_ns;
                        break;
                    }
                }
            }
        });

        SoftPwm {
            pwm_thread: Some(pwm_thread),
            sender,
        }
    }

    pub(crate) fn reconfigure(&mut self, period: Duration, pulse_width: Duration) {
        let _ = self.sender.send(Msg::Reconfigure(period, pulse_width));
        unsafe {
            MSG_WAITING.store(true, Ordering::Release);
        }
    }

    pub(crate) fn stop(&mut self) -> Result<()> {
        let _ = self.sender.send(Msg::Stop);
        unsafe {
            MSG_WAITING.store(true, Ordering::Release);
        }

        if let Some(pwm_thread) = self.pwm_thread.take() {
            match pwm_thread.join() {
                Ok(r) => return r,
                Err(_) => return Err(Error::ThreadPanic),
            }
        }

        Ok(())
    }
}

impl Drop for SoftPwm {
    fn drop(&mut self) {
        // Don't wait for the pwm thread to exit if the main thread is panicking,
        // because we could potentially block indefinitely while unwinding if the
        // pwm thread doesn't respond to the Stop message for some reason.
        if !thread::panicking() {
            let _ = self.stop();
        }
    }
}

// Required because Sender isn't Sync. Implementing Sync for SoftPwm is
// safe because all usage of Sender::send() is locked behind &mut self.
unsafe impl Sync for SoftPwm {}

#[inline(always)]
fn get_time_ns() -> i64 {
    let mut ts = timespec {
        tv_sec: 0,
        tv_nsec: 0,
    };

    unsafe {
        libc::clock_gettime(CLOCK_MONOTONIC, &mut ts);
    }

    (ts.tv_sec as i64 * 1_000_000_000) + ts.tv_nsec as i64
}

#[inline(always)]
fn sleep_ns(ns: i64) {
    let ts = timespec {
        tv_sec: (ns / 1_000_000_000) as time_t,
        tv_nsec: (ns % 1_000_000_000) as c_long,
    };

    unsafe {
        libc::clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, ptr::null_mut());
    }
}
<|endoftext|>


<commit_before>//! Tests for various types of file (video, image, compressed, etc).
//!
//! Currently this is dependent on the file’s name and extension, because
//! those are the only metadata that we have access to without reading the
//! file’s contents.

use fs::File;

#[derive(Debug)]
pub struct FileExtensions;

impl FileExtensions {

    /// An “immediate” file is something that can be run or activated somehow
    /// in order to kick off the build of a project. It’s usually only present
    /// in directories full of source code.
    pub fn is_immediate(&self, file: &File) -> bool {
        file.name.starts_with("README") || file.name_is_one_of( &[
            "Makefile", "Cargo.toml", "SConstruct", "CMakeLists.txt",
            "build.gradle", "Rakefile", "Gruntfile.js",
            "Gruntfile.coffee",
        ])
    }

    pub fn is_image(&self, file: &File) -> bool {
        file.extension_is_one_of( &[
            "png", "jpeg", "jpg", "gif", "bmp", "tiff", "tif",
            "ppm", "pgm", "pbm", "pnm", "webp", "raw", "arw",
            "svg", "stl", "eps", "dvi", "ps", "cbr",
            "cbz", "xpm", "ico", "cr2",
        ])
    }

    pub fn is_video(&self, file: &File) -> bool {
        file.extension_is_one_of( &[
            "avi", "flv", "m2v", "mkv", "mov", "mp4", "mpeg",
            "mpg", "ogm", "ogv", "vob", "wmv",
        ])
    }

    pub fn is_music(&self, file: &File) -> bool {
        file.extension_is_one_of( &[
            "aac", "m4a", "mp3", "ogg", "wma",
        ])
    }

    // Lossless music, rather than any other kind of data...
    pub fn is_lossless(&self, file: &File) -> bool {
        file.extension_is_one_of( &[
            "alac", "ape", "flac", "wav",
        ])
    }

    pub fn is_crypto(&self, file: &File) -> bool {
        file.extension_is_one_of( &[
            "asc", "enc", "gpg", "pgp", "sig", "signature", "pfx", "p12",
        ])
    }

    pub fn is_document(&self, file: &File) -> bool {
        file.extension_is_one_of( &[
            "djvu", "doc", "docx", "dvi", "eml", "eps", "fotd",
            "odp", "odt", "pdf", "ppt", "pptx", "rtf",
            "xls", "xlsx",
        ])
    }

    pub fn is_compressed(&self, file: &File) -> bool {
        file.extension_is_one_of( &[
            "zip", "tar", "Z", "gz", "bz2", "a", "ar", "7z",
            "iso", "dmg", "tc", "rar", "par", "tgz",
        ])
    }

    pub fn is_temp(&self, file: &File) -> bool {
        file.name.ends_with('~')
            || (file.name.starts_with('#') && file.name.ends_with('#'))
            || file.extension_is_one_of( &[ "tmp", "swp", "swo", "swn", "bak" ])
    }

    pub fn is_compiled(&self, file: &File) -> bool {
        if file.extension_is_one_of( &[ "class", "elc", "hi", "o", "pyc" ]) {
            true
        }
        else if let Some(dir) = file.parent_dir {
            file.get_source_files().iter().any(|path| dir.contains(path))
        }
        else {
            false
        }
    }
}
<commit_msg>Update filetype.rs<commit_after>//! Tests for various types of file (video, image, compressed, etc).
//!
//! Currently this is dependent on the file’s name and extension, because
//! those are the only metadata that we have access to without reading the
//! file’s contents.

use fs::File;

#[derive(Debug)]
pub struct FileExtensions;

impl FileExtensions {

    /// An “immediate” file is something that can be run or activated somehow
    /// in order to kick off the build of a project. It’s usually only present
    /// in directories full of source code.
    pub fn is_immediate(&self, file: &File) -> bool {
        file.name.starts_with("README") || file.name_is_one_of( &[
            "Makefile", "Cargo.toml", "SConstruct", "CMakeLists.txt",
            "build.gradle", "Rakefile", "Gruntfile.js",
            "Gruntfile.coffee",
        ])
    }

    pub fn is_image(&self, file: &File) -> bool {
        file.extension_is_one_of( &[
            "png", "jpeg", "jpg", "gif", "bmp", "tiff", "tif",
            "ppm", "pgm", "pbm", "pnm", "webp", "raw", "arw",
            "svg", "stl", "eps", "dvi", "ps", "cbr",
            "cbz", "xpm", "ico", "cr2",
        ])
    }

    pub fn is_video(&self, file: &File) -> bool {
        file.extension_is_one_of( &[
            "avi", "flv", "m2v", "mkv", "mov", "mp4", "mpeg",
            "mpg", "ogm", "ogv", "vob", "wmv", "webm", "m2ts",
            "ts",
        ])
    }

    pub fn is_music(&self, file: &File) -> bool {
        file.extension_is_one_of( &[
            "aac", "m4a", "mp3", "ogg", "wma", "mka", "opus",
        ])
    }

    // Lossless music, rather than any other kind of data...
    pub fn is_lossless(&self, file: &File) -> bool {
        file.extension_is_one_of( &[
            "alac", "ape", "flac", "wav",
        ])
    }

    pub fn is_crypto(&self, file: &File) -> bool {
        file.extension_is_one_of( &[
            "asc", "enc", "gpg", "pgp", "sig", "signature", "pfx", "p12",
        ])
    }

    pub fn is_document(&self, file: &File) -> bool {
        file.extension_is_one_of( &[
            "djvu", "doc", "docx", "dvi", "eml", "eps", "fotd",
            "odp", "odt", "pdf", "ppt", "pptx", "rtf",
            "xls", "xlsx",
        ])
    }

    pub fn is_compressed(&self, file: &File) -> bool {
        file.extension_is_one_of( &[
            "zip", "tar", "Z", "gz", "bz2", "a", "ar", "7z",
            "iso", "dmg", "tc", "rar", "par", "tgz",
        ])
    }

    pub fn is_temp(&self, file: &File) -> bool {
        file.name.ends_with('~')
            || (file.name.starts_with('#') && file.name.ends_with('#'))
            || file.extension_is_one_of( &[ "tmp", "swp", "swo", "swn", "bak" ])
    }

    pub fn is_compiled(&self, file: &File) -> bool {
        if file.extension_is_one_of( &[ "class", "elc", "hi", "o", "pyc" ]) {
            true
        }
        else if let Some(dir) = file.parent_dir {
            file.get_source_files().iter().any(|path| dir.contains(path))
        }
        else {
            false
        }
    }
}
<|endoftext|>


<commit_before>mod gdt;
mod idt;
mod pic;
mod timer;

static IRQ_OFFSET: u8 = 0x20;

pub fn idle()
{
	unsafe
	{
		asm!("hlt");
	}
}

pub fn halt() -> !
{
	loop
	{
		unsafe
		{
			asm!("cli");
			asm!("hlt");
		}
	}
}

pub fn request_int3()
{
	unsafe
	{
		asm!("int $$0x03");
	}
	pic::disable_irq(0);
}

pub fn setup()
{
	gdt::init_gdt();
	pic::remap_pic(IRQ_OFFSET);
	idt::init_idt();
	timer::set_interval(50);
}

#[no_mangle]
pub fn isr_handler(_ds: u32, _edi:u32, _esi:u32, _ebp:u32, _esp:u32, _ebx:u32, _edx:u32, _ecx:u32, _eax:u32, ino: u32, ec:u32, _eip:u32, _cs:u32, _eflags:u32, _useresp:u32, _ss:u32)
{
	::kernel::interrupts::handle_interrupt(ino, ec);

	// Ack IRQ
	if ino >= (IRQ_OFFSET as u32)
	{
		pic::acknowledge_irq(ino as u8 - IRQ_OFFSET);
	}
}

pub fn enable_interrupts()
{
	pic::enable_irq(0);
	pic::enable_irq(1);
	unsafe
	{
		asm!("sti");
	}
}
<commit_msg>Packed arguments of isr_handler in a struct<commit_after>mod gdt;
mod idt;
mod pic;
mod timer;

static IRQ_OFFSET: u8 = 0x20;

#[repr(C)]
pub struct InterruptArguments {
	_ds: u32, _edi: u32, _esi: u32, _ebp: u32, _esp: u32, _ebx: u32, _edx: u32, _ecx: u32, _eax: u32,
	interrupt_number: u32,
	error_code: u32,
	_eip: u32, _cs: u32, _eflags: u32, _useresp: u32, _ss: u32,
}

pub fn idle()
{
	unsafe
	{
		asm!("hlt");
	}
}

pub fn halt() -> !
{
	loop
	{
		unsafe
		{
			asm!("cli");
			asm!("hlt");
		}
	}
}

pub fn request_int3()
{
	unsafe
	{
		asm!("int $$0x03");
	}
	pic::disable_irq(0);
}

pub fn setup()
{
	gdt::init_gdt();
	pic::remap_pic(IRQ_OFFSET);
	idt::init_idt();
	timer::set_interval(50);
}

#[no_mangle]
pub extern "C" fn isr_handler(args: InterruptArguments)
{
	::kernel::interrupts::handle_interrupt(args.interrupt_number, args.error_code);

	// Ack IRQ
	if args.interrupt_number >= (IRQ_OFFSET as u32)
	{
		pic::acknowledge_irq(args.interrupt_number as u8 - IRQ_OFFSET);
	}
}

pub fn enable_interrupts()
{
	pic::enable_irq(0);
	pic::enable_irq(1);
	unsafe
	{
		asm!("sti");
	}
}
<|endoftext|>


<commit_before>use Prefab;
use Rng;
use calx_grid;
use calx_grid::Dir6;
use euclid::{vec2, Vector2D};
use field::Field;
use form::Form;
use location::{Location, Portal};
use mapfile;
use rand::{self, Rand, SeedableRng};
use serde;
use std::cmp;
use std::collections::BTreeSet;
use std::collections::HashMap;
use std::io::Cursor;
use std::slice;
use terrain::Terrain;
use world::Loadout;

/// Static generated world.
pub struct Worldgen {
    seed: u32,
    terrain: Field<Terrain>,
    portals: HashMap<Location, Portal>,
    spawns: Vec<(Location, Loadout)>,
    player_entry: Location,
}

impl Worldgen {
    pub fn new(seed: u32) -> Worldgen {
        let mut ret = Worldgen {
            seed: seed,
            terrain: Field::new(),
            portals: HashMap::new(),
            spawns: Vec::new(),
            player_entry: Location::new(0, 0, 0),
        };

        let mut rng: Rng = SeedableRng::from_seed([seed, seed, seed, seed]);
        ret.gen_overworld(&mut rng);
        //ret.sprint_map();
        ret.gen_caves(&mut rng, Location::new(0, 0, 1));

        ret
    }

    fn sprint_map(&mut self) {
        const SPRINT_PREFAB: &'static str = include_str!("../../sprint.ron");

        let sprint_prefab = mapfile::load_prefab(&mut Cursor::new(SPRINT_PREFAB))
            .expect("Corrupt sprint file");

        // Top-left of the default on-screen area.
        let origin = Location::new(-21, -22, 0);
        self.load_prefab(origin, &sprint_prefab);
    }

    fn load_prefab(&mut self, origin: Location, prefab: &Prefab) {
        for (p, &(ref terrain, ref entities)) in prefab.iter() {
            let loc = origin + p;

            self.terrain.set(loc, *terrain);

            for spawn in entities.iter() {
                if spawn == "player" {
                    self.player_entry = loc;
                } else {
                    let form = Form::named(spawn).expect(&format!(
                        "Bad prefab: Form '{}' not found!",
                        spawn
                    ));
                    self.spawns.push((loc, form.loadout.clone()));
                }
            }
        }
    }

    pub fn seed(&self) -> u32 { self.seed }

    pub fn get_terrain(&self, loc: Location) -> Terrain { self.terrain.get(loc) }

    pub fn get_portal(&self, loc: Location) -> Option<Location> {
        self.portals.get(&loc).map(|&p| loc + p)
    }

    pub fn spawns(&self) -> slice::Iter<(Location, Loadout)> { self.spawns.iter() }

    pub fn player_entry(&self) -> Location { self.player_entry }

    fn gen_overworld<R: rand::Rng>(&mut self, rng: &mut R) {
        use Terrain::*;

        let noise_offset = rng.gen_range(0, 100);

        for y in -128..128 {
            for x in -128..128 {
                let x = x as i8;
                let y = y as i8;
                let loc = Location::new(x, y, 0);
                let noise = Location::new(x, y, noise_offset).noise();

                self.terrain.set(
                    loc,
                    match noise {
                        n if n > 0.8 => Tree,
                        n if n > -0.8 => Grass,
                        _ => Water,
                    },
                );
            }
        }
    }

    fn gen_caves<R: rand::Rng>(&mut self, rng: &mut R, entrance: Location) {
        use self::Prototerrain::*;

        let mut cells_to_dig = 700;

        let mut map = screen_map(Location::new(0, 0, entrance.z));

        debug_assert!(map.get(entrance) == Unused);

        // Create portal enclosure
        // TODO: Backportal
        entry_cave_enclosure(&mut map, entrance);

        let entrance = entrance + vec2(1, 1);

        let mut edge: BTreeSet<Location> = Dir6::iter()
            .map(|&d| entrance + vec2(2, 2) + d)
            .filter(|&loc| map.get(loc) == Unused)
            .collect();

        // Arbitrary long iteration, should break after digging a sufficient number of cells before
        // this.
        for _ in 0..10000 {
            if edge.is_empty() {
                break;
            }

            let dig_loc = *rand::sample(rng, edge.iter(), 1)[0];

            // Prefer digging narrow corridors, there's an increasing chance to abort the dig when the
            // selected location is in a very open space.
            let adjacent_floors = Dir6::iter()
                .filter(|d| map.get(dig_loc + **d) == Floor)
                .count();
            if rng.gen_range(0, cmp::max(1, adjacent_floors * adjacent_floors)) != 0 {
                continue;
            }

            map.set(dig_loc, Floor);
            edge.extend(Dir6::iter().map(|&d| dig_loc + d).filter(|&loc| {
                map.get(loc) == Unused
            }));

            cells_to_dig -= 1;
            if cells_to_dig == 0 {
                break;
            }
        }

        // Postprocess
        let cells: Vec<_> = map.iter().map(|(&loc, &c)| (loc, c)).collect();
        for (loc, c) in cells.into_iter() {
            // Clear pillars
            if c == Unused {
                let adjacent_floors = Dir6::iter().filter(|d| map.get(loc + **d) == Floor).count();

                if adjacent_floors == 6 {
                    map.set(loc, Floor);
                }
            }
        }

        // Map to actual terrains
        self.terrain.extend(map.iter().map(|(&loc, &t)| {
            let t = match t {
                Outside => Terrain::Empty,
                Unused => Terrain::Rock,
                Border => Terrain::Rock,
                Floor => Terrain::Ground,
                Wall => Terrain::Rock,
                Door => Terrain::Door,
            };
            (loc, t)
        }));
    }
}

impl serde::Serialize for Worldgen {
    fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
        self.seed.serialize(s)
    }
}

impl<'a> serde::Deserialize<'a> for Worldgen {
    fn deserialize<D: serde::Deserializer<'a>>(d: D) -> Result<Self, D::Error> {
        Ok(Worldgen::new(serde::Deserialize::deserialize(d)?))
    }
}

#[derive(Copy, Clone, Eq, PartialEq, Debug)]
enum Prototerrain {
    /// Area completely outside the map to be generated.
    Outside,
    /// Area that should be filled with map content but hasn't been yet.
    Unused,
    /// Area that the player cannot enter but that may be visible on screen.
    Border,
    Floor,
    Wall,
    Door,
}

impl Default for Prototerrain {
    fn default() -> Self { Prototerrain::Outside }
}

fn screen_map(origin: Location) -> Field<Prototerrain> {
    let mut ret = Field::new();

    // Cells two cells away from the live area at the bottom of the screen can still affect
    // the visible terrain via cell reshaping, so add those as well to the border.
    const BORDER_MASK: [(i32, i32); 9] = [
        (-1, -1),
        (0, -1),
        (1, 0),
        (1, 1),
        (0, 1),
        (-1, 0),
        (2, 1),
        (2, 2),
        (1, 2),
    ];

    for &v in ::onscreen_locations() {
        let loc = origin + v;
        // Paint border for every cell, all except the one from the cells at the actual border will
        // be overwritten.
        for d in &BORDER_MASK {
            let vec = vec2(d.0, d.1);
            if ret.get(loc + vec) == Default::default() {
                ret.set(loc + vec, Prototerrain::Border);
            }
        }

        ret.set(loc, Prototerrain::Unused);
    }

    ret
}

fn entry_cave_enclosure(map: &mut Field<Prototerrain>, entrance: Location) {
    use self::Prototerrain::*;

    debug_assert!(map.get(entrance) == Unused);

    const DOWNBOUND_ENCLOSURE: [(i32, i32); 7] = [
        (-2, -2),
        (-1, -2),
        (0, -1),
        (-1, 0),
        (-2, -1),
        (1, 0),
        (0, 1),
    ];

    for &v in &DOWNBOUND_ENCLOSURE {
        let loc = entrance + vec2(v.0, v.1);
        map.set(loc, Wall);
    }

    // Portal site
    map.set(entrance - vec2(1, 1), Floor);
    // Entrance cell
    map.set(entrance, Floor);
    // Enclosure mouth
    map.set(entrance + vec2(1, 1), Floor);
}
<commit_msg>Punch through to caves<commit_after>use Prefab;
use Rng;
use calx_grid::Dir6;
use euclid::vec2;
use field::Field;
use form::Form;
use location::{Location, Portal};
use mapfile;
use rand::{self, Rand, SeedableRng};
use serde;
use std::cmp;
use std::collections::BTreeSet;
use std::collections::HashMap;
use std::io::Cursor;
use std::slice;
use terrain::Terrain;
use world::Loadout;

/// Static generated world.
pub struct Worldgen {
    seed: u32,
    terrain: Field<Terrain>,
    portals: HashMap<Location, Portal>,
    spawns: Vec<(Location, Loadout)>,
    player_entry: Location,
}

impl Worldgen {
    pub fn new(seed: u32) -> Worldgen {
        let mut ret = Worldgen {
            seed: seed,
            terrain: Field::new(),
            portals: HashMap::new(),
            spawns: Vec::new(),
            player_entry: Location::new(0, 0, 0),
        };

        let mut rng: Rng = SeedableRng::from_seed([seed, seed, seed, seed]);
        ret.gen_overworld(&mut rng);
        ret.cave_entrance(Location::new(10, 0, 0), Location::new(0, 0, 1));
        ret.gen_caves(&mut rng, Location::new(0, 0, 1));

        ret
    }

    fn sprint_map(&mut self) {
        const SPRINT_PREFAB: &'static str = include_str!("../../sprint.ron");

        let sprint_prefab = mapfile::load_prefab(&mut Cursor::new(SPRINT_PREFAB))
            .expect("Corrupt sprint file");

        // Top-left of the default on-screen area.
        let origin = Location::new(-21, -22, 0);
        self.load_prefab(origin, &sprint_prefab);
    }

    fn load_prefab(&mut self, origin: Location, prefab: &Prefab) {
        for (p, &(ref terrain, ref entities)) in prefab.iter() {
            let loc = origin + p;

            self.terrain.set(loc, *terrain);

            for spawn in entities.iter() {
                if spawn == "player" {
                    self.player_entry = loc;
                } else {
                    let form = Form::named(spawn).expect(&format!(
                        "Bad prefab: Form '{}' not found!",
                        spawn
                    ));
                    self.spawns.push((loc, form.loadout.clone()));
                }
            }
        }
    }

    pub fn seed(&self) -> u32 { self.seed }

    pub fn get_terrain(&self, loc: Location) -> Terrain { self.terrain.get(loc) }

    pub fn get_portal(&self, loc: Location) -> Option<Location> {
        self.portals.get(&loc).map(|&p| loc + p)
    }

    pub fn spawns(&self) -> slice::Iter<(Location, Loadout)> { self.spawns.iter() }

    pub fn player_entry(&self) -> Location { self.player_entry }

    fn gen_overworld<R: rand::Rng>(&mut self, rng: &mut R) {
        use Terrain::*;

        let noise_offset = rng.gen_range(0, 100);

        for y in -40..40 {
            for x in -40..40 {
                let x = x as i8;
                let y = y as i8;
                let loc = Location::new(x, y, 0);
                let noise = Location::new(x, y, noise_offset).noise();

                self.terrain.set(
                    loc,
                    match noise {
                        n if n > 0.8 => Tree,
                        n if n > -0.8 => Grass,
                        _ => Water,
                    },
                );
            }
        }
    }

    fn gen_caves<R: rand::Rng>(&mut self, rng: &mut R, entrance: Location) {
        use self::Prototerrain::*;

        let mut cells_to_dig = 700;

        let mut map = screen_map(Location::new(0, 0, entrance.z));

        debug_assert!(map.get(entrance) == Unused);

        // Create portal enclosure
        entry_cave_enclosure(&mut map, entrance);

        let entrance = entrance + vec2(1, 1);

        let mut edge: BTreeSet<Location> = Dir6::iter()
            .map(|&d| entrance + vec2(2, 2) + d)
            .filter(|&loc| map.get(loc) == Unused)
            .collect();

        // Arbitrary long iteration, should break after digging a sufficient number of cells before
        // this.
        for _ in 0..10000 {
            if edge.is_empty() {
                break;
            }

            let dig_loc = *rand::sample(rng, edge.iter(), 1)[0];

            // Prefer digging narrow corridors, there's an increasing chance to abort the dig when the
            // selected location is in a very open space.
            let adjacent_floors = Dir6::iter()
                .filter(|d| map.get(dig_loc + **d) == Floor)
                .count();
            if rng.gen_range(0, cmp::max(1, adjacent_floors * adjacent_floors)) != 0 {
                continue;
            }

            map.set(dig_loc, Floor);
            edge.extend(Dir6::iter().map(|&d| dig_loc + d).filter(|&loc| {
                map.get(loc) == Unused
            }));

            cells_to_dig -= 1;
            if cells_to_dig == 0 {
                break;
            }
        }

        // Postprocess
        let cells: Vec<_> = map.iter().map(|(&loc, &c)| (loc, c)).collect();
        for (loc, c) in cells.into_iter() {
            // Clear pillars
            if c == Unused {
                let adjacent_floors = Dir6::iter().filter(|d| map.get(loc + **d) == Floor).count();

                if adjacent_floors == 6 {
                    map.set(loc, Floor);
                }
            }
        }

        // Map to actual terrains
        self.terrain.extend(map.iter().map(|(&loc, &t)| {
            let t = match t {
                Outside => Terrain::Empty,
                Unused => Terrain::Rock,
                Border => Terrain::Rock,
                Floor => Terrain::Ground,
                Wall => Terrain::Rock,
                Door => Terrain::Door,
            };
            (loc, t)
        }));

        // XXX: This thing needs to be more automatic
        // Make the backportal cell have transparent terrain
        self.terrain.set(entrance - vec2(1, 1), Terrain::Empty);
    }

    /// Make a cave entrance going down.
    fn cave_entrance(&mut self, loc: Location, cave_start: Location) {
        const DOWNBOUND_ENCLOSURE: [(i32, i32); 5] = [(1, 0), (0, 1), (2, 1), (1, 2), (2, 2)];

        for &v in &DOWNBOUND_ENCLOSURE {
            let loc = loc + vec2(v.0, v.1);
            self.terrain.set(loc, Terrain::Rock);
        }

        self.terrain.set(loc, Terrain::Ground);
        self.terrain.set(loc + vec2(1, 1), Terrain::Ground);

        // Connect the points
        self.portal(loc + vec2(1, 1), cave_start);
        self.portal(cave_start - vec2(1, 1), loc);
    }

    /// Punch a (one-way) portal between two points.
    fn portal(&mut self, origin: Location, destination: Location) {
        self.portals.insert(
            origin,
            Portal::new(origin, destination),
        );
        self.terrain.set(origin, Terrain::Empty);
    }
}

impl serde::Serialize for Worldgen {
    fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
        self.seed.serialize(s)
    }
}

impl<'a> serde::Deserialize<'a> for Worldgen {
    fn deserialize<D: serde::Deserializer<'a>>(d: D) -> Result<Self, D::Error> {
        Ok(Worldgen::new(serde::Deserialize::deserialize(d)?))
    }
}

#[derive(Copy, Clone, Eq, PartialEq, Debug)]
enum Prototerrain {
    /// Area completely outside the map to be generated.
    Outside,
    /// Area that should be filled with map content but hasn't been yet.
    Unused,
    /// Area that the player cannot enter but that may be visible on screen.
    Border,
    Floor,
    Wall,
    Door,
}

impl Default for Prototerrain {
    fn default() -> Self { Prototerrain::Outside }
}

fn screen_map(origin: Location) -> Field<Prototerrain> {
    let mut ret = Field::new();

    // Cells two cells away from the live area at the bottom of the screen can still affect
    // the visible terrain via cell reshaping, so add those as well to the border.
    const BORDER_MASK: [(i32, i32); 9] = [
        (-1, -1),
        (0, -1),
        (1, 0),
        (1, 1),
        (0, 1),
        (-1, 0),
        (2, 1),
        (2, 2),
        (1, 2),
    ];

    for &v in ::onscreen_locations() {
        let loc = origin + v;
        // Paint border for every cell, all except the one from the cells at the actual border will
        // be overwritten.
        for d in &BORDER_MASK {
            let vec = vec2(d.0, d.1);
            if ret.get(loc + vec) == Default::default() {
                ret.set(loc + vec, Prototerrain::Border);
            }
        }

        ret.set(loc, Prototerrain::Unused);
    }

    ret
}

fn entry_cave_enclosure(map: &mut Field<Prototerrain>, entrance: Location) {
    use self::Prototerrain::*;

    debug_assert!(map.get(entrance) == Unused);

    const UPBOUND_ENCLOSURE: [(i32, i32); 7] = [
        (-2, -2),
        (-1, -2),
        (0, -1),
        (-1, 0),
        (-2, -1),
        (1, 0),
        (0, 1),
    ];

    for &v in &UPBOUND_ENCLOSURE {
        let loc = entrance + vec2(v.0, v.1);
        map.set(loc, Wall);
    }

    // Portal site
    map.set(entrance - vec2(1, 1), Floor);
    // Entrance cell
    map.set(entrance, Floor);
    // Enclosure mouth
    map.set(entrance + vec2(1, 1), Floor);
}
<|endoftext|>


<commit_before>use {IsZero, Dot, Lerp, Point};
use std::ops::{Mul, MulAssign, Div, DivAssign, Neg, Add, AddAssign, Sub, SubAssign, Index, IndexMut};

// VECTOR 3
// ================================================================================================

#[derive(Debug, Clone, Copy, PartialEq)]
#[repr(C)]
pub struct Vector3 {
    pub x: f32,
    pub y: f32,
    pub z: f32
}

impl Vector3 {
    pub fn new(x: f32, y: f32, z: f32) -> Vector3 {
        Vector3 {
            x: x,
            y: y,
            z: z
        }
    }

    pub fn zero() -> Vector3 {
        Vector3::new(0.0, 0.0, 0.0)
    }

    pub fn one() -> Vector3 {
        Vector3::new(1.0, 1.0, 1.0)
    }

    pub fn up() -> Vector3 {
        Vector3::new(0.0, 1.0, 0.0)
    }

    pub fn down() -> Vector3 {
        Vector3::new(0.0, -1.0, 0.0)
    }

    pub fn forward() -> Vector3 {
        Vector3::new(0.0, 0.0, -1.0)
    }

    pub fn cross(first: Vector3, second: Vector3) -> Vector3 {
        Vector3 {
            x: first.y * second.z - first.z * second.y,
            y: first.z * second.x - first.x * second.z,
            z: first.x * second.y - first.y * second.x,
        }
    }

    /// Normalizes the vector, returning the old length.
    ///
    /// If the vector is the zero vector it is not altered.
    pub fn normalize(&mut self) -> f32 {
        if self.is_zero() {
            0.0
        } else {
            let magnitude = self.magnitude();
            let one_over_magnitude = 1.0 / magnitude;
            self.x *= one_over_magnitude;
            self.y *= one_over_magnitude;
            self.z *= one_over_magnitude;

            magnitude
        }
    }

    /// Returns the normalized version of the vector.
    ///
    /// If the vector is the zero vector a copy is returned.
    pub fn normalized(&self) -> Vector3 {
        if self.is_zero() {
            *self
        } else {
            let mut copy = *self;
            copy.normalize();
            copy
        }
    }

    pub fn is_normalized(&self) -> bool {
        (self.dot(self) - 1.0).is_zero()
    }

    pub fn magnitude(&self) -> f32 {
        self.magnitude_squared().sqrt()
    }

    pub fn magnitude_squared(&self) -> f32 {
        self.x * self.x + self.y * self.y + self.z * self.z
    }

    // Safely reinterprets a slice of Vector3s to a slice of f32s. This is a cheap operation and
    // does not copy any data.
    pub fn as_ref(vectors: &[Vector3]) -> &[f32] {
        unsafe {
            ::std::slice::from_raw_parts(
                vectors.as_ptr() as *const f32,
                vectors.len() * 3)
        }
    }

    // pub fn cross(&self, rhs: Vector3) -> Vector3 {
    //     Vector3::new(
    //         self.y * rhs.z - self.z * rhs.y,
    //         self.z * rhs.x - self.x * rhs.z,
    //         self.x * rhs.y - self.y * rhs.x)
    // }
}

impl Default for Vector3 {
    fn default() -> Vector3 {
        Vector3 {
            x: 0.0,
            y: 0.0,
            z: 0.0,
        }
    }
}

impl Dot for Vector3 {
    type Output = f32;

    fn dot(self, rhs: Vector3) -> f32 {
        self.x * rhs.x + self.y * rhs.y + self.z * rhs.z
    }
}

impl Dot<[f32; 3]> for Vector3 {
    type Output = f32;

    fn dot(self, rhs: [f32; 3]) -> f32 {
        self.x * rhs[0] + self.y * rhs[1] + self.z * rhs[2]
    }
}

impl Dot<Vector3> for [f32; 3] {
    type Output = f32;

    fn dot(self, rhs: Vector3) -> f32 {
        rhs.dot(self)
    }
}

// impl<'a> Dot<&'a [f32; 3]> for Vector3 {
//     type Output = f32;
//
//     fn dot(self, rhs: &[f32; 3]) -> f32 {
//         self.dot(*rhs)
//     }
// }

impl AddAssign for Vector3 {
    fn add_assign(&mut self, rhs: Vector3) {
        self.x += rhs.x;
        self.y += rhs.y;
        self.z += rhs.z;
    }
}

impl Add for Vector3 {
    type Output = Vector3;

    fn add(mut self, rhs: Vector3) -> Vector3 {
        self += rhs;
        self
    }
}

impl SubAssign for Vector3 {
    fn sub_assign(&mut self, rhs: Vector3) {
        self.x -= rhs.x;
        self.y -= rhs.y;
        self.z -= rhs.z;
    }
}

impl Sub for Vector3 {
    type Output = Vector3;

    fn sub(mut self, rhs: Vector3) -> Vector3 {
        self -= rhs;
        self
    }
}

impl MulAssign for Vector3 {
    fn mul_assign(&mut self, rhs: Vector3) {
        self.x *= rhs.x;
        self.y *= rhs.y;
        self.z *= rhs.z;
    }
}

impl Mul for Vector3 {
    type Output = Vector3;

    fn mul(mut self, rhs: Vector3) -> Vector3 {
        self *= rhs;
        self
    }
}

impl MulAssign<f32> for Vector3 {
    fn mul_assign(&mut self, rhs: f32) {
        self.x *= rhs;
        self.y *= rhs;
        self.z *= rhs;
    }
}

impl Mul<f32> for Vector3 {
    type Output = Vector3;

    fn mul(mut self, rhs: f32) -> Vector3 {
        self *= rhs;
        self
    }
}

impl Mul<Vector3> for f32 {
    type Output = Vector3;

    fn mul(self, rhs: Vector3) -> Vector3 {
        rhs * self
    }
}

impl Neg for Vector3 {
    type Output = Vector3;

    fn neg(self) -> Vector3 {
        Vector3::new(-self.x, -self.y, -self.z)
    }
}

impl DivAssign<f32> for Vector3 {
    fn div_assign(&mut self, rhs: f32) {
        self.x /= rhs;
        self.y /= rhs;
        self.z /= rhs;
    }
}

impl Div<f32> for Vector3 {
    type Output = Vector3;

    fn div(mut self, rhs: f32) -> Vector3 {
        self /= rhs;
        self
    }
}

impl Div<Vector3> for f32 {
    type Output = Vector3;

    fn div(self, rhs: Vector3) -> Vector3 {
        rhs / self
    }
}

impl IsZero for Vector3 {
    fn is_zero(self) -> bool {
        self.dot(self).is_zero()
    }
}

// TODO: Is `usize` an appropriate index? Especially considering the valid values are 0..3?
impl Index<usize> for Vector3 {
    type Output = f32;

    fn index(&self, index: usize) -> &f32 {
        match index {
            0 => &self.x,
            1 => &self.y,
            2 => &self.z,
            // TODO: Use `unreachable()` intrinsic in release mode.
            _ => panic!("Index {} is out of bounds for Vector3", index),
        }
    }
}

impl IndexMut<usize> for Vector3 {
    fn index_mut(&mut self, index: usize) -> &mut f32 {
        match index {
            0 => &mut self.x,
            1 => &mut self.y,
            2 => &mut self.z,
            // TODO: Use `unreachable()` intrinsic in release mode.
            _ => panic!("Index {} is out of bounds for Vector3", index),
        }
    }
}

impl<'a> From<&'a [f32]> for Vector3 {
    fn from(from: &[f32]) -> Vector3 {
        assert!(from.len() == 3);

        Vector3 {
            x: from[0],
            y: from[1],
            z: from[2],
        }
    }
}

impl <'a> From<[f32; 3]> for Vector3 {
    fn from(from: [f32; 3]) -> Vector3 {
        Vector3 {
            x: from[0],
            y: from[1],
            z: from[2],
        }
    }
}

impl From<Point> for Vector3 {
    /// Creates a new `Vector3` from a `Point`.
    ///
    /// This behaves as if the point had been subtracted from the origin, yielding a `Vector3` with
    /// the same x, y, and z coordinates as the original point. The conversion can be expressed as
    /// `(x, y, z, 1.0) => <x, y, z>`.
    fn from(from: Point) -> Vector3 {
        Vector3 {
            x: from.x,
            y: from.y,
            z: from.z,
        }
    }
}

impl From<(f32, f32, f32)> for Vector3 {
    fn from(from: (f32, f32, f32)) -> Vector3 {
        Vector3 {
            x: from.0,
            y: from.1,
            z: from.2,
        }
    }
}

impl Into<[f32; 3]> for Vector3 {
    fn into(self) -> [f32; 3] {
        [self.x, self.y, self.z]
    }
}

impl Into<(f32, f32, f32)> for Vector3 {
    fn into(self) -> (f32, f32, f32) {
        (self.x, self.y, self.z)
    }
}

// VECTOR 2
// ================================================================================================

#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
pub struct Vector2 {
    pub x: f32,
    pub y: f32,
}

impl Vector2 {
    pub fn new(x: f32, y: f32) -> Vector2 {
        Vector2 {
            x: x,
            y: y,
        }
    }

    pub fn as_ref(vectors: &[Vector2]) -> &[f32] {
        use std::slice;

        unsafe {
            slice::from_raw_parts(
                vectors.as_ptr() as *const f32,
                vectors.len() * 2)
        }
    }

    pub fn slice_from_f32_slice(data: &[f32]) -> &[Vector2] {
        use std::slice;

        assert!(data.len() % 2 == 0, "Slice must have an even number of elements to be converted to a slice of Vector2");
        unsafe {
            slice::from_raw_parts(
                data.as_ptr() as *const Vector2,
                data.len() / 2,
            )
        }
    }
}

impl Default for Vector2 {
    fn default() -> Vector2 {
        Vector2 {
            x: 0.0,
            y: 0.0,
        }
    }
}

impl Lerp for Vector2 {
    fn lerp(t: f32, from: Vector2, to: Vector2) -> Vector2 {
        from + (to - from) * t
    }
}

impl Add for Vector2 {
    type Output = Vector2;

    fn add(self, rhs: Vector2) -> Vector2 {
        Vector2 {
            x: self.x + rhs.x,
            y: self.y + rhs.y,
        }
    }
}

impl Sub for Vector2 {
    type Output = Vector2;

    fn sub(self, rhs: Vector2) -> Vector2 {
        Vector2 {
            x: self.x - rhs.x,
            y: self.y - rhs.y,
        }
    }
}

impl Mul for Vector2 {
    type Output = Vector2;

    fn mul(self, rhs: Vector2) -> Vector2 {
        Vector2 {
            x: self.x * rhs.x,
            y: self.y * rhs.y,
        }
    }
}

impl Mul<f32> for Vector2 {
    type Output = Vector2;

    fn mul(self, rhs: f32) -> Vector2 {
        Vector2 {
            x: self.x * rhs,
            y: self.y * rhs,
        }
    }
}

impl Mul<Vector2> for f32 {
    type Output = Vector2;

    fn mul(self, rhs: Vector2) -> Vector2 {
        rhs * self
    }
}
<commit_msg>Add Vector3 utility methods<commit_after>use {IsZero, Dot, Lerp, Point};
use std::ops::{Mul, MulAssign, Div, DivAssign, Neg, Add, AddAssign, Sub, SubAssign, Index, IndexMut};

// VECTOR 3
// ================================================================================================

#[derive(Debug, Clone, Copy, PartialEq)]
#[repr(C)]
pub struct Vector3 {
    pub x: f32,
    pub y: f32,
    pub z: f32
}

impl Vector3 {
    pub fn new(x: f32, y: f32, z: f32) -> Vector3 {
        Vector3 {
            x: x,
            y: y,
            z: z
        }
    }

    pub fn zero() -> Vector3 {
        Vector3::new(0.0, 0.0, 0.0)
    }

    pub fn one() -> Vector3 {
        Vector3::new(1.0, 1.0, 1.0)
    }

    pub fn up() -> Vector3 {
        Vector3::new(0.0, 1.0, 0.0)
    }

    pub fn down() -> Vector3 {
        Vector3::new(0.0, -1.0, 0.0)
    }

    pub fn forward() -> Vector3 {
        Vector3::new(0.0, 0.0, -1.0)
    }

    pub fn cross(first: Vector3, second: Vector3) -> Vector3 {
        Vector3 {
            x: first.y * second.z - first.z * second.y,
            y: first.z * second.x - first.x * second.z,
            z: first.x * second.y - first.y * second.x,
        }
    }

    pub fn set_x(mut self, x: f32) -> Vector3 {
        self.x = x;
        self
    }

    pub fn set_y(mut self, y: f32) -> Vector3 {
        self.y = y;
        self
    }

    pub fn set_z(mut self, z: f32) -> Vector3 {
        self.z = z;
        self
    }

    /// Normalizes the vector, returning the old length.
    ///
    /// If the vector is the zero vector it is not altered.
    pub fn normalize(&mut self) -> f32 {
        if self.is_zero() {
            0.0
        } else {
            let magnitude = self.magnitude();
            let one_over_magnitude = 1.0 / magnitude;
            self.x *= one_over_magnitude;
            self.y *= one_over_magnitude;
            self.z *= one_over_magnitude;

            magnitude
        }
    }

    /// Returns the normalized version of the vector.
    ///
    /// If the vector is the zero vector a copy is returned.
    pub fn normalized(&self) -> Vector3 {
        if self.is_zero() {
            *self
        } else {
            let mut copy = *self;
            copy.normalize();
            copy
        }
    }

    pub fn is_normalized(&self) -> bool {
        (self.dot(self) - 1.0).is_zero()
    }

    pub fn magnitude(&self) -> f32 {
        self.magnitude_squared().sqrt()
    }

    pub fn magnitude_squared(&self) -> f32 {
        self.x * self.x + self.y * self.y + self.z * self.z
    }

    // Safely reinterprets a slice of Vector3s to a slice of f32s. This is a cheap operation and
    // does not copy any data.
    pub fn as_ref(vectors: &[Vector3]) -> &[f32] {
        unsafe {
            ::std::slice::from_raw_parts(
                vectors.as_ptr() as *const f32,
                vectors.len() * 3)
        }
    }

    // pub fn cross(&self, rhs: Vector3) -> Vector3 {
    //     Vector3::new(
    //         self.y * rhs.z - self.z * rhs.y,
    //         self.z * rhs.x - self.x * rhs.z,
    //         self.x * rhs.y - self.y * rhs.x)
    // }
}

impl Default for Vector3 {
    fn default() -> Vector3 {
        Vector3 {
            x: 0.0,
            y: 0.0,
            z: 0.0,
        }
    }
}

impl Dot for Vector3 {
    type Output = f32;

    fn dot(self, rhs: Vector3) -> f32 {
        self.x * rhs.x + self.y * rhs.y + self.z * rhs.z
    }
}

impl Dot<[f32; 3]> for Vector3 {
    type Output = f32;

    fn dot(self, rhs: [f32; 3]) -> f32 {
        self.x * rhs[0] + self.y * rhs[1] + self.z * rhs[2]
    }
}

impl Dot<Vector3> for [f32; 3] {
    type Output = f32;

    fn dot(self, rhs: Vector3) -> f32 {
        rhs.dot(self)
    }
}

// impl<'a> Dot<&'a [f32; 3]> for Vector3 {
//     type Output = f32;
//
//     fn dot(self, rhs: &[f32; 3]) -> f32 {
//         self.dot(*rhs)
//     }
// }

impl AddAssign for Vector3 {
    fn add_assign(&mut self, rhs: Vector3) {
        self.x += rhs.x;
        self.y += rhs.y;
        self.z += rhs.z;
    }
}

impl Add for Vector3 {
    type Output = Vector3;

    fn add(mut self, rhs: Vector3) -> Vector3 {
        self += rhs;
        self
    }
}

impl SubAssign for Vector3 {
    fn sub_assign(&mut self, rhs: Vector3) {
        self.x -= rhs.x;
        self.y -= rhs.y;
        self.z -= rhs.z;
    }
}

impl Sub for Vector3 {
    type Output = Vector3;

    fn sub(mut self, rhs: Vector3) -> Vector3 {
        self -= rhs;
        self
    }
}

impl MulAssign for Vector3 {
    fn mul_assign(&mut self, rhs: Vector3) {
        self.x *= rhs.x;
        self.y *= rhs.y;
        self.z *= rhs.z;
    }
}

impl Mul for Vector3 {
    type Output = Vector3;

    fn mul(mut self, rhs: Vector3) -> Vector3 {
        self *= rhs;
        self
    }
}

impl MulAssign<f32> for Vector3 {
    fn mul_assign(&mut self, rhs: f32) {
        self.x *= rhs;
        self.y *= rhs;
        self.z *= rhs;
    }
}

impl Mul<f32> for Vector3 {
    type Output = Vector3;

    fn mul(mut self, rhs: f32) -> Vector3 {
        self *= rhs;
        self
    }
}

impl Mul<Vector3> for f32 {
    type Output = Vector3;

    fn mul(self, rhs: Vector3) -> Vector3 {
        rhs * self
    }
}

impl Neg for Vector3 {
    type Output = Vector3;

    fn neg(self) -> Vector3 {
        Vector3::new(-self.x, -self.y, -self.z)
    }
}

impl DivAssign<f32> for Vector3 {
    fn div_assign(&mut self, rhs: f32) {
        self.x /= rhs;
        self.y /= rhs;
        self.z /= rhs;
    }
}

impl Div<f32> for Vector3 {
    type Output = Vector3;

    fn div(mut self, rhs: f32) -> Vector3 {
        self /= rhs;
        self
    }
}

impl Div<Vector3> for f32 {
    type Output = Vector3;

    fn div(self, rhs: Vector3) -> Vector3 {
        rhs / self
    }
}

impl IsZero for Vector3 {
    fn is_zero(self) -> bool {
        self.dot(self).is_zero()
    }
}

// TODO: Is `usize` an appropriate index? Especially considering the valid values are 0..3?
impl Index<usize> for Vector3 {
    type Output = f32;

    fn index(&self, index: usize) -> &f32 {
        match index {
            0 => &self.x,
            1 => &self.y,
            2 => &self.z,
            // TODO: Use `unreachable()` intrinsic in release mode.
            _ => panic!("Index {} is out of bounds for Vector3", index),
        }
    }
}

impl IndexMut<usize> for Vector3 {
    fn index_mut(&mut self, index: usize) -> &mut f32 {
        match index {
            0 => &mut self.x,
            1 => &mut self.y,
            2 => &mut self.z,
            // TODO: Use `unreachable()` intrinsic in release mode.
            _ => panic!("Index {} is out of bounds for Vector3", index),
        }
    }
}

impl<'a> From<&'a [f32]> for Vector3 {
    fn from(from: &[f32]) -> Vector3 {
        assert!(from.len() == 3);

        Vector3 {
            x: from[0],
            y: from[1],
            z: from[2],
        }
    }
}

impl <'a> From<[f32; 3]> for Vector3 {
    fn from(from: [f32; 3]) -> Vector3 {
        Vector3 {
            x: from[0],
            y: from[1],
            z: from[2],
        }
    }
}

impl From<Point> for Vector3 {
    /// Creates a new `Vector3` from a `Point`.
    ///
    /// This behaves as if the point had been subtracted from the origin, yielding a `Vector3` with
    /// the same x, y, and z coordinates as the original point. The conversion can be expressed as
    /// `(x, y, z, 1.0) => <x, y, z>`.
    fn from(from: Point) -> Vector3 {
        Vector3 {
            x: from.x,
            y: from.y,
            z: from.z,
        }
    }
}

impl From<(f32, f32, f32)> for Vector3 {
    fn from(from: (f32, f32, f32)) -> Vector3 {
        Vector3 {
            x: from.0,
            y: from.1,
            z: from.2,
        }
    }
}

impl Into<[f32; 3]> for Vector3 {
    fn into(self) -> [f32; 3] {
        [self.x, self.y, self.z]
    }
}

impl Into<(f32, f32, f32)> for Vector3 {
    fn into(self) -> (f32, f32, f32) {
        (self.x, self.y, self.z)
    }
}

// VECTOR 2
// ================================================================================================

#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
pub struct Vector2 {
    pub x: f32,
    pub y: f32,
}

impl Vector2 {
    pub fn new(x: f32, y: f32) -> Vector2 {
        Vector2 {
            x: x,
            y: y,
        }
    }

    pub fn as_ref(vectors: &[Vector2]) -> &[f32] {
        use std::slice;

        unsafe {
            slice::from_raw_parts(
                vectors.as_ptr() as *const f32,
                vectors.len() * 2)
        }
    }

    pub fn slice_from_f32_slice(data: &[f32]) -> &[Vector2] {
        use std::slice;

        assert!(data.len() % 2 == 0, "Slice must have an even number of elements to be converted to a slice of Vector2");
        unsafe {
            slice::from_raw_parts(
                data.as_ptr() as *const Vector2,
                data.len() / 2,
            )
        }
    }
}

impl Default for Vector2 {
    fn default() -> Vector2 {
        Vector2 {
            x: 0.0,
            y: 0.0,
        }
    }
}

impl Lerp for Vector2 {
    fn lerp(t: f32, from: Vector2, to: Vector2) -> Vector2 {
        from + (to - from) * t
    }
}

impl Add for Vector2 {
    type Output = Vector2;

    fn add(self, rhs: Vector2) -> Vector2 {
        Vector2 {
            x: self.x + rhs.x,
            y: self.y + rhs.y,
        }
    }
}

impl Sub for Vector2 {
    type Output = Vector2;

    fn sub(self, rhs: Vector2) -> Vector2 {
        Vector2 {
            x: self.x - rhs.x,
            y: self.y - rhs.y,
        }
    }
}

impl Mul for Vector2 {
    type Output = Vector2;

    fn mul(self, rhs: Vector2) -> Vector2 {
        Vector2 {
            x: self.x * rhs.x,
            y: self.y * rhs.y,
        }
    }
}

impl Mul<f32> for Vector2 {
    type Output = Vector2;

    fn mul(self, rhs: f32) -> Vector2 {
        Vector2 {
            x: self.x * rhs,
            y: self.y * rhs,
        }
    }
}

impl Mul<Vector2> for f32 {
    type Output = Vector2;

    fn mul(self, rhs: Vector2) -> Vector2 {
        rhs * self
    }
}
<|endoftext|>


<commit_before>use std::path::PathBuf;
use std::result::Result as RResult;
use std::ops::Deref;

use toml::{Parser, Value};

/**
 * Errors which are related to configuration-file loading
 */
pub mod error {
    use std::error::Error;
    use std::fmt::{Display, Formatter};
    use std::fmt::Error as FmtError;

    /**
     * The kind of an error
     */
    #[derive(Clone, Debug, PartialEq)]
    pub enum ConfigErrorKind {
        NoConfigFileFound,
    }

    /**
     * Configuration error type
     */
    #[derive(Debug)]
    pub struct ConfigError {
        kind: ConfigErrorKind,
        cause: Option<Box<Error>>,
    }

    impl ConfigError {

        /**
         * Instantiate a new ConfigError, optionally with cause
         */
        pub fn new(kind: ConfigErrorKind, cause: Option<Box<Error>>) -> ConfigError {
            ConfigError {
                kind: kind,
                cause: cause,
            }
        }

        /**
         * get the Kind of the Error
         */
        pub fn err_type(&self) -> ConfigErrorKind {
            self.kind.clone()
        }

        /**
         * Get the string, the ConfigError can be described with
         */
        pub fn as_str(e: &ConfigError) -> &'static str {
            match e.err_type() {
                ConfigErrorKind::NoConfigFileFound   => "No config file found",
            }
        }

    }

    impl Display for ConfigError {

        fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
            try!(write!(fmt, "{}", ConfigError::as_str(self)));
            Ok(())
        }

    }

    impl Error for ConfigError {

        fn description(&self) -> &str {
            ConfigError::as_str(self)
        }

        fn cause(&self) -> Option<&Error> {
            self.cause.as_ref().map(|e| &**e)
        }

    }

}

use self::error::{ConfigError, ConfigErrorKind};

/**
 * Result type of this module. Either T or ConfigError
 */
pub type Result<T> = RResult<T, ConfigError>;

/**
 * Configuration object
 *
 * Holds all config variables which are globally available plus the configuration object from the
 * config parser, which can be accessed.
 */
#[derive(Debug)]
pub struct Configuration {

    /**
     * The plain configuration object for direct access if necessary
     */
    config: Value,

    /**
     * The verbosity the program should run with
     */
    verbosity: bool,

    /**
     * The editor which should be used
     */
    editor: Option<String>,

    /**
     * The options the editor should get when opening some file
     */
    editor_opts: String,
}

impl Configuration {

    /**
     * Get a new configuration object.
     *
     * The passed runtimepath is used for searching the configuration file, whereas several file
     * names are tested. If that does not work, the home directory and the XDG basedir are tested
     * with all variants.
     *
     * If that doesn't work either, an error is returned.
     */
    pub fn new(rtp: &PathBuf) -> Result<Configuration> {
        fetch_config(&rtp).map(|cfg| {
            let verbosity   = get_verbosity(&cfg);
            let editor      = get_editor(&cfg);
            let editor_opts = get_editor_opts(&cfg);

            debug!("Building configuration");
            debug!("  - verbosity  : {:?}", verbosity);
            debug!("  - editor     : {:?}", editor);
            debug!("  - editor-opts: {}", editor_opts);

            Configuration {
                config: cfg,
                verbosity: verbosity,
                editor: editor,
                editor_opts: editor_opts,
            }
        })
    }

    pub fn editor(&self) -> Option<&String> {
        self.editor.as_ref()
    }

    #[allow(dead_code)] // Why do I actually need this annotation on a pub function?
    pub fn config(&self) -> &Value {
        &self.config
    }

    pub fn store_config(&self) -> Option<&Value> {
        match &self.config {
            &Value::Table(ref tabl) => tabl.get("store"),
            _ => None,
        }
    }

}

impl Deref for Configuration {
    type Target = Value;

    fn deref(&self) -> &Value {
        &self.config
    }

}

fn get_verbosity(v: &Value) -> bool {
    match v {
        &Value::Table(ref t) => t.get("verbose")
                .map(|v| match v { &Value::Boolean(b) => b, _ => false, })
                .unwrap_or(false),
        _ => false,
    }
}

fn get_editor(v: &Value) -> Option<String> {
    match v {
        &Value::Table(ref t) => t.get("editor")
                .and_then(|v| match v { &Value::String(ref s) => Some(s.clone()), _ => None, }),
        _ => None,
    }
}

fn get_editor_opts(v: &Value) -> String {
    match v {
        &Value::Table(ref t) => t.get("editor-opts")
                .and_then(|v| match v { &Value::String(ref s) => Some(s.clone()), _ => None, })
                .unwrap_or(String::new()),
        _ => String::new(),
    }
}

/**
 * Helper to fetch the config file
 *
 * Tests several variants for the config file path and uses the first one which works.
 */
fn fetch_config(rtp: &PathBuf) -> Result<Value> {
    use std::env;
    use std::fs::File;
    use std::io::Read;
    use std::io::Write;
    use std::io::stderr;

    use xdg_basedir;
    use itertools::Itertools;

    use libimagutil::variants::generate_variants as gen_vars;

    let variants = vec!["config", "config.toml", "imagrc", "imagrc.toml"];
    let modifier = |base: &PathBuf, v: &'static str| {
        let mut base = base.clone();
        base.push(format!("{}", v));
        base
    };

    vec![
        gen_vars(rtp.clone(), variants.clone(), &modifier),

        env::var("HOME").map(|home| gen_vars(PathBuf::from(home), variants.clone(), &modifier))
                        .unwrap_or(vec![]),

        xdg_basedir::get_data_home().map(|data_dir| gen_vars(data_dir, variants.clone(), &modifier))
                                    .unwrap_or(vec![]),
    ].iter()
        .flatten()
        .filter(|path| path.exists() && path.is_file())
        .map(|path| {
            let content = {
                let mut s = String::new();
                let f = File::open(path);
                if f.is_err() {
                }
                let mut f = f.unwrap();
                f.read_to_string(&mut s).ok();
                s
            };
            let mut parser = Parser::new(&content[..]);
            let res = parser.parse();
            if res.is_none() {
                write!(stderr(), "Config file parser error:").ok();
                for error in parser.errors {
                    write!(stderr(), "At [{}][{}] <> {}", error.lo, error.hi, error).ok();
                    write!(stderr(), "in: '{}'", &content[error.lo..error.hi]).ok();
                }
                None
            } else {
                res
            }
        })
        .filter(|loaded| loaded.is_some())
        .nth(0)
        .map(|inner| Value::Table(inner.unwrap()))
        .ok_or(ConfigError::new(ConfigErrorKind::NoConfigFileFound, None))
}

<commit_msg>Add missing "return None" in file opening error case<commit_after>use std::path::PathBuf;
use std::result::Result as RResult;
use std::ops::Deref;

use toml::{Parser, Value};

/**
 * Errors which are related to configuration-file loading
 */
pub mod error {
    use std::error::Error;
    use std::fmt::{Display, Formatter};
    use std::fmt::Error as FmtError;

    /**
     * The kind of an error
     */
    #[derive(Clone, Debug, PartialEq)]
    pub enum ConfigErrorKind {
        NoConfigFileFound,
    }

    /**
     * Configuration error type
     */
    #[derive(Debug)]
    pub struct ConfigError {
        kind: ConfigErrorKind,
        cause: Option<Box<Error>>,
    }

    impl ConfigError {

        /**
         * Instantiate a new ConfigError, optionally with cause
         */
        pub fn new(kind: ConfigErrorKind, cause: Option<Box<Error>>) -> ConfigError {
            ConfigError {
                kind: kind,
                cause: cause,
            }
        }

        /**
         * get the Kind of the Error
         */
        pub fn err_type(&self) -> ConfigErrorKind {
            self.kind.clone()
        }

        /**
         * Get the string, the ConfigError can be described with
         */
        pub fn as_str(e: &ConfigError) -> &'static str {
            match e.err_type() {
                ConfigErrorKind::NoConfigFileFound   => "No config file found",
            }
        }

    }

    impl Display for ConfigError {

        fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
            try!(write!(fmt, "{}", ConfigError::as_str(self)));
            Ok(())
        }

    }

    impl Error for ConfigError {

        fn description(&self) -> &str {
            ConfigError::as_str(self)
        }

        fn cause(&self) -> Option<&Error> {
            self.cause.as_ref().map(|e| &**e)
        }

    }

}

use self::error::{ConfigError, ConfigErrorKind};

/**
 * Result type of this module. Either T or ConfigError
 */
pub type Result<T> = RResult<T, ConfigError>;

/**
 * Configuration object
 *
 * Holds all config variables which are globally available plus the configuration object from the
 * config parser, which can be accessed.
 */
#[derive(Debug)]
pub struct Configuration {

    /**
     * The plain configuration object for direct access if necessary
     */
    config: Value,

    /**
     * The verbosity the program should run with
     */
    verbosity: bool,

    /**
     * The editor which should be used
     */
    editor: Option<String>,

    /**
     * The options the editor should get when opening some file
     */
    editor_opts: String,
}

impl Configuration {

    /**
     * Get a new configuration object.
     *
     * The passed runtimepath is used for searching the configuration file, whereas several file
     * names are tested. If that does not work, the home directory and the XDG basedir are tested
     * with all variants.
     *
     * If that doesn't work either, an error is returned.
     */
    pub fn new(rtp: &PathBuf) -> Result<Configuration> {
        fetch_config(&rtp).map(|cfg| {
            let verbosity   = get_verbosity(&cfg);
            let editor      = get_editor(&cfg);
            let editor_opts = get_editor_opts(&cfg);

            debug!("Building configuration");
            debug!("  - verbosity  : {:?}", verbosity);
            debug!("  - editor     : {:?}", editor);
            debug!("  - editor-opts: {}", editor_opts);

            Configuration {
                config: cfg,
                verbosity: verbosity,
                editor: editor,
                editor_opts: editor_opts,
            }
        })
    }

    pub fn editor(&self) -> Option<&String> {
        self.editor.as_ref()
    }

    #[allow(dead_code)] // Why do I actually need this annotation on a pub function?
    pub fn config(&self) -> &Value {
        &self.config
    }

    pub fn store_config(&self) -> Option<&Value> {
        match &self.config {
            &Value::Table(ref tabl) => tabl.get("store"),
            _ => None,
        }
    }

}

impl Deref for Configuration {
    type Target = Value;

    fn deref(&self) -> &Value {
        &self.config
    }

}

fn get_verbosity(v: &Value) -> bool {
    match v {
        &Value::Table(ref t) => t.get("verbose")
                .map(|v| match v { &Value::Boolean(b) => b, _ => false, })
                .unwrap_or(false),
        _ => false,
    }
}

fn get_editor(v: &Value) -> Option<String> {
    match v {
        &Value::Table(ref t) => t.get("editor")
                .and_then(|v| match v { &Value::String(ref s) => Some(s.clone()), _ => None, }),
        _ => None,
    }
}

fn get_editor_opts(v: &Value) -> String {
    match v {
        &Value::Table(ref t) => t.get("editor-opts")
                .and_then(|v| match v { &Value::String(ref s) => Some(s.clone()), _ => None, })
                .unwrap_or(String::new()),
        _ => String::new(),
    }
}

/**
 * Helper to fetch the config file
 *
 * Tests several variants for the config file path and uses the first one which works.
 */
fn fetch_config(rtp: &PathBuf) -> Result<Value> {
    use std::env;
    use std::fs::File;
    use std::io::Read;
    use std::io::Write;
    use std::io::stderr;

    use xdg_basedir;
    use itertools::Itertools;

    use libimagutil::variants::generate_variants as gen_vars;

    let variants = vec!["config", "config.toml", "imagrc", "imagrc.toml"];
    let modifier = |base: &PathBuf, v: &'static str| {
        let mut base = base.clone();
        base.push(format!("{}", v));
        base
    };

    vec![
        gen_vars(rtp.clone(), variants.clone(), &modifier),

        env::var("HOME").map(|home| gen_vars(PathBuf::from(home), variants.clone(), &modifier))
                        .unwrap_or(vec![]),

        xdg_basedir::get_data_home().map(|data_dir| gen_vars(data_dir, variants.clone(), &modifier))
                                    .unwrap_or(vec![]),
    ].iter()
        .flatten()
        .filter(|path| path.exists() && path.is_file())
        .map(|path| {
            let content = {
                let mut s = String::new();
                let f = File::open(path);
                if f.is_err() {
                    return None
                }
                let mut f = f.unwrap();
                f.read_to_string(&mut s).ok();
                s
            };

            let mut parser = Parser::new(&content[..]);
            let res = parser.parse();

            if res.is_none() {
                write!(stderr(), "Config file parser error:").ok();
                for error in parser.errors {
                    write!(stderr(), "At [{}][{}] <> {}", error.lo, error.hi, error).ok();
                    write!(stderr(), "in: '{}'", &content[error.lo..error.hi]).ok();
                }
                None
            } else {
                res
            }
        })
        .filter(|loaded| loaded.is_some())
        .nth(0)
        .map(|inner| Value::Table(inner.unwrap()))
        .ok_or(ConfigError::new(ConfigErrorKind::NoConfigFileFound, None))
}

<|endoftext|>