<commit_before>// NOTE need to store the drawable in lua, because it's a reference to a drawable a lua object

use std::default::Default;
use std::fmt::{self, Display, Formatter};
use std::rc::Rc;
use rustwlc::{Geometry, Point, Size};
use rlua::{self, Table, Lua, UserData, ToLua, Value};
use super::drawable::Drawable;
use super::property::Property;

use super::class::{self, Class, ClassBuilder};
use super::object::{Object, Objectable, ObjectBuilder};

#[derive(Clone, Debug)]
pub struct DrawinState {
    // Note that the drawable is stored in Lua.
    // TODO WINDOW_OBJECT_HEADER??
    ontop: bool,
    visible: bool,
    cursor: String,
    geometry: Geometry,
    geometry_dirty: bool
}

#[derive(Clone, Debug)]
pub struct Drawin<'lua>(Table<'lua>);

impl UserData for DrawinState {}

impl Default for DrawinState {
    fn default() -> Self {
        DrawinState {
            ontop: false,
            visible: false,
            cursor: String::default(),
            geometry: Geometry::zero(),
            geometry_dirty: false
        }
    }
}

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

impl <'lua> Drawin<'lua> {
    fn new(lua: &Lua) -> rlua::Result<Object> {
        let class = class::class_setup(lua, "drawin")?;
        Ok(object_setup(lua, Drawin::allocate(lua, class)?)?.build())
    }

    fn update_drawing(&mut self) -> rlua::Result<()> {
        let state = self.state()?;
        let table = &self.0;
        let mut drawable = Drawable::cast(table.get::<_, Table>("drawable")?.into())?;
        drawable.set_geometry(state.geometry)?;
        table.raw_set::<_, Table>("drawable", drawable.get_table())?;
        Ok(())
    }

    fn get_visible(&mut self) -> rlua::Result<bool> {
        let drawin = self.state()?;
        Ok(drawin.visible)
    }

    fn set_visible(&mut self, val: bool) -> rlua::Result<()> {
        let mut drawin = self.state()?;
        drawin.visible = val;
        self.map()?;
        self.set_state(drawin)
    }

    fn map(&mut self) -> rlua::Result<()> {
        // TODO other things
        self.update_drawing()
    }

    fn get_geometry(&self) -> rlua::Result<Geometry> {
        Ok(self.state()?.geometry)
    }

    fn resize(&mut self, geometry: Geometry) -> rlua::Result<()> {
        let mut state = self.state()?;
        let old_geometry = state.geometry;
        state.geometry = geometry;
        if state.geometry.size.w <= 0 {
            state.geometry.size.w = old_geometry.size.w;
        }
        if state.geometry.size.h <= 0 {
            state.geometry.size.h = old_geometry.size.h
        }
        state.geometry_dirty = true;
        self.update_drawing()?;
        // TODO emit signals
        // TODO update screen workareas like in awesome? Might not be necessary
        self.set_state(state)
    }
}

impl <'lua> ToLua<'lua> for Drawin<'lua> {
    fn to_lua(self, lua: &'lua Lua) -> rlua::Result<Value<'lua>> {
        self.0.to_lua(lua)
    }
}

impl_objectable!(Drawin, DrawinState);

pub fn init(lua: &Lua) -> rlua::Result<Class> {
    property_setup(lua, method_setup(lua, Class::builder(lua, Some(Rc::new(Drawin::new)), None, None)?)?)?
        .save_class("drawin")?
        .build()
}

fn method_setup<'lua>(lua: &'lua Lua, builder: ClassBuilder<'lua>) -> rlua::Result<ClassBuilder<'lua>> {
    // TODO Do properly
    use super::dummy;
    builder.method("connect_signal".into(), lua.create_function(dummy))?
           .method("__call".into(), lua.create_function(|lua, _: Value| Drawin::new(lua)))
}

fn property_setup<'lua>(lua: &'lua Lua, builder: ClassBuilder<'lua>) -> rlua::Result<ClassBuilder<'lua>> {
    builder
        .property(Property::new("visible".into(),
                                Some(lua.create_function(set_visible)),
                                Some(lua.create_function(get_visible)),
                                Some(lua.create_function(set_visible))))
}

fn object_setup<'lua>(lua: &'lua Lua, builder: ObjectBuilder<'lua>) -> rlua::Result<ObjectBuilder<'lua>> {
    // TODO Do properly
    let table = lua.create_table();
    let drawable_table = Drawable::new(lua)?.to_lua(lua)?;
    table.set("drawable", drawable_table)?;
    table.set("geometry", lua.create_function(drawin_geometry))?;
    builder.add_to_meta(table)
}

fn set_visible<'lua>(_: &'lua Lua, (table, visible): (Table<'lua>, bool))
                     -> rlua::Result<()> {
    let mut drawin = Drawin::cast(table.into())?;
    drawin.set_visible(visible)
    // TODO signal
}

fn get_visible<'lua>(_: &'lua Lua, table: Table<'lua>) -> rlua::Result<bool> {
    let mut drawin = Drawin::cast(table.into())?;
    drawin.get_visible()
    // TODO signal
}

fn drawin_geometry<'lua>(lua: &'lua Lua, (drawin, geometry): (Table<'lua>, Table<'lua>)) -> rlua::Result<Table<'lua>> {
    let mut drawin = Drawin::cast(drawin.into())?;
    let w = geometry.get::<_, i32>("width")?;
    let h = geometry.get::<_, i32>("height")?;
    let x = geometry.get::<_, i32>("x")?;
    let y = geometry.get::<_, i32>("y")?;
    if x > 0 && y > 0 {
        let geo = Geometry {
            origin: Point { x, y },
            size: Size { w: w as u32, h: h as u32 }
        };
        drawin.resize(geo)?;
    }
    let new_geo = drawin.get_geometry()?;
    let Size { w, h } = new_geo.size;
    let Point { x, y } = new_geo.origin;
    let res = lua.create_table();
    res.set("x", x)?;
    res.set("y", y)?;
    res.set("height", h)?;
    res.set("width", w)?;
    Ok(res)
}
<commit_msg>Made note about changing drawin new<commit_after>// NOTE need to store the drawable in lua, because it's a reference to a drawable a lua object

use std::default::Default;
use std::fmt::{self, Display, Formatter};
use std::rc::Rc;
use rustwlc::{Geometry, Point, Size};
use rlua::{self, Table, Lua, UserData, ToLua, Value};
use super::drawable::Drawable;
use super::property::Property;

use super::class::{self, Class, ClassBuilder};
use super::object::{Object, Objectable, ObjectBuilder};

#[derive(Clone, Debug)]
pub struct DrawinState {
    // Note that the drawable is stored in Lua.
    // TODO WINDOW_OBJECT_HEADER??
    ontop: bool,
    visible: bool,
    cursor: String,
    geometry: Geometry,
    geometry_dirty: bool
}

#[derive(Clone, Debug)]
pub struct Drawin<'lua>(Table<'lua>);

impl UserData for DrawinState {}

impl Default for DrawinState {
    fn default() -> Self {
        DrawinState {
            ontop: false,
            visible: false,
            cursor: String::default(),
            geometry: Geometry::zero(),
            geometry_dirty: false
        }
    }
}

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

impl <'lua> Drawin<'lua> {
    fn new(lua: &Lua) -> rlua::Result<Object> {
        let class = class::class_setup(lua, "drawin")?;
        Ok(object_setup(lua, Drawin::allocate(lua, class)?)?.build())
    }

    fn update_drawing(&mut self) -> rlua::Result<()> {
        let state = self.state()?;
        let table = &self.0;
        let mut drawable = Drawable::cast(table.get::<_, Table>("drawable")?.into())?;
        drawable.set_geometry(state.geometry)?;
        table.raw_set::<_, Table>("drawable", drawable.get_table())?;
        Ok(())
    }

    fn get_visible(&mut self) -> rlua::Result<bool> {
        let drawin = self.state()?;
        Ok(drawin.visible)
    }

    fn set_visible(&mut self, val: bool) -> rlua::Result<()> {
        let mut drawin = self.state()?;
        drawin.visible = val;
        self.map()?;
        self.set_state(drawin)
    }

    fn map(&mut self) -> rlua::Result<()> {
        // TODO other things
        self.update_drawing()
    }

    fn get_geometry(&self) -> rlua::Result<Geometry> {
        Ok(self.state()?.geometry)
    }

    fn resize(&mut self, geometry: Geometry) -> rlua::Result<()> {
        let mut state = self.state()?;
        let old_geometry = state.geometry;
        state.geometry = geometry;
        if state.geometry.size.w <= 0 {
            state.geometry.size.w = old_geometry.size.w;
        }
        if state.geometry.size.h <= 0 {
            state.geometry.size.h = old_geometry.size.h
        }
        state.geometry_dirty = true;
        self.update_drawing()?;
        // TODO emit signals
        // TODO update screen workareas like in awesome? Might not be necessary
        self.set_state(state)
    }
}

impl <'lua> ToLua<'lua> for Drawin<'lua> {
    fn to_lua(self, lua: &'lua Lua) -> rlua::Result<Value<'lua>> {
        self.0.to_lua(lua)
    }
}

impl_objectable!(Drawin, DrawinState);

pub fn init(lua: &Lua) -> rlua::Result<Class> {
    property_setup(lua, method_setup(lua, Class::builder(lua, Some(Rc::new(Drawin::new)), None, None)?)?)?
        .save_class("drawin")?
        .build()
}

fn method_setup<'lua>(lua: &'lua Lua, builder: ClassBuilder<'lua>) -> rlua::Result<ClassBuilder<'lua>> {
    // TODO Do properly
    use super::dummy;
    builder.method("connect_signal".into(), lua.create_function(dummy))?
            // TODO This should be adding properties, e.g like luaA_class_new
           .method("__call".into(), lua.create_function(|lua, _: Value| Drawin::new(lua)))
}

fn property_setup<'lua>(lua: &'lua Lua, builder: ClassBuilder<'lua>) -> rlua::Result<ClassBuilder<'lua>> {
    builder
        .property(Property::new("visible".into(),
                                Some(lua.create_function(set_visible)),
                                Some(lua.create_function(get_visible)),
                                Some(lua.create_function(set_visible))))
}

fn object_setup<'lua>(lua: &'lua Lua, builder: ObjectBuilder<'lua>) -> rlua::Result<ObjectBuilder<'lua>> {
    // TODO Do properly
    let table = lua.create_table();
    let drawable_table = Drawable::new(lua)?.to_lua(lua)?;
    table.set("drawable", drawable_table)?;
    table.set("geometry", lua.create_function(drawin_geometry))?;
    builder.add_to_meta(table)
}

fn set_visible<'lua>(_: &'lua Lua, (table, visible): (Table<'lua>, bool))
                     -> rlua::Result<()> {
    let mut drawin = Drawin::cast(table.into())?;
    drawin.set_visible(visible)
    // TODO signal
}

fn get_visible<'lua>(_: &'lua Lua, table: Table<'lua>) -> rlua::Result<bool> {
    let mut drawin = Drawin::cast(table.into())?;
    drawin.get_visible()
    // TODO signal
}

fn drawin_geometry<'lua>(lua: &'lua Lua, (drawin, geometry): (Table<'lua>, Table<'lua>)) -> rlua::Result<Table<'lua>> {
    let mut drawin = Drawin::cast(drawin.into())?;
    let w = geometry.get::<_, i32>("width")?;
    let h = geometry.get::<_, i32>("height")?;
    let x = geometry.get::<_, i32>("x")?;
    let y = geometry.get::<_, i32>("y")?;
    if x > 0 && y > 0 {
        let geo = Geometry {
            origin: Point { x, y },
            size: Size { w: w as u32, h: h as u32 }
        };
        drawin.resize(geo)?;
    }
    let new_geo = drawin.get_geometry()?;
    let Size { w, h } = new_geo.size;
    let Point { x, y } = new_geo.origin;
    let res = lua.create_table();
    res.set("x", x)?;
    res.set("y", y)?;
    res.set("height", h)?;
    res.set("width", w)?;
    Ok(res)
}
<|endoftext|>


<commit_before>//! "Dummy" environment for testing wasm translation.

use cranelift_codegen::cursor::FuncCursor;
use cranelift_codegen::ir::immediates::Imm64;
use cranelift_codegen::ir::types::*;
use cranelift_codegen::ir::{self, InstBuilder};
use cranelift_codegen::settings;
use cranelift_entity::{EntityRef, PrimaryMap};
use environ::{FuncEnvironment, GlobalVariable, ModuleEnvironment, WasmResult};
use func_translator::FuncTranslator;
use std::string::String;
use std::vec::Vec;
use target_lexicon::Triple;
use translation_utils::{
    DefinedFuncIndex, FuncIndex, Global, GlobalIndex, Memory, MemoryIndex, SignatureIndex, Table,
    TableIndex,
};
use wasmparser;

/// Compute a `ir::ExternalName` for a given wasm function index.
fn get_func_name(func_index: FuncIndex) -> ir::ExternalName {
    ir::ExternalName::user(0, func_index.index() as u32)
}

/// A collection of names under which a given entity is exported.
pub struct Exportable<T> {
    /// A wasm entity.
    pub entity: T,

    /// Names under which the entity is exported.
    pub export_names: Vec<String>,
}

impl<T> Exportable<T> {
    pub fn new(entity: T) -> Self {
        Self {
            entity,
            export_names: Vec::new(),
        }
    }
}

/// The main state belonging to a `DummyEnvironment`. This is split out from
/// `DummyEnvironment` to allow it to be borrowed separately from the
/// `FuncTranslator` field.
pub struct DummyModuleInfo {
    /// Target description.
    pub triple: Triple,

    /// Compilation setting flags.
    pub flags: settings::Flags,

    /// Signatures as provided by `declare_signature`.
    pub signatures: Vec<ir::Signature>,

    /// Module and field names of imported functions as provided by `declare_func_import`.
    pub imported_funcs: Vec<(String, String)>,

    /// Functions, imported and local.
    pub functions: PrimaryMap<FuncIndex, Exportable<SignatureIndex>>,

    /// Function bodies.
    pub function_bodies: PrimaryMap<DefinedFuncIndex, ir::Function>,

    /// Tables as provided by `declare_table`.
    pub tables: Vec<Exportable<Table>>,

    /// Memories as provided by `declare_memory`.
    pub memories: Vec<Exportable<Memory>>,

    /// Globals as provided by `declare_global`.
    pub globals: Vec<Exportable<Global>>,

    /// The start function.
    pub start_func: Option<FuncIndex>,
}

impl DummyModuleInfo {
    /// Allocates the data structures with the given flags.
    pub fn with_triple_flags(triple: Triple, flags: settings::Flags) -> Self {
        Self {
            triple,
            flags,
            signatures: Vec::new(),
            imported_funcs: Vec::new(),
            functions: PrimaryMap::new(),
            function_bodies: PrimaryMap::new(),
            tables: Vec::new(),
            memories: Vec::new(),
            globals: Vec::new(),
            start_func: None,
        }
    }
}

/// This `ModuleEnvironment` implementation is a "naïve" one, doing essentially nothing and
/// emitting placeholders when forced to. Don't try to execute code translated for this
/// environment, essentially here for translation debug purposes.
pub struct DummyEnvironment {
    /// Module information.
    pub info: DummyModuleInfo,

    /// Function translation.
    trans: FuncTranslator,

    /// Vector of wasm bytecode size for each function.
    pub func_bytecode_sizes: Vec<usize>,
}

impl DummyEnvironment {
    /// Allocates the data structures with default flags.
    pub fn with_triple(triple: Triple) -> Self {
        Self::with_triple_flags(triple, settings::Flags::new(settings::builder()))
    }

    /// Allocates the data structures with the given flags.
    pub fn with_triple_flags(triple: Triple, flags: settings::Flags) -> Self {
        Self {
            info: DummyModuleInfo::with_triple_flags(triple, flags),
            trans: FuncTranslator::new(),
            func_bytecode_sizes: Vec::new(),
        }
    }

    /// Return a `DummyFuncEnvironment` for translating functions within this
    /// `DummyEnvironment`.
    pub fn func_env(&self) -> DummyFuncEnvironment {
        DummyFuncEnvironment::new(&self.info)
    }
}

/// The `FuncEnvironment` implementation for use by the `DummyEnvironment`.
pub struct DummyFuncEnvironment<'dummy_environment> {
    pub mod_info: &'dummy_environment DummyModuleInfo,
}

impl<'dummy_environment> DummyFuncEnvironment<'dummy_environment> {
    pub fn new(mod_info: &'dummy_environment DummyModuleInfo) -> Self {
        Self { mod_info }
    }

    // Create a signature for `sigidx` amended with a `vmctx` argument after the standard wasm
    // arguments.
    fn vmctx_sig(&self, sigidx: SignatureIndex) -> ir::Signature {
        let mut sig = self.mod_info.signatures[sigidx].clone();
        sig.params.push(ir::AbiParam::special(
            self.pointer_type(),
            ir::ArgumentPurpose::VMContext,
        ));
        sig
    }
}

impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environment> {
    fn triple(&self) -> &Triple {
        &self.mod_info.triple
    }

    fn flags(&self) -> &settings::Flags {
        &self.mod_info.flags
    }

    fn make_global(&mut self, func: &mut ir::Function, index: GlobalIndex) -> GlobalVariable {
        // Just create a dummy `vmctx` global.
        let offset = ((index * 8) as i32 + 8).into();
        let gv = func.create_global_value(ir::GlobalValueData::VMContext { offset });
        GlobalVariable::Memory {
            gv,
            ty: self.mod_info.globals[index].entity.ty,
        }
    }

    fn make_heap(&mut self, func: &mut ir::Function, _index: MemoryIndex) -> ir::Heap {
        // Create a static heap whose base address is stored at `vmctx+0`.
        let addr = func.create_global_value(ir::GlobalValueData::VMContext { offset: 0.into() });
        let gv = func.create_global_value(ir::GlobalValueData::Deref {
            base: addr,
            offset: 0.into(),
        });

        func.create_heap(ir::HeapData {
            base: gv,
            min_size: 0.into(),
            guard_size: 0x8000_0000.into(),
            style: ir::HeapStyle::Static {
                bound: 0x1_0000_0000.into(),
            },
        })
    }

    fn make_table(&mut self, func: &mut ir::Function, _index: TableIndex) -> ir::Table {
        // Create a table whose base address is stored at `vmctx+0`.
        let base_gv_addr =
            func.create_global_value(ir::GlobalValueData::VMContext { offset: 0.into() });
        let base_gv = func.create_global_value(ir::GlobalValueData::Deref {
            base: base_gv_addr,
            offset: 0.into(),
        });
        let bound_gv_addr =
            func.create_global_value(ir::GlobalValueData::VMContext { offset: 0.into() });
        let bound_gv = func.create_global_value(ir::GlobalValueData::Deref {
            base: bound_gv_addr,
            offset: 0.into(),
        });

        func.create_table(ir::TableData {
            base_gv,
            min_size: Imm64::new(0),
            bound_gv,
            element_size: Imm64::new(i64::from(self.pointer_bytes()) * 2),
        })
    }

    fn make_indirect_sig(&mut self, func: &mut ir::Function, index: SignatureIndex) -> ir::SigRef {
        // A real implementation would probably change the calling convention and add `vmctx` and
        // signature index arguments.
        func.import_signature(self.vmctx_sig(index))
    }

    fn make_direct_func(&mut self, func: &mut ir::Function, index: FuncIndex) -> ir::FuncRef {
        let sigidx = self.mod_info.functions[index].entity;
        // A real implementation would probably add a `vmctx` argument.
        // And maybe attempt some signature de-duplication.
        let signature = func.import_signature(self.vmctx_sig(sigidx));
        let name = get_func_name(index);
        func.import_function(ir::ExtFuncData {
            name,
            signature,
            colocated: false,
        })
    }

    fn translate_call_indirect(
        &mut self,
        mut pos: FuncCursor,
        _table_index: TableIndex,
        _table: ir::Table,
        _sig_index: SignatureIndex,
        sig_ref: ir::SigRef,
        callee: ir::Value,
        call_args: &[ir::Value],
    ) -> WasmResult<ir::Inst> {
        // Pass the current function's vmctx parameter on to the callee.
        let vmctx = pos
            .func
            .special_param(ir::ArgumentPurpose::VMContext)
            .expect("Missing vmctx parameter");

        // The `callee` value is an index into a table of function pointers.
        // Apparently, that table is stored at absolute address 0 in this dummy environment.
        // TODO: Generate bounds checking code.
        let ptr = self.pointer_type();
        let callee_offset = if ptr == I32 {
            pos.ins().imul_imm(callee, 4)
        } else {
            let ext = pos.ins().uextend(I64, callee);
            pos.ins().imul_imm(ext, 4)
        };
        let mut mflags = ir::MemFlags::new();
        mflags.set_notrap();
        mflags.set_aligned();
        let func_ptr = pos.ins().load(ptr, mflags, callee_offset, 0);

        // Build a value list for the indirect call instruction containing the callee, call_args,
        // and the vmctx parameter.
        let mut args = ir::ValueList::default();
        args.push(func_ptr, &mut pos.func.dfg.value_lists);
        args.extend(call_args.iter().cloned(), &mut pos.func.dfg.value_lists);
        args.push(vmctx, &mut pos.func.dfg.value_lists);

        Ok(pos
            .ins()
            .CallIndirect(ir::Opcode::CallIndirect, VOID, sig_ref, args)
            .0)
    }

    fn translate_call(
        &mut self,
        mut pos: FuncCursor,
        _callee_index: FuncIndex,
        callee: ir::FuncRef,
        call_args: &[ir::Value],
    ) -> WasmResult<ir::Inst> {
        // Pass the current function's vmctx parameter on to the callee.
        let vmctx = pos
            .func
            .special_param(ir::ArgumentPurpose::VMContext)
            .expect("Missing vmctx parameter");

        // Build a value list for the call instruction containing the call_args and the vmctx
        // parameter.
        let mut args = ir::ValueList::default();
        args.extend(call_args.iter().cloned(), &mut pos.func.dfg.value_lists);
        args.push(vmctx, &mut pos.func.dfg.value_lists);

        Ok(pos.ins().Call(ir::Opcode::Call, VOID, callee, args).0)
    }

    fn translate_memory_grow(
        &mut self,
        mut pos: FuncCursor,
        _index: MemoryIndex,
        _heap: ir::Heap,
        _val: ir::Value,
    ) -> WasmResult<ir::Value> {
        Ok(pos.ins().iconst(I32, -1))
    }

    fn translate_memory_size(
        &mut self,
        mut pos: FuncCursor,
        _index: MemoryIndex,
        _heap: ir::Heap,
    ) -> WasmResult<ir::Value> {
        Ok(pos.ins().iconst(I32, -1))
    }
}

impl<'data> ModuleEnvironment<'data> for DummyEnvironment {
    fn flags(&self) -> &settings::Flags {
        &self.info.flags
    }

    fn get_func_name(&self, func_index: FuncIndex) -> ir::ExternalName {
        get_func_name(func_index)
    }

    fn declare_signature(&mut self, sig: &ir::Signature) {
        self.info.signatures.push(sig.clone());
    }

    fn get_signature(&self, sig_index: SignatureIndex) -> &ir::Signature {
        &self.info.signatures[sig_index]
    }

    fn declare_func_import(
        &mut self,
        sig_index: SignatureIndex,
        module: &'data str,
        field: &'data str,
    ) {
        assert_eq!(
            self.info.functions.len(),
            self.info.imported_funcs.len(),
            "Imported functions must be declared first"
        );
        self.info.functions.push(Exportable::new(sig_index));
        self.info
            .imported_funcs
            .push((String::from(module), String::from(field)));
    }

    fn get_num_func_imports(&self) -> usize {
        self.info.imported_funcs.len()
    }

    fn declare_func_type(&mut self, sig_index: SignatureIndex) {
        self.info.functions.push(Exportable::new(sig_index));
    }

    fn get_func_type(&self, func_index: FuncIndex) -> SignatureIndex {
        self.info.functions[func_index].entity
    }

    fn declare_global(&mut self, global: Global) {
        self.info.globals.push(Exportable::new(global));
    }

    fn get_global(&self, global_index: GlobalIndex) -> &Global {
        &self.info.globals[global_index].entity
    }

    fn declare_table(&mut self, table: Table) {
        self.info.tables.push(Exportable::new(table));
    }
    fn declare_table_elements(
        &mut self,
        _table_index: TableIndex,
        _base: Option<GlobalIndex>,
        _offset: usize,
        _elements: Vec<FuncIndex>,
    ) {
        // We do nothing
    }
    fn declare_memory(&mut self, memory: Memory) {
        self.info.memories.push(Exportable::new(memory));
    }
    fn declare_data_initialization(
        &mut self,
        _memory_index: MemoryIndex,
        _base: Option<GlobalIndex>,
        _offset: usize,
        _data: &'data [u8],
    ) {
        // We do nothing
    }

    fn declare_func_export(&mut self, func_index: FuncIndex, name: &'data str) {
        self.info.functions[func_index]
            .export_names
            .push(String::from(name));
    }

    fn declare_table_export(&mut self, table_index: TableIndex, name: &'data str) {
        self.info.tables[table_index]
            .export_names
            .push(String::from(name));
    }

    fn declare_memory_export(&mut self, memory_index: MemoryIndex, name: &'data str) {
        self.info.memories[memory_index]
            .export_names
            .push(String::from(name));
    }

    fn declare_global_export(&mut self, global_index: GlobalIndex, name: &'data str) {
        self.info.globals[global_index]
            .export_names
            .push(String::from(name));
    }

    fn declare_start_func(&mut self, func_index: FuncIndex) {
        debug_assert!(self.info.start_func.is_none());
        self.info.start_func = Some(func_index);
    }

    fn define_function_body(&mut self, body_bytes: &'data [u8]) -> WasmResult<()> {
        let func = {
            let mut func_environ = DummyFuncEnvironment::new(&self.info);
            let func_index =
                FuncIndex::new(self.get_num_func_imports() + self.info.function_bodies.len());
            let name = get_func_name(func_index);
            let sig = func_environ.vmctx_sig(self.get_func_type(func_index));
            let mut func = ir::Function::with_name_signature(name, sig);
            let reader = wasmparser::BinaryReader::new(body_bytes);
            self.trans
                .translate_from_reader(reader, &mut func, &mut func_environ)?;
            func
        };
        self.func_bytecode_sizes.push(body_bytes.len());
        self.info.function_bodies.push(func);
        Ok(())
    }
}
<commit_msg>Elaborate on some comments.<commit_after>//! "Dummy" implementations of `ModuleEnvironment` and `FuncEnvironment` for testing
//! wasm translation.

use cranelift_codegen::cursor::FuncCursor;
use cranelift_codegen::ir::immediates::Imm64;
use cranelift_codegen::ir::types::*;
use cranelift_codegen::ir::{self, InstBuilder};
use cranelift_codegen::settings;
use cranelift_entity::{EntityRef, PrimaryMap};
use environ::{FuncEnvironment, GlobalVariable, ModuleEnvironment, WasmResult};
use func_translator::FuncTranslator;
use std::string::String;
use std::vec::Vec;
use target_lexicon::Triple;
use translation_utils::{
    DefinedFuncIndex, FuncIndex, Global, GlobalIndex, Memory, MemoryIndex, SignatureIndex, Table,
    TableIndex,
};
use wasmparser;

/// Compute a `ir::ExternalName` for a given wasm function index.
fn get_func_name(func_index: FuncIndex) -> ir::ExternalName {
    ir::ExternalName::user(0, func_index.index() as u32)
}

/// A collection of names under which a given entity is exported.
pub struct Exportable<T> {
    /// A wasm entity.
    pub entity: T,

    /// Names under which the entity is exported.
    pub export_names: Vec<String>,
}

impl<T> Exportable<T> {
    pub fn new(entity: T) -> Self {
        Self {
            entity,
            export_names: Vec::new(),
        }
    }
}

/// The main state belonging to a `DummyEnvironment`. This is split out from
/// `DummyEnvironment` to allow it to be borrowed separately from the
/// `FuncTranslator` field.
pub struct DummyModuleInfo {
    /// Target description.
    pub triple: Triple,

    /// Compilation setting flags.
    pub flags: settings::Flags,

    /// Signatures as provided by `declare_signature`.
    pub signatures: Vec<ir::Signature>,

    /// Module and field names of imported functions as provided by `declare_func_import`.
    pub imported_funcs: Vec<(String, String)>,

    /// Functions, imported and local.
    pub functions: PrimaryMap<FuncIndex, Exportable<SignatureIndex>>,

    /// Function bodies.
    pub function_bodies: PrimaryMap<DefinedFuncIndex, ir::Function>,

    /// Tables as provided by `declare_table`.
    pub tables: Vec<Exportable<Table>>,

    /// Memories as provided by `declare_memory`.
    pub memories: Vec<Exportable<Memory>>,

    /// Globals as provided by `declare_global`.
    pub globals: Vec<Exportable<Global>>,

    /// The start function.
    pub start_func: Option<FuncIndex>,
}

impl DummyModuleInfo {
    /// Allocates the data structures with the given flags.
    pub fn with_triple_flags(triple: Triple, flags: settings::Flags) -> Self {
        Self {
            triple,
            flags,
            signatures: Vec::new(),
            imported_funcs: Vec::new(),
            functions: PrimaryMap::new(),
            function_bodies: PrimaryMap::new(),
            tables: Vec::new(),
            memories: Vec::new(),
            globals: Vec::new(),
            start_func: None,
        }
    }
}

/// This `ModuleEnvironment` implementation is a "naïve" one, doing essentially nothing and
/// emitting placeholders when forced to. Don't try to execute code translated for this
/// environment, essentially here for translation debug purposes.
pub struct DummyEnvironment {
    /// Module information.
    pub info: DummyModuleInfo,

    /// Function translation.
    trans: FuncTranslator,

    /// Vector of wasm bytecode size for each function.
    pub func_bytecode_sizes: Vec<usize>,
}

impl DummyEnvironment {
    /// Allocates the data structures with default flags.
    pub fn with_triple(triple: Triple) -> Self {
        Self::with_triple_flags(triple, settings::Flags::new(settings::builder()))
    }

    /// Allocates the data structures with the given flags.
    pub fn with_triple_flags(triple: Triple, flags: settings::Flags) -> Self {
        Self {
            info: DummyModuleInfo::with_triple_flags(triple, flags),
            trans: FuncTranslator::new(),
            func_bytecode_sizes: Vec::new(),
        }
    }

    /// Return a `DummyFuncEnvironment` for translating functions within this
    /// `DummyEnvironment`.
    pub fn func_env(&self) -> DummyFuncEnvironment {
        DummyFuncEnvironment::new(&self.info)
    }
}

/// The `FuncEnvironment` implementation for use by the `DummyEnvironment`.
pub struct DummyFuncEnvironment<'dummy_environment> {
    pub mod_info: &'dummy_environment DummyModuleInfo,
}

impl<'dummy_environment> DummyFuncEnvironment<'dummy_environment> {
    pub fn new(mod_info: &'dummy_environment DummyModuleInfo) -> Self {
        Self { mod_info }
    }

    // Create a signature for `sigidx` amended with a `vmctx` argument after the standard wasm
    // arguments.
    fn vmctx_sig(&self, sigidx: SignatureIndex) -> ir::Signature {
        let mut sig = self.mod_info.signatures[sigidx].clone();
        sig.params.push(ir::AbiParam::special(
            self.pointer_type(),
            ir::ArgumentPurpose::VMContext,
        ));
        sig
    }
}

impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environment> {
    fn triple(&self) -> &Triple {
        &self.mod_info.triple
    }

    fn flags(&self) -> &settings::Flags {
        &self.mod_info.flags
    }

    fn make_global(&mut self, func: &mut ir::Function, index: GlobalIndex) -> GlobalVariable {
        // Just create a dummy `vmctx` global.
        let offset = ((index * 8) as i32 + 8).into();
        let gv = func.create_global_value(ir::GlobalValueData::VMContext { offset });
        GlobalVariable::Memory {
            gv,
            ty: self.mod_info.globals[index].entity.ty,
        }
    }

    fn make_heap(&mut self, func: &mut ir::Function, _index: MemoryIndex) -> ir::Heap {
        // Create a static heap whose base address is stored at `vmctx+0`.
        let addr = func.create_global_value(ir::GlobalValueData::VMContext { offset: 0.into() });
        let gv = func.create_global_value(ir::GlobalValueData::Deref {
            base: addr,
            offset: 0.into(),
        });

        func.create_heap(ir::HeapData {
            base: gv,
            min_size: 0.into(),
            guard_size: 0x8000_0000.into(),
            style: ir::HeapStyle::Static {
                bound: 0x1_0000_0000.into(),
            },
        })
    }

    fn make_table(&mut self, func: &mut ir::Function, _index: TableIndex) -> ir::Table {
        // Create a table whose base address is stored at `vmctx+0`.
        let base_gv_addr =
            func.create_global_value(ir::GlobalValueData::VMContext { offset: 0.into() });
        let base_gv = func.create_global_value(ir::GlobalValueData::Deref {
            base: base_gv_addr,
            offset: 0.into(),
        });
        let bound_gv_addr =
            func.create_global_value(ir::GlobalValueData::VMContext { offset: 0.into() });
        let bound_gv = func.create_global_value(ir::GlobalValueData::Deref {
            base: bound_gv_addr,
            offset: 0.into(),
        });

        func.create_table(ir::TableData {
            base_gv,
            min_size: Imm64::new(0),
            bound_gv,
            element_size: Imm64::new(i64::from(self.pointer_bytes()) * 2),
        })
    }

    fn make_indirect_sig(&mut self, func: &mut ir::Function, index: SignatureIndex) -> ir::SigRef {
        // A real implementation would probably change the calling convention and add `vmctx` and
        // signature index arguments.
        func.import_signature(self.vmctx_sig(index))
    }

    fn make_direct_func(&mut self, func: &mut ir::Function, index: FuncIndex) -> ir::FuncRef {
        let sigidx = self.mod_info.functions[index].entity;
        // A real implementation would probably add a `vmctx` argument.
        // And maybe attempt some signature de-duplication.
        let signature = func.import_signature(self.vmctx_sig(sigidx));
        let name = get_func_name(index);
        func.import_function(ir::ExtFuncData {
            name,
            signature,
            colocated: false,
        })
    }

    fn translate_call_indirect(
        &mut self,
        mut pos: FuncCursor,
        _table_index: TableIndex,
        _table: ir::Table,
        _sig_index: SignatureIndex,
        sig_ref: ir::SigRef,
        callee: ir::Value,
        call_args: &[ir::Value],
    ) -> WasmResult<ir::Inst> {
        // Pass the current function's vmctx parameter on to the callee.
        let vmctx = pos
            .func
            .special_param(ir::ArgumentPurpose::VMContext)
            .expect("Missing vmctx parameter");

        // The `callee` value is an index into a table of function pointers.
        // Apparently, that table is stored at absolute address 0 in this dummy environment.
        // TODO: Generate bounds checking code.
        let ptr = self.pointer_type();
        let callee_offset = if ptr == I32 {
            pos.ins().imul_imm(callee, 4)
        } else {
            let ext = pos.ins().uextend(I64, callee);
            pos.ins().imul_imm(ext, 4)
        };
        let mut mflags = ir::MemFlags::new();
        mflags.set_notrap();
        mflags.set_aligned();
        let func_ptr = pos.ins().load(ptr, mflags, callee_offset, 0);

        // Build a value list for the indirect call instruction containing the callee, call_args,
        // and the vmctx parameter.
        let mut args = ir::ValueList::default();
        args.push(func_ptr, &mut pos.func.dfg.value_lists);
        args.extend(call_args.iter().cloned(), &mut pos.func.dfg.value_lists);
        args.push(vmctx, &mut pos.func.dfg.value_lists);

        Ok(pos
            .ins()
            .CallIndirect(ir::Opcode::CallIndirect, VOID, sig_ref, args)
            .0)
    }

    fn translate_call(
        &mut self,
        mut pos: FuncCursor,
        _callee_index: FuncIndex,
        callee: ir::FuncRef,
        call_args: &[ir::Value],
    ) -> WasmResult<ir::Inst> {
        // Pass the current function's vmctx parameter on to the callee.
        let vmctx = pos
            .func
            .special_param(ir::ArgumentPurpose::VMContext)
            .expect("Missing vmctx parameter");

        // Build a value list for the call instruction containing the call_args and the vmctx
        // parameter.
        let mut args = ir::ValueList::default();
        args.extend(call_args.iter().cloned(), &mut pos.func.dfg.value_lists);
        args.push(vmctx, &mut pos.func.dfg.value_lists);

        Ok(pos.ins().Call(ir::Opcode::Call, VOID, callee, args).0)
    }

    fn translate_memory_grow(
        &mut self,
        mut pos: FuncCursor,
        _index: MemoryIndex,
        _heap: ir::Heap,
        _val: ir::Value,
    ) -> WasmResult<ir::Value> {
        Ok(pos.ins().iconst(I32, -1))
    }

    fn translate_memory_size(
        &mut self,
        mut pos: FuncCursor,
        _index: MemoryIndex,
        _heap: ir::Heap,
    ) -> WasmResult<ir::Value> {
        Ok(pos.ins().iconst(I32, -1))
    }
}

impl<'data> ModuleEnvironment<'data> for DummyEnvironment {
    fn flags(&self) -> &settings::Flags {
        &self.info.flags
    }

    fn get_func_name(&self, func_index: FuncIndex) -> ir::ExternalName {
        get_func_name(func_index)
    }

    fn declare_signature(&mut self, sig: &ir::Signature) {
        self.info.signatures.push(sig.clone());
    }

    fn get_signature(&self, sig_index: SignatureIndex) -> &ir::Signature {
        &self.info.signatures[sig_index]
    }

    fn declare_func_import(
        &mut self,
        sig_index: SignatureIndex,
        module: &'data str,
        field: &'data str,
    ) {
        assert_eq!(
            self.info.functions.len(),
            self.info.imported_funcs.len(),
            "Imported functions must be declared first"
        );
        self.info.functions.push(Exportable::new(sig_index));
        self.info
            .imported_funcs
            .push((String::from(module), String::from(field)));
    }

    fn get_num_func_imports(&self) -> usize {
        self.info.imported_funcs.len()
    }

    fn declare_func_type(&mut self, sig_index: SignatureIndex) {
        self.info.functions.push(Exportable::new(sig_index));
    }

    fn get_func_type(&self, func_index: FuncIndex) -> SignatureIndex {
        self.info.functions[func_index].entity
    }

    fn declare_global(&mut self, global: Global) {
        self.info.globals.push(Exportable::new(global));
    }

    fn get_global(&self, global_index: GlobalIndex) -> &Global {
        &self.info.globals[global_index].entity
    }

    fn declare_table(&mut self, table: Table) {
        self.info.tables.push(Exportable::new(table));
    }
    fn declare_table_elements(
        &mut self,
        _table_index: TableIndex,
        _base: Option<GlobalIndex>,
        _offset: usize,
        _elements: Vec<FuncIndex>,
    ) {
        // We do nothing
    }
    fn declare_memory(&mut self, memory: Memory) {
        self.info.memories.push(Exportable::new(memory));
    }
    fn declare_data_initialization(
        &mut self,
        _memory_index: MemoryIndex,
        _base: Option<GlobalIndex>,
        _offset: usize,
        _data: &'data [u8],
    ) {
        // We do nothing
    }

    fn declare_func_export(&mut self, func_index: FuncIndex, name: &'data str) {
        self.info.functions[func_index]
            .export_names
            .push(String::from(name));
    }

    fn declare_table_export(&mut self, table_index: TableIndex, name: &'data str) {
        self.info.tables[table_index]
            .export_names
            .push(String::from(name));
    }

    fn declare_memory_export(&mut self, memory_index: MemoryIndex, name: &'data str) {
        self.info.memories[memory_index]
            .export_names
            .push(String::from(name));
    }

    fn declare_global_export(&mut self, global_index: GlobalIndex, name: &'data str) {
        self.info.globals[global_index]
            .export_names
            .push(String::from(name));
    }

    fn declare_start_func(&mut self, func_index: FuncIndex) {
        debug_assert!(self.info.start_func.is_none());
        self.info.start_func = Some(func_index);
    }

    fn define_function_body(&mut self, body_bytes: &'data [u8]) -> WasmResult<()> {
        let func = {
            let mut func_environ = DummyFuncEnvironment::new(&self.info);
            let func_index =
                FuncIndex::new(self.get_num_func_imports() + self.info.function_bodies.len());
            let name = get_func_name(func_index);
            let sig = func_environ.vmctx_sig(self.get_func_type(func_index));
            let mut func = ir::Function::with_name_signature(name, sig);
            let reader = wasmparser::BinaryReader::new(body_bytes);
            self.trans
                .translate_from_reader(reader, &mut func, &mut func_environ)?;
            func
        };
        self.func_bytecode_sizes.push(body_bytes.len());
        self.info.function_bodies.push(func);
        Ok(())
    }
}
<|endoftext|>


<commit_before>//! Higher order geometric traits.
//!
//! This module defines higher order traits for operations on a graph. It also
//! provides aliases for geometric types to improve readability of type
//! constraints. These traits can be used as contraints to prove to the
//! compiler that certain operations are supported without specifying
//! complicated relationships.
//!
//! The traits in this module have blanket implementations that apply when
//! certain geometric and operational traits are implemented. For example, if a
//! type implements `AsPosition` and the `Output` type of that implementation
//! also implements `Cross` and `Normalize`, then a `Geometry` using that type
//! as its `Vertex` attribute will likely implement the `FaceNormal` trait in
//! this module.
//!
//! # Examples
//!
//! A function that subdivides triangular faces in a mesh:
//!
//! ```rust
//! use plexus::prelude::*;
//! ```

use std::ops::{Add, Sub};

use self::alias::*;
use crate::geometry::convert::AsPosition;
use crate::geometry::ops::{Average, Cross, Interpolate, Normalize, Project};
use crate::geometry::Geometry;
use crate::graph::container::Reborrow;
use crate::graph::storage::convert::AsStorage;
use crate::graph::topology::{Edge, Face, Vertex};
use crate::graph::view::{EdgeView, FaceView};
use crate::graph::GraphError;

pub trait FaceNormal: Geometry {
    type Normal;

    fn normal<M>(face: FaceView<M, Self>) -> Result<Self::Normal, GraphError>
    where
        M: Reborrow,
        M::Target: AsStorage<Edge<Self>> + AsStorage<Face<Self>> + AsStorage<Vertex<Self>>;
}

impl<G> FaceNormal for G
where
    G: Geometry,
    G::Vertex: AsPosition,
    VertexPosition<G>: Clone + Sub,
    <VertexPosition<G> as Sub>::Output: Cross,
    <<VertexPosition<G> as Sub>::Output as Cross>::Output: Normalize,
{
    type Normal = <<VertexPosition<G> as Sub>::Output as Cross>::Output;

    fn normal<M>(face: FaceView<M, Self>) -> Result<Self::Normal, GraphError>
    where
        M: Reborrow,
        M::Target: AsStorage<Edge<Self>> + AsStorage<Face<Self>> + AsStorage<Vertex<Self>>,
    {
        let positions = face
            .reachable_vertices()
            .take(3)
            .map(|vertex| vertex.geometry.as_position().clone())
            .collect::<Vec<_>>();
        let (a, b, c) = (&positions[0], &positions[1], &positions[2]);
        let ab = a.clone() - b.clone();
        let bc = b.clone() - c.clone();
        Ok(ab.cross(bc).normalize())
    }
}

pub trait FaceCentroid: Geometry {
    type Centroid;

    fn centroid<M>(face: FaceView<M, Self>) -> Result<Self::Centroid, GraphError>
    where
        M: Reborrow,
        M::Target: AsStorage<Edge<Self>> + AsStorage<Face<Self>> + AsStorage<Vertex<Self>>;
}

impl<G> FaceCentroid for G
where
    G: Geometry,
    G::Vertex: Average,
{
    type Centroid = G::Vertex;

    fn centroid<M>(face: FaceView<M, Self>) -> Result<Self::Centroid, GraphError>
    where
        M: Reborrow,
        M::Target: AsStorage<Edge<Self>> + AsStorage<Face<Self>> + AsStorage<Vertex<Self>>,
    {
        Ok(G::Vertex::average(
            face.reachable_vertices()
                .map(|vertex| vertex.geometry.clone()),
        ))
    }
}

pub trait EdgeMidpoint: Geometry {
    type Midpoint;

    fn midpoint<M>(edge: EdgeView<M, Self>) -> Result<Self::Midpoint, GraphError>
    where
        M: Reborrow,
        M::Target: AsStorage<Edge<Self>> + AsStorage<Vertex<Self>>;
}

impl<G> EdgeMidpoint for G
where
    G: Geometry,
    G::Vertex: AsPosition,
    VertexPosition<G>: Clone + Interpolate,
{
    type Midpoint = <VertexPosition<G> as Interpolate>::Output;

    fn midpoint<M>(edge: EdgeView<M, Self>) -> Result<Self::Midpoint, GraphError>
    where
        M: Reborrow,
        M::Target: AsStorage<Edge<Self>> + AsStorage<Vertex<Self>>,
    {
        let a = edge
            .reachable_source_vertex()
            .ok_or_else(|| GraphError::TopologyNotFound)?
            .geometry
            .as_position()
            .clone();
        let b = edge
            .reachable_destination_vertex()
            .ok_or_else(|| GraphError::TopologyNotFound)?
            .geometry
            .as_position()
            .clone();
        Ok(a.midpoint(b))
    }
}

pub trait EdgeLateral: Geometry {
    type Lateral;

    fn lateral<M>(edge: EdgeView<M, Self>) -> Result<Self::Lateral, GraphError>
    where
        M: Reborrow,
        M::Target: AsStorage<Edge<Self>> + AsStorage<Vertex<Self>>;
}

impl<G> EdgeLateral for G
where
    G: Geometry,
    G::Vertex: AsPosition,
    VertexPosition<G>: Clone
        + Add<
            <<VertexPosition<G> as Sub>::Output as Project>::Output,
            Output = VertexPosition<G>,
        > + Sub,
    <VertexPosition<G> as Sub>::Output: Normalize + Project,
{
    type Lateral = <VertexPosition<G> as Sub>::Output;

    fn lateral<M>(edge: EdgeView<M, Self>) -> Result<Self::Lateral, GraphError>
    where
        M: Reborrow,
        M::Target: AsStorage<Edge<Self>> + AsStorage<Vertex<Self>>,
    {
        let a = edge
            .reachable_source_vertex()
            .ok_or_else(|| GraphError::TopologyNotFound)?
            .geometry
            .as_position()
            .clone();
        let b = edge
            .reachable_destination_vertex()
            .ok_or_else(|| GraphError::TopologyNotFound)?
            .geometry
            .as_position()
            .clone();
        let c = edge
            .reachable_opposite_edge()
            .ok_or_else(|| GraphError::TopologyNotFound)?
            .reachable_previous_edge()
            .ok_or_else(|| GraphError::TopologyNotFound)?
            .reachable_destination_vertex()
            .ok_or_else(|| GraphError::TopologyNotFound)?
            .geometry
            .as_position()
            .clone();
        let ab = a - b.clone();
        let cb = c.clone() - b.clone();
        let p = b + ab.project(cb);
        Ok((p - c).normalize())
    }
}

pub mod alias {
    use std::ops::Mul;

    use super::*;

    pub type VertexPosition<G> = <<G as Geometry>::Vertex as AsPosition>::Target;
    pub type ScaledFaceNormal<G, T> = <<G as FaceNormal>::Normal as Mul<T>>::Output;
    pub type ScaledEdgeLateral<G, T> = <<G as EdgeLateral>::Lateral as Mul<T>>::Output;
}
<commit_msg>Provide example for use of higher-order geometric traits for graphs.<commit_after>//! Higher order geometric traits.
//!
//! This module defines higher order traits for operations on a graph. It also
//! provides aliases for geometric types to improve readability of type
//! constraints. These traits can be used as contraints to prove to the
//! compiler that certain operations are supported without specifying
//! complicated relationships.
//!
//! The traits in this module have blanket implementations that apply when
//! certain geometric and operational traits are implemented. For example, if a
//! type implements `AsPosition` and the `Output` type of that implementation
//! also implements `Cross` and `Normalize`, then a `Geometry` using that type
//! as its `Vertex` attribute will likely implement the `FaceNormal` trait in
//! this module.
//!
//! # Examples
//!
//! A function that subdivides faces in a graph by splitting edges:
//!
//! ```rust
//! use plexus::geometry::convert::AsPosition;
//! use plexus::geometry::Geometry;
//! use plexus::graph::geometry::alias::VertexPosition;
//! use plexus::graph::geometry::EdgeMidpoint;
//! use plexus::graph::{FaceView, GraphError, MeshGraph};
//! use plexus::prelude::*;
//!
//! // Requires `EdgeMidpoint` to split edges.
//! pub fn subdivide<G>(
//!     face: FaceView<&mut MeshGraph<G>, G>,
//! ) -> Result<FaceView<&mut MeshGraph<G>, G>, GraphError>
//! where
//!     G: EdgeMidpoint<Midpoint = VertexPosition<G>> + Geometry,
//!     G::Vertex: AsPosition,
//! {
//!     let arity = face.arity();
//!     let mut edge = face.into_edge();
//!     let mut splits = Vec::with_capacity(arity);
//!     for _ in 0..arity {
//!         let vertex = edge.split()?;
//!         splits.push(vertex.key());
//!         edge = vertex.into_outgoing_edge().into_next_edge();
//!     }
//!     let mut face = edge.into_face().unwrap();
//!     for (a, b) in splits.into_iter().perimeter() {
//!         face = face.bisect(a, b)?.into_face().unwrap();
//!     }
//!     Ok(face)
//! }
//! ```

use std::ops::{Add, Sub};

use self::alias::*;
use crate::geometry::convert::AsPosition;
use crate::geometry::ops::{Average, Cross, Interpolate, Normalize, Project};
use crate::geometry::Geometry;
use crate::graph::container::Reborrow;
use crate::graph::storage::convert::AsStorage;
use crate::graph::topology::{Edge, Face, Vertex};
use crate::graph::view::{EdgeView, FaceView};
use crate::graph::GraphError;

pub trait FaceNormal: Geometry {
    type Normal;

    fn normal<M>(face: FaceView<M, Self>) -> Result<Self::Normal, GraphError>
    where
        M: Reborrow,
        M::Target: AsStorage<Edge<Self>> + AsStorage<Face<Self>> + AsStorage<Vertex<Self>>;
}

impl<G> FaceNormal for G
where
    G: Geometry,
    G::Vertex: AsPosition,
    VertexPosition<G>: Clone + Sub,
    <VertexPosition<G> as Sub>::Output: Cross,
    <<VertexPosition<G> as Sub>::Output as Cross>::Output: Normalize,
{
    type Normal = <<VertexPosition<G> as Sub>::Output as Cross>::Output;

    fn normal<M>(face: FaceView<M, Self>) -> Result<Self::Normal, GraphError>
    where
        M: Reborrow,
        M::Target: AsStorage<Edge<Self>> + AsStorage<Face<Self>> + AsStorage<Vertex<Self>>,
    {
        let positions = face
            .reachable_vertices()
            .take(3)
            .map(|vertex| vertex.geometry.as_position().clone())
            .collect::<Vec<_>>();
        let (a, b, c) = (&positions[0], &positions[1], &positions[2]);
        let ab = a.clone() - b.clone();
        let bc = b.clone() - c.clone();
        Ok(ab.cross(bc).normalize())
    }
}

pub trait FaceCentroid: Geometry {
    type Centroid;

    fn centroid<M>(face: FaceView<M, Self>) -> Result<Self::Centroid, GraphError>
    where
        M: Reborrow,
        M::Target: AsStorage<Edge<Self>> + AsStorage<Face<Self>> + AsStorage<Vertex<Self>>;
}

impl<G> FaceCentroid for G
where
    G: Geometry,
    G::Vertex: Average,
{
    type Centroid = G::Vertex;

    fn centroid<M>(face: FaceView<M, Self>) -> Result<Self::Centroid, GraphError>
    where
        M: Reborrow,
        M::Target: AsStorage<Edge<Self>> + AsStorage<Face<Self>> + AsStorage<Vertex<Self>>,
    {
        Ok(G::Vertex::average(
            face.reachable_vertices()
                .map(|vertex| vertex.geometry.clone()),
        ))
    }
}

pub trait EdgeMidpoint: Geometry {
    type Midpoint;

    fn midpoint<M>(edge: EdgeView<M, Self>) -> Result<Self::Midpoint, GraphError>
    where
        M: Reborrow,
        M::Target: AsStorage<Edge<Self>> + AsStorage<Vertex<Self>>;
}

impl<G> EdgeMidpoint for G
where
    G: Geometry,
    G::Vertex: AsPosition,
    VertexPosition<G>: Clone + Interpolate,
{
    type Midpoint = <VertexPosition<G> as Interpolate>::Output;

    fn midpoint<M>(edge: EdgeView<M, Self>) -> Result<Self::Midpoint, GraphError>
    where
        M: Reborrow,
        M::Target: AsStorage<Edge<Self>> + AsStorage<Vertex<Self>>,
    {
        let a = edge
            .reachable_source_vertex()
            .ok_or_else(|| GraphError::TopologyNotFound)?
            .geometry
            .as_position()
            .clone();
        let b = edge
            .reachable_destination_vertex()
            .ok_or_else(|| GraphError::TopologyNotFound)?
            .geometry
            .as_position()
            .clone();
        Ok(a.midpoint(b))
    }
}

pub trait EdgeLateral: Geometry {
    type Lateral;

    fn lateral<M>(edge: EdgeView<M, Self>) -> Result<Self::Lateral, GraphError>
    where
        M: Reborrow,
        M::Target: AsStorage<Edge<Self>> + AsStorage<Vertex<Self>>;
}

impl<G> EdgeLateral for G
where
    G: Geometry,
    G::Vertex: AsPosition,
    VertexPosition<G>: Clone
        + Add<
            <<VertexPosition<G> as Sub>::Output as Project>::Output,
            Output = VertexPosition<G>,
        > + Sub,
    <VertexPosition<G> as Sub>::Output: Normalize + Project,
{
    type Lateral = <VertexPosition<G> as Sub>::Output;

    fn lateral<M>(edge: EdgeView<M, Self>) -> Result<Self::Lateral, GraphError>
    where
        M: Reborrow,
        M::Target: AsStorage<Edge<Self>> + AsStorage<Vertex<Self>>,
    {
        let a = edge
            .reachable_source_vertex()
            .ok_or_else(|| GraphError::TopologyNotFound)?
            .geometry
            .as_position()
            .clone();
        let b = edge
            .reachable_destination_vertex()
            .ok_or_else(|| GraphError::TopologyNotFound)?
            .geometry
            .as_position()
            .clone();
        let c = edge
            .reachable_opposite_edge()
            .ok_or_else(|| GraphError::TopologyNotFound)?
            .reachable_previous_edge()
            .ok_or_else(|| GraphError::TopologyNotFound)?
            .reachable_destination_vertex()
            .ok_or_else(|| GraphError::TopologyNotFound)?
            .geometry
            .as_position()
            .clone();
        let ab = a - b.clone();
        let cb = c.clone() - b.clone();
        let p = b + ab.project(cb);
        Ok((p - c).normalize())
    }
}

pub mod alias {
    use std::ops::Mul;

    use super::*;

    pub type VertexPosition<G> = <<G as Geometry>::Vertex as AsPosition>::Target;
    pub type ScaledFaceNormal<G, T> = <<G as FaceNormal>::Normal as Mul<T>>::Output;
    pub type ScaledEdgeLateral<G, T> = <<G as EdgeLateral>::Lateral as Mul<T>>::Output;
}
<|endoftext|>


<commit_before>// Copyright 2014 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use crate::{Atom, StaticAtomSet};
#[cfg(feature = "serde_support")]
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::borrow::Cow;
use std::fmt;

impl<Static: StaticAtomSet> ::precomputed_hash::PrecomputedHash for Atom<Static> {
    fn precomputed_hash(&self) -> u32 {
        self.get_hash()
    }
}

impl<'a, Static: StaticAtomSet> From<&'a Atom<Static>> for Atom<Static> {
    fn from(atom: &'a Self) -> Self {
        atom.clone()
    }
}

impl<Static: StaticAtomSet> PartialEq<str> for Atom<Static> {
    fn eq(&self, other: &str) -> bool {
        &self[..] == other
    }
}

impl<Static: StaticAtomSet> PartialEq<Atom<Static>> for str {
    fn eq(&self, other: &Atom<Static>) -> bool {
        self == &other[..]
    }
}

impl<Static: StaticAtomSet> PartialEq<String> for Atom<Static> {
    fn eq(&self, other: &String) -> bool {
        &self[..] == &other[..]
    }
}

impl<'a, Static: StaticAtomSet> From<&'a str> for Atom<Static> {
    #[inline]
    fn from(string_to_add: &str) -> Self {
        Atom::from(Cow::Borrowed(string_to_add))
    }
}

impl<Static: StaticAtomSet> From<String> for Atom<Static> {
    #[inline]
    fn from(string_to_add: String) -> Self {
        Atom::from(Cow::Owned(string_to_add))
    }
}

impl<Static: StaticAtomSet> fmt::Display for Atom<Static> {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        <str as fmt::Display>::fmt(self, f)
    }
}

impl<Static: StaticAtomSet> AsRef<str> for Atom<Static> {
    fn as_ref(&self) -> &str {
        &self
    }
}

#[cfg(feature = "serde_support")]
impl<Static: StaticAtomSet> Serialize for Atom<Static> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let string: &str = self.as_ref();
        string.serialize(serializer)
    }
}

#[cfg(feature = "serde_support")]
impl<'a, Static: StaticAtomSet> Deserialize<'a> for Atom<Static> {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'a>,
    {
        let string: String = Deserialize::deserialize(deserializer)?;
        Ok(Atom::from(string))
    }
}
<commit_msg>Use a custom Visitor in Deserialize<commit_after>// Copyright 2014 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use crate::{Atom, StaticAtomSet};
#[cfg(feature = "serde_support")]
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::borrow::Cow;
use std::fmt;

impl<Static: StaticAtomSet> ::precomputed_hash::PrecomputedHash for Atom<Static> {
    fn precomputed_hash(&self) -> u32 {
        self.get_hash()
    }
}

impl<'a, Static: StaticAtomSet> From<&'a Atom<Static>> for Atom<Static> {
    fn from(atom: &'a Self) -> Self {
        atom.clone()
    }
}

impl<Static: StaticAtomSet> PartialEq<str> for Atom<Static> {
    fn eq(&self, other: &str) -> bool {
        &self[..] == other
    }
}

impl<Static: StaticAtomSet> PartialEq<Atom<Static>> for str {
    fn eq(&self, other: &Atom<Static>) -> bool {
        self == &other[..]
    }
}

impl<Static: StaticAtomSet> PartialEq<String> for Atom<Static> {
    fn eq(&self, other: &String) -> bool {
        &self[..] == &other[..]
    }
}

impl<'a, Static: StaticAtomSet> From<&'a str> for Atom<Static> {
    #[inline]
    fn from(string_to_add: &str) -> Self {
        Atom::from(Cow::Borrowed(string_to_add))
    }
}

impl<Static: StaticAtomSet> From<String> for Atom<Static> {
    #[inline]
    fn from(string_to_add: String) -> Self {
        Atom::from(Cow::Owned(string_to_add))
    }
}

impl<Static: StaticAtomSet> fmt::Display for Atom<Static> {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        <str as fmt::Display>::fmt(self, f)
    }
}

impl<Static: StaticAtomSet> AsRef<str> for Atom<Static> {
    fn as_ref(&self) -> &str {
        &self
    }
}

#[cfg(feature = "serde_support")]
impl<Static: StaticAtomSet> Serialize for Atom<Static> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let string: &str = self.as_ref();
        string.serialize(serializer)
    }
}

#[cfg(feature = "serde_support")]
impl<'a, Static: StaticAtomSet> Deserialize<'a> for Atom<Static> {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'a>,
    {
        use serde::de;
        use std::marker::PhantomData;

        struct AtomVisitor<Static: StaticAtomSet>(PhantomData<Static>);

        impl<'de, Static: StaticAtomSet> de::Visitor<'de> for AtomVisitor<Static> {
            type Value = Atom<Static>;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                write!(formatter, "an Atom")
            }

            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
            where
                E: de::Error,
            {
                Ok(Atom::from(v))
            }

            fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
            where
                E: de::Error,
            {
                Ok(Atom::from(v))
            }
        }

        deserializer.deserialize_string(AtomVisitor(PhantomData))
    }
}
<|endoftext|>


<commit_before>use backend::{Context, Facade};
use buffer::sub::{self, SubBuffer};
use buffer::alloc::Buffer;
use buffer::BufferType;

use std::mem;
use std::rc::Rc;

pub struct Builder<R> {
    context: Rc<Context>,
    data: R,
}

pub enum BuilderParam<'a, T: 'a> {
    Data(&'a [T]),
    Empty(usize),
}

impl<'a, T: 'a> BuilderParam<'a, T> {
    fn get_num_elements(&self) -> usize {
        match self {
            &BuilderParam::Data(ref data) => data.len(),
            &BuilderParam::Empty(num) => num,
        }
    }

    fn get_buffer_size(&self) -> usize {
        match self {
            &BuilderParam::Data(ref data) => data.len() * mem::size_of::<T>(),
            &BuilderParam::Empty(num) => num * mem::size_of::<T>(),
        }
    }
}

impl Builder<()> {
    pub fn new<F>(facade: &F) -> Builder<()> where F: Facade {
        Builder {
            context: facade.get_context().clone(),
            data: (),
        }
    }
}

impl<R> Builder<R> {
    pub fn add_empty<'a, O>(self, len: usize) -> Builder<<R as BuilderTupleAdd<'a, O>>::Output>
                        where R: BuilderTupleAdd<'a, O>
    {
        Builder {
            context: self.context,
            data: self.data.add_empty(len),
        }
    }

    pub fn add_data<'a, O>(self, data: &'a [O]) -> Builder<<R as BuilderTupleAdd<'a, O>>::Output>
                           where R: BuilderTupleAdd<'a, O>
    {
        Builder {
            context: self.context,
            data: self.data.add_data(data),
        }
    }

    pub fn build<O>(self) -> O where R: BuilderParamsList<O> {
        self.data.build(&self.context)
    }
}

pub trait BuilderParamsList<O> {
    fn build(self, context: &Rc<Context>) -> O;
}

pub trait BuilderTupleAdd<'a, T> {
    type Output;

    fn add_empty(self, usize) -> Self::Output;
    fn add_data(self, &'a [T]) -> Self::Output;
}

macro_rules! implement {
    () => {};

    ($first_in:ident $first_out:ident) => {
        implement!($first_in $first_out,);
    };

    ($first_in:ident $first_out:ident, $($rest_in:ident $rest_out:ident),*) => {
        impl<'a, $first_in: 'a, $($rest_in: 'a,)* $first_out $(, $rest_out)*>
            BuilderParamsList<($first_out $(, $rest_out)*)>
            for (BuilderParam<'a, $first_in>, $(BuilderParam<'a, $rest_in>),*)
            where $first_out: From<SubBuffer<$first_in>> $(, $rest_out: From<SubBuffer<$rest_in>>)*,
                  $first_in: Copy + Send + 'static $(, $rest_in: Copy + Send + 'static)*
        {
            #[allow(non_snake_case)]
            #[allow(unused_mut)]
            fn build(self, context: &Rc<Context>) -> ($first_out $(, $rest_out)*) {
                let ($first_in, $($rest_in),*) = self;
                let size = $first_in.get_buffer_size() $(+ $rest_in.get_buffer_size())*;

                // TODO: buffer type?
                let buffer = Buffer::empty(context, BufferType::ArrayBuffer, size, false).unwrap();
                let buffer = Rc::new(buffer);

                let mut offset = 0;

                $(
                    let $rest_out = sub::build_sub_buffer(buffer.clone(), offset,
                                                          $rest_in.get_num_elements());
                    offset += $rest_in.get_buffer_size();
                    match $rest_in {
                        BuilderParam::Empty(_) => (),
                        BuilderParam::Data(data) => $rest_out.write(data),
                    };
                    let $rest_out = $rest_out.into();
                )*

                let $first_out = sub::build_sub_buffer(buffer, offset,
                                                       $first_in.get_num_elements());
                match $first_in {
                    BuilderParam::Empty(_) => (),
                    BuilderParam::Data(data) => $first_out.write(data),
                };
                let $first_out = $first_out.into();

                ($first_out $(, $rest_out)*)
            }
        }

        impl<'a, T: 'a, $first_in: 'a $(, $rest_in: 'a)*> BuilderTupleAdd<'a, T>
            for (BuilderParam<'a, $first_in>, $(BuilderParam<'a, $rest_in>),*)
        {
            type Output = (BuilderParam<'a, $first_in>, $(BuilderParam<'a, $rest_in>,)* BuilderParam<'a, T>);

            #[allow(non_snake_case)]
            fn add_empty(self, len: usize) -> Self::Output {
                let ($first_in, $($rest_in),*) = self;
                ($first_in, $($rest_in,)* BuilderParam::Empty(len))
            }

            #[allow(non_snake_case)]
            fn add_data(self, data: &'a [T]) -> Self::Output {
                let ($first_in, $($rest_in),*) = self;
                ($first_in, $($rest_in,)* BuilderParam::Data(data))
            }
        }

        implement!($($rest_in $rest_out),*);
    };
}

implement!(I1 O1, I2 O2, I3 O3, I4 O4, I5 O5, I6 O6, I7 O7, I8 O8, I9 O9);

impl<'a, T: 'a> BuilderTupleAdd<'a, T> for () {
    type Output = (BuilderParam<'a, T>,);

    fn add_empty(self, len: usize) -> Self::Output {
        (BuilderParam::Empty(len),)
    }

    fn add_data(self, data: &'a [T]) -> Self::Output {
        (BuilderParam::Data(data),)
    }
}
<commit_msg>Add docs to buffer::Builder<commit_after>use backend::{Context, Facade};
use buffer::sub::{self, SubBuffer};
use buffer::alloc::Buffer;
use buffer::BufferType;

use std::mem;
use std::rc::Rc;

/// Struct that allows you to build multiple subbuffers stored inside the same buffer.
///
/// # Example
///
/// ```no_run
/// # #[macro_use]
/// # extern crate glium;
/// # fn main() {
/// # let display: glium::Display = unsafe { std::mem::uninitialized() };
/// # #[derive(Copy, Clone)] struct Vertex { field: f32 } implement_vertex!(Vertex, field);
/// let (vb1, vb2) = glium::buffer::Builder::new(&display)
///                         .add_empty(12)    // vb1
///                         .add_empty(16)    // vb2
///                         .build();
///
/// // rustc needs some hints about the types of the buffers,
/// // so you may have to write something like this:
/// let vb1: glium::vertex::VertexBuffer<Vertex> = vb1;
/// let vb2: glium::vertex::VertexBuffer<Vertex> = vb2;
/// # }
/// ```
///
pub struct Builder<R> {
    context: Rc<Context>,
    data: R,
}

/// An input parameter stored inside the `Builder` and that will be processed when building
/// the buffers.
pub enum BuilderParam<'a, T: 'a> {
    /// Some initial data to be put in the buffer.
    Data(&'a [T]),
    /// Empty space.
    Empty(usize),
}

impl<'a, T: 'a> BuilderParam<'a, T> {
    /// Returns the number of elements requested.
    fn get_num_elements(&self) -> usize {
        match self {
            &BuilderParam::Data(ref data) => data.len(),
            &BuilderParam::Empty(num) => num,
        }
    }

    /// Returns the size in bytes of this part of the buffer.
    fn get_buffer_size(&self) -> usize {
        match self {
            &BuilderParam::Data(ref data) => data.len() * mem::size_of::<T>(),
            &BuilderParam::Empty(num) => num * mem::size_of::<T>(),
        }
    }
}

impl Builder<()> {
    /// Builds a new empty builder.
    pub fn new<F>(facade: &F) -> Builder<()> where F: Facade {
        Builder {
            context: facade.get_context().clone(),
            data: (),
        }
    }
}

impl<R> Builder<R> {
    /// Adds an empty buffer to the list of buffers to create.
    pub fn add_empty<'a, O>(self, len: usize) -> Builder<<R as BuilderTupleAdd<'a, O>>::Output>
                        where R: BuilderTupleAdd<'a, O>
    {
        Builder {
            context: self.context,
            data: self.data.add_empty(len),
        }
    }

    /// Adds a buffer with some data to the list of buffers to create.
    pub fn add_data<'a, O>(self, data: &'a [O]) -> Builder<<R as BuilderTupleAdd<'a, O>>::Output>
                           where R: BuilderTupleAdd<'a, O>
    {
        Builder {
            context: self.context,
            data: self.data.add_data(data),
        }
    }

    /// Consumes the builder and returns the generated buffers.
    pub fn build<O>(self) -> O where R: BuilderParamsList<O> {
        self.data.build(&self.context)
    }
}

/// List of `BuilderParam`. The template parameter `O` represents the possible buffers list output
/// when `build` is called.
pub trait BuilderParamsList<O> {
    /// Builds the list of buffers.
    fn build(self, context: &Rc<Context>) -> O;
}

/// List of `BuilderParam` that can add a buffer whose content is of type `T` to their list.
pub trait BuilderTupleAdd<'a, T> {
    /// The resulting type after a new buffer is added to the list.
    type Output;

    /// Adds an empty buffer to the list and returns the new list.
    fn add_empty(self, usize) -> Self::Output;
    /// Adds a buffer with data to the list and returns the new list.
    fn add_data(self, &'a [T]) -> Self::Output;
}

macro_rules! implement {
    () => {};

    ($first_in:ident $first_out:ident) => {
        implement!($first_in $first_out,);
    };

    ($first_in:ident $first_out:ident, $($rest_in:ident $rest_out:ident),*) => {
        impl<'a, $first_in: 'a, $($rest_in: 'a,)* $first_out $(, $rest_out)*>
            BuilderParamsList<($first_out $(, $rest_out)*)>
            for (BuilderParam<'a, $first_in>, $(BuilderParam<'a, $rest_in>),*)
            where $first_out: From<SubBuffer<$first_in>> $(, $rest_out: From<SubBuffer<$rest_in>>)*,
                  $first_in: Copy + Send + 'static $(, $rest_in: Copy + Send + 'static)*
        {
            #[allow(non_snake_case)]
            #[allow(unused_mut)]
            fn build(self, context: &Rc<Context>) -> ($first_out $(, $rest_out)*) {
                let ($first_in, $($rest_in),*) = self;
                let size = $first_in.get_buffer_size() $(+ $rest_in.get_buffer_size())*;

                // TODO: buffer type?
                let buffer = Buffer::empty(context, BufferType::ArrayBuffer, size, false).unwrap();
                let buffer = Rc::new(buffer);

                let mut offset = 0;

                $(
                    let $rest_out = sub::build_sub_buffer(buffer.clone(), offset,
                                                          $rest_in.get_num_elements());
                    offset += $rest_in.get_buffer_size();
                    match $rest_in {
                        BuilderParam::Empty(_) => (),
                        BuilderParam::Data(data) => $rest_out.write(data),
                    };
                    let $rest_out = $rest_out.into();
                )*

                let $first_out = sub::build_sub_buffer(buffer, offset,
                                                       $first_in.get_num_elements());
                match $first_in {
                    BuilderParam::Empty(_) => (),
                    BuilderParam::Data(data) => $first_out.write(data),
                };
                let $first_out = $first_out.into();

                ($first_out $(, $rest_out)*)
            }
        }

        impl<'a, T: 'a, $first_in: 'a $(, $rest_in: 'a)*> BuilderTupleAdd<'a, T>
            for (BuilderParam<'a, $first_in>, $(BuilderParam<'a, $rest_in>),*)
        {
            type Output = (BuilderParam<'a, $first_in>, $(BuilderParam<'a, $rest_in>,)* BuilderParam<'a, T>);

            #[allow(non_snake_case)]
            fn add_empty(self, len: usize) -> Self::Output {
                let ($first_in, $($rest_in),*) = self;
                ($first_in, $($rest_in,)* BuilderParam::Empty(len))
            }

            #[allow(non_snake_case)]
            fn add_data(self, data: &'a [T]) -> Self::Output {
                let ($first_in, $($rest_in),*) = self;
                ($first_in, $($rest_in,)* BuilderParam::Data(data))
            }
        }

        implement!($($rest_in $rest_out),*);
    };
}

implement!(I1 O1, I2 O2, I3 O3, I4 O4, I5 O5, I6 O6, I7 O7, I8 O8, I9 O9);

impl<'a, T: 'a> BuilderTupleAdd<'a, T> for () {
    type Output = (BuilderParam<'a, T>,);

    fn add_empty(self, len: usize) -> Self::Output {
        (BuilderParam::Empty(len),)
    }

    fn add_data(self, data: &'a [T]) -> Self::Output {
        (BuilderParam::Data(data),)
    }
}
<|endoftext|>


<commit_before>/// Behavior of arguments when they are encountered while parsing
#[derive(Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub(crate) enum ArgAction {
    StoreValue,
    Flag,
    Help,
    Version,
}
<commit_msg>refactor(parser): Loosen Action trait requirements<commit_after>/// Behavior of arguments when they are encountered while parsing
#[derive(Clone, Debug)]
#[non_exhaustive]
pub(crate) enum ArgAction {
    StoreValue,
    Flag,
    Help,
    Version,
}
<|endoftext|>


<commit_before>use std::{
    io::{self, Error, ErrorKind},
    net::SocketAddr,
};

use tokio::net::lookup_host;

use crate::context::Context;

/// Perform a DNS resolution
pub async fn resolve(_: &Context, addr: &str, port: u16) -> io::Result<Vec<SocketAddr>> {
    match lookup_host((addr, port)).await {
        Ok(v) => Ok(v.collect()),
        Err(err) => {
            let err = Error::new(
                ErrorKind::Other,
                format!("dns resolve {}:{} error: {}", addr, port, err),
            );
            Err(err)
        }
    }
}
<commit_msg>Warn when using tokio DNS resolver<commit_after>use std::{
    io::{self, Error, ErrorKind},
    net::SocketAddr,
    sync::atomic::{AtomicBool, Ordering},
};

use log::warn;
use tokio::net::lookup_host;

use crate::context::Context;

/// Perform a DNS resolution
pub async fn resolve(_: &Context, addr: &str, port: u16) -> io::Result<Vec<SocketAddr>> {
    static TOKIO_USED: AtomicBool = AtomicBool::new(false);
    if !TOKIO_USED.swap(true, Ordering::Relaxed) {
        warn!("Tokio resolver is used. Performance might deteriorate.");
    }

    match lookup_host((addr, port)).await {
        Ok(v) => Ok(v.collect()),
        Err(err) => {
            let err = Error::new(
                ErrorKind::Other,
                format!("dns resolve {}:{} error: {}", addr, port, err),
            );
            Err(err)
        }
    }
}
<|endoftext|>


<commit_before>#![feature(associated_consts)]

pub extern crate futures;
extern crate c3po;
extern crate mainsail;
extern crate rigging;
extern crate cargonauts_config;
pub extern crate serde;
pub extern crate serde_json as json;
pub extern crate tokio_redis as redis;
extern crate tokio_service;

#[allow(unused_imports)]
#[macro_use] extern crate compass_rose;
#[macro_use] extern crate proc_macro_hack;

#[doc(hidden)]
pub use compass_rose::*;

proc_macro_item_decl! {
    /// The routes DSL
    routes! => routes_impl
}

pub mod config {
    pub use cargonauts_config::CargonautsConfig;
}

#[macro_use]
pub mod resources {
    pub use rigging::Error;
    pub use rigging::environment::Environment;

    pub use rigging::resource::{Resource, Relationship};

    #[macro_export]
    macro_rules! relation {
        ($rel:ident => $resource:ident) => {
            pub struct $rel;

            impl $crate::resources::Relationship for $rel {
                type Related = $resource;
            }
        }
    }
}

pub mod methods {
    pub use rigging::method::*;
    pub use rigging::routes::{Route, Kind};
    pub use mainsail::methods::*;
}

pub mod formats {

    pub use rigging::format::{Format, BuildFormat, Template, TemplateKey};
    pub use mainsail::formats::Debug;
    pub use mainsail::formats::jsonapi::JsonApi;
    pub use mainsail::formats::handlebars::Handlebars;

    pub mod jsonapi {
        pub use mainsail::formats::jsonapi::{ApiSerialize, ApiDeserialize, Fields, ClientIdPolicy};
    }
}

#[doc(hidden)]
pub mod routing {
    pub use rigging::resource::{ResourceEndpoint, RelationEndpoint, RelationshipLink, RelIds, HasOneEndpoint, HasManyEndpoint};
    pub use rigging::endpoint::{Endpoint, EndpointService};
    pub use rigging::routes::{RoutingTable, RouteBuilder, Handler, path};
    pub use rigging::routes::{AssetHandler, default_asset_handler};
    pub use rigging::environment::EnvBuilder;
    pub use rigging::http::BoxFuture as HttpFuture;
    pub use rigging::format::FormatLender;
}

pub use server::serve;

pub mod server {
    pub use rigging::http::{Request, Response, Error, Service, NewService, serve, Handle, Method, StatusCode};

    pub mod pool {
        pub use rigging::connections::Configure;
        pub use c3po::{Pool, Config};
    }
}

pub mod clients {
    pub use rigging::connections::{Client, ConnectClient, Configure, NewServiceLike};
    pub use c3po::{Config as PoolConfig, Conn};

    pub mod mock {
        pub use rigging::connections::mock::MockConnection;
    }
}

pub mod middleware {
    pub use rigging::endpoint::Request;

    pub mod http {
        pub use rigging::http::{Request, Response, Error, BoxFuture};
    }

    pub use tokio_service::Service;

    pub trait Middleware<S>: Default
    where
        S: Service<Request = Request, Response = http::Response, Error = http::Error, Future = http::BoxFuture>
    {
        type WrappedService: Service<Request = Request, Response = http::Response, Error = http::Error, Future = http::BoxFuture>;

        fn wrap(self, service: S) -> Self::WrappedService;
    }
}
<commit_msg>Export HttpMethod in methods also.<commit_after>#![feature(associated_consts)]

pub extern crate futures;
extern crate c3po;
extern crate mainsail;
extern crate rigging;
extern crate cargonauts_config;
pub extern crate serde;
pub extern crate serde_json as json;
pub extern crate tokio_redis as redis;
extern crate tokio_service;

#[allow(unused_imports)]
#[macro_use] extern crate compass_rose;
#[macro_use] extern crate proc_macro_hack;

#[doc(hidden)]
pub use compass_rose::*;

proc_macro_item_decl! {
    /// The routes DSL
    routes! => routes_impl
}

pub mod config {
    pub use cargonauts_config::CargonautsConfig;
}

#[macro_use]
pub mod resources {
    pub use rigging::Error;
    pub use rigging::environment::Environment;

    pub use rigging::resource::{Resource, Relationship};

    #[macro_export]
    macro_rules! relation {
        ($rel:ident => $resource:ident) => {
            pub struct $rel;

            impl $crate::resources::Relationship for $rel {
                type Related = $resource;
            }
        }
    }
}

pub mod methods {
    pub use rigging::method::*;
    pub use rigging::routes::{Route, Kind};
    pub use rigging::http::Method as HttpMethod;
    pub use mainsail::methods::*;
}

pub mod formats {

    pub use rigging::format::{Format, BuildFormat, Template, TemplateKey};
    pub use mainsail::formats::Debug;
    pub use mainsail::formats::jsonapi::JsonApi;
    pub use mainsail::formats::handlebars::Handlebars;

    pub mod jsonapi {
        pub use mainsail::formats::jsonapi::{ApiSerialize, ApiDeserialize, Fields, ClientIdPolicy};
    }
}

#[doc(hidden)]
pub mod routing {
    pub use rigging::resource::{ResourceEndpoint, RelationEndpoint, RelationshipLink, RelIds, HasOneEndpoint, HasManyEndpoint};
    pub use rigging::endpoint::{Endpoint, EndpointService};
    pub use rigging::routes::{RoutingTable, RouteBuilder, Handler, path};
    pub use rigging::routes::{AssetHandler, default_asset_handler};
    pub use rigging::environment::EnvBuilder;
    pub use rigging::http::BoxFuture as HttpFuture;
    pub use rigging::format::FormatLender;
}

pub use server::serve;

pub mod server {
    pub use rigging::http::{Request, Response, Error, Service, NewService, serve, Handle, Method, StatusCode};

    pub mod pool {
        pub use rigging::connections::Configure;
        pub use c3po::{Pool, Config};
    }
}

pub mod clients {
    pub use rigging::connections::{Client, ConnectClient, Configure, NewServiceLike};
    pub use c3po::{Config as PoolConfig, Conn};

    pub mod mock {
        pub use rigging::connections::mock::MockConnection;
    }
}

pub mod middleware {
    pub use rigging::endpoint::Request;

    pub mod http {
        pub use rigging::http::{Request, Response, Error, BoxFuture};
    }

    pub use tokio_service::Service;

    pub trait Middleware<S>: Default
    where
        S: Service<Request = Request, Response = http::Response, Error = http::Error, Future = http::BoxFuture>
    {
        type WrappedService: Service<Request = Request, Response = http::Response, Error = http::Error, Future = http::BoxFuture>;

        fn wrap(self, service: S) -> Self::WrappedService;
    }
}
<|endoftext|>


<commit_before>use input::Input;
use ncurses;
use ncurses::ll::{attr_t, chtype, mmask_t};
use ncurses::NCURSES_ATTR_SHIFT;

fn NCURSES_BITS(mask: u32, shift: u32) -> u32 {
    mask << (shift + NCURSES_ATTR_SHIFT) as usize
}

pub fn COLOR_PAIR(n: chtype) -> attr_t {
    NCURSES_BITS(n as u32, 0u32) as attr_t
}

pub const COLOR_BLACK: i16 = 0;
pub const COLOR_RED: i16 = 1;
pub const COLOR_GREEN: i16 = 2;
pub const COLOR_YELLOW: i16 = 3;
pub const COLOR_BLUE: i16 = 4;
pub const COLOR_MAGENTA: i16 = 5;
pub const COLOR_CYAN: i16 = 6;
pub const COLOR_WHITE: i16 = 7;

pub const A_ATTRIBUTES: attr_t = (!0u32 << (0u32 + NCURSES_ATTR_SHIFT)) as attr_t;
pub const A_BLINK: attr_t = (1u32 << (11u32 + NCURSES_ATTR_SHIFT)) as attr_t;
pub const A_BOLD: attr_t = (1u32 << (13u32 + NCURSES_ATTR_SHIFT)) as attr_t;
pub const A_CHARTEXT: attr_t = (1u32 << (0u32 + NCURSES_ATTR_SHIFT)) as attr_t;
pub const A_COLOR: attr_t = ((((1u32) << 8) - 1u32) << (0u32 + NCURSES_ATTR_SHIFT)) as attr_t;
pub const A_DIM: attr_t = (1u32 << (12u32 + NCURSES_ATTR_SHIFT)) as attr_t;
pub const A_ITALIC: attr_t = (1u32 << (23 + NCURSES_ATTR_SHIFT)) as attr_t;
pub const A_LEFTLINE: attr_t = 0; // Not supported on ncurses
pub const A_NORMAL: attr_t = 0u32 as attr_t;
pub const A_OVERLINE: attr_t = 0; // Not supported on ncurses
pub const A_RIGHTLINE: attr_t = 0; // Not supported on ncurses
pub const A_STRIKEOUT: attr_t = 0; // Not supported on ncurses
pub const A_UNDERLINE: attr_t = (1u32 << (9 + NCURSES_ATTR_SHIFT)) as attr_t;

// pub fn A_STANDOUT() -> attr_t
// { NCURSES_BITS(1u32, 8u32) as attr_t }
//
// pub fn A_REVERSE() -> attr_t
// { NCURSES_BITS(1u32, 10u32) as attr_t }

pub const KEY_RESIZE: i32 = 0632;

pub const KEY_OFFSET: i32 = 0o0400;
pub const KEY_F15: i32 = (KEY_OFFSET + 0x17);
pub const KEY_EVENT: i32 = (KEY_OFFSET + 0o633);

pub const SPECIAL_KEY_CODES: [Input; 108] = [Input::KeyCodeYes,

                                             Input::KeyBreak,
                                             Input::KeyDown,
                                             Input::KeyUp,
                                             Input::KeyLeft,
                                             Input::KeyRight,
                                             Input::KeyHome,
                                             Input::KeyBackspace,

                                             Input::KeyF0,
                                             Input::KeyF1,
                                             Input::KeyF2,
                                             Input::KeyF3,
                                             Input::KeyF4,
                                             Input::KeyF5,
                                             Input::KeyF6,
                                             Input::KeyF7,
                                             Input::KeyF8,
                                             Input::KeyF9,
                                             Input::KeyF10,
                                             Input::KeyF11,
                                             Input::KeyF12,
                                             Input::KeyF13,
                                             Input::KeyF14,
                                             Input::KeyF15,
                                             // ncurses reserves space for 64 function keys, but we've
                                             // only implemented 15. This has to be taken into account
                                             // when converting the integer into an index of this array
                                             Input::KeyDL,
                                             Input::KeyIL,
                                             Input::KeyDC,
                                             Input::KeyIC,
                                             Input::KeyEIC,
                                             Input::KeyClear,
                                             Input::KeyEOS,
                                             Input::KeyEOL,
                                             Input::KeySF,
                                             Input::KeySR,
                                             Input::KeyNPage,
                                             Input::KeyPPage,
                                             Input::KeySTab,
                                             Input::KeyCTab,
                                             Input::KeyCATab,
                                             Input::KeyEnter,
                                             Input::KeySReset,
                                             Input::KeyReset,
                                             Input::KeyPrint,
                                             Input::KeyLL,
                                             Input::KeyA1,
                                             Input::KeyA3,
                                             Input::KeyB2,
                                             Input::KeyC1,
                                             Input::KeyC3,
                                             Input::KeyBTab,
                                             Input::KeyBeg,
                                             Input::KeyCancel,
                                             Input::KeyClose,
                                             Input::KeyCommand,
                                             Input::KeyCopy,
                                             Input::KeyCreate,
                                             Input::KeyEnd,
                                             Input::KeyExit,
                                             Input::KeyFind,
                                             Input::KeyHelp,
                                             Input::KeyMark,
                                             Input::KeyMessage,
                                             Input::KeyMove,
                                             Input::KeyNext,
                                             Input::KeyOpen,
                                             Input::KeyOptions,
                                             Input::KeyPrevious,
                                             Input::KeyRedo,
                                             Input::KeyReference,
                                             Input::KeyRefresh,
                                             Input::KeyReplace,
                                             Input::KeyRestart,
                                             Input::KeyResume,
                                             Input::KeySave,
                                             Input::KeySBeg,
                                             Input::KeySCancel,
                                             Input::KeySCommand,
                                             Input::KeySCopy,
                                             Input::KeySCreate,
                                             Input::KeySDC,
                                             Input::KeySDL,
                                             Input::KeySelect,
                                             Input::KeySEnd,
                                             Input::KeySEOL,
                                             Input::KeySExit,
                                             Input::KeySFind,
                                             Input::KeySHelp,
                                             Input::KeySHome,
                                             Input::KeySIC,

                                             Input::KeySLeft,
                                             Input::KeySMessage,
                                             Input::KeySMove,
                                             Input::KeySNext,
                                             Input::KeySOptions,
                                             Input::KeySPrevious,
                                             Input::KeySPrint,
                                             Input::KeySRedo,
                                             Input::KeySReplace,
                                             Input::KeySRight,
                                             Input::KeySResume,
                                             Input::KeySSave,
                                             Input::KeySSuspend,
                                             Input::KeySUndo,
                                             Input::KeySuspend,
                                             Input::KeyUndo,
                                             Input::KeyMouse,
                                             Input::KeyResize,
                                             Input::KeyEvent];

pub const ALL_MOUSE_EVENTS: mmask_t = ncurses::ALL_MOUSE_EVENTS as mmask_t;
<commit_msg>Defined A_REVERSE and A_STANDOUT for the ncurses side<commit_after>use input::Input;
use ncurses;
use ncurses::ll::{attr_t, chtype, mmask_t};
use ncurses::NCURSES_ATTR_SHIFT;

fn NCURSES_BITS(mask: u32, shift: u32) -> u32 {
    mask << (shift + NCURSES_ATTR_SHIFT) as usize
}

pub fn COLOR_PAIR(n: chtype) -> attr_t {
    NCURSES_BITS(n as u32, 0u32) as attr_t
}

pub const COLOR_BLACK: i16 = 0;
pub const COLOR_RED: i16 = 1;
pub const COLOR_GREEN: i16 = 2;
pub const COLOR_YELLOW: i16 = 3;
pub const COLOR_BLUE: i16 = 4;
pub const COLOR_MAGENTA: i16 = 5;
pub const COLOR_CYAN: i16 = 6;
pub const COLOR_WHITE: i16 = 7;

pub const A_ATTRIBUTES: attr_t = (!0u32 << (0u32 + NCURSES_ATTR_SHIFT)) as attr_t;
pub const A_BLINK: attr_t = (1u32 << (11u32 + NCURSES_ATTR_SHIFT)) as attr_t;
pub const A_BOLD: attr_t = (1u32 << (13u32 + NCURSES_ATTR_SHIFT)) as attr_t;
pub const A_CHARTEXT: attr_t = (1u32 << (0u32 + NCURSES_ATTR_SHIFT)) as attr_t;
pub const A_COLOR: attr_t = ((((1u32) << 8) - 1u32) << (0u32 + NCURSES_ATTR_SHIFT)) as attr_t;
pub const A_DIM: attr_t = (1u32 << (12u32 + NCURSES_ATTR_SHIFT)) as attr_t;
pub const A_ITALIC: attr_t = (1u32 << (23 + NCURSES_ATTR_SHIFT)) as attr_t;
pub const A_LEFTLINE: attr_t = 0; // Not supported on ncurses
pub const A_NORMAL: attr_t = 0u32 as attr_t;
pub const A_OVERLINE: attr_t = 0; // Not supported on ncurses
pub const A_REVERSE: attr_t = (1u32 << (10 + NCURSES_ATTR_SHIFT)) as attr_t;
pub const A_RIGHTLINE: attr_t = 0; // Not supported on ncurses
pub const A_STANDOUT: attr_t = (1u32 << (8 + NCURSES_ATTR_SHIFT)) as attr_t;
pub const A_STRIKEOUT: attr_t = 0; // Not supported on ncurses
pub const A_UNDERLINE: attr_t = (1u32 << (9 + NCURSES_ATTR_SHIFT)) as attr_t;

pub const KEY_RESIZE: i32 = 0632;

pub const KEY_OFFSET: i32 = 0o0400;
pub const KEY_F15: i32 = (KEY_OFFSET + 0x17);
pub const KEY_EVENT: i32 = (KEY_OFFSET + 0o633);

pub const SPECIAL_KEY_CODES: [Input; 108] = [Input::KeyCodeYes,

                                             Input::KeyBreak,
                                             Input::KeyDown,
                                             Input::KeyUp,
                                             Input::KeyLeft,
                                             Input::KeyRight,
                                             Input::KeyHome,
                                             Input::KeyBackspace,

                                             Input::KeyF0,
                                             Input::KeyF1,
                                             Input::KeyF2,
                                             Input::KeyF3,
                                             Input::KeyF4,
                                             Input::KeyF5,
                                             Input::KeyF6,
                                             Input::KeyF7,
                                             Input::KeyF8,
                                             Input::KeyF9,
                                             Input::KeyF10,
                                             Input::KeyF11,
                                             Input::KeyF12,
                                             Input::KeyF13,
                                             Input::KeyF14,
                                             Input::KeyF15,
                                             // ncurses reserves space for 64 function keys, but we've
                                             // only implemented 15. This has to be taken into account
                                             // when converting the integer into an index of this array
                                             Input::KeyDL,
                                             Input::KeyIL,
                                             Input::KeyDC,
                                             Input::KeyIC,
                                             Input::KeyEIC,
                                             Input::KeyClear,
                                             Input::KeyEOS,
                                             Input::KeyEOL,
                                             Input::KeySF,
                                             Input::KeySR,
                                             Input::KeyNPage,
                                             Input::KeyPPage,
                                             Input::KeySTab,
                                             Input::KeyCTab,
                                             Input::KeyCATab,
                                             Input::KeyEnter,
                                             Input::KeySReset,
                                             Input::KeyReset,
                                             Input::KeyPrint,
                                             Input::KeyLL,
                                             Input::KeyA1,
                                             Input::KeyA3,
                                             Input::KeyB2,
                                             Input::KeyC1,
                                             Input::KeyC3,
                                             Input::KeyBTab,
                                             Input::KeyBeg,
                                             Input::KeyCancel,
                                             Input::KeyClose,
                                             Input::KeyCommand,
                                             Input::KeyCopy,
                                             Input::KeyCreate,
                                             Input::KeyEnd,
                                             Input::KeyExit,
                                             Input::KeyFind,
                                             Input::KeyHelp,
                                             Input::KeyMark,
                                             Input::KeyMessage,
                                             Input::KeyMove,
                                             Input::KeyNext,
                                             Input::KeyOpen,
                                             Input::KeyOptions,
                                             Input::KeyPrevious,
                                             Input::KeyRedo,
                                             Input::KeyReference,
                                             Input::KeyRefresh,
                                             Input::KeyReplace,
                                             Input::KeyRestart,
                                             Input::KeyResume,
                                             Input::KeySave,
                                             Input::KeySBeg,
                                             Input::KeySCancel,
                                             Input::KeySCommand,
                                             Input::KeySCopy,
                                             Input::KeySCreate,
                                             Input::KeySDC,
                                             Input::KeySDL,
                                             Input::KeySelect,
                                             Input::KeySEnd,
                                             Input::KeySEOL,
                                             Input::KeySExit,
                                             Input::KeySFind,
                                             Input::KeySHelp,
                                             Input::KeySHome,
                                             Input::KeySIC,

                                             Input::KeySLeft,
                                             Input::KeySMessage,
                                             Input::KeySMove,
                                             Input::KeySNext,
                                             Input::KeySOptions,
                                             Input::KeySPrevious,
                                             Input::KeySPrint,
                                             Input::KeySRedo,
                                             Input::KeySReplace,
                                             Input::KeySRight,
                                             Input::KeySResume,
                                             Input::KeySSave,
                                             Input::KeySSuspend,
                                             Input::KeySUndo,
                                             Input::KeySuspend,
                                             Input::KeyUndo,
                                             Input::KeyMouse,
                                             Input::KeyResize,
                                             Input::KeyEvent];

pub const ALL_MOUSE_EVENTS: mmask_t = ncurses::ALL_MOUSE_EVENTS as mmask_t;
<|endoftext|>