<commit_before>//! Allow access to the various flavours of sass contexts:
//! https://github.com/sass/libsass/wiki/API-Sass-Context

use std::{ffi,ptr};
use sass_sys;
use util;
use ptr::Unique;
use std::sync::{Arc,RwLock};

#[derive(Debug, Clone)]
pub enum OutputStyle {
    Nested,
    Expanded,
    Compact,
    Compressed
}

#[derive(Debug)]
pub struct SassOptions {
    pub raw: Unique<sass_sys::Struct_Sass_Options>
}

impl SassOptions {

    /// Set the sass functions in the context, expects an array
    /// of tuples, each tuple contains the signature and function pointer.
    pub fn set_sass_functions(&mut self, sf:Vec<sass_sys::Sass_C_Function_Callback>) {
        // create list of all custom functions
        let len = sf.len();
        unsafe {
            let fn_list = sass_sys::sass_make_function_list(len);
            for (i,sass_fn) in sf.into_iter().enumerate() {
                sass_sys::sass_function_set_list_entry(fn_list, i, sass_fn);
            }
            sass_sys::sass_option_set_c_functions(self.raw.get_mut(), fn_list);
        }
    }

    pub fn set_output_style(&mut self, style: OutputStyle) {
        let style = match style {
            OutputStyle::Nested => sass_sys::SASS_STYLE_NESTED,
            OutputStyle::Expanded => sass_sys::SASS_STYLE_EXPANDED,
            OutputStyle::Compact => sass_sys::SASS_STYLE_COMPACT,
            OutputStyle::Compressed => sass_sys::SASS_STYLE_COMPRESSED,
        };
        unsafe {
            sass_sys::sass_option_set_output_style(self.raw.get_mut(), style);
        }
    }
}

pub struct SassContext {
    // Need Unique to send between threads, libsass is thread safe
    pub raw: Unique<sass_sys::Struct_Sass_Context>,
    pub sass_options: Arc<RwLock<SassOptions>>
}

pub struct SassFileContext {
    // Need Unique to send between threads, libsass is thread safe
    context: Unique<sass_sys::Struct_Sass_File_Context>,
    pub sass_context: SassContext
}

impl SassFileContext {
    pub fn new(input_file_path:&str) -> SassFileContext {
        let c_str = ffi::CString::new(input_file_path).unwrap();
        let file_context = unsafe { sass_sys::sass_make_file_context(c_str.as_ptr()) };
        let file_sass_context = unsafe {sass_sys::sass_file_context_get_context(file_context)};
        let options = unsafe {sass_sys::sass_context_get_options(file_sass_context)};
        let sass_options = Arc::new(RwLock::new(SassOptions {
            raw: unsafe {Unique::new(options)}
        }));
        SassFileContext {
            context: unsafe {Unique::new(file_context)},
            sass_context: SassContext {
                raw: unsafe {Unique::new(file_sass_context)},
                sass_options: sass_options
            }
        }
    }

    pub fn compile(&mut self) -> Result<String,String> {
        unsafe { sass_sys::sass_compile_file_context(self.context.get_mut())};
        let ctx_out = unsafe {self.sass_context.raw.get_mut()};
        let error_status = unsafe {sass_sys::sass_context_get_error_status(ctx_out)};
        let error_message = unsafe {sass_sys::sass_context_get_error_message(ctx_out)};
        let output_string = unsafe {sass_sys::sass_context_get_output_string(ctx_out)};
        if error_status != 0  {
            if error_message != ptr::null() {
                Result::Err(util::build_string(error_message))
            } else {
                Result::Err("Unknown error".to_string())
            }
        } else {
            Result::Ok(util::build_string(output_string))
        }
    }

}

impl Drop for SassFileContext {
    fn drop(&mut self) {
        unsafe {
            sass_sys::sass_delete_file_context(self.context.get_mut())
        }
    }
}
<commit_msg>Add SassDataContext<commit_after>//! Allow access to the various flavours of sass contexts:
//! https://github.com/sass/libsass/wiki/API-Sass-Context

use std::{ffi,ptr};
use sass_sys;
use util;
use ptr::Unique;
use std::sync::{Arc,RwLock};

#[derive(Debug, Clone)]
pub enum OutputStyle {
    Nested,
    Expanded,
    Compact,
    Compressed
}

#[derive(Debug)]
pub struct SassOptions {
    pub raw: Unique<sass_sys::Struct_Sass_Options>
}

impl SassOptions {

    /// Set the sass functions in the context, expects an array
    /// of tuples, each tuple contains the signature and function pointer.
    pub fn set_sass_functions(&mut self, sf:Vec<sass_sys::Sass_C_Function_Callback>) {
        // create list of all custom functions
        let len = sf.len();
        unsafe {
            let fn_list = sass_sys::sass_make_function_list(len);
            for (i,sass_fn) in sf.into_iter().enumerate() {
                sass_sys::sass_function_set_list_entry(fn_list, i, sass_fn);
            }
            sass_sys::sass_option_set_c_functions(self.raw.get_mut(), fn_list);
        }
    }

    pub fn set_output_style(&mut self, style: OutputStyle) {
        let style = match style {
            OutputStyle::Nested => sass_sys::SASS_STYLE_NESTED,
            OutputStyle::Expanded => sass_sys::SASS_STYLE_EXPANDED,
            OutputStyle::Compact => sass_sys::SASS_STYLE_COMPACT,
            OutputStyle::Compressed => sass_sys::SASS_STYLE_COMPRESSED,
        };
        unsafe {
            sass_sys::sass_option_set_output_style(self.raw.get_mut(), style);
        }
    }
}

pub struct SassContext {
    // Need Unique to send between threads, libsass is thread safe
    pub raw: Unique<sass_sys::Struct_Sass_Context>,
    pub sass_options: Arc<RwLock<SassOptions>>
}

pub struct SassDataContext {
    // Need Unique to send between threads, libsass is thread safe
    context: Unique<sass_sys::Struct_Sass_Data_Context>,
    pub sass_context: SassContext
}

impl SassDataContext {
    pub fn new(data:&str) -> SassDataContext {
        let c_str = ffi::CString::new(data).unwrap();
        let data_context = unsafe { sass_sys::sass_make_data_context(c_str.into_raw()) };
        let data_sass_context = unsafe {sass_sys::sass_data_context_get_context(data_context)};
        let options = unsafe {sass_sys::sass_context_get_options(data_sass_context)};
        let sass_options = Arc::new(RwLock::new(SassOptions {
            raw: unsafe {Unique::new(options)}
        }));
        SassDataContext {
            context: unsafe {Unique::new(data_context)},
            sass_context: SassContext {
                raw: unsafe {Unique::new(data_sass_context)},
                sass_options: sass_options
            }
        }
    }

    pub fn compile(&mut self) -> Result<String,String> {
        unsafe { sass_sys::sass_compile_data_context(self.context.get_mut())};
        let ctx_out = unsafe {self.sass_context.raw.get_mut()};
        let error_status = unsafe {sass_sys::sass_context_get_error_status(ctx_out)};
        let error_message = unsafe {sass_sys::sass_context_get_error_message(ctx_out)};
        let output_string = unsafe {sass_sys::sass_context_get_output_string(ctx_out)};
        if error_status != 0  {
            if error_message != ptr::null() {
                Result::Err(util::build_string(error_message))
            } else {
                Result::Err("Unknown error".to_string())
            }
        } else {
            Result::Ok(util::build_string(output_string))
        }
    }
}

impl Drop for SassDataContext {
    fn drop(&mut self) {
        unsafe {
            sass_sys::sass_delete_data_context(self.context.get_mut())
        }
    }
}

pub struct SassFileContext {
    // Need Unique to send between threads, libsass is thread safe
    context: Unique<sass_sys::Struct_Sass_File_Context>,
    pub sass_context: SassContext
}

impl SassFileContext {
    pub fn new(input_file_path:&str) -> SassFileContext {
        let c_str = ffi::CString::new(input_file_path).unwrap();
        let file_context = unsafe { sass_sys::sass_make_file_context(c_str.as_ptr()) };
        let file_sass_context = unsafe {sass_sys::sass_file_context_get_context(file_context)};
        let options = unsafe {sass_sys::sass_context_get_options(file_sass_context)};
        let sass_options = Arc::new(RwLock::new(SassOptions {
            raw: unsafe {Unique::new(options)}
        }));
        SassFileContext {
            context: unsafe {Unique::new(file_context)},
            sass_context: SassContext {
                raw: unsafe {Unique::new(file_sass_context)},
                sass_options: sass_options
            }
        }
    }

    pub fn compile(&mut self) -> Result<String,String> {
        unsafe { sass_sys::sass_compile_file_context(self.context.get_mut())};
        let ctx_out = unsafe {self.sass_context.raw.get_mut()};
        let error_status = unsafe {sass_sys::sass_context_get_error_status(ctx_out)};
        let error_message = unsafe {sass_sys::sass_context_get_error_message(ctx_out)};
        let output_string = unsafe {sass_sys::sass_context_get_output_string(ctx_out)};
        if error_status != 0  {
            if error_message != ptr::null() {
                Result::Err(util::build_string(error_message))
            } else {
                Result::Err("Unknown error".to_string())
            }
        } else {
            Result::Ok(util::build_string(output_string))
        }
    }

}

impl Drop for SassFileContext {
    fn drop(&mut self) {
        unsafe {
            sass_sys::sass_delete_file_context(self.context.get_mut())
        }
    }
}
<|endoftext|>


<commit_before>/*!
A binding for SDL2_ttf.
 */

extern crate sdl2;
extern crate sdl2_sys;

#[macro_use]
extern crate bitflags;

#[allow(non_camel_case_types, dead_code)]
mod ffi;
mod font;
mod context;

// Setup linking for all targets.
#[cfg(target_os="macos")]
mod mac {
    #[cfg(mac_framework)]
    #[link(kind="framework", name="SDL2_ttf")]
    extern {}

    #[cfg(not(mac_framework))]
    #[link(name="SDL2_ttf")]
    extern {}
}

#[cfg(any(target_os="windows", target_os="linux", target_os="freebsd"))]
mod others {
    #[link(name="SDL2_ttf")]
    extern {}
}

pub use context::{
    init, has_been_initialized, get_linked_version, Sdl2TtfContext
};
pub use font::{
    Font, FontStyle, Hinting, GlyphMetrics, PartialRendering, FontError,
    FontResult, STYLE_NORMAL, STYLE_BOLD, STYLE_ITALIC, STYLE_UNDERLINE, STYLE_STRIKETHROUGH
};
<commit_msg>fix clippy warnings<commit_after>/*!
A binding for `SDL2_ttf`.
 */

extern crate sdl2;
extern crate sdl2_sys;

#[macro_use]
extern crate bitflags;

#[allow(non_camel_case_types, dead_code)]
mod ffi;
mod font;
mod context;

// Setup linking for all targets.
#[cfg(target_os="macos")]
mod mac {
    #[cfg(mac_framework)]
    #[link(kind="framework", name="SDL2_ttf")]
    extern {}

    #[cfg(not(mac_framework))]
    #[link(name="SDL2_ttf")]
    extern {}
}

#[cfg(any(target_os="windows", target_os="linux", target_os="freebsd"))]
mod others {
    #[link(name="SDL2_ttf")]
    extern {}
}

pub use context::{
    init, has_been_initialized, get_linked_version, Sdl2TtfContext
};
pub use font::{
    Font, FontStyle, Hinting, GlyphMetrics, PartialRendering, FontError,
    FontResult, STYLE_NORMAL, STYLE_BOLD, STYLE_ITALIC, STYLE_UNDERLINE, STYLE_STRIKETHROUGH
};
<|endoftext|>


<commit_before>use game::{Position, Move};
use types::{NumNodes, NumMoves, NumPlies};

#[derive(Clone, Show)]
pub struct State {
    pub pos: Position,
    pub prev_pos: Option<Position>,
    pub prev_move: Option<Move>,
    pub param: Param,
}

#[derive(Clone, Show)]
pub struct Param {
    pub ponder: bool,
    pub search_moves: Option<Vec<Move>>,
    pub depth: Option<NumPlies>,
    pub nodes: Option<NumNodes>,
    pub mate: Option<NumMoves>,
}

#[derive(PartialEq, Eq, Copy, Clone, Show)]
pub enum Cmd {
    SetDebug(bool),
    PonderHit,
    Stop,
}
<commit_msg>Add constructor for search::Param<commit_after>use game::{Position, Move};
use types::{NumNodes, NumMoves, NumPlies};

#[derive(Clone, Show)]
pub struct State {
    pub pos: Position,
    pub prev_pos: Option<Position>,
    pub prev_move: Option<Move>,
    pub param: Param,
}

#[derive(Clone, Show)]
pub struct Param {
    pub ponder: bool,
    pub search_moves: Option<Vec<Move>>,
    pub depth: Option<NumPlies>,
    pub nodes: Option<NumNodes>,
    pub mate: Option<NumMoves>,
}
impl Param {
    pub fn new() -> Self {
        Param {
            ponder: false,
            search_moves: None,
            depth: None,
            nodes: None,
            mate: None,
        }
    }
}

#[derive(PartialEq, Eq, Copy, Clone, Show)]
pub enum Cmd {
    SetDebug(bool),
    PonderHit,
    Stop,
}
<|endoftext|>


<commit_before>
use serialize::json::Json;
use time::Timespec;

use std::sync::Arc;
use std::mem;

use from::{From, RcFrom, FromSelect};
use field::{Field, UntypedField};
use predicate::{
    RcPredicate,
    ToOrPredicate,
    ToAndPredicate,
    ToExcludePredicate
};
use to_sql::{ToSql};
use order_by::{OrderBy};
use join::{Join};

use field::{
    FieldDef,
    I8Comparable,
    I16Comparable,
    I32Comparable,
    I64Comparable,
    F32Comparable,
    F64Comparable,
    StringComparable,
    JsonComparable,
    TimespecComparable,

    I8ComparableList,
    I16ComparableList,
    I32ComparableList,
    I64ComparableList,
    F32ComparableList,
    F64ComparableList,
    StringComparableList,
    JsonComparableList,
    TimespecComparableList
};

#[deriving(Clone)]
pub enum Select {
    SelectOnly(Vec<FieldDef<()>>),
    SelectAll
}

pub trait ToSelectQuery: Send + Sync + ToSql {
    fn upcast(self) -> RcSelectQuery {
        Arc::new(box self as BoxedSelectQuery)
    }
}

#[deriving(Clone)]
pub struct LimitOne;

#[deriving(Clone)]
pub struct LimitTwo;

#[deriving(Clone)]
pub struct LimitMany;

#[deriving(Clone)]
pub struct SelectQuery<T, L, M> {
    pub select: Select,
    pub from: RcFrom,
    pub where_: Option<RcPredicate>,
    pub limit: Option<uint>,
    pub offset: Option<uint>,
    pub order_by: Vec<OrderBy>,
    pub joins: Vec<Join>
}

macro_rules! set_where(
    ($s:ident, $pr:expr, $w:ident, $new_pr:expr) => ({
        let mut query = $s.clone();
        match $s.get_where() {
            &Some(ref $w) => {
                query.set_where($new_pr);
            },
            &None => {
                query.set_where($pr);
            }
        }
        query
    })
)

pub trait Queryable: Clone {
    fn get_where(&self) -> &Option<RcPredicate>;
    fn set_where(&mut self, RcPredicate);
    fn unset_where(&mut self);

    fn or(&self, predicate: RcPredicate) -> Self {
        set_where!(self, predicate, w, w.or(predicate))
    }

    fn where_(&self, predicate: RcPredicate) -> Self {
        set_where!(self, predicate, w, w.and(predicate))
    }

    fn and(&self, predicate: RcPredicate) -> Self {
        self.where_(predicate)
    }

    fn exclude(&self, predicate: RcPredicate) -> Self {
       set_where!(self, predicate.exclude(), w, w.and(predicate.exclude()))
    }

    fn and_exclude(&self, predicate: RcPredicate) -> Self {
       self.exclude(predicate)
    }

    fn or_exclude(&self, predicate: RcPredicate) -> Self {
       set_where!(self, predicate.exclude(), w, w.or(predicate.exclude()))
    }

}

macro_rules! with_clone(
    ($slf: ident, $v:ident, $ex:expr) => ({
        let mut $v = $slf.clone();
        $ex;
        $v
    })
)

pub trait Orderable: Clone {
    fn get_order_by_mut(&mut self) -> &mut Vec<OrderBy>;
    fn set_order_by(&mut self, Vec<OrderBy>);

    fn order_by<F: Clone>(&self, field: &Field<F>) -> Self {
        with_clone!(self, query, query.set_order_by(
            vec![OrderBy::by(field)]
        ))
    }

    fn order_by_fields<F: Clone>(&self, fields: &[&Field<F>]) -> Self {
        with_clone!(self, query, query.set_order_by(
            fields.iter().map(|f| OrderBy::by(*f)).collect()
        ))
    }

    fn reverse_by<F: Clone>(&self, field: &Field<F>) -> Self {
        with_clone!(self, query, query.set_order_by(
            vec![OrderBy::reverse_by(field)]
        ))
    }

    fn reverse_by_fields<F: Clone>(&self, fields: &[&Field<F>]) -> Self {
        with_clone!(self, query, query.set_order_by(
            fields.iter().map(|f| OrderBy::reverse_by(*f)).collect()
        ))
    }

    fn order_append<F: Clone>(&self, field: &Field<F>) -> Self {
        with_clone!(self, query, query.get_order_by_mut().push(OrderBy::by(field)))
    }

    fn order_prepend<F: Clone>(&self, field: &Field<F>) -> Self {
        with_clone!(self, query, query.get_order_by_mut().insert(0, OrderBy::by(field)))
    }

    fn reverse_append<F: Clone>(&self, field: &Field<F>) -> Self {
        with_clone!(self, query, query.get_order_by_mut().push(OrderBy::reverse_by(field)))
    }

    fn reverse_prepend<F: Clone>(&self, field: &Field<F>) -> Self {
        with_clone!(self, query, query.get_order_by_mut().insert(0, OrderBy::reverse_by(field)))
    }

}

impl<T: Clone, L: Clone, M: Clone> SelectQuery<T, L, M> {

    pub fn new(select: Select, from: RcFrom) -> SelectQuery<T, L, M> {
        SelectQuery {
            select: select,
            from: from,
            where_: None,
            limit: None,
            offset: None,
            order_by: vec![],
            joins: vec![]
        }
    }

    pub fn limit(&self, limit: uint) -> SelectQuery<T, LimitOne, M> {
        let mut query = self.clone();
        query.limit = Some(limit);
        unsafe{ mem::transmute(query) }
    }

    pub fn first(&self) -> SelectQuery<T, LimitOne, M> {
        let mut query = self.clone();
        query.limit = Some(1);
        unsafe{ mem::transmute(query) }
    }

    pub fn offset(&self, offset: uint) -> SelectQuery<T, L, M> {
        with_clone!(self, query, query.offset = Some(offset))
    }

    pub fn alias(&self, alias: &str) -> FromSelect<T, L, M> {
        FromSelect { select: self.clone(), alias: alias.to_string() }
    }

    pub fn from_as(&self, alias: &str) -> FromSelect<T, L, M> {
        self.alias(alias)
    }

    pub fn inner_join(&self, from: &From, on: RcPredicate) -> SelectQuery<T, L, M> {
        with_clone!(self, query, query.joins.push(Join::inner_join(from.upcast_from(), on)))
    }

    pub fn full_outer_join(&self, from: &From, on: RcPredicate) -> SelectQuery<T, L, M> {
        with_clone!(self, query, query.joins.push(Join::full_outer_join(from.upcast_from(), on)))
    }

    pub fn right_outer_join(&self, from: &From, on: RcPredicate) -> SelectQuery<T, L, M> {
        with_clone!(self, query, query.joins.push(Join::right_outer_join(from.upcast_from(), on)))
    }

    pub fn left_outer_join(&self, from: &From, on: RcPredicate) -> SelectQuery<T, L, M> {
        with_clone!(self, query, query.joins.push(Join::left_outer_join(from.upcast_from(), on)))
    }

    pub fn full_join(&self, from: &From, on: RcPredicate) -> SelectQuery<T, L, M> {
        with_clone!(self, query, query.joins.push(Join::full_join(from.upcast_from(), on)))
    }

    pub fn left_join(&self, from: &From, on: RcPredicate) -> SelectQuery<T, L, M> {
        with_clone!(self, query, query.joins.push(Join::left_join(from.upcast_from(), on)))
    }

    pub fn right_join(&self, from: &From, on: RcPredicate) -> SelectQuery<T, L, M> {
        with_clone!(self, query, query.joins.push(Join::right_join(from.upcast_from(), on)))
    }

    pub fn natural_join(&self, from: &From) -> SelectQuery<T, L, M> {
        with_clone!(self, query, query.joins.push(Join::natural_join(from.upcast_from())))
    }

    pub fn natural_left_join(&self, from: &From) -> SelectQuery<T, L, M> {
        with_clone!(self, query, query.joins.push(Join::natural_left_join(from.upcast_from())))
    }

    pub fn natural_right_join(&self, from: &From) -> SelectQuery<T, L, M> {
        with_clone!(self, query, query.joins.push(Join::natural_right_join(from.upcast_from())))
    }

    pub fn natural_full_join(&self, from: &From) -> SelectQuery<T, L, M> {
        with_clone!(self, query, query.joins.push(Join::natural_full_join(from.upcast_from())))
    }

    pub fn cross_join(&self, from: &From) -> SelectQuery<T, L, M> {
        with_clone!(self, query, query.joins.push(Join::cross_join(from.upcast_from())))
    }
}

pub trait Selectable<M: Clone>: From {
    // FIXME: Unify select_N after [generics](https://github.com/rust-lang/rfcs/issues/376)

    fn select_1<T: Clone>(&self, field: &Field<T>) -> SelectQuery<(T), LimitMany, M> {
        SelectQuery::new(SelectOnly(vec![field.to_def().clone_with_erase()]), self.upcast_from())
    }

    fn select_2<T1: Clone, T2: Clone>(&self, field1: &Field<T1>, field2: &Field<T2>) -> SelectQuery<(T1, T2), LimitMany, M> {
        SelectQuery::new(SelectOnly(vec![field1.to_def().clone_with_erase(), field2.to_def().clone_with_erase()]), self.upcast_from())
    }

    fn select(&self, fields: &[&UntypedField]) -> SelectQuery<(), LimitMany, M> {
        SelectQuery::new(SelectOnly(fields.iter().map(|f| f.to_def().clone_with_erase()).collect()), self.upcast_from())
    }

    fn select_all(&self) -> SelectQuery<(), LimitMany, M> {
        SelectQuery::new(SelectAll, self.upcast_from())
    }
}

impl<T: Clone, L: Clone, M: Clone> Queryable for SelectQuery<T, L, M> {
    fn get_where(&self) -> &Option<RcPredicate> { &self.where_ }
    fn set_where(&mut self, predicate: RcPredicate) { self.where_ = Some(predicate); }
    fn unset_where(&mut self) { self.where_ = None; }
}

impl<T: Clone, L: Clone, M: Clone> Orderable for SelectQuery<T, L, M> {
    fn get_order_by_mut(&mut self) -> &mut Vec<OrderBy> { &mut self.order_by }
    fn set_order_by(&mut self, order_by: Vec<OrderBy>) { self.order_by = order_by }
}

impl<T: Clone, L: Clone, M: Clone> ToSelectQuery for SelectQuery<T, L, M> { }

pub type BoxedSelectQuery = Box<ToSelectQuery + Send + Sync>;
pub type RcSelectQuery = Arc<BoxedSelectQuery>;

impl<M: Clone> I8Comparable for SelectQuery<(i8), LimitOne, M> { }
impl<M: Clone> I16Comparable for SelectQuery<(i16), LimitOne, M> { }
impl<M: Clone> I32Comparable for SelectQuery<(i32), LimitOne, M> { }
impl<M: Clone> I64Comparable for SelectQuery<(i64), LimitOne, M> { }
impl<M: Clone> F32Comparable for SelectQuery<(f32), LimitOne, M> { }
impl<M: Clone> F64Comparable for SelectQuery<(f64), LimitOne, M> { }
impl<M: Clone> StringComparable for SelectQuery<(String), LimitOne, M> { }
impl<M: Clone> JsonComparable for SelectQuery<(Json), LimitOne, M> { }
impl<M: Clone> TimespecComparable for SelectQuery<(Timespec), LimitOne, M> { }

impl<M: Clone> I8ComparableList for SelectQuery<(i8), LimitMany, M> { }
impl<M: Clone> I16ComparableList for SelectQuery<(i16), LimitMany, M> { }
impl<M: Clone> I32ComparableList for SelectQuery<(i32), LimitMany, M> { }
impl<M: Clone> I64ComparableList for SelectQuery<(i64), LimitMany, M> { }
impl<M: Clone> F32ComparableList for SelectQuery<(f32), LimitMany, M> { }
impl<M: Clone> F64ComparableList for SelectQuery<(f64), LimitMany, M> { }
impl<M: Clone> StringComparableList for SelectQuery<(String), LimitMany, M> { }
impl<M: Clone> JsonComparableList for SelectQuery<(Json), LimitMany, M> { }
impl<M: Clone> TimespecComparableList for SelectQuery<(Timespec), LimitMany, M> { }

<commit_msg>feat: add `unjoin` to cleanup joins<commit_after>
use serialize::json::Json;
use time::Timespec;

use std::sync::Arc;
use std::mem;

use from::{From, RcFrom, FromSelect};
use field::{Field, UntypedField};
use predicate::{
    RcPredicate,
    ToOrPredicate,
    ToAndPredicate,
    ToExcludePredicate
};
use to_sql::{ToSql};
use order_by::{OrderBy};
use join::{Join};

use field::{
    FieldDef,
    I8Comparable,
    I16Comparable,
    I32Comparable,
    I64Comparable,
    F32Comparable,
    F64Comparable,
    StringComparable,
    JsonComparable,
    TimespecComparable,

    I8ComparableList,
    I16ComparableList,
    I32ComparableList,
    I64ComparableList,
    F32ComparableList,
    F64ComparableList,
    StringComparableList,
    JsonComparableList,
    TimespecComparableList
};

#[deriving(Clone)]
pub enum Select {
    SelectOnly(Vec<FieldDef<()>>),
    SelectAll
}

pub trait ToSelectQuery: Send + Sync + ToSql {
    fn upcast(self) -> RcSelectQuery {
        Arc::new(box self as BoxedSelectQuery)
    }
}

#[deriving(Clone)]
pub struct LimitOne;

#[deriving(Clone)]
pub struct LimitTwo;

#[deriving(Clone)]
pub struct LimitMany;

#[deriving(Clone)]
pub struct SelectQuery<T, L, M> {
    pub select: Select,
    pub from: RcFrom,
    pub where_: Option<RcPredicate>,
    pub limit: Option<uint>,
    pub offset: Option<uint>,
    pub order_by: Vec<OrderBy>,
    pub joins: Vec<Join>
}

macro_rules! set_where(
    ($s:ident, $pr:expr, $w:ident, $new_pr:expr) => ({
        let mut query = $s.clone();
        match $s.get_where() {
            &Some(ref $w) => {
                query.set_where($new_pr);
            },
            &None => {
                query.set_where($pr);
            }
        }
        query
    })
)

pub trait Queryable: Clone {
    fn get_where(&self) -> &Option<RcPredicate>;
    fn set_where(&mut self, RcPredicate);
    fn unset_where(&mut self);

    fn or(&self, predicate: RcPredicate) -> Self {
        set_where!(self, predicate, w, w.or(predicate))
    }

    fn where_(&self, predicate: RcPredicate) -> Self {
        set_where!(self, predicate, w, w.and(predicate))
    }

    fn and(&self, predicate: RcPredicate) -> Self {
        self.where_(predicate)
    }

    fn exclude(&self, predicate: RcPredicate) -> Self {
       set_where!(self, predicate.exclude(), w, w.and(predicate.exclude()))
    }

    fn and_exclude(&self, predicate: RcPredicate) -> Self {
       self.exclude(predicate)
    }

    fn or_exclude(&self, predicate: RcPredicate) -> Self {
       set_where!(self, predicate.exclude(), w, w.or(predicate.exclude()))
    }

}

macro_rules! with_clone(
    ($slf: ident, $v:ident, $ex:expr) => ({
        let mut $v = $slf.clone();
        $ex;
        $v
    })
)

pub trait Orderable: Clone {
    fn get_order_by_mut(&mut self) -> &mut Vec<OrderBy>;
    fn set_order_by(&mut self, Vec<OrderBy>);

    fn order_by<F: Clone>(&self, field: &Field<F>) -> Self {
        with_clone!(self, query, query.set_order_by(
            vec![OrderBy::by(field)]
        ))
    }

    fn order_by_fields<F: Clone>(&self, fields: &[&Field<F>]) -> Self {
        with_clone!(self, query, query.set_order_by(
            fields.iter().map(|f| OrderBy::by(*f)).collect()
        ))
    }

    fn reverse_by<F: Clone>(&self, field: &Field<F>) -> Self {
        with_clone!(self, query, query.set_order_by(
            vec![OrderBy::reverse_by(field)]
        ))
    }

    fn reverse_by_fields<F: Clone>(&self, fields: &[&Field<F>]) -> Self {
        with_clone!(self, query, query.set_order_by(
            fields.iter().map(|f| OrderBy::reverse_by(*f)).collect()
        ))
    }

    fn order_append<F: Clone>(&self, field: &Field<F>) -> Self {
        with_clone!(self, query, query.get_order_by_mut().push(OrderBy::by(field)))
    }

    fn order_prepend<F: Clone>(&self, field: &Field<F>) -> Self {
        with_clone!(self, query, query.get_order_by_mut().insert(0, OrderBy::by(field)))
    }

    fn reverse_append<F: Clone>(&self, field: &Field<F>) -> Self {
        with_clone!(self, query, query.get_order_by_mut().push(OrderBy::reverse_by(field)))
    }

    fn reverse_prepend<F: Clone>(&self, field: &Field<F>) -> Self {
        with_clone!(self, query, query.get_order_by_mut().insert(0, OrderBy::reverse_by(field)))
    }

}

impl<T: Clone, L: Clone, M: Clone> SelectQuery<T, L, M> {

    pub fn new(select: Select, from: RcFrom) -> SelectQuery<T, L, M> {
        SelectQuery {
            select: select,
            from: from,
            where_: None,
            limit: None,
            offset: None,
            order_by: vec![],
            joins: vec![]
        }
    }

    pub fn limit(&self, limit: uint) -> SelectQuery<T, LimitOne, M> {
        let mut query = self.clone();
        query.limit = Some(limit);
        unsafe{ mem::transmute(query) }
    }

    pub fn first(&self) -> SelectQuery<T, LimitOne, M> {
        let mut query = self.clone();
        query.limit = Some(1);
        unsafe{ mem::transmute(query) }
    }

    pub fn offset(&self, offset: uint) -> SelectQuery<T, L, M> {
        with_clone!(self, query, query.offset = Some(offset))
    }

    pub fn alias(&self, alias: &str) -> FromSelect<T, L, M> {
        FromSelect { select: self.clone(), alias: alias.to_string() }
    }

    pub fn from_as(&self, alias: &str) -> FromSelect<T, L, M> {
        self.alias(alias)
    }

    pub fn inner_join(&self, from: &From, on: RcPredicate) -> SelectQuery<T, L, M> {
        with_clone!(self, query, query.joins.push(Join::inner_join(from.upcast_from(), on)))
    }

    pub fn full_outer_join(&self, from: &From, on: RcPredicate) -> SelectQuery<T, L, M> {
        with_clone!(self, query, query.joins.push(Join::full_outer_join(from.upcast_from(), on)))
    }

    pub fn right_outer_join(&self, from: &From, on: RcPredicate) -> SelectQuery<T, L, M> {
        with_clone!(self, query, query.joins.push(Join::right_outer_join(from.upcast_from(), on)))
    }

    pub fn left_outer_join(&self, from: &From, on: RcPredicate) -> SelectQuery<T, L, M> {
        with_clone!(self, query, query.joins.push(Join::left_outer_join(from.upcast_from(), on)))
    }

    pub fn full_join(&self, from: &From, on: RcPredicate) -> SelectQuery<T, L, M> {
        with_clone!(self, query, query.joins.push(Join::full_join(from.upcast_from(), on)))
    }

    pub fn left_join(&self, from: &From, on: RcPredicate) -> SelectQuery<T, L, M> {
        with_clone!(self, query, query.joins.push(Join::left_join(from.upcast_from(), on)))
    }

    pub fn right_join(&self, from: &From, on: RcPredicate) -> SelectQuery<T, L, M> {
        with_clone!(self, query, query.joins.push(Join::right_join(from.upcast_from(), on)))
    }

    pub fn natural_join(&self, from: &From) -> SelectQuery<T, L, M> {
        with_clone!(self, query, query.joins.push(Join::natural_join(from.upcast_from())))
    }

    pub fn natural_left_join(&self, from: &From) -> SelectQuery<T, L, M> {
        with_clone!(self, query, query.joins.push(Join::natural_left_join(from.upcast_from())))
    }

    pub fn natural_right_join(&self, from: &From) -> SelectQuery<T, L, M> {
        with_clone!(self, query, query.joins.push(Join::natural_right_join(from.upcast_from())))
    }

    pub fn natural_full_join(&self, from: &From) -> SelectQuery<T, L, M> {
        with_clone!(self, query, query.joins.push(Join::natural_full_join(from.upcast_from())))
    }

    pub fn cross_join(&self, from: &From) -> SelectQuery<T, L, M> {
        with_clone!(self, query, query.joins.push(Join::cross_join(from.upcast_from())))
    }

    pub fn unjoin(&self) -> SelectQuery<T, L, M> {
        with_clone!(self, query, query.joins = vec![])
    }
}

pub trait Selectable<M: Clone>: From {
    // FIXME: Unify select_N after [generics](https://github.com/rust-lang/rfcs/issues/376)

    fn select_1<T: Clone>(&self, field: &Field<T>) -> SelectQuery<(T), LimitMany, M> {
        SelectQuery::new(SelectOnly(vec![field.to_def().clone_with_erase()]), self.upcast_from())
    }

    fn select_2<T1: Clone, T2: Clone>(&self, field1: &Field<T1>, field2: &Field<T2>) -> SelectQuery<(T1, T2), LimitMany, M> {
        SelectQuery::new(SelectOnly(vec![field1.to_def().clone_with_erase(), field2.to_def().clone_with_erase()]), self.upcast_from())
    }

    fn select(&self, fields: &[&UntypedField]) -> SelectQuery<(), LimitMany, M> {
        SelectQuery::new(SelectOnly(fields.iter().map(|f| f.to_def().clone_with_erase()).collect()), self.upcast_from())
    }

    fn select_all(&self) -> SelectQuery<(), LimitMany, M> {
        SelectQuery::new(SelectAll, self.upcast_from())
    }
}

impl<T: Clone, L: Clone, M: Clone> Queryable for SelectQuery<T, L, M> {
    fn get_where(&self) -> &Option<RcPredicate> { &self.where_ }
    fn set_where(&mut self, predicate: RcPredicate) { self.where_ = Some(predicate); }
    fn unset_where(&mut self) { self.where_ = None; }
}

impl<T: Clone, L: Clone, M: Clone> Orderable for SelectQuery<T, L, M> {
    fn get_order_by_mut(&mut self) -> &mut Vec<OrderBy> { &mut self.order_by }
    fn set_order_by(&mut self, order_by: Vec<OrderBy>) { self.order_by = order_by }
}

impl<T: Clone, L: Clone, M: Clone> ToSelectQuery for SelectQuery<T, L, M> { }

pub type BoxedSelectQuery = Box<ToSelectQuery + Send + Sync>;
pub type RcSelectQuery = Arc<BoxedSelectQuery>;

impl<M: Clone> I8Comparable for SelectQuery<(i8), LimitOne, M> { }
impl<M: Clone> I16Comparable for SelectQuery<(i16), LimitOne, M> { }
impl<M: Clone> I32Comparable for SelectQuery<(i32), LimitOne, M> { }
impl<M: Clone> I64Comparable for SelectQuery<(i64), LimitOne, M> { }
impl<M: Clone> F32Comparable for SelectQuery<(f32), LimitOne, M> { }
impl<M: Clone> F64Comparable for SelectQuery<(f64), LimitOne, M> { }
impl<M: Clone> StringComparable for SelectQuery<(String), LimitOne, M> { }
impl<M: Clone> JsonComparable for SelectQuery<(Json), LimitOne, M> { }
impl<M: Clone> TimespecComparable for SelectQuery<(Timespec), LimitOne, M> { }

impl<M: Clone> I8ComparableList for SelectQuery<(i8), LimitMany, M> { }
impl<M: Clone> I16ComparableList for SelectQuery<(i16), LimitMany, M> { }
impl<M: Clone> I32ComparableList for SelectQuery<(i32), LimitMany, M> { }
impl<M: Clone> I64ComparableList for SelectQuery<(i64), LimitMany, M> { }
impl<M: Clone> F32ComparableList for SelectQuery<(f32), LimitMany, M> { }
impl<M: Clone> F64ComparableList for SelectQuery<(f64), LimitMany, M> { }
impl<M: Clone> StringComparableList for SelectQuery<(String), LimitMany, M> { }
impl<M: Clone> JsonComparableList for SelectQuery<(Json), LimitMany, M> { }
impl<M: Clone> TimespecComparableList for SelectQuery<(Timespec), LimitMany, M> { }

<|endoftext|>


<commit_before>use super::*;
use russell_lab::Vector;

/// Defines the kind of shape
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Kind {
    Lin2,
    Lin3,
    Lin5,
    Tri3,
    Tri6,
    Tri15,
    Qua4,
    Qua8,
    Qua9,
    Tet4,
    Tet10,
    Hex8,
    Hex20,
    Joint,
    Lin4,
    Tri10,
    Qua12,
    Qua16,
    Beam,
}

/// Defines the functionality of shape
pub trait Shape {
    /// Calculates the interpolation functions at natural coordinate ξ
    ///
    /// ```text
    /// interp[m](ξ) = Sᵐ(ξ)
    /// ```
    fn calc_interp(&mut self, ksi: &Vector);

    /// Calculates the derivatives of interpolation fn at natural coordinate ξ
    ///
    /// ```text
    /// deriv[m][i](ξ) = ({dSᵐ(ξ)/dξ}_ξ)[i]
    /// ```
    fn calc_deriv(&mut self, ksi: &Vector);

    /// Returns the previously computed interpolation fn for point m
    ///
    /// ```text
    /// interp[m](ξ) = Sᵐ(ξ)
    /// ```
    fn get_interp(&self, m: usize) -> f64;

    /// Returns the previously computed derivative of interpolation fn for point m
    ///
    /// ```text
    /// deriv[m][i](ξ) = ({dSᵐ(ξ)/dξ}_ξ)[i]
    /// ```
    fn get_deriv(&self, deriv: &mut Vector, m: usize);

    /// Returns the number of dimensions
    fn get_ndim(&self) -> usize;

    /// Returns the number of points
    fn get_npoint(&self) -> usize;

    /// Returns the number of edges
    fn get_nedge(&self) -> usize;

    /// Returns the number of faces
    fn get_nface(&self) -> usize;

    /// Returns natural coordinates @ point m
    ///
    /// ```text
    /// coord = ξᵐ = vector{r, s, t} @ point m
    /// ```
    fn get_ksi(&self, ksi: &mut Vector, m: usize);
}

/// Returns new Shape
pub fn new(kind: Kind) -> Box<dyn Shape> {
    match kind {
        Kind::Qua4 => Box::new(Qua4::new()),
        Kind::Hex8 => Box::new(Hex8::new()),
        _ => panic!("Shape kind {:?} is not available yet", kind),
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

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

    // Holds arguments for numerical differentiation
    struct Arguments {
        shape: Box<dyn Shape>, // shape
        at_ksi: Vector,        // at nat coord value
        ksi: Vector,           // temporary nat coord
        m: usize,              // point index
        i: usize,              // dimension index
    }

    // Computes the interpolation fn @ m as a function of x = ksi[i]
    fn sm(x: f64, args: &mut Arguments) -> f64 {
        for i in 0..args.shape.get_ndim() {
            args.ksi[i] = args.at_ksi[i];
        }
        args.ksi[args.i] = x;
        args.shape.calc_interp(&args.ksi);
        args.shape.get_interp(args.m)
    }

    #[test]
    fn calc_interp_works() {
        let kinds = vec![Kind::Hex8, Kind::Qua4];
        for kind in kinds {
            let mut shape = new(kind);
            let ndim = shape.get_ndim();
            let npoint = shape.get_npoint();
            let mut ksi = Vector::new(ndim);
            for m in 0..npoint {
                shape.get_ksi(&mut ksi, m);
                shape.calc_interp(&ksi);
                for n in 0..npoint {
                    let smn = shape.get_interp(n);
                    if m == n {
                        assert_approx_eq!(smn, 1.0, 1e-15);
                    } else {
                        assert_approx_eq!(smn, 0.0, 1e-15);
                    }
                }
            }
        }
    }

    #[test]
    fn calc_deriv_works() {
        let kinds = vec![Kind::Hex8, Kind::Qua4];
        for kind in kinds {
            let mut shape = new(kind);
            let ndim = shape.get_ndim();
            let npoint = shape.get_npoint();
            let mut at_ksi = Vector::new(ndim);
            for i in 0..ndim {
                at_ksi[i] = 0.25;
            }
            let args = &mut Arguments {
                shape: new(kind),
                at_ksi,
                ksi: Vector::new(ndim),
                m: 0,
                i: 0,
            };
            let mut dsm_dksi = Vector::new(ndim);
            shape.calc_deriv(&args.at_ksi);
            for m in 0..npoint {
                shape.get_deriv(&mut dsm_dksi, m);
                args.m = m;
                for i in 0..ndim {
                    args.i = i;
                    assert_deriv_approx_eq!(dsm_dksi[i], args.at_ksi[i], sm, args, 1e-13);
                }
            }
        }
    }

    #[test]
    fn getters_work() {
        let kinds = vec![Kind::Hex8, Kind::Qua4];
        for kind in kinds {
            let shape = new(kind);
            match kind {
                Kind::Qua4 => {
                    assert_eq!(shape.get_ndim(), 2);
                    assert_eq!(shape.get_npoint(), 4);
                    assert_eq!(shape.get_nedge(), 4);
                    assert_eq!(shape.get_nface(), 0);
                }
                Kind::Hex8 => {
                    assert_eq!(shape.get_ndim(), 3);
                    assert_eq!(shape.get_npoint(), 8);
                    assert_eq!(shape.get_nedge(), 12);
                    assert_eq!(shape.get_nface(), 6);
                }
                _ => panic!("Shape kind \"{:?}\" is not available yet", kind),
            }
        }
    }
}
<commit_msg>Remove PartialEq<commit_after>use super::*;
use russell_lab::Vector;

/// Defines the kind of shape
#[derive(Clone, Copy, Debug)]
pub enum Kind {
    Lin2,
    Lin3,
    Lin5,
    Tri3,
    Tri6,
    Tri15,
    Qua4,
    Qua8,
    Qua9,
    Tet4,
    Tet10,
    Hex8,
    Hex20,
    Joint,
    Lin4,
    Tri10,
    Qua12,
    Qua16,
    Beam,
}

/// Defines the functionality of shape
pub trait Shape {
    /// Calculates the interpolation functions at natural coordinate ξ
    ///
    /// ```text
    /// interp[m](ξ) = Sᵐ(ξ)
    /// ```
    fn calc_interp(&mut self, ksi: &Vector);

    /// Calculates the derivatives of interpolation fn at natural coordinate ξ
    ///
    /// ```text
    /// deriv[m][i](ξ) = ({dSᵐ(ξ)/dξ}_ξ)[i]
    /// ```
    fn calc_deriv(&mut self, ksi: &Vector);

    /// Returns the previously computed interpolation fn for point m
    ///
    /// ```text
    /// interp[m](ξ) = Sᵐ(ξ)
    /// ```
    fn get_interp(&self, m: usize) -> f64;

    /// Returns the previously computed derivative of interpolation fn for point m
    ///
    /// ```text
    /// deriv[m][i](ξ) = ({dSᵐ(ξ)/dξ}_ξ)[i]
    /// ```
    fn get_deriv(&self, deriv: &mut Vector, m: usize);

    /// Returns the number of dimensions
    fn get_ndim(&self) -> usize;

    /// Returns the number of points
    fn get_npoint(&self) -> usize;

    /// Returns the number of edges
    fn get_nedge(&self) -> usize;

    /// Returns the number of faces
    fn get_nface(&self) -> usize;

    /// Returns natural coordinates @ point m
    ///
    /// ```text
    /// coord = ξᵐ = vector{r, s, t} @ point m
    /// ```
    fn get_ksi(&self, ksi: &mut Vector, m: usize);
}

/// Returns new Shape
pub fn new(kind: Kind) -> Box<dyn Shape> {
    match kind {
        Kind::Qua4 => Box::new(Qua4::new()),
        Kind::Hex8 => Box::new(Hex8::new()),
        _ => panic!("Shape kind {:?} is not available yet", kind),
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

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

    // Holds arguments for numerical differentiation
    struct Arguments {
        shape: Box<dyn Shape>, // shape
        at_ksi: Vector,        // at nat coord value
        ksi: Vector,           // temporary nat coord
        m: usize,              // point index
        i: usize,              // dimension index
    }

    // Computes the interpolation fn @ m as a function of x = ksi[i]
    fn sm(x: f64, args: &mut Arguments) -> f64 {
        for i in 0..args.shape.get_ndim() {
            args.ksi[i] = args.at_ksi[i];
        }
        args.ksi[args.i] = x;
        args.shape.calc_interp(&args.ksi);
        args.shape.get_interp(args.m)
    }

    #[test]
    fn calc_interp_works() {
        let kinds = vec![Kind::Hex8, Kind::Qua4];
        for kind in kinds {
            let mut shape = new(kind);
            let ndim = shape.get_ndim();
            let npoint = shape.get_npoint();
            let mut ksi = Vector::new(ndim);
            for m in 0..npoint {
                shape.get_ksi(&mut ksi, m);
                shape.calc_interp(&ksi);
                for n in 0..npoint {
                    let smn = shape.get_interp(n);
                    if m == n {
                        assert_approx_eq!(smn, 1.0, 1e-15);
                    } else {
                        assert_approx_eq!(smn, 0.0, 1e-15);
                    }
                }
            }
        }
    }

    #[test]
    fn calc_deriv_works() {
        let kinds = vec![Kind::Hex8, Kind::Qua4];
        for kind in kinds {
            let mut shape = new(kind);
            let ndim = shape.get_ndim();
            let npoint = shape.get_npoint();
            let mut at_ksi = Vector::new(ndim);
            for i in 0..ndim {
                at_ksi[i] = 0.25;
            }
            let args = &mut Arguments {
                shape: new(kind),
                at_ksi,
                ksi: Vector::new(ndim),
                m: 0,
                i: 0,
            };
            let mut dsm_dksi = Vector::new(ndim);
            shape.calc_deriv(&args.at_ksi);
            for m in 0..npoint {
                shape.get_deriv(&mut dsm_dksi, m);
                args.m = m;
                for i in 0..ndim {
                    args.i = i;
                    assert_deriv_approx_eq!(dsm_dksi[i], args.at_ksi[i], sm, args, 1e-13);
                }
            }
        }
    }

    #[test]
    fn getters_work() {
        let kinds = vec![Kind::Hex8, Kind::Qua4];
        for kind in kinds {
            let shape = new(kind);
            match kind {
                Kind::Qua4 => {
                    assert_eq!(shape.get_ndim(), 2);
                    assert_eq!(shape.get_npoint(), 4);
                    assert_eq!(shape.get_nedge(), 4);
                    assert_eq!(shape.get_nface(), 0);
                }
                Kind::Hex8 => {
                    assert_eq!(shape.get_ndim(), 3);
                    assert_eq!(shape.get_npoint(), 8);
                    assert_eq!(shape.get_nedge(), 12);
                    assert_eq!(shape.get_nface(), 6);
                }
                _ => panic!("Shape kind \"{:?}\" is not available yet", kind),
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::fmt::{Debug, Display, Formatter};
use std::fmt;

use super::parser::FileHeaderParser;
use storage::file_id::*;

#[derive(Debug)]
pub enum FileHeaderSpec {
    Null,
    Bool,
    Integer,
    UInteger,
    Float,
    Text,
    Key { name: &'static str, value_type: Box<FileHeaderSpec> },
    Map { keys: Vec<FileHeaderSpec> },
    Array { allowed_types: Vec<FileHeaderSpec> },
}

#[derive(Debug)]
#[derive(Clone)]
pub enum FileHeaderData {
    Null,
    Bool(bool),
    Integer(i64),
    UInteger(u64),
    Float(f64),
    Text(String),
    Key { name: String, value: Box<FileHeaderData> },
    Map { keys: Vec<FileHeaderData> },
    Array { values: Box<Vec<FileHeaderData>> },
}

impl Display for FileHeaderSpec {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        match self {
            &FileHeaderSpec::Null       => write!(fmt, "NULL"),
            &FileHeaderSpec::Bool       => write!(fmt, "Bool"),
            &FileHeaderSpec::Integer    => write!(fmt, "Integer"),
            &FileHeaderSpec::UInteger   => write!(fmt, "UInteger"),
            &FileHeaderSpec::Float      => write!(fmt, "Float"),
            &FileHeaderSpec::Text       => write!(fmt, "Text"),
            &FileHeaderSpec::Key{name: ref n, value_type: ref vt} => {
                write!(fmt, "Key({:?}) -> {:?}", n, vt)
            }
            &FileHeaderSpec::Map{keys: ref ks} => {
                write!(fmt, "Map -> {:?}", ks)
            }
            &FileHeaderSpec::Array{allowed_types: ref at}  => {
                write!(fmt, "Array({:?})", at)
            }
        }
    }

}

pub struct MatchError<'a> {
    summary: String,
    expected: &'a FileHeaderSpec,
    found: &'a FileHeaderData
}

impl<'a> MatchError<'a> {

    pub fn new(s: String,
               ex: &'a FileHeaderSpec,
               found: &'a FileHeaderData) -> MatchError<'a> {
        MatchError {
            summary: s,
            expected: ex,
            found: found,
        }
    }

    pub fn format(&self) -> String {
        format!("MatchError: {:?}\nExpected: {:?}\nFound: {:?}\n",
               self.summary, self.expected, self.found)
    }
}

impl<'a> Error for MatchError<'a> {

    fn description(&self) -> &str {
        &self.summary[..]
    }

    fn cause(&self) -> Option<&Error> {
        None
    }

}

impl<'a> Debug for MatchError<'a> {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "{}", self.format());
        Ok(())
    }

}

impl<'a> Display for MatchError<'a> {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "{}", self.format());
        Ok(())
    }

}

pub fn match_header_spec<'a>(spec: &'a FileHeaderSpec, data: &'a FileHeaderData)
    -> Option<MatchError<'a>>
{
    debug!("Start matching:\n'{:?}'\non\n{:?}", spec, data);
    match (spec, data) {
        (&FileHeaderSpec::Null,     &FileHeaderData::Null)           => { }
        (&FileHeaderSpec::Bool,     &FileHeaderData::Bool(_))        => { }
        (&FileHeaderSpec::Integer,  &FileHeaderData::Integer(_))     => { }
        (&FileHeaderSpec::UInteger, &FileHeaderData::UInteger(_))    => { }
        (&FileHeaderSpec::Float,    &FileHeaderData::Float(_))       => { }
        (&FileHeaderSpec::Text,     &FileHeaderData::Text(_))        => { }

        (
            &FileHeaderSpec::Key{name: ref kname, value_type: ref vtype},
            &FileHeaderData::Key{name: ref n, value: ref val}
        ) => {
            debug!("Matching Key: '{:?}' == '{:?}', Value: '{:?}' == '{:?}'",
                    kname, n,
                    vtype, val);
            if kname != n {
                debug!("Keys not matching");
                unimplemented!();
            }
            return match_header_spec(&*vtype, &*val);
        }

        (
            &FileHeaderSpec::Map{keys: ref sks},
            &FileHeaderData::Map{keys: ref dks}
        ) => {
            debug!("Matching Map: '{:?}' == '{:?}'", sks, dks);

            for (s, d) in sks.iter().zip(dks.iter()) {
                let res = match_header_spec(s, d);
                if res.is_some() {
                    return res;
                }
            }
        }

        (
            &FileHeaderSpec::Array{allowed_types: ref vtypes},
            &FileHeaderData::Array{values: ref vs}
        ) => {
            debug!("Matching Array: '{:?}' == '{:?}'", vtypes, vs);
            for (t, v) in vtypes.iter().zip(vs.iter()) {
                let res = match_header_spec(t, v);
                if res.is_some() {
                    return res;
                }
            }
        }

        (k, v) => {
            return Some(MatchError::new(String::from("Expected type does not match found type"),
                                 k, v
                                 ))
        }
    }
    None
}

/*
 * Internal abstract view on a file. Does not exist on the FS and is just kept
 * internally until it is written to disk.
 */
pub struct File {
    header  : FileHeaderData,
    data    : String,
    id      : FileID,
}

impl File {

    pub fn new() -> File {
        File {
            header: FileHeaderData::Null,
            data: String::from(""),
            id: File::get_new_file_id(),
        }
    }

    pub fn from_parser_result(id: FileID, header: FileHeaderData, data: String) -> File {
        File {
            header: header,
            data: data,
            id: id,
        }
    }

    pub fn new_with_header(h: FileHeaderData) -> File {
        File {
            header: h,
            data: String::from(""),
            id: File::get_new_file_id(),
        }
    }

    pub fn new_with_data(d: String) -> File {
        File {
            header: FileHeaderData::Null,
            data: d,
            id: File::get_new_file_id(),
        }
    }

    pub fn new_with_content(h: FileHeaderData, d: String) -> File {
        File {
            header: h,
            data: d,
            id: File::get_new_file_id(),
        }
    }

    pub fn contents(&self) -> (FileHeaderData, String) {
        (self.header.clone(), self.data.clone())
    }

    pub fn id(&self) -> FileID {
        self.id.clone()
    }

    fn get_new_file_id() -> FileID {
        use uuid::Uuid;
        Uuid::new_v4().to_hyphenated_string()
    }
}

impl Debug for File {

    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "File[{:?}] header: '{:?}', data: '{:?}')",
            self.id, self.header, self.data)
    }
}

<commit_msg>Do debug output when creating a file object<commit_after>use std::error::Error;
use std::fmt::{Debug, Display, Formatter};
use std::fmt;

use super::parser::FileHeaderParser;
use storage::file_id::*;

#[derive(Debug)]
pub enum FileHeaderSpec {
    Null,
    Bool,
    Integer,
    UInteger,
    Float,
    Text,
    Key { name: &'static str, value_type: Box<FileHeaderSpec> },
    Map { keys: Vec<FileHeaderSpec> },
    Array { allowed_types: Vec<FileHeaderSpec> },
}

#[derive(Debug)]
#[derive(Clone)]
pub enum FileHeaderData {
    Null,
    Bool(bool),
    Integer(i64),
    UInteger(u64),
    Float(f64),
    Text(String),
    Key { name: String, value: Box<FileHeaderData> },
    Map { keys: Vec<FileHeaderData> },
    Array { values: Box<Vec<FileHeaderData>> },
}

impl Display for FileHeaderSpec {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        match self {
            &FileHeaderSpec::Null       => write!(fmt, "NULL"),
            &FileHeaderSpec::Bool       => write!(fmt, "Bool"),
            &FileHeaderSpec::Integer    => write!(fmt, "Integer"),
            &FileHeaderSpec::UInteger   => write!(fmt, "UInteger"),
            &FileHeaderSpec::Float      => write!(fmt, "Float"),
            &FileHeaderSpec::Text       => write!(fmt, "Text"),
            &FileHeaderSpec::Key{name: ref n, value_type: ref vt} => {
                write!(fmt, "Key({:?}) -> {:?}", n, vt)
            }
            &FileHeaderSpec::Map{keys: ref ks} => {
                write!(fmt, "Map -> {:?}", ks)
            }
            &FileHeaderSpec::Array{allowed_types: ref at}  => {
                write!(fmt, "Array({:?})", at)
            }
        }
    }

}

pub struct MatchError<'a> {
    summary: String,
    expected: &'a FileHeaderSpec,
    found: &'a FileHeaderData
}

impl<'a> MatchError<'a> {

    pub fn new(s: String,
               ex: &'a FileHeaderSpec,
               found: &'a FileHeaderData) -> MatchError<'a> {
        MatchError {
            summary: s,
            expected: ex,
            found: found,
        }
    }

    pub fn format(&self) -> String {
        format!("MatchError: {:?}\nExpected: {:?}\nFound: {:?}\n",
               self.summary, self.expected, self.found)
    }
}

impl<'a> Error for MatchError<'a> {

    fn description(&self) -> &str {
        &self.summary[..]
    }

    fn cause(&self) -> Option<&Error> {
        None
    }

}

impl<'a> Debug for MatchError<'a> {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "{}", self.format());
        Ok(())
    }

}

impl<'a> Display for MatchError<'a> {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "{}", self.format());
        Ok(())
    }

}

pub fn match_header_spec<'a>(spec: &'a FileHeaderSpec, data: &'a FileHeaderData)
    -> Option<MatchError<'a>>
{
    debug!("Start matching:\n'{:?}'\non\n{:?}", spec, data);
    match (spec, data) {
        (&FileHeaderSpec::Null,     &FileHeaderData::Null)           => { }
        (&FileHeaderSpec::Bool,     &FileHeaderData::Bool(_))        => { }
        (&FileHeaderSpec::Integer,  &FileHeaderData::Integer(_))     => { }
        (&FileHeaderSpec::UInteger, &FileHeaderData::UInteger(_))    => { }
        (&FileHeaderSpec::Float,    &FileHeaderData::Float(_))       => { }
        (&FileHeaderSpec::Text,     &FileHeaderData::Text(_))        => { }

        (
            &FileHeaderSpec::Key{name: ref kname, value_type: ref vtype},
            &FileHeaderData::Key{name: ref n, value: ref val}
        ) => {
            debug!("Matching Key: '{:?}' == '{:?}', Value: '{:?}' == '{:?}'",
                    kname, n,
                    vtype, val);
            if kname != n {
                debug!("Keys not matching");
                unimplemented!();
            }
            return match_header_spec(&*vtype, &*val);
        }

        (
            &FileHeaderSpec::Map{keys: ref sks},
            &FileHeaderData::Map{keys: ref dks}
        ) => {
            debug!("Matching Map: '{:?}' == '{:?}'", sks, dks);

            for (s, d) in sks.iter().zip(dks.iter()) {
                let res = match_header_spec(s, d);
                if res.is_some() {
                    return res;
                }
            }
        }

        (
            &FileHeaderSpec::Array{allowed_types: ref vtypes},
            &FileHeaderData::Array{values: ref vs}
        ) => {
            debug!("Matching Array: '{:?}' == '{:?}'", vtypes, vs);
            for (t, v) in vtypes.iter().zip(vs.iter()) {
                let res = match_header_spec(t, v);
                if res.is_some() {
                    return res;
                }
            }
        }

        (k, v) => {
            return Some(MatchError::new(String::from("Expected type does not match found type"),
                                 k, v
                                 ))
        }
    }
    None
}

/*
 * Internal abstract view on a file. Does not exist on the FS and is just kept
 * internally until it is written to disk.
 */
pub struct File {
    header  : FileHeaderData,
    data    : String,
    id      : FileID,
}

impl File {

    pub fn new() -> File {
        let f = File {
            header: FileHeaderData::Null,
            data: String::from(""),
            id: File::get_new_file_id(),
        };
        debug!("Create new File object: {:?}", f);
        f
    }

    pub fn from_parser_result(id: FileID, header: FileHeaderData, data: String) -> File {
        let f = File {
            header: header,
            data: data,
            id: id,
        };
        debug!("Create new File object from parser result: {:?}", f);
        f
    }

    pub fn new_with_header(h: FileHeaderData) -> File {
        let f = File {
            header: h,
            data: String::from(""),
            id: File::get_new_file_id(),
        };
        debug!("Create new File object with header: {:?}", f);
        f
    }

    pub fn new_with_data(d: String) -> File {
        let f = File {
            header: FileHeaderData::Null,
            data: d,
            id: File::get_new_file_id(),
        };
        debug!("Create new File object with data: {:?}", f);
        f
    }

    pub fn new_with_content(h: FileHeaderData, d: String) -> File {
        let f = File {
            header: h,
            data: d,
            id: File::get_new_file_id(),
        };
        debug!("Create new File object with content: {:?}", f);
        f
    }

    pub fn contents(&self) -> (FileHeaderData, String) {
        (self.header.clone(), self.data.clone())
    }

    pub fn id(&self) -> FileID {
        self.id.clone()
    }

    fn get_new_file_id() -> FileID {
        use uuid::Uuid;
        Uuid::new_v4().to_hyphenated_string()
    }
}

impl Debug for File {

    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "File[{:?}] header: '{:?}', data: '{:?}')",
            self.id, self.header, self.data)
    }
}

<|endoftext|>


<commit_before>//! The generic implementation of a "handle" proxy object used throughout wlroots-rs.

use std::{clone::Clone, cell::Cell, fmt, rc::Weak, hash::{Hash, Hasher}, ptr,
          panic, marker::PhantomData};

use errors::{HandleErr, HandleResult};

/// A non-owned reference counted handle to a resource.
///
/// The resource could be destroyed at any time, it depends on the resource.
///
/// For example an output is destroyed when it's physical output is "disconnected"
/// on DRM. "disconnected" depends on the output (e.g. sometimes turning it off counts
/// as "disconnected").
/// However, when the backend is instead headless an output lives until it is
/// destroyed explicitly by the library user.
///
/// Some resources are completely controlled by the user. For example although
/// you refer to a `Seat` with handles it is only destroyed when you call the
/// special destroy method on the seat handle.
///
/// Please refer to the specific resource documentation for a description of
/// the lifetime particular to that resource.
pub struct Handle<D: Clone, T, W: Handleable<D, T> + Sized> {
    pub(crate) ptr: *mut T,
    pub(crate) handle: Weak<Cell<bool>>,
    pub(crate) _marker: PhantomData<W>,
    pub(crate) data: D
}

pub trait Handleable<D: Clone, T> {
    /// Constructs the resource manager from a raw pointer of the resource
    /// this handleable manages. **This should increment the reference count**.
    ///
    /// # Safety
    /// The pointer must be valid and must already have been set up by wlroots-rs
    /// internal mechanisms. If you have to ask, it probably isn't.
    #[doc(hidden)]
    unsafe fn from_ptr(resource_ptr: *mut T) -> Self where Self: Sized;

    /// Gets the pointer to the resource this object manages.
    #[doc(hidden)]
    unsafe fn as_ptr(&self) -> *mut T;

    /// Gets the resource from the handle.
    ///
    /// This is used internally to upgrade a handle, and should not be used.
    /// Thus the documentation is hidden and it's marked `unsafe`.
    ///
    /// If you _need_ to use this, use `Handle::upgrade` instead.
    #[doc(hidden)]
    unsafe fn from_handle(&Handle<D, T, Self>) -> HandleResult<Self> where Self: Sized;

    /// Creates a weak reference to the resource.
    fn weak_reference(&self) -> Handle<D, T, Self> where Self: Sized;
}

impl <D: Clone, T, W: Handleable<D, T>> Clone for Handle<D, T, W> {
    fn clone(&self) -> Self {
        Handle { ptr: self.ptr,
                 handle: self.handle.clone(),
                 _marker: PhantomData,
                 data: self.data.clone()
        }
    }
}

impl <D: Clone, T, W: Handleable<D, T>> fmt::Debug for Handle<D, T, W> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Handle with pointer: {:p}", self.ptr)
    }
}

impl <D: Clone, T, W: Handleable<D, T>> Hash for Handle<D, T, W> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.ptr.hash(state);
    }
}

impl <D: Clone, T, W: Handleable<D, T>> PartialEq for Handle<D, T, W> {
    fn eq(&self, other: &Handle<D, T, W>) -> bool {
        self.ptr == other.ptr
    }
}

impl <D: Clone, T, W: Handleable<D, T>> Eq for Handle<D, T, W> {}

impl <D: Default + Clone, T, W: Handleable<D, T>> Default for Handle<D, T, W> {
    /// Constructs a new handle that is always invalid. Calling `run` on this
    /// will always fail.
    ///
    /// This is useful for pre-filling a value before it's provided by the server, or
    /// for mocking/testing.
    fn default() -> Self {
        Handle { ptr: ptr::null_mut(),
                 handle: Weak::new(),
                 _marker: PhantomData,
                 data: D::default() }
    }
}

impl <D: Clone, T, W: Handleable<D, T>> Handle<D, T, W> {
    /// Creates an output::Handle from the raw pointer, using the saved
    /// user data to recreate the memory model.
    ///
    /// # Panics
    /// This function is allowed to panic when attempting to upgrade the handle.
    #[allow(dead_code)]
    pub(crate) unsafe fn from_ptr(ptr: *mut T) -> Handle<D, T, W> {
        let wrapped_resource = W::from_ptr(ptr);
        wrapped_resource.weak_reference()
    }

    /// Get the pointer to the resource this manages.
    ///
    /// # Safety
    /// There's no guarantees that this pointer is not dangling.
    #[doc(hidden)]
    pub unsafe fn as_ptr(&self) -> *mut T {
        self.ptr
    }

    /// Run a function with a reference to the resource if it's still alive.
    ///
    /// Returns the result of the function, if successful.
    ///
    /// # Safety
    /// By enforcing a rather harsh limit on the lifetime of the resource
    /// to a short lived scope of an anonymous function,
    /// this function ensures the resource does not live longer
    /// than it exists.
    ///
    /// # Panics
    /// This function will panic if multiple mutable borrows are detected.
    /// This will happen if you call `upgrade` directly within this callback,
    /// or if a handle to the same resource was upgraded some where else up the stack.
    pub fn run<F, R>(&self, runner: F) -> HandleResult<R>
        where F: FnOnce(&mut W) -> R
    {
        let mut wrapped_obj = unsafe { self.upgrade()? };
        // We catch panics here to deal with an extreme edge case.
        //
        // If the library user catches panics from the `run` function then their
        // resource used flag will still be set to `true` when it should be set
        // to `false`.
        let res = panic::catch_unwind(panic::AssertUnwindSafe(|| runner(&mut wrapped_obj)));
        self.handle.upgrade().map(|check| {
            // Sanity check that it hasn't been tampered with. If so, we should just panic.
            // If we are currently panicking this will abort.
            if !check.get() {
                wlr_log!(WLR_ERROR, "After running callback, mutable lock was false");
                panic!("Lock in incorrect state!");
            }
            check.set(false);
        });
        match res {
            Ok(res) => Ok(res),
            Err(err) => panic::resume_unwind(err)
        }
    }

    /// Upgrades a handle to a reference to the backing object.
    ///
    /// # Safety
    /// This returns an "owned" value when really you don't own it all.
    /// Depending on the type, it's possible that the resource will be freed
    /// once this returned value is dropped, causing a possible double free.
    /// Potentially it instead is just unbound, it depends on the resource.
    ///
    /// Regardless, you should not use this interface. Use the `run` method.
    #[doc(hidden)]
    pub unsafe fn upgrade(&self) -> HandleResult<W> {
        self.handle.upgrade()
            .ok_or(HandleErr::AlreadyDropped)
            // NOTE
            // We drop the Rc here because having two would allow a dangling
            // pointer to exist!
            .and_then(|check| {
                let wrapper_obj = W::from_handle(self)?;
                if check.get() {
                    return Err(HandleErr::AlreadyDropped)
                }
                check.set(true);
                Ok(wrapper_obj)
            })

    }
}
<commit_msg>Check before we try to reconstruct the object<commit_after>//! The generic implementation of a "handle" proxy object used throughout wlroots-rs.

use std::{clone::Clone, cell::Cell, fmt, rc::Weak, hash::{Hash, Hasher}, ptr,
          panic, marker::PhantomData};

use errors::{HandleErr, HandleResult};

/// A non-owned reference counted handle to a resource.
///
/// The resource could be destroyed at any time, it depends on the resource.
///
/// For example an output is destroyed when it's physical output is "disconnected"
/// on DRM. "disconnected" depends on the output (e.g. sometimes turning it off counts
/// as "disconnected").
/// However, when the backend is instead headless an output lives until it is
/// destroyed explicitly by the library user.
///
/// Some resources are completely controlled by the user. For example although
/// you refer to a `Seat` with handles it is only destroyed when you call the
/// special destroy method on the seat handle.
///
/// Please refer to the specific resource documentation for a description of
/// the lifetime particular to that resource.
pub struct Handle<D: Clone, T, W: Handleable<D, T> + Sized> {
    pub(crate) ptr: *mut T,
    pub(crate) handle: Weak<Cell<bool>>,
    pub(crate) _marker: PhantomData<W>,
    pub(crate) data: D
}

pub trait Handleable<D: Clone, T> {
    /// Constructs the resource manager from a raw pointer of the resource
    /// this handleable manages. **This should increment the reference count**.
    ///
    /// # Safety
    /// The pointer must be valid and must already have been set up by wlroots-rs
    /// internal mechanisms. If you have to ask, it probably isn't.
    #[doc(hidden)]
    unsafe fn from_ptr(resource_ptr: *mut T) -> Self where Self: Sized;

    /// Gets the pointer to the resource this object manages.
    #[doc(hidden)]
    unsafe fn as_ptr(&self) -> *mut T;

    /// Gets the resource from the handle.
    ///
    /// This is used internally to upgrade a handle, and should not be used.
    /// Thus the documentation is hidden and it's marked `unsafe`.
    ///
    /// If you _need_ to use this, use `Handle::upgrade` instead.
    #[doc(hidden)]
    unsafe fn from_handle(&Handle<D, T, Self>) -> HandleResult<Self> where Self: Sized;

    /// Creates a weak reference to the resource.
    fn weak_reference(&self) -> Handle<D, T, Self> where Self: Sized;
}

impl <D: Clone, T, W: Handleable<D, T>> Clone for Handle<D, T, W> {
    fn clone(&self) -> Self {
        Handle { ptr: self.ptr,
                 handle: self.handle.clone(),
                 _marker: PhantomData,
                 data: self.data.clone()
        }
    }
}

impl <D: Clone, T, W: Handleable<D, T>> fmt::Debug for Handle<D, T, W> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Handle with pointer: {:p}", self.ptr)
    }
}

impl <D: Clone, T, W: Handleable<D, T>> Hash for Handle<D, T, W> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.ptr.hash(state);
    }
}

impl <D: Clone, T, W: Handleable<D, T>> PartialEq for Handle<D, T, W> {
    fn eq(&self, other: &Handle<D, T, W>) -> bool {
        self.ptr == other.ptr
    }
}

impl <D: Clone, T, W: Handleable<D, T>> Eq for Handle<D, T, W> {}

impl <D: Default + Clone, T, W: Handleable<D, T>> Default for Handle<D, T, W> {
    /// Constructs a new handle that is always invalid. Calling `run` on this
    /// will always fail.
    ///
    /// This is useful for pre-filling a value before it's provided by the server, or
    /// for mocking/testing.
    fn default() -> Self {
        Handle { ptr: ptr::null_mut(),
                 handle: Weak::new(),
                 _marker: PhantomData,
                 data: D::default() }
    }
}

impl <D: Clone, T, W: Handleable<D, T>> Handle<D, T, W> {
    /// Creates an output::Handle from the raw pointer, using the saved
    /// user data to recreate the memory model.
    ///
    /// # Panics
    /// This function is allowed to panic when attempting to upgrade the handle.
    #[allow(dead_code)]
    pub(crate) unsafe fn from_ptr(ptr: *mut T) -> Handle<D, T, W> {
        let wrapped_resource = W::from_ptr(ptr);
        wrapped_resource.weak_reference()
    }

    /// Get the pointer to the resource this manages.
    ///
    /// # Safety
    /// There's no guarantees that this pointer is not dangling.
    #[doc(hidden)]
    pub unsafe fn as_ptr(&self) -> *mut T {
        self.ptr
    }

    /// Run a function with a reference to the resource if it's still alive.
    ///
    /// Returns the result of the function, if successful.
    ///
    /// # Safety
    /// By enforcing a rather harsh limit on the lifetime of the resource
    /// to a short lived scope of an anonymous function,
    /// this function ensures the resource does not live longer
    /// than it exists.
    ///
    /// # Panics
    /// This function will panic if multiple mutable borrows are detected.
    /// This will happen if you call `upgrade` directly within this callback,
    /// or if a handle to the same resource was upgraded some where else up the stack.
    pub fn run<F, R>(&self, runner: F) -> HandleResult<R>
        where F: FnOnce(&mut W) -> R
    {
        let mut wrapped_obj = unsafe { self.upgrade()? };
        // We catch panics here to deal with an extreme edge case.
        //
        // If the library user catches panics from the `run` function then their
        // resource used flag will still be set to `true` when it should be set
        // to `false`.
        let res = panic::catch_unwind(panic::AssertUnwindSafe(|| runner(&mut wrapped_obj)));
        self.handle.upgrade().map(|check| {
            // Sanity check that it hasn't been tampered with. If so, we should just panic.
            // If we are currently panicking this will abort.
            if !check.get() {
                wlr_log!(WLR_ERROR, "After running callback, mutable lock was false");
                panic!("Lock in incorrect state!");
            }
            check.set(false);
        });
        match res {
            Ok(res) => Ok(res),
            Err(err) => panic::resume_unwind(err)
        }
    }

    /// Upgrades a handle to a reference to the backing object.
    ///
    /// # Safety
    /// This returns an "owned" value when really you don't own it all.
    /// Depending on the type, it's possible that the resource will be freed
    /// once this returned value is dropped, causing a possible double free.
    /// Potentially it instead is just unbound, it depends on the resource.
    ///
    /// Regardless, you should not use this interface. Use the `run` method.
    #[doc(hidden)]
    pub unsafe fn upgrade(&self) -> HandleResult<W> {
        self.handle.upgrade()
            .ok_or(HandleErr::AlreadyDropped)
            // NOTE
            // We drop the Rc here because having two would allow a dangling
            // pointer to exist!
            .and_then(|check| {
                if check.get() {
                    return Err(HandleErr::AlreadyDropped)
                }
                let wrapper_obj = W::from_handle(self)?;
                check.set(true);
                Ok(wrapper_obj)
            })

    }
}
<|endoftext|>