<commit_before>use std::cell::RefCell;
use std::collections::HashMap;
use std::fmt::{Debug, Error, Formatter};
use std::ops::Deref;
use std::rc::Rc;

use super::super::ast::{Node, Root};
use super::super::parser;

struct InnerBuiltinFunction {
    name: String,
    call_target: fn(Vec<Value>) -> Value,
}

#[derive(Clone)]
struct BuiltinFunction(Rc<InnerBuiltinFunction>);

impl BuiltinFunction {
    pub fn new(name: String, call_target: fn(Vec<Value>) -> Value) -> Self {
        Self(Rc::new(InnerBuiltinFunction { name, call_target }))
    }

    pub fn call(&self, arguments: Vec<Value>) -> Value {
        let call_target = &self.0.call_target;
        call_target(arguments)
    }

    pub fn name(&self) -> String {
        self.0.name.clone()
    }
}

impl Debug for BuiltinFunction {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.write_str(&self.name())
    }
}

fn builtin_println(arguments: Vec<Value>) -> Value {
    for argument in arguments.into_iter() {
        use Value::*;
        match argument {
            BuiltinFunction(builtin_function) => println!("{:?}", builtin_function),
            Integer(value) => println!("{}", value),
            other @ _ => println!("{:?}", other),
        };
    }
    Value::Null
}

trait Frame {
    fn get(&self, name: String) -> Option<Value>;
    fn set(&mut self, name: String, value: Value);
}

#[derive(Clone)]
struct BuiltinFrame(Rc<HashMap<String, Value>>);

impl BuiltinFrame {
    fn bootstrap() -> Self {
        let mut locals = HashMap::<String, Value>::new();
        let functions = vec![("println".to_string(), builtin_println)];
        for (name, function) in functions.into_iter() {
            locals.insert(
                name.clone(),
                BuiltinFunction::new(name, function).into(),
            );
        }
        Self(Rc::new(locals))
    }
}

impl Frame for BuiltinFrame {
    fn get(&self, name: String) -> Option<Value> {
        self.0.get(&name).map(Value::to_owned)
    }

    fn set(&mut self, _name: String, _value: Value) {
        unreachable!("Cannot set in builtin scope")
    }
}

#[derive(Clone, Debug)]
enum Value {
    Null,
    BuiltinFunction(BuiltinFunction),
    Integer(i64),
}

impl From<BuiltinFunction> for Value {
    fn from(builtin_function: BuiltinFunction) -> Self {
        Self::BuiltinFunction(builtin_function)
    }
}

struct InnerStaticFrame {
    locals: HashMap<String, Value>,
    builtin_frame: BuiltinFrame,
}

#[derive(Clone)]
struct StaticFrame(Rc<RefCell<InnerStaticFrame>>);

impl StaticFrame {
    fn new(builtin_frame: BuiltinFrame) -> Self {
        Self(Rc::new(RefCell::new(InnerStaticFrame {
            locals: HashMap::new(),
            builtin_frame,
        })))
    }
}

impl Frame for StaticFrame {
    fn get(&self, name: String) -> Option<Value> {
        let inner = self.0.borrow();
        if let Some(value) = inner.locals.get(&name) {
            Some(value.to_owned())
        } else {
            inner.builtin_frame.get(name)
        }
    }

    fn set(&mut self, name: String, value: Value) {
        let mut inner = self.0.borrow_mut();
        inner.locals.insert(name, value);
    }
}

struct Module {
    source: String,
    root: Root,
    static_frame: StaticFrame,
}

impl Module {
    fn new_from_source(source: String, builtin_frame: BuiltinFrame) -> Self {
        let root = parser::parse(&source);
        Self {
            source,
            root,
            static_frame: StaticFrame::new(builtin_frame),
        }
    }
}

trait Eval<F: Frame> {
    fn eval(&self, frame: &mut F) -> Value;
}

impl<F: Frame> Eval<F> for Module {
    fn eval(&self, frame: &mut F) -> Value {
        for node in self.root.nodes.iter() {
            node.eval(frame);
        }
        Value::Null
    }
}

impl<F: Frame> Eval<F> for Node {
    fn eval(&self, frame: &mut F) -> Value {
        match self {
            Node::Identifier(identifier) => {
                let name = identifier.value.clone();
                frame
                    .get(name.clone())
                    .expect(&format!("Not found: {}", name))
            }
            Node::Integer(integer) => Value::Integer(integer.value),
            Node::Let(let_) => {
                let rhs = match &let_.rhs {
                    Some(rhs) => rhs.eval(frame),
                    None => Value::Null,
                };
                let lhs: String = let_.lhs.value.clone();
                frame.set(lhs, rhs);
                Value::Null
            }
            Node::PostfixCall(call) => {
                let target = call.target.eval(frame);
                let arguments: Vec<Value> = call
                    .arguments
                    .iter()
                    .map(|argument| argument.eval(frame))
                    .collect();
                match target {
                    Value::BuiltinFunction(builtin_function) => builtin_function.call(arguments),
                    other @ _ => unreachable!("Cannot call: {:?}", other),
                }
            }
            Node::Var(var) => {
                let rhs = match &var.rhs {
                    Some(rhs) => rhs.eval(frame),
                    None => Value::Null,
                };
                let lhs: String = var.lhs.value.clone();
                frame.set(lhs, rhs);
                Value::Null
            }
            other @ _ => unreachable!("Cannot eval: {}", other),
        }
    }
}

pub struct Vm {
    builtin_frame: BuiltinFrame,
}

impl Vm {
    pub fn new() -> Self {
        Self {
            builtin_frame: BuiltinFrame::bootstrap(),
        }
    }

    pub fn eval_source(&self, source: String) {
        let module = Module::new_from_source(source, self.builtin_frame.clone());
        module.eval(&mut module.static_frame.clone());
    }
}
<commit_msg>Implement function calls and returns<commit_after>use std::cell::RefCell;
use std::collections::HashMap;
use std::fmt::{Debug, Error, Formatter};
use std::ops::Deref;
use std::rc::Rc;

use super::super::ast::{Function as AstFunction, Node, Root};
use super::super::parser;

struct InnerBuiltinFunction {
    name: String,
    call_target: fn(Vec<Value>) -> Value,
}

#[derive(Clone)]
struct BuiltinFunction(Rc<InnerBuiltinFunction>);

impl BuiltinFunction {
    pub fn new(name: String, call_target: fn(Vec<Value>) -> Value) -> Self {
        Self(Rc::new(InnerBuiltinFunction { name, call_target }))
    }

    pub fn call(&self, arguments: Vec<Value>) -> Value {
        let call_target = &self.0.call_target;
        call_target(arguments)
    }

    pub fn name(&self) -> String {
        self.0.name.clone()
    }
}

impl Debug for BuiltinFunction {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.write_str(&self.name())
    }
}

fn builtin_println(arguments: Vec<Value>) -> Value {
    for argument in arguments.into_iter() {
        use Value::*;
        match argument {
            BuiltinFunction(builtin_function) => println!("{:?}", builtin_function),
            Integer(value) => println!("{}", value),
            other @ _ => println!("{:?}", other),
        };
    }
    Value::Null
}

#[derive(Clone)]
struct Function {
    /// The static frame (module scope) in which this function was defined.
    static_frame: StaticFrame,
    /// If it's a closure then this is the captured/closed-over frame.
    // captured_frame: Option<Box<dyn Frame>>,
    root: AstFunction,
}

impl Function {
    fn new(static_frame: StaticFrame, root: AstFunction) -> Self {
        Self { static_frame, root }
    }
}

impl Debug for Function {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.write_str("function")
    }
}

trait Frame {
    fn get(&self, name: String) -> Option<Value>;
    fn set(&mut self, name: String, value: Value);
    /// Every function gets access to the static frame (module scope) in
    /// which it was defined.
    fn capture_static(&self) -> StaticFrame;
}

#[derive(Clone)]
struct BuiltinFrame(Rc<HashMap<String, Value>>);

impl BuiltinFrame {
    fn bootstrap() -> Self {
        let mut locals = HashMap::<String, Value>::new();
        let functions = vec![("println".to_string(), builtin_println)];
        for (name, function) in functions.into_iter() {
            locals.insert(name.clone(), BuiltinFunction::new(name, function).into());
        }
        Self(Rc::new(locals))
    }
}

impl Frame for BuiltinFrame {
    fn get(&self, name: String) -> Option<Value> {
        self.0.get(&name).map(Value::to_owned)
    }

    fn set(&mut self, _name: String, _value: Value) {
        unreachable!("BuiltinFrame doesn't support set")
    }

    fn capture_static(&self) -> StaticFrame {
        unreachable!("BuiltinFrame doesn't support capture_static")
    }
}

#[derive(Clone, Debug)]
enum Value {
    Null,
    BuiltinFunction(BuiltinFunction),
    Function(Function),
    Integer(i64),
}

impl From<BuiltinFunction> for Value {
    fn from(builtin_function: BuiltinFunction) -> Self {
        Self::BuiltinFunction(builtin_function)
    }
}

struct InnerStaticFrame {
    locals: HashMap<String, Value>,
    builtin_frame: BuiltinFrame,
}

#[derive(Clone)]
struct StaticFrame(Rc<RefCell<InnerStaticFrame>>);

impl StaticFrame {
    fn new(builtin_frame: BuiltinFrame) -> Self {
        Self(Rc::new(RefCell::new(InnerStaticFrame {
            locals: HashMap::new(),
            builtin_frame,
        })))
    }
}

impl Frame for StaticFrame {
    fn get(&self, name: String) -> Option<Value> {
        let inner = self.0.borrow();
        if let Some(value) = inner.locals.get(&name) {
            Some(value.to_owned())
        } else {
            inner.builtin_frame.get(name)
        }
    }

    fn set(&mut self, name: String, value: Value) {
        let mut inner = self.0.borrow_mut();
        inner.locals.insert(name, value);
    }

    fn capture_static(&self) -> StaticFrame {
        self.clone()
    }
}

struct Module {
    source: String,
    root: Root,
    static_frame: StaticFrame,
}

impl Module {
    fn new_from_source(source: String, builtin_frame: BuiltinFrame) -> Self {
        let root = parser::parse(&source);
        Self {
            source,
            root,
            static_frame: StaticFrame::new(builtin_frame),
        }
    }
}

#[derive(Debug)]
enum Action {
    // Regular implicit return of evaluating a statement or expression.
    Value(Value),
    // "Interrupt" to return a value from a function.
    Return(Option<Value>),
}

// Get the value or early-return if it's a `Return` action.
macro_rules! value {
    ($x:expr) => {{
        match $x {
            Action::Value(val) => val,
            ret @ Action::Return(_) => return ret,
        }
    }};
}

trait Eval<F: Frame> {
    fn eval(&self, frame: &mut F) -> Action;
}

impl<F: Frame> Eval<F> for Module {
    fn eval(&self, frame: &mut F) -> Action {
        for node in self.root.nodes.iter() {
            node.eval(frame);
        }
        Action::Value(Value::Null)
    }
}

impl<F: Frame> Eval<F> for Node {
    fn eval(&self, frame: &mut F) -> Action {
        let value: Value = match self {
            Node::Block(block) => {
                if let Some((last_node, nodes)) = block.nodes.split_last() {
                    for node in nodes {
                        value!(node.eval(frame));
                    }
                    value!(last_node.eval(frame))
                } else {
                    Value::Null
                }
            }
            Node::Function(ast_function) => {
                let function = Function::new(frame.capture_static(), ast_function.clone());
                let value = Value::Function(function);
                if let Some(name) = &ast_function.name {
                    frame.set(name.clone(), value.clone())
                }
                value
            }
            Node::Identifier(identifier) => {
                let name = identifier.value.clone();
                frame
                    .get(name.clone())
                    .expect(&format!("Not found: {}", name))
            }
            Node::Integer(integer) => Value::Integer(integer.value),
            Node::Let(let_) => {
                let rhs = match &let_.rhs {
                    Some(rhs) => value!(rhs.eval(frame)),
                    None => Value::Null,
                };
                let lhs: String = let_.lhs.value.clone();
                frame.set(lhs, rhs);
                Value::Null
            }
            Node::PostfixCall(call) => {
                let target = value!(call.target.eval(frame));
                let mut arguments = Vec::<Value>::with_capacity(call.arguments.len());
                for (index, argument) in call.arguments.iter().enumerate() {
                    let value = value!(argument.eval(frame));
                    arguments.push(value)
                }
                assert_eq!(arguments.len(), call.arguments.len(),);
                eval_function(target, arguments)
            }
            Node::Return(ret) => {
                if let Some(rhs) = &ret.rhs {
                    let value = value!(rhs.eval(frame));
                    return Action::Return(Some(value))
                } else {
                    return Action::Return(None)
                }
            }
            Node::Var(var) => {
                let rhs = match &var.rhs {
                    Some(rhs) => value!(rhs.eval(frame)),
                    None => Value::Null,
                };
                let lhs: String = var.lhs.value.clone();
                frame.set(lhs, rhs);
                Value::Null
            }
            other @ _ => unreachable!("Cannot eval: {}", other),
        };
        Action::Value(value)
    }
}

fn eval_function(target: Value, arguments: Vec<Value>) -> Value {
    match target {
        Value::BuiltinFunction(builtin_function) => builtin_function.call(arguments),
        Value::Function(function) => {
            let new_frame = function.static_frame;
            let action = function.root.body.eval(&mut new_frame.clone());
            match action {
                // Implicit return.
                Action::Value(value) => value,
                // Explicit return.
                Action::Return(value) => value.unwrap_or(Value::Null),
            }
        }
        other @ _ => unreachable!("Cannot call: {:?}", other),
    }
}

pub struct Vm {
    builtin_frame: BuiltinFrame,
}

impl Vm {
    pub fn new() -> Self {
        Self {
            builtin_frame: BuiltinFrame::bootstrap(),
        }
    }

    pub fn eval_source(&self, source: String) {
        let module = Module::new_from_source(source, self.builtin_frame.clone());
        module.eval(&mut module.static_frame.clone());
    }
}
<|endoftext|>


<commit_before>use itertools::Itertools;
use std::collections::{HashMap, HashSet};
use std::fmt;
use rand::random;

pub type Point = (isize, isize);

#[derive(Debug, Clone)]
pub struct World {
    width: isize,
    height: isize,
    generation: HashSet<Point>,
    neighbours: HashMap<Point, usize>,
    age: usize,
}

impl World {
    pub fn new(width: isize, height: isize)  -> World {
        World { width: width, height: height, age: 0,
                generation: HashSet::new(), neighbours: HashMap::new(), }
    }

    pub fn seed(mut self, maybe_seed: Option<HashSet<Point>>) -> World {
        let cur_gen_cap = self.generation.capacity();
        let max_gen_cap = (self.width * self.height) as usize;
        if cur_gen_cap < max_gen_cap {
            self.generation.reserve(max_gen_cap - cur_gen_cap);
        }

        match maybe_seed {
            Some(seed) => self.generation = seed.clone(),
            None => {
                (0..self.width).cartesian_product(0..self.height)
                    .filter(|_| random())
                    .fold(&mut self.generation, |acc, point| {
                        acc.insert(point);
                        acc
                    });
            }
        };
        self.calculate_neighbours();
        self
    }

    pub fn evolve(&mut self) -> &World {
        let mut next_generation = HashSet::with_capacity(self.generation.len() * 2);
        self.neighbours.iter()
            .filter(|&(n, c)| self.decide_fate(n, *c))
            .map(|(n, _)| *n)
            .fold(&mut next_generation, |acc, point| {
                acc.insert(point);
                acc
            });
        self.generation = next_generation;
        self.calculate_neighbours();
        self.age += 1;
        self
    }

    fn calculate_neighbours(&mut self) {
        self.neighbours.clear();
        for &(x, y) in self.generation.iter() {
            (-1..2)
            .cartesian_product(-1..2)
            .filter(|&(dx, dy)| dx != 0 || dy != 0)
            .map(|(dx, dy)| (dx + x, dy + y))
            .fold(&mut self.neighbours, |acc, point| {
                *acc.entry(point).or_insert(0) += 1;
                acc
            });
        };
    }

    fn decide_fate(&self, p: &Point, c: usize) -> bool {
        if self.generation.contains(p) {
            c == 3 || c == 2
        } else {
            c == 3
        }
    }
}

impl fmt::Display for World {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut buf = String::with_capacity(((self.width + 2) * (self.height + 2) + 50) as usize);
        for x in 0..self.width + 2 {
            buf.push(if x == 0 { '┌' } else if x == self.width + 1 { '┐' } else { '─' });
        }
        buf.push('\n');
        for y in 0..self.height {
            buf.push('│');
            for x in 0..self.width {
                buf.push(if self.generation.contains(&(x, y)) { '*' } else { ' ' });
            }
            buf.push('|');
            if y == 0 {
                buf.push_str(&format!(" cells: {}", self.generation.len()));
            }
            if y == 1 {
                buf.push_str(&format!(" age: {}", self.age));
            }
            buf.push('\n');
        }
        for x in 0..self.width + 2 {
            buf.push(if x == 0 { '└' } else if x == self.width + 1 { '┘' } else { '─' });
        }
        f.write_str(&buf)
    }
}
<commit_msg>change reserve to with_capacity<commit_after>use itertools::Itertools;
use std::collections::{HashMap, HashSet};
use std::fmt;
use rand::random;

pub type Point = (isize, isize);

#[derive(Debug, Clone)]
pub struct World {
    width: isize,
    height: isize,
    generation: HashSet<Point>,
    neighbours: HashMap<Point, usize>,
    age: usize,
}

impl World {
    pub fn new(width: isize, height: isize)  -> World {
        World { width: width, height: height, age: 0,
                generation: HashSet::with_capacity((width * height) as usize),
                neighbours: HashMap::new(), }
    }

    pub fn seed(mut self, maybe_seed: Option<HashSet<Point>>) -> World {
        match maybe_seed {
            Some(seed) => self.generation = seed.clone(),
            None => {
                (0..self.width).cartesian_product(0..self.height)
                    .filter(|_| random())
                    .fold(&mut self.generation, |acc, point| {
                        acc.insert(point);
                        acc
                    });
            }
        };
        self.calculate_neighbours();
        self
    }

    pub fn evolve(&mut self) -> &World {
        let mut next_generation = HashSet::with_capacity(self.generation.len() * 2);
        self.neighbours.iter()
            .filter(|&(n, c)| self.decide_fate(n, *c))
            .map(|(n, _)| *n)
            .fold(&mut next_generation, |acc, point| {
                acc.insert(point);
                acc
            });
        self.generation = next_generation;
        self.calculate_neighbours();
        self.age += 1;
        self
    }

    fn calculate_neighbours(&mut self) {
        self.neighbours.clear();
        for &(x, y) in self.generation.iter() {
            (-1..2)
            .cartesian_product(-1..2)
            .filter(|&(dx, dy)| dx != 0 || dy != 0)
            .map(|(dx, dy)| (dx + x, dy + y))
            .fold(&mut self.neighbours, |acc, point| {
                *acc.entry(point).or_insert(0) += 1;
                acc
            });
        };
    }

    fn decide_fate(&self, p: &Point, c: usize) -> bool {
        if self.generation.contains(p) {
            c == 3 || c == 2
        } else {
            c == 3
        }
    }
}

impl fmt::Display for World {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut buf = String::with_capacity(((self.width + 2) * (self.height + 2) + 50) as usize);
        for x in 0..self.width + 2 {
            buf.push(if x == 0 { '┌' } else if x == self.width + 1 { '┐' } else { '─' });
        }
        buf.push('\n');
        for y in 0..self.height {
            buf.push('│');
            for x in 0..self.width {
                buf.push(if self.generation.contains(&(x, y)) { '*' } else { ' ' });
            }
            buf.push('|');
            if y == 0 {
                buf.push_str(&format!(" cells: {}", self.generation.len()));
            }
            if y == 1 {
                buf.push_str(&format!(" age: {}", self.age));
            }
            buf.push('\n');
        }
        for x in 0..self.width + 2 {
            buf.push(if x == 0 { '└' } else if x == self.width + 1 { '┘' } else { '─' });
        }
        f.write_str(&buf)
    }
}
<|endoftext|>


<commit_before>#![cfg(windows)]

extern crate winapi;
extern crate gleam;

use com::{ComPtr, ToResult, HResult, as_ptr};
use std::ptr;
use std::rc::Rc;
use winapi::shared::dxgi1_2::DXGI_SWAP_CHAIN_DESC1;
use winapi::shared::dxgi1_2::IDXGIFactory2;
use winapi::shared::minwindef::{TRUE, FALSE};
use winapi::shared::windef::HWND;
use winapi::um::d3d11::ID3D11Device;
use winapi::um::dcomp::IDCompositionDevice;
use winapi::um::dcomp::IDCompositionTarget;
use winapi::um::dcomp::IDCompositionVisual;

pub mod com;
mod egl;

pub struct DirectComposition {
    d3d_device: ComPtr<ID3D11Device>,
    dxgi_factory: ComPtr<IDXGIFactory2>,

    egl: Rc<egl::SharedEglThings>,
    pub gleam: Rc<gleam::gl::Gl>,

    composition_device: ComPtr<IDCompositionDevice>,
    root_visual: ComPtr<IDCompositionVisual>,

    #[allow(unused)]  // Needs to be kept alive
    composition_target: ComPtr<IDCompositionTarget>,
}

impl DirectComposition {
    /// Initialize DirectComposition in the given window
    ///
    /// # Safety
    ///
    /// `hwnd` must be a valid handle to a window.
    pub unsafe fn new(hwnd: HWND) -> HResult<Self> {
        let d3d_device = ComPtr::new_with(|ptr_ptr| winapi::um::d3d11::D3D11CreateDevice(
            ptr::null_mut(),
            winapi::um::d3dcommon::D3D_DRIVER_TYPE_HARDWARE,
            ptr::null_mut(),
            winapi::um::d3d11::D3D11_CREATE_DEVICE_BGRA_SUPPORT |
            if cfg!(debug_assertions) {
                winapi::um::d3d11::D3D11_CREATE_DEVICE_DEBUG
            } else {
                0
            },
            ptr::null_mut(),
            0,
            winapi::um::d3d11::D3D11_SDK_VERSION,
            ptr_ptr,
            &mut 0,
            ptr::null_mut(),
        ))?;

        let egl = egl::SharedEglThings::new(d3d_device.as_raw());
        let gleam = gleam::gl::GlesFns::load_with(|name| egl.get_proc_address(name));

        let dxgi_device = d3d_device.cast::<winapi::shared::dxgi::IDXGIDevice>()?;

        // https://msdn.microsoft.com/en-us/library/windows/desktop/hh404556(v=vs.85).aspx#code-snippet-1
        // “Because you can create a Direct3D device without creating a swap chain,
        //  you might need to retrieve the factory that is used to create the device
        //  in order to create a swap chain.”
        let adapter = ComPtr::new_with(|ptr_ptr| dxgi_device.GetAdapter(ptr_ptr))?;
        let dxgi_factory = ComPtr::<IDXGIFactory2>::new_with_uuid(|uuid, ptr_ptr| {
            adapter.GetParent(uuid, ptr_ptr)
        })?;

        // Create the DirectComposition device object.
        let composition_device = ComPtr::<IDCompositionDevice>::new_with_uuid(|uuid, ptr_ptr| {
            winapi::um::dcomp::DCompositionCreateDevice(&*dxgi_device, uuid,ptr_ptr)
        })?;

        // Create the composition target object based on the
        // specified application window.
        let composition_target = ComPtr::new_with(|ptr_ptr| {
            composition_device.CreateTargetForHwnd(hwnd, TRUE, ptr_ptr)
        })?;

        let root_visual = ComPtr::new_with(|ptr_ptr| composition_device.CreateVisual(ptr_ptr))?;
        composition_target.SetRoot(&*root_visual).to_result()?;

        Ok(DirectComposition {
            d3d_device, dxgi_factory,
            egl, gleam,
            composition_device, composition_target, root_visual,
        })
    }

    /// Execute changes to the DirectComposition scene.
    pub fn commit(&self) -> HResult<()> {
        unsafe {
            self.composition_device.Commit().to_result()
        }
    }

    pub fn create_d3d_visual(&self, width: u32, height: u32) -> HResult<D3DVisual> {
        unsafe {
            let desc = DXGI_SWAP_CHAIN_DESC1 {
                Width: width,
                Height: height,
                Format: winapi::shared::dxgiformat::DXGI_FORMAT_B8G8R8A8_UNORM,
                Stereo: FALSE,
                SampleDesc: winapi::shared::dxgitype::DXGI_SAMPLE_DESC {
                    Count: 1,
                    Quality: 0,
                },
                BufferUsage: winapi::shared::dxgitype::DXGI_USAGE_RENDER_TARGET_OUTPUT,
                BufferCount: 2,
                Scaling: winapi::shared::dxgi1_2::DXGI_SCALING_STRETCH,
                SwapEffect: winapi::shared::dxgi::DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL,
                AlphaMode:  winapi::shared::dxgi1_2::DXGI_ALPHA_MODE_PREMULTIPLIED,
                Flags: 0,
            };
            let swap_chain = ComPtr::<winapi::shared::dxgi1_2::IDXGISwapChain1>::new_with(|ptr_ptr| {
                self.dxgi_factory.CreateSwapChainForComposition(
                    as_ptr(&self.d3d_device),
                    &desc,
                    ptr::null_mut(),
                    ptr_ptr,
                )
            })?;
            let back_buffer = ComPtr::<winapi::um::d3d11::ID3D11Texture2D>::new_with_uuid(|uuid, ptr_ptr| {
                swap_chain.GetBuffer(0, uuid, ptr_ptr)
            })?;
            let egl = egl::PerVisualEglThings::new(self.egl.clone(), &*back_buffer, width, height);
            let gleam = self.gleam.clone();

            let visual = ComPtr::new_with(|ptr_ptr| self.composition_device.CreateVisual(ptr_ptr))?;
            visual.SetContent(&*****swap_chain).to_result()?;
            self.root_visual.AddVisual(&*visual, FALSE, ptr::null_mut()).to_result()?;

            Ok(D3DVisual { visual, swap_chain, back_buffer, egl, gleam })
        }
    }
}

/// A DirectComposition "visual" configured for rendering with Direct3D.
pub struct D3DVisual {
    visual: ComPtr<IDCompositionVisual>,
    swap_chain: ComPtr<winapi::shared::dxgi1_2::IDXGISwapChain1>,

    #[allow(unused)]  // FIXME: does this need to be kept alive?
    back_buffer: ComPtr<winapi::um::d3d11::ID3D11Texture2D>,

    egl: egl::PerVisualEglThings,
    pub gleam: Rc<gleam::gl::Gl>,
}

impl D3DVisual {
    pub fn set_offset_x(&self, offset_x: f32) -> HResult<()> {
        unsafe {
            self.visual.SetOffsetX_1(offset_x).to_result()
        }
    }

    pub fn set_offset_y(&self, offset_y: f32) -> HResult<()> {
        unsafe {
            self.visual.SetOffsetY_1(offset_y).to_result()
        }
    }

    pub fn make_current(&self) {
        self.egl.make_current()
    }

    pub fn present(&self) {
        self.gleam.finish();
        unsafe {
            self.swap_chain.Present(0, 0).to_result().unwrap()
        }
    }
}
<commit_msg>Keeping a reference to back_buffer isn’t necessary.<commit_after>#![cfg(windows)]

extern crate winapi;
extern crate gleam;

use com::{ComPtr, ToResult, HResult, as_ptr};
use std::ptr;
use std::rc::Rc;
use winapi::shared::dxgi1_2::DXGI_SWAP_CHAIN_DESC1;
use winapi::shared::dxgi1_2::IDXGIFactory2;
use winapi::shared::minwindef::{TRUE, FALSE};
use winapi::shared::windef::HWND;
use winapi::um::d3d11::ID3D11Device;
use winapi::um::dcomp::IDCompositionDevice;
use winapi::um::dcomp::IDCompositionTarget;
use winapi::um::dcomp::IDCompositionVisual;

pub mod com;
mod egl;

pub struct DirectComposition {
    d3d_device: ComPtr<ID3D11Device>,
    dxgi_factory: ComPtr<IDXGIFactory2>,

    egl: Rc<egl::SharedEglThings>,
    pub gleam: Rc<gleam::gl::Gl>,

    composition_device: ComPtr<IDCompositionDevice>,
    root_visual: ComPtr<IDCompositionVisual>,

    #[allow(unused)]  // Needs to be kept alive
    composition_target: ComPtr<IDCompositionTarget>,
}

impl DirectComposition {
    /// Initialize DirectComposition in the given window
    ///
    /// # Safety
    ///
    /// `hwnd` must be a valid handle to a window.
    pub unsafe fn new(hwnd: HWND) -> HResult<Self> {
        let d3d_device = ComPtr::new_with(|ptr_ptr| winapi::um::d3d11::D3D11CreateDevice(
            ptr::null_mut(),
            winapi::um::d3dcommon::D3D_DRIVER_TYPE_HARDWARE,
            ptr::null_mut(),
            winapi::um::d3d11::D3D11_CREATE_DEVICE_BGRA_SUPPORT |
            if cfg!(debug_assertions) {
                winapi::um::d3d11::D3D11_CREATE_DEVICE_DEBUG
            } else {
                0
            },
            ptr::null_mut(),
            0,
            winapi::um::d3d11::D3D11_SDK_VERSION,
            ptr_ptr,
            &mut 0,
            ptr::null_mut(),
        ))?;

        let egl = egl::SharedEglThings::new(d3d_device.as_raw());
        let gleam = gleam::gl::GlesFns::load_with(|name| egl.get_proc_address(name));

        let dxgi_device = d3d_device.cast::<winapi::shared::dxgi::IDXGIDevice>()?;

        // https://msdn.microsoft.com/en-us/library/windows/desktop/hh404556(v=vs.85).aspx#code-snippet-1
        // “Because you can create a Direct3D device without creating a swap chain,
        //  you might need to retrieve the factory that is used to create the device
        //  in order to create a swap chain.”
        let adapter = ComPtr::new_with(|ptr_ptr| dxgi_device.GetAdapter(ptr_ptr))?;
        let dxgi_factory = ComPtr::<IDXGIFactory2>::new_with_uuid(|uuid, ptr_ptr| {
            adapter.GetParent(uuid, ptr_ptr)
        })?;

        // Create the DirectComposition device object.
        let composition_device = ComPtr::<IDCompositionDevice>::new_with_uuid(|uuid, ptr_ptr| {
            winapi::um::dcomp::DCompositionCreateDevice(&*dxgi_device, uuid,ptr_ptr)
        })?;

        // Create the composition target object based on the
        // specified application window.
        let composition_target = ComPtr::new_with(|ptr_ptr| {
            composition_device.CreateTargetForHwnd(hwnd, TRUE, ptr_ptr)
        })?;

        let root_visual = ComPtr::new_with(|ptr_ptr| composition_device.CreateVisual(ptr_ptr))?;
        composition_target.SetRoot(&*root_visual).to_result()?;

        Ok(DirectComposition {
            d3d_device, dxgi_factory,
            egl, gleam,
            composition_device, composition_target, root_visual,
        })
    }

    /// Execute changes to the DirectComposition scene.
    pub fn commit(&self) -> HResult<()> {
        unsafe {
            self.composition_device.Commit().to_result()
        }
    }

    pub fn create_d3d_visual(&self, width: u32, height: u32) -> HResult<D3DVisual> {
        unsafe {
            let desc = DXGI_SWAP_CHAIN_DESC1 {
                Width: width,
                Height: height,
                Format: winapi::shared::dxgiformat::DXGI_FORMAT_B8G8R8A8_UNORM,
                Stereo: FALSE,
                SampleDesc: winapi::shared::dxgitype::DXGI_SAMPLE_DESC {
                    Count: 1,
                    Quality: 0,
                },
                BufferUsage: winapi::shared::dxgitype::DXGI_USAGE_RENDER_TARGET_OUTPUT,
                BufferCount: 2,
                Scaling: winapi::shared::dxgi1_2::DXGI_SCALING_STRETCH,
                SwapEffect: winapi::shared::dxgi::DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL,
                AlphaMode:  winapi::shared::dxgi1_2::DXGI_ALPHA_MODE_PREMULTIPLIED,
                Flags: 0,
            };
            let swap_chain = ComPtr::<winapi::shared::dxgi1_2::IDXGISwapChain1>::new_with(|ptr_ptr| {
                self.dxgi_factory.CreateSwapChainForComposition(
                    as_ptr(&self.d3d_device),
                    &desc,
                    ptr::null_mut(),
                    ptr_ptr,
                )
            })?;
            let back_buffer = ComPtr::<winapi::um::d3d11::ID3D11Texture2D>::new_with_uuid(|uuid, ptr_ptr| {
                swap_chain.GetBuffer(0, uuid, ptr_ptr)
            })?;
            let egl = egl::PerVisualEglThings::new(self.egl.clone(), &*back_buffer, width, height);
            let gleam = self.gleam.clone();

            let visual = ComPtr::new_with(|ptr_ptr| self.composition_device.CreateVisual(ptr_ptr))?;
            visual.SetContent(&*****swap_chain).to_result()?;
            self.root_visual.AddVisual(&*visual, FALSE, ptr::null_mut()).to_result()?;

            Ok(D3DVisual { visual, swap_chain, egl, gleam })
        }
    }
}

/// A DirectComposition "visual" configured for rendering with Direct3D.
pub struct D3DVisual {
    visual: ComPtr<IDCompositionVisual>,
    swap_chain: ComPtr<winapi::shared::dxgi1_2::IDXGISwapChain1>,
    egl: egl::PerVisualEglThings,
    pub gleam: Rc<gleam::gl::Gl>,
}

impl D3DVisual {
    pub fn set_offset_x(&self, offset_x: f32) -> HResult<()> {
        unsafe {
            self.visual.SetOffsetX_1(offset_x).to_result()
        }
    }

    pub fn set_offset_y(&self, offset_y: f32) -> HResult<()> {
        unsafe {
            self.visual.SetOffsetY_1(offset_y).to_result()
        }
    }

    pub fn make_current(&self) {
        self.egl.make_current()
    }

    pub fn present(&self) {
        self.gleam.finish();
        unsafe {
            self.swap_chain.Present(0, 0).to_result().unwrap()
        }
    }
}
<|endoftext|>


<commit_before>use neon::prelude::*;
use neon::types::JsDate;

pub fn create_date(mut cx: FunctionContext) -> JsResult<JsDate> {
    let date = cx.date(31415);
    Ok(date)
}

pub fn create_date_from_value(mut cx: FunctionContext) -> JsResult<JsDate> {
    let time = cx.argument::<JsNumber>(0)?.value(&mut cx);
    let date = cx.date(time);
    Ok(date)
}

pub fn check_date_is_valid(mut cx: FunctionContext) -> JsResult<JsBoolean> {
    let time = cx.argument::<JsNumber>(0)?.value(&mut cx);
    let date = cx.date(time);
    let is_valid = date.is_valid(&mut cx);
    Ok(cx.boolean(is_valid))
}

pub fn try_new_date(mut cx: FunctionContext) -> JsResult<JsUndefined> {
    let date_overflow = JsDate::try_new(&mut cx, JsDate::MAX_VALUE + 1.0);
    let date_underflow = JsDate::try_new(&mut cx, JsDate::MIN_VALUE - 1.0);
    assert_eq!(date_overflow.unwrap_err(), neon::types::DateErrorKind::Overflow);
    assert_eq!(date_underflow.unwrap_err(), neon::types::DateErrorKind::Underflow);
    Ok(cx.undefined())
}

pub fn check_date_is_invalid(mut cx: FunctionContext) -> JsResult<JsBoolean> {
    let time = JsDate::MIN_VALUE - 1.0;
    let date = cx.date(time);
    let is_valid = date.is_valid(&mut cx);
    let val = date.value(&mut cx);
    Ok(cx.boolean(is_valid))
}

pub fn create_and_get_invalid_date(mut cx: FunctionContext) -> JsResult<JsNumber> {
    let time = JsDate::MAX_VALUE + 1.0;
    let date = cx.date(time).value(&mut cx);
    assert!(!cx.date(time).is_valid(&mut cx));
    assert!(cx.date(time).value(&mut cx).is_nan());
    Ok(cx.number(date))
}

pub fn get_date_value(mut cx: FunctionContext) -> JsResult<JsNumber> {
    let date = cx.date(31415);
    let value = date.value(&mut cx);
    println!("{:?}", value);
    Ok(cx.number(value))
}
<commit_msg>test: add additional date api test cases<commit_after>use neon::prelude::*;
use neon::types::JsDate;

pub fn create_date(mut cx: FunctionContext) -> JsResult<JsDate> {
    let date = cx.date(31415);
    Ok(date)
}

pub fn create_date_from_value(mut cx: FunctionContext) -> JsResult<JsDate> {
    let time = cx.argument::<JsNumber>(0)?.value(&mut cx);
    let date = cx.date(time);
    Ok(date)
}

pub fn check_date_is_valid(mut cx: FunctionContext) -> JsResult<JsBoolean> {
    let time = cx.argument::<JsNumber>(0)?.value(&mut cx);
    let date = cx.date(time);
    let is_valid = date.is_valid(&mut cx);
    Ok(cx.boolean(is_valid))
}

pub fn try_new_date(mut cx: FunctionContext) -> JsResult<JsUndefined> {
    let date_overflow = JsDate::try_new(&mut cx, JsDate::MAX_VALUE + 1.0);
    let date_underflow = JsDate::try_new(&mut cx, JsDate::MIN_VALUE - 1.0);
    assert_eq!(date_overflow.unwrap_err(), neon::types::DateErrorKind::Overflow);
    assert_eq!(date_underflow.unwrap_err(), neon::types::DateErrorKind::Underflow);
    Ok(cx.undefined())
}

pub fn check_date_is_invalid(mut cx: FunctionContext) -> JsResult<JsBoolean> {
    let time = JsDate::MIN_VALUE - 1.0;
    let date = cx.date(time);
    let is_valid = date.is_valid(&mut cx);
    let val = date.value(&mut cx);
    Ok(cx.boolean(is_valid))
}

pub fn create_and_get_invalid_date(mut cx: FunctionContext) -> JsResult<JsNumber> {
    let time = JsDate::MAX_VALUE + 1.0;
    let date = cx.date(time).value(&mut cx);
    assert!(!cx.date(time).is_valid(&mut cx));
    assert!(cx.date(time).value(&mut cx).is_nan());

    let time = JsDate::MIN_VALUE - 1.0;
    let date = cx.date(time).value(&mut cx);
    assert!(!cx.date(time).is_valid(&mut cx));
    assert!(cx.date(time).value(&mut cx).is_nan());

    let time = JsDate::MAX_VALUE + 2.0;
    let date = cx.date(time).value(&mut cx);
    assert!(!cx.date(time).is_valid(&mut cx));
    assert!(cx.date(time).value(&mut cx).is_nan());

    let time = JsDate::MAX_VALUE + 3.0;
    let date = cx.date(time).value(&mut cx);
    assert!(!cx.date(time).is_valid(&mut cx));
    assert!(cx.date(time).value(&mut cx).is_nan());

    let time = JsDate::MAX_VALUE + 1_000.0;
    let date = cx.date(time).value(&mut cx);
    assert!(!cx.date(time).is_valid(&mut cx));
    assert!(cx.date(time).value(&mut cx).is_nan());

    Ok(cx.number(date))
}

pub fn get_date_value(mut cx: FunctionContext) -> JsResult<JsNumber> {
    let date = cx.date(31415);
    let value = date.value(&mut cx);
    println!("{:?}", value);
    Ok(cx.number(value))
}
<|endoftext|>


<commit_before><commit_msg>Fix the head-tracker quaternion multiplication order<commit_after><|endoftext|>


<commit_before>use std::cell::{Cell, RefCell};
use std::collections::{HashMap, VecDeque};
use std::fmt;
use std::io;
use std::ops::{Deref, DerefMut, BitAndAssign};
use std::rc::Rc;
use std::time::{Duration, Instant};

use futures::{Future, Async, Poll};
use relay;

use proto::{KeepAlive, KA};

pub struct Pool<T> {
    inner: Rc<RefCell<PoolInner<T>>>,
}

struct PoolInner<T> {
    enabled: bool,
    // These are internal Conns sitting in the event loop in the KeepAlive
    // state, waiting to receive a new Request to send on the socket.
    idle: HashMap<Rc<String>, Vec<Entry<T>>>,
    // These are outstanding Checkouts that are waiting for a socket to be
    // able to send a Request one. This is used when "racing" for a new
    // connection.
    //
    // The Client starts 2 tasks, 1 to connect a new socket, and 1 to wait
    // for the Pool to receive an idle Conn. When a Conn becomes idle,
    // this list is checked for any parked Checkouts, and tries to notify
    // them that the Conn could be used instead of waiting for a brand new
    // connection.
    parked: HashMap<Rc<String>, VecDeque<relay::Sender<Entry<T>>>>,
    timeout: Option<Duration>,
}

impl<T: Clone> Pool<T> {
    pub fn new(enabled: bool, timeout: Option<Duration>) -> Pool<T> {
        Pool {
            inner: Rc::new(RefCell::new(PoolInner {
                enabled: enabled,
                idle: HashMap::new(),
                parked: HashMap::new(),
                timeout: timeout,
            })),
        }
    }

    pub fn checkout(&self, key: &str) -> Checkout<T> {
        Checkout {
            key: Rc::new(key.to_owned()),
            pool: self.clone(),
            parked: None,
        }
    }

    fn put(&mut self, key: Rc<String>, entry: Entry<T>) {
        trace!("Pool::put {:?}", key);
        let mut inner = self.inner.borrow_mut();
        //let inner = &mut *inner;
        let mut remove_parked = false;
        let mut entry = Some(entry);
        if let Some(parked) = inner.parked.get_mut(&key) {
            while let Some(tx) = parked.pop_front() {
                if tx.is_canceled() {
                    trace!("Pool::put removing canceled parked {:?}", key);
                } else {
                    tx.complete(entry.take().unwrap());
                }
                /*
                match tx.send(entry.take().unwrap()) {
                    Ok(()) => break,
                    Err(e) => {
                        trace!("Pool::put removing canceled parked {:?}", key);
                        entry = Some(e);
                    }
                }
                */
            }
            remove_parked = parked.is_empty();
        }
        if remove_parked {
            inner.parked.remove(&key);
        }

        match entry {
            Some(entry) => {
                inner.idle.entry(key)
                     .or_insert(Vec::new())
                     .push(entry);
            }
            None => trace!("Pool::put found parked {:?}", key),
        }
    }

    pub fn pooled(&self, key: Rc<String>, value: T) -> Pooled<T> {
        trace!("Pool::pooled {:?}", key);
        Pooled {
            entry: Entry {
                value: value,
                is_reused: false,
                status: Rc::new(Cell::new(TimedKA::Busy)),
            },
            key: key,
            pool: self.clone(),
        }
    }

    fn is_enabled(&self) -> bool {
        self.inner.borrow().enabled
    }

    fn reuse(&self, key: Rc<String>, mut entry: Entry<T>) -> Pooled<T> {
        trace!("Pool::reuse {:?}", key);
        entry.is_reused = true;
        entry.status.set(TimedKA::Busy);
        Pooled {
            entry: entry,
            key: key,
            pool: self.clone(),
        }
    }

    fn park(&mut self, key: Rc<String>, tx: relay::Sender<Entry<T>>) {
        trace!("Pool::park {:?}", key);
        self.inner.borrow_mut()
            .parked.entry(key)
            .or_insert(VecDeque::new())
            .push_back(tx);
    }
}

impl<T> Pool<T> {
    fn clean_parked(&mut self, key: &Rc<String>) {
        trace!("Pool::clean_parked {:?}", key);
        let mut inner = self.inner.borrow_mut();

        let mut remove_parked = false;
        if let Some(parked) = inner.parked.get_mut(key) {
            parked.retain(|tx| {
                !tx.is_canceled()
            });
            remove_parked = parked.is_empty();
        }
        if remove_parked {
            inner.parked.remove(key);
        }
    }
}

impl<T> Clone for Pool<T> {
    fn clone(&self) -> Pool<T> {
        Pool {
            inner: self.inner.clone(),
        }
    }
}

#[derive(Clone)]
pub struct Pooled<T> {
    entry: Entry<T>,
    key: Rc<String>,
    pool: Pool<T>,
}

impl<T> Deref for Pooled<T> {
    type Target = T;
    fn deref(&self) -> &T {
        &self.entry.value
    }
}

impl<T> DerefMut for Pooled<T> {
    fn deref_mut(&mut self) -> &mut T {
        &mut self.entry.value
    }
}

impl<T: Clone> KeepAlive for Pooled<T> {
    fn busy(&mut self) {
        self.entry.status.set(TimedKA::Busy);
    }

    fn disable(&mut self) {
        self.entry.status.set(TimedKA::Disabled);
    }

    fn idle(&mut self) {
        let previous = self.status();
        self.entry.status.set(TimedKA::Idle(Instant::now()));
        if let KA::Idle = previous {
            trace!("Pooled::idle already idle");
            return;
        }
        self.entry.is_reused = true;
        if self.pool.is_enabled() {
            self.pool.put(self.key.clone(), self.entry.clone());
        }
    }

    fn status(&self) -> KA {
        match self.entry.status.get() {
            TimedKA::Idle(_) => KA::Idle,
            TimedKA::Busy => KA::Busy,
            TimedKA::Disabled => KA::Disabled,
        }
    }
}

impl<T> fmt::Debug for Pooled<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Pooled")
            .field("status", &self.entry.status.get())
            .field("key", &self.key)
            .finish()
    }
}

impl<T: Clone> BitAndAssign<bool> for Pooled<T> {
    fn bitand_assign(&mut self, enabled: bool) {
        if !enabled {
            self.disable();
        }
    }
}

#[derive(Clone)]
struct Entry<T> {
    value: T,
    is_reused: bool,
    status: Rc<Cell<TimedKA>>,
}

#[derive(Clone, Copy, Debug)]
enum TimedKA {
    Idle(Instant),
    Busy,
    Disabled,
}

pub struct Checkout<T> {
    key: Rc<String>,
    pool: Pool<T>,
    parked: Option<relay::Receiver<Entry<T>>>,
}

impl<T: Clone> Future for Checkout<T> {
    type Item = Pooled<T>;
    type Error = io::Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        trace!("Checkout::poll");
        let mut drop_parked = false;
        if let Some(ref mut rx) = self.parked {
            match rx.poll() {
                Ok(Async::Ready(entry)) => {
                    trace!("Checkout::poll found client in relay for {:?}", self.key);
                    return Ok(Async::Ready(self.pool.reuse(self.key.clone(), entry)));
                },
                Ok(Async::NotReady) => (),
                Err(_canceled) => drop_parked = true,
            }
        }
        if drop_parked {
            self.parked.take();
        }
        let expiration = Expiration::new(self.pool.inner.borrow().timeout);
        let key = &self.key;
        trace!("Checkout::poll url = {:?}, expiration = {:?}", key, expiration.0);
        let mut should_remove = false;
        let entry = self.pool.inner.borrow_mut().idle.get_mut(key).and_then(|list| {
            trace!("Checkout::poll key found {:?}", key);
            while let Some(entry) = list.pop() {
                match entry.status.get() {
                    TimedKA::Idle(idle_at) if !expiration.expires(idle_at) => {
                        trace!("Checkout::poll found idle client for {:?}", key);
                        should_remove = list.is_empty();
                        return Some(entry);
                    },
                    _ => {
                        trace!("Checkout::poll removing unacceptable pooled {:?}", key);
                        // every other case the Entry should just be dropped
                        // 1. Idle but expired
                        // 2. Busy (something else somehow took it?)
                        // 3. Disabled don't reuse of course
                    }
                }
            }
            should_remove = true;
            None
        });

        if should_remove {
            self.pool.inner.borrow_mut().idle.remove(key);
        }
        match entry {
            Some(entry) => Ok(Async::Ready(self.pool.reuse(self.key.clone(), entry))),
            None => {
                if self.parked.is_none() {
                    let (tx, mut rx) = relay::channel();
                    let _ = rx.poll(); // park this task
                    self.pool.park(self.key.clone(), tx);
                    self.parked = Some(rx);
                }
                Ok(Async::NotReady)
            },
        }
    }
}

impl<T> Drop for Checkout<T> {
    fn drop(&mut self) {
        self.parked.take();
        self.pool.clean_parked(&self.key);
    }
}

struct Expiration(Option<Duration>);

impl Expiration {
    fn new(dur: Option<Duration>) -> Expiration {
        Expiration(dur)
    }

    fn expires(&self, instant: Instant) -> bool {
        match self.0 {
            Some(timeout) => instant.elapsed() > timeout,
            None => false,
        }
    }
}

#[cfg(test)]
mod tests {
    use std::rc::Rc;
    use std::time::Duration;
    use futures::{Async, Future};
    use futures::future;
    use proto::KeepAlive;
    use super::Pool;

    #[test]
    fn test_pool_checkout_smoke() {
        let pool = Pool::new(true, Some(Duration::from_secs(5)));
        let key = Rc::new("foo".to_string());
        let mut pooled = pool.pooled(key.clone(), 41);
        pooled.idle();

        match pool.checkout(&key).poll().unwrap() {
            Async::Ready(pooled) => assert_eq!(*pooled, 41),
            _ => panic!("not ready"),
        }
    }

    #[test]
    fn test_pool_checkout_returns_none_if_expired() {
        future::lazy(|| {
            let pool = Pool::new(true, Some(Duration::from_secs(1)));
            let key = Rc::new("foo".to_string());
            let mut pooled = pool.pooled(key.clone(), 41);
            pooled.idle();
            ::std::thread::sleep(pool.inner.borrow().timeout.unwrap());
            assert!(pool.checkout(&key).poll().unwrap().is_not_ready());
            ::futures::future::ok::<(), ()>(())
        }).wait().unwrap();
    }

    #[test]
    fn test_pool_removes_expired() {
        let pool = Pool::new(true, Some(Duration::from_secs(1)));
        let key = Rc::new("foo".to_string());

        let mut pooled1 = pool.pooled(key.clone(), 41);
        pooled1.idle();
        let mut pooled2 = pool.pooled(key.clone(), 5);
        pooled2.idle();
        let mut pooled3 = pool.pooled(key.clone(), 99);
        pooled3.idle();

        assert_eq!(pool.inner.borrow().idle.get(&key).map(|entries| entries.len()), Some(3));
        ::std::thread::sleep(pool.inner.borrow().timeout.unwrap());

        pooled1.idle();
        pooled2.idle(); // idle after sleep, not expired
        pool.checkout(&key).poll().unwrap();
        assert_eq!(pool.inner.borrow().idle.get(&key).map(|entries| entries.len()), Some(1));
        pool.checkout(&key).poll().unwrap();
        assert!(pool.inner.borrow().idle.get(&key).is_none());
    }

    #[test]
    fn test_pool_checkout_task_unparked() {
        let pool = Pool::new(true, Some(Duration::from_secs(10)));
        let key = Rc::new("foo".to_string());
        let pooled1 = pool.pooled(key.clone(), 41);

        let mut pooled = pooled1.clone();
        let checkout = pool.checkout(&key).join(future::lazy(move || {
            // the checkout future will park first,
            // and then this lazy future will be polled, which will insert
            // the pooled back into the pool
            //
            // this test makes sure that doing so will unpark the checkout
            pooled.idle();
            Ok(())
        })).map(|(entry, _)| entry);
        assert_eq!(*checkout.wait().unwrap(), *pooled1);
    }

    #[test]
    fn test_pool_checkout_drop_cleans_up_parked() {
        future::lazy(|| {
            let pool = Pool::new(true, Some(Duration::from_secs(10)));
            let key = Rc::new("localhost:12345".to_string());
            let _pooled1 = pool.pooled(key.clone(), 41);
            let mut checkout1 = pool.checkout(&key);
            let mut checkout2 = pool.checkout(&key);

            // first poll needed to get into Pool's parked
            checkout1.poll().unwrap();
            assert_eq!(pool.inner.borrow().parked.get(&key).unwrap().len(), 1);
            checkout2.poll().unwrap();
            assert_eq!(pool.inner.borrow().parked.get(&key).unwrap().len(), 2);

            // on drop, clean up Pool
            drop(checkout1);
            assert_eq!(pool.inner.borrow().parked.get(&key).unwrap().len(), 1);

            drop(checkout2);
            assert!(pool.inner.borrow().parked.get(&key).is_none());

            ::futures::future::ok::<(), ()>(())
        }).wait().unwrap();
    }
}
<commit_msg>fix(client): fix panic in Pool<commit_after>use std::cell::{Cell, RefCell};
use std::collections::{HashMap, VecDeque};
use std::fmt;
use std::io;
use std::ops::{Deref, DerefMut, BitAndAssign};
use std::rc::Rc;
use std::time::{Duration, Instant};

use futures::{Future, Async, Poll};
use relay;

use proto::{KeepAlive, KA};

pub struct Pool<T> {
    inner: Rc<RefCell<PoolInner<T>>>,
}

struct PoolInner<T> {
    enabled: bool,
    // These are internal Conns sitting in the event loop in the KeepAlive
    // state, waiting to receive a new Request to send on the socket.
    idle: HashMap<Rc<String>, Vec<Entry<T>>>,
    // These are outstanding Checkouts that are waiting for a socket to be
    // able to send a Request one. This is used when "racing" for a new
    // connection.
    //
    // The Client starts 2 tasks, 1 to connect a new socket, and 1 to wait
    // for the Pool to receive an idle Conn. When a Conn becomes idle,
    // this list is checked for any parked Checkouts, and tries to notify
    // them that the Conn could be used instead of waiting for a brand new
    // connection.
    parked: HashMap<Rc<String>, VecDeque<relay::Sender<Entry<T>>>>,
    timeout: Option<Duration>,
}

impl<T: Clone> Pool<T> {
    pub fn new(enabled: bool, timeout: Option<Duration>) -> Pool<T> {
        Pool {
            inner: Rc::new(RefCell::new(PoolInner {
                enabled: enabled,
                idle: HashMap::new(),
                parked: HashMap::new(),
                timeout: timeout,
            })),
        }
    }

    pub fn checkout(&self, key: &str) -> Checkout<T> {
        Checkout {
            key: Rc::new(key.to_owned()),
            pool: self.clone(),
            parked: None,
        }
    }

    fn put(&mut self, key: Rc<String>, entry: Entry<T>) {
        trace!("Pool::put {:?}", key);
        let mut inner = self.inner.borrow_mut();
        //let inner = &mut *inner;
        let mut remove_parked = false;
        let mut entry = Some(entry);
        if let Some(parked) = inner.parked.get_mut(&key) {
            while let Some(tx) = parked.pop_front() {
                if tx.is_canceled() {
                    trace!("Pool::put removing canceled parked {:?}", key);
                } else {
                    tx.complete(entry.take().unwrap());
                    break;
                }
                /*
                match tx.send(entry.take().unwrap()) {
                    Ok(()) => break,
                    Err(e) => {
                        trace!("Pool::put removing canceled parked {:?}", key);
                        entry = Some(e);
                    }
                }
                */
            }
            remove_parked = parked.is_empty();
        }
        if remove_parked {
            inner.parked.remove(&key);
        }

        match entry {
            Some(entry) => {
                inner.idle.entry(key)
                     .or_insert(Vec::new())
                     .push(entry);
            }
            None => trace!("Pool::put found parked {:?}", key),
        }
    }

    pub fn pooled(&self, key: Rc<String>, value: T) -> Pooled<T> {
        trace!("Pool::pooled {:?}", key);
        Pooled {
            entry: Entry {
                value: value,
                is_reused: false,
                status: Rc::new(Cell::new(TimedKA::Busy)),
            },
            key: key,
            pool: self.clone(),
        }
    }

    fn is_enabled(&self) -> bool {
        self.inner.borrow().enabled
    }

    fn reuse(&self, key: Rc<String>, mut entry: Entry<T>) -> Pooled<T> {
        trace!("Pool::reuse {:?}", key);
        entry.is_reused = true;
        entry.status.set(TimedKA::Busy);
        Pooled {
            entry: entry,
            key: key,
            pool: self.clone(),
        }
    }

    fn park(&mut self, key: Rc<String>, tx: relay::Sender<Entry<T>>) {
        trace!("Pool::park {:?}", key);
        self.inner.borrow_mut()
            .parked.entry(key)
            .or_insert(VecDeque::new())
            .push_back(tx);
    }
}

impl<T> Pool<T> {
    fn clean_parked(&mut self, key: &Rc<String>) {
        trace!("Pool::clean_parked {:?}", key);
        let mut inner = self.inner.borrow_mut();

        let mut remove_parked = false;
        if let Some(parked) = inner.parked.get_mut(key) {
            parked.retain(|tx| {
                !tx.is_canceled()
            });
            remove_parked = parked.is_empty();
        }
        if remove_parked {
            inner.parked.remove(key);
        }
    }
}

impl<T> Clone for Pool<T> {
    fn clone(&self) -> Pool<T> {
        Pool {
            inner: self.inner.clone(),
        }
    }
}

#[derive(Clone)]
pub struct Pooled<T> {
    entry: Entry<T>,
    key: Rc<String>,
    pool: Pool<T>,
}

impl<T> Deref for Pooled<T> {
    type Target = T;
    fn deref(&self) -> &T {
        &self.entry.value
    }
}

impl<T> DerefMut for Pooled<T> {
    fn deref_mut(&mut self) -> &mut T {
        &mut self.entry.value
    }
}

impl<T: Clone> KeepAlive for Pooled<T> {
    fn busy(&mut self) {
        self.entry.status.set(TimedKA::Busy);
    }

    fn disable(&mut self) {
        self.entry.status.set(TimedKA::Disabled);
    }

    fn idle(&mut self) {
        let previous = self.status();
        self.entry.status.set(TimedKA::Idle(Instant::now()));
        if let KA::Idle = previous {
            trace!("Pooled::idle already idle");
            return;
        }
        self.entry.is_reused = true;
        if self.pool.is_enabled() {
            self.pool.put(self.key.clone(), self.entry.clone());
        }
    }

    fn status(&self) -> KA {
        match self.entry.status.get() {
            TimedKA::Idle(_) => KA::Idle,
            TimedKA::Busy => KA::Busy,
            TimedKA::Disabled => KA::Disabled,
        }
    }
}

impl<T> fmt::Debug for Pooled<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Pooled")
            .field("status", &self.entry.status.get())
            .field("key", &self.key)
            .finish()
    }
}

impl<T: Clone> BitAndAssign<bool> for Pooled<T> {
    fn bitand_assign(&mut self, enabled: bool) {
        if !enabled {
            self.disable();
        }
    }
}

#[derive(Clone)]
struct Entry<T> {
    value: T,
    is_reused: bool,
    status: Rc<Cell<TimedKA>>,
}

#[derive(Clone, Copy, Debug)]
enum TimedKA {
    Idle(Instant),
    Busy,
    Disabled,
}

pub struct Checkout<T> {
    key: Rc<String>,
    pool: Pool<T>,
    parked: Option<relay::Receiver<Entry<T>>>,
}

impl<T: Clone> Future for Checkout<T> {
    type Item = Pooled<T>;
    type Error = io::Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        trace!("Checkout::poll");
        let mut drop_parked = false;
        if let Some(ref mut rx) = self.parked {
            match rx.poll() {
                Ok(Async::Ready(entry)) => {
                    trace!("Checkout::poll found client in relay for {:?}", self.key);
                    return Ok(Async::Ready(self.pool.reuse(self.key.clone(), entry)));
                },
                Ok(Async::NotReady) => (),
                Err(_canceled) => drop_parked = true,
            }
        }
        if drop_parked {
            self.parked.take();
        }
        let expiration = Expiration::new(self.pool.inner.borrow().timeout);
        let key = &self.key;
        trace!("Checkout::poll url = {:?}, expiration = {:?}", key, expiration.0);
        let mut should_remove = false;
        let entry = self.pool.inner.borrow_mut().idle.get_mut(key).and_then(|list| {
            trace!("Checkout::poll key found {:?}", key);
            while let Some(entry) = list.pop() {
                match entry.status.get() {
                    TimedKA::Idle(idle_at) if !expiration.expires(idle_at) => {
                        trace!("Checkout::poll found idle client for {:?}", key);
                        should_remove = list.is_empty();
                        return Some(entry);
                    },
                    _ => {
                        trace!("Checkout::poll removing unacceptable pooled {:?}", key);
                        // every other case the Entry should just be dropped
                        // 1. Idle but expired
                        // 2. Busy (something else somehow took it?)
                        // 3. Disabled don't reuse of course
                    }
                }
            }
            should_remove = true;
            None
        });

        if should_remove {
            self.pool.inner.borrow_mut().idle.remove(key);
        }
        match entry {
            Some(entry) => Ok(Async::Ready(self.pool.reuse(self.key.clone(), entry))),
            None => {
                if self.parked.is_none() {
                    let (tx, mut rx) = relay::channel();
                    let _ = rx.poll(); // park this task
                    self.pool.park(self.key.clone(), tx);
                    self.parked = Some(rx);
                }
                Ok(Async::NotReady)
            },
        }
    }
}

impl<T> Drop for Checkout<T> {
    fn drop(&mut self) {
        self.parked.take();
        self.pool.clean_parked(&self.key);
    }
}

struct Expiration(Option<Duration>);

impl Expiration {
    fn new(dur: Option<Duration>) -> Expiration {
        Expiration(dur)
    }

    fn expires(&self, instant: Instant) -> bool {
        match self.0 {
            Some(timeout) => instant.elapsed() > timeout,
            None => false,
        }
    }
}

#[cfg(test)]
mod tests {
    use std::rc::Rc;
    use std::time::Duration;
    use futures::{Async, Future};
    use futures::future;
    use proto::KeepAlive;
    use super::Pool;

    #[test]
    fn test_pool_checkout_smoke() {
        let pool = Pool::new(true, Some(Duration::from_secs(5)));
        let key = Rc::new("foo".to_string());
        let mut pooled = pool.pooled(key.clone(), 41);
        pooled.idle();

        match pool.checkout(&key).poll().unwrap() {
            Async::Ready(pooled) => assert_eq!(*pooled, 41),
            _ => panic!("not ready"),
        }
    }

    #[test]
    fn test_pool_checkout_returns_none_if_expired() {
        future::lazy(|| {
            let pool = Pool::new(true, Some(Duration::from_secs(1)));
            let key = Rc::new("foo".to_string());
            let mut pooled = pool.pooled(key.clone(), 41);
            pooled.idle();
            ::std::thread::sleep(pool.inner.borrow().timeout.unwrap());
            assert!(pool.checkout(&key).poll().unwrap().is_not_ready());
            ::futures::future::ok::<(), ()>(())
        }).wait().unwrap();
    }

    #[test]
    fn test_pool_removes_expired() {
        let pool = Pool::new(true, Some(Duration::from_secs(1)));
        let key = Rc::new("foo".to_string());

        let mut pooled1 = pool.pooled(key.clone(), 41);
        pooled1.idle();
        let mut pooled2 = pool.pooled(key.clone(), 5);
        pooled2.idle();
        let mut pooled3 = pool.pooled(key.clone(), 99);
        pooled3.idle();

        assert_eq!(pool.inner.borrow().idle.get(&key).map(|entries| entries.len()), Some(3));
        ::std::thread::sleep(pool.inner.borrow().timeout.unwrap());

        pooled1.idle();
        pooled2.idle(); // idle after sleep, not expired
        pool.checkout(&key).poll().unwrap();
        assert_eq!(pool.inner.borrow().idle.get(&key).map(|entries| entries.len()), Some(1));
        pool.checkout(&key).poll().unwrap();
        assert!(pool.inner.borrow().idle.get(&key).is_none());
    }

    #[test]
    fn test_pool_checkout_task_unparked() {
        let pool = Pool::new(true, Some(Duration::from_secs(10)));
        let key = Rc::new("foo".to_string());
        let pooled1 = pool.pooled(key.clone(), 41);

        let mut pooled = pooled1.clone();
        let checkout = pool.checkout(&key).join(future::lazy(move || {
            // the checkout future will park first,
            // and then this lazy future will be polled, which will insert
            // the pooled back into the pool
            //
            // this test makes sure that doing so will unpark the checkout
            pooled.idle();
            Ok(())
        })).map(|(entry, _)| entry);
        assert_eq!(*checkout.wait().unwrap(), *pooled1);
    }

    #[test]
    fn test_pool_checkout_drop_cleans_up_parked() {
        future::lazy(|| {
            let pool = Pool::new(true, Some(Duration::from_secs(10)));
            let key = Rc::new("localhost:12345".to_string());
            let _pooled1 = pool.pooled(key.clone(), 41);
            let mut checkout1 = pool.checkout(&key);
            let mut checkout2 = pool.checkout(&key);

            // first poll needed to get into Pool's parked
            checkout1.poll().unwrap();
            assert_eq!(pool.inner.borrow().parked.get(&key).unwrap().len(), 1);
            checkout2.poll().unwrap();
            assert_eq!(pool.inner.borrow().parked.get(&key).unwrap().len(), 2);

            // on drop, clean up Pool
            drop(checkout1);
            assert_eq!(pool.inner.borrow().parked.get(&key).unwrap().len(), 1);

            drop(checkout2);
            assert!(pool.inner.borrow().parked.get(&key).is_none());

            ::futures::future::ok::<(), ()>(())
        }).wait().unwrap();
    }
}
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
use std::fmt;

// To ensure we don't use stdlib allocating types by accident
#[allow(dead_code)]
struct Vec;
#[allow(dead_code)]
struct Box;
#[allow(dead_code)]
struct HashMap;
#[allow(dead_code)]
struct String;

macro_rules! box_database {
    ($($(#[$attr:meta])* $boxenum:ident $boxtype:expr),*,) => {
        #[derive(Clone, Copy, PartialEq)]
        pub enum BoxType {
            $($(#[$attr])* $boxenum),*,
            UnknownBox(u32),
        }

        impl From<u32> for BoxType {
            fn from(t: u32) -> BoxType {
                use self::BoxType::*;
                match t {
                    $($(#[$attr])* $boxtype => $boxenum),*,
                    _ => UnknownBox(t),
                }
            }
        }

        impl Into<u32> for BoxType {
            fn into(self) -> u32 {
                use self::BoxType::*;
                match self {
                    $($(#[$attr])* $boxenum => $boxtype),*,
                    UnknownBox(t) => t,
                }
            }
        }

    }
}

impl fmt::Debug for BoxType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let fourcc: FourCC = From::from(self.clone());
        fourcc.fmt(f)
    }
}

#[derive(Default, PartialEq, Clone)]
pub struct FourCC {
    pub value: [u8; 4],
}

impl From<u32> for FourCC {
    fn from(number: u32) -> FourCC {
        FourCC {
            value: number.to_be_bytes(),
        }
    }
}

impl From<BoxType> for FourCC {
    fn from(t: BoxType) -> FourCC {
        let box_num: u32 = Into::into(t);
        From::from(box_num)
    }
}

impl From<[u8; 4]> for FourCC {
    fn from(v: [u8; 4]) -> FourCC {
        FourCC { value: v }
    }
}

impl fmt::Debug for FourCC {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match std::str::from_utf8(&self.value) {
            Ok(s) => f.write_str(s),
            Err(_) => self.value.fmt(f),
        }
    }
}

impl fmt::Display for FourCC {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(std::str::from_utf8(&self.value).unwrap_or("null"))
    }
}

impl PartialEq<&[u8; 4]> for FourCC {
    fn eq(&self, other: &&[u8; 4]) -> bool {
        self.value.eq(*other)
    }
}

#[deny(unreachable_patterns)]
box_database!(
    FileTypeBox                       0x6674_7970, // "ftyp"
    MediaDataBox                      0x6d64_6174, // "mdat"
    PrimaryItemBox                    0x7069_746d, // "pitm"
    ItemInfoBox                       0x6969_6e66, // "iinf"
    ItemInfoEntry                     0x696e_6665, // "infe"
    ItemLocationBox                   0x696c_6f63, // "iloc"
    MovieBox                          0x6d6f_6f76, // "moov"
    MovieHeaderBox                    0x6d76_6864, // "mvhd"
    TrackBox                          0x7472_616b, // "trak"
    TrackHeaderBox                    0x746b_6864, // "tkhd"
    EditBox                           0x6564_7473, // "edts"
    MediaBox                          0x6d64_6961, // "mdia"
    EditListBox                       0x656c_7374, // "elst"
    MediaHeaderBox                    0x6d64_6864, // "mdhd"
    HandlerBox                        0x6864_6c72, // "hdlr"
    MediaInformationBox               0x6d69_6e66, // "minf"
    ImageReferenceBox                 0x6972_6566, // "iref"
    ImagePropertiesBox                0x6970_7270, // "iprp"
    ItemPropertyContainerBox          0x6970_636f, // "ipco"
    ItemPropertyAssociationBox        0x6970_6d61, // "ipma"
    ColorInformationBox               0x636f_6c72, // "colr"
    PixelInformationBox               0x7069_7869, // "pixi"
    AuxiliaryTypeProperty             0x6175_7843, // "auxC"
    SampleTableBox                    0x7374_626c, // "stbl"
    SampleDescriptionBox              0x7374_7364, // "stsd"
    TimeToSampleBox                   0x7374_7473, // "stts"
    SampleToChunkBox                  0x7374_7363, // "stsc"
    SampleSizeBox                     0x7374_737a, // "stsz"
    ChunkOffsetBox                    0x7374_636f, // "stco"
    ChunkLargeOffsetBox               0x636f_3634, // "co64"
    SyncSampleBox                     0x7374_7373, // "stss"
    AVCSampleEntry                    0x6176_6331, // "avc1"
    AVC3SampleEntry                   0x6176_6333, // "avc3" - Need to check official name in spec.
    AVCConfigurationBox               0x6176_6343, // "avcC"
    H263SampleEntry                   0x7332_3633, // "s263"
    H263SpecificBox                   0x6432_3633, // "d263"
    MP4AudioSampleEntry               0x6d70_3461, // "mp4a"
    MP4VideoSampleEntry               0x6d70_3476, // "mp4v"
    AMRNBSampleEntry                  0x7361_6d72, // "samr" - AMR narrow-band
    AMRWBSampleEntry                  0x7361_7762, // "sawb" - AMR wide-band
    AMRSpecificBox                    0x6461_6d72, // "damr"
    ESDBox                            0x6573_6473, // "esds"
    VP8SampleEntry                    0x7670_3038, // "vp08"
    VP9SampleEntry                    0x7670_3039, // "vp09"
    VPCodecConfigurationBox           0x7670_6343, // "vpcC"
    AV1SampleEntry                    0x6176_3031, // "av01"
    AV1CodecConfigurationBox          0x6176_3143, // "av1C"
    FLACSampleEntry                   0x664c_6143, // "fLaC"
    FLACSpecificBox                   0x6466_4c61, // "dfLa"
    OpusSampleEntry                   0x4f70_7573, // "Opus"
    OpusSpecificBox                   0x644f_7073, // "dOps"
    ProtectedVisualSampleEntry        0x656e_6376, // "encv" - Need to check official name in spec.
    ProtectedAudioSampleEntry         0x656e_6361, // "enca" - Need to check official name in spec.
    MovieExtendsBox                   0x6d76_6578, // "mvex"
    MovieExtendsHeaderBox             0x6d65_6864, // "mehd"
    QTWaveAtom                        0x7761_7665, // "wave" - quicktime atom
    ProtectionSystemSpecificHeaderBox 0x7073_7368, // "pssh"
    SchemeInformationBox              0x7363_6869, // "schi"
    TrackEncryptionBox                0x7465_6e63, // "tenc"
    ProtectionSchemeInfoBox           0x7369_6e66, // "sinf"
    OriginalFormatBox                 0x6672_6d61, // "frma"
    SchemeTypeBox                     0x7363_686d, // "schm"
    MP3AudioSampleEntry               0x2e6d_7033, // ".mp3" - from F4V.
    CompositionOffsetBox              0x6374_7473, // "ctts"
    LPCMAudioSampleEntry              0x6c70_636d, // "lpcm" - quicktime atom
    ALACSpecificBox                   0x616c_6163, // "alac" - Also used by ALACSampleEntry
    UuidBox                           0x7575_6964, // "uuid"
    MetadataBox                       0x6d65_7461, // "meta"
    MetadataHeaderBox                 0x6d68_6472, // "mhdr"
    MetadataItemKeysBox               0x6b65_7973, // "keys"
    MetadataItemListEntry             0x696c_7374, // "ilst"
    MetadataItemDataEntry             0x6461_7461, // "data"
    MetadataItemNameBox               0x6e61_6d65, // "name"
    UserdataBox                       0x7564_7461, // "udta"
    AlbumEntry                        0xa961_6c62, // "©alb"
    ArtistEntry                       0xa941_5254, // "©ART"
    ArtistLowercaseEntry              0xa961_7274, // "©art"
    AlbumArtistEntry                  0x6141_5254, // "aART"
    CommentEntry                      0xa963_6d74, // "©cmt"
    DateEntry                         0xa964_6179, // "©day"
    TitleEntry                        0xa96e_616d, // "©nam"
    CustomGenreEntry                  0xa967_656e, // "©gen"
    StandardGenreEntry                0x676e_7265, // "gnre"
    TrackNumberEntry                  0x7472_6b6e, // "trkn"
    DiskNumberEntry                   0x6469_736b, // "disk"
    ComposerEntry                     0xa977_7274, // "©wrt"
    EncoderEntry                      0xa974_6f6f, // "©too"
    EncodedByEntry                    0xa965_6e63, // "©enc"
    TempoEntry                        0x746d_706f, // "tmpo"
    CopyrightEntry                    0x6370_7274, // "cprt"
    CompilationEntry                  0x6370_696c, // "cpil"
    CoverArtEntry                     0x636f_7672, // "covr"
    AdvisoryEntry                     0x7274_6e67, // "rtng"
    RatingEntry                       0x7261_7465, // "rate"
    GroupingEntry                     0xa967_7270, // "©grp"
    MediaTypeEntry                    0x7374_696b, // "stik"
    PodcastEntry                      0x7063_7374, // "pcst"
    CategoryEntry                     0x6361_7467, // "catg"
    KeywordEntry                      0x6b65_7977, // "keyw"
    PodcastUrlEntry                   0x7075_726c, // "purl"
    PodcastGuidEntry                  0x6567_6964, // "egid"
    DescriptionEntry                  0x6465_7363, // "desc"
    LongDescriptionEntry              0x6c64_6573, // "ldes"
    LyricsEntry                       0xa96c_7972, // "©lyr"
    TVNetworkNameEntry                0x7476_6e6e, // "tvnn"
    TVShowNameEntry                   0x7476_7368, // "tvsh"
    TVEpisodeNameEntry                0x7476_656e, // "tven"
    TVSeasonNumberEntry               0x7476_736e, // "tvsn"
    TVEpisodeNumberEntry              0x7476_6573, // "tves"
    PurchaseDateEntry                 0x7075_7264, // "purd"
    GaplessPlaybackEntry              0x7067_6170, // "pgap"
    OwnerEntry                        0x6f77_6e72, // "ownr"
    HDVideoEntry                      0x6864_7664, // "hdvd"
    SortNameEntry                     0x736f_6e6d, // "sonm"
    SortAlbumEntry                    0x736f_616c, // "soal"
    SortArtistEntry                   0x736f_6172, // "soar"
    SortAlbumArtistEntry              0x736f_6161, // "soaa"
    SortComposerEntry                 0x736f_636f, // "soco"
);
<commit_msg>Make box database entries feature-gated<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
use std::fmt;

// To ensure we don't use stdlib allocating types by accident
#[allow(dead_code)]
struct Vec;
#[allow(dead_code)]
struct Box;
#[allow(dead_code)]
struct HashMap;
#[allow(dead_code)]
struct String;

macro_rules! box_database {
    ($($(#[$attr:meta])* $boxenum:ident $boxtype:expr),*,) => {
        #[derive(Clone, Copy, PartialEq)]
        pub enum BoxType {
            $($(#[$attr])* $boxenum),*,
            UnknownBox(u32),
        }

        impl From<u32> for BoxType {
            fn from(t: u32) -> BoxType {
                use self::BoxType::*;
                match t {
                    $($(#[$attr])* $boxtype => $boxenum),*,
                    _ => UnknownBox(t),
                }
            }
        }

        impl Into<u32> for BoxType {
            fn into(self) -> u32 {
                use self::BoxType::*;
                match self {
                    $($(#[$attr])* $boxenum => $boxtype),*,
                    UnknownBox(t) => t,
                }
            }
        }

    }
}

impl fmt::Debug for BoxType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let fourcc: FourCC = From::from(self.clone());
        fourcc.fmt(f)
    }
}

#[derive(Default, PartialEq, Clone)]
pub struct FourCC {
    pub value: [u8; 4],
}

impl From<u32> for FourCC {
    fn from(number: u32) -> FourCC {
        FourCC {
            value: number.to_be_bytes(),
        }
    }
}

impl From<BoxType> for FourCC {
    fn from(t: BoxType) -> FourCC {
        let box_num: u32 = Into::into(t);
        From::from(box_num)
    }
}

impl From<[u8; 4]> for FourCC {
    fn from(v: [u8; 4]) -> FourCC {
        FourCC { value: v }
    }
}

impl fmt::Debug for FourCC {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match std::str::from_utf8(&self.value) {
            Ok(s) => f.write_str(s),
            Err(_) => self.value.fmt(f),
        }
    }
}

impl fmt::Display for FourCC {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(std::str::from_utf8(&self.value).unwrap_or("null"))
    }
}

impl PartialEq<&[u8; 4]> for FourCC {
    fn eq(&self, other: &&[u8; 4]) -> bool {
        self.value.eq(*other)
    }
}

#[deny(unreachable_patterns)]
box_database!(
    FileTypeBox                       0x6674_7970, // "ftyp"
    MediaDataBox                      0x6d64_6174, // "mdat"
    PrimaryItemBox                    0x7069_746d, // "pitm"
    ItemInfoBox                       0x6969_6e66, // "iinf"
    ItemInfoEntry                     0x696e_6665, // "infe"
    ItemLocationBox                   0x696c_6f63, // "iloc"
    MovieBox                          0x6d6f_6f76, // "moov"
    MovieHeaderBox                    0x6d76_6864, // "mvhd"
    TrackBox                          0x7472_616b, // "trak"
    TrackHeaderBox                    0x746b_6864, // "tkhd"
    EditBox                           0x6564_7473, // "edts"
    MediaBox                          0x6d64_6961, // "mdia"
    EditListBox                       0x656c_7374, // "elst"
    MediaHeaderBox                    0x6d64_6864, // "mdhd"
    HandlerBox                        0x6864_6c72, // "hdlr"
    MediaInformationBox               0x6d69_6e66, // "minf"
    ImageReferenceBox                 0x6972_6566, // "iref"
    ImagePropertiesBox                0x6970_7270, // "iprp"
    ItemPropertyContainerBox          0x6970_636f, // "ipco"
    ItemPropertyAssociationBox        0x6970_6d61, // "ipma"
    ColorInformationBox               0x636f_6c72, // "colr"
    PixelInformationBox               0x7069_7869, // "pixi"
    AuxiliaryTypeProperty             0x6175_7843, // "auxC"
    SampleTableBox                    0x7374_626c, // "stbl"
    SampleDescriptionBox              0x7374_7364, // "stsd"
    TimeToSampleBox                   0x7374_7473, // "stts"
    SampleToChunkBox                  0x7374_7363, // "stsc"
    SampleSizeBox                     0x7374_737a, // "stsz"
    ChunkOffsetBox                    0x7374_636f, // "stco"
    ChunkLargeOffsetBox               0x636f_3634, // "co64"
    SyncSampleBox                     0x7374_7373, // "stss"
    AVCSampleEntry                    0x6176_6331, // "avc1"
    AVC3SampleEntry                   0x6176_6333, // "avc3" - Need to check official name in spec.
    AVCConfigurationBox               0x6176_6343, // "avcC"
    H263SampleEntry                   0x7332_3633, // "s263"
    H263SpecificBox                   0x6432_3633, // "d263"
    MP4AudioSampleEntry               0x6d70_3461, // "mp4a"
    MP4VideoSampleEntry               0x6d70_3476, // "mp4v"
    #[cfg(feature = "3gpp")]
    AMRNBSampleEntry                  0x7361_6d72, // "samr" - AMR narrow-band
    #[cfg(feature = "3gpp")]
    AMRWBSampleEntry                  0x7361_7762, // "sawb" - AMR wide-band
    #[cfg(feature = "3gpp")]
    AMRSpecificBox                    0x6461_6d72, // "damr"
    ESDBox                            0x6573_6473, // "esds"
    VP8SampleEntry                    0x7670_3038, // "vp08"
    VP9SampleEntry                    0x7670_3039, // "vp09"
    VPCodecConfigurationBox           0x7670_6343, // "vpcC"
    AV1SampleEntry                    0x6176_3031, // "av01"
    AV1CodecConfigurationBox          0x6176_3143, // "av1C"
    FLACSampleEntry                   0x664c_6143, // "fLaC"
    FLACSpecificBox                   0x6466_4c61, // "dfLa"
    OpusSampleEntry                   0x4f70_7573, // "Opus"
    OpusSpecificBox                   0x644f_7073, // "dOps"
    ProtectedVisualSampleEntry        0x656e_6376, // "encv" - Need to check official name in spec.
    ProtectedAudioSampleEntry         0x656e_6361, // "enca" - Need to check official name in spec.
    MovieExtendsBox                   0x6d76_6578, // "mvex"
    MovieExtendsHeaderBox             0x6d65_6864, // "mehd"
    QTWaveAtom                        0x7761_7665, // "wave" - quicktime atom
    ProtectionSystemSpecificHeaderBox 0x7073_7368, // "pssh"
    SchemeInformationBox              0x7363_6869, // "schi"
    TrackEncryptionBox                0x7465_6e63, // "tenc"
    ProtectionSchemeInfoBox           0x7369_6e66, // "sinf"
    OriginalFormatBox                 0x6672_6d61, // "frma"
    SchemeTypeBox                     0x7363_686d, // "schm"
    MP3AudioSampleEntry               0x2e6d_7033, // ".mp3" - from F4V.
    CompositionOffsetBox              0x6374_7473, // "ctts"
    LPCMAudioSampleEntry              0x6c70_636d, // "lpcm" - quicktime atom
    ALACSpecificBox                   0x616c_6163, // "alac" - Also used by ALACSampleEntry
    UuidBox                           0x7575_6964, // "uuid"
    MetadataBox                       0x6d65_7461, // "meta"
    MetadataHeaderBox                 0x6d68_6472, // "mhdr"
    MetadataItemKeysBox               0x6b65_7973, // "keys"
    MetadataItemListEntry             0x696c_7374, // "ilst"
    MetadataItemDataEntry             0x6461_7461, // "data"
    MetadataItemNameBox               0x6e61_6d65, // "name"
    UserdataBox                       0x7564_7461, // "udta"
    AlbumEntry                        0xa961_6c62, // "©alb"
    ArtistEntry                       0xa941_5254, // "©ART"
    ArtistLowercaseEntry              0xa961_7274, // "©art"
    AlbumArtistEntry                  0x6141_5254, // "aART"
    CommentEntry                      0xa963_6d74, // "©cmt"
    DateEntry                         0xa964_6179, // "©day"
    TitleEntry                        0xa96e_616d, // "©nam"
    CustomGenreEntry                  0xa967_656e, // "©gen"
    StandardGenreEntry                0x676e_7265, // "gnre"
    TrackNumberEntry                  0x7472_6b6e, // "trkn"
    DiskNumberEntry                   0x6469_736b, // "disk"
    ComposerEntry                     0xa977_7274, // "©wrt"
    EncoderEntry                      0xa974_6f6f, // "©too"
    EncodedByEntry                    0xa965_6e63, // "©enc"
    TempoEntry                        0x746d_706f, // "tmpo"
    CopyrightEntry                    0x6370_7274, // "cprt"
    CompilationEntry                  0x6370_696c, // "cpil"
    CoverArtEntry                     0x636f_7672, // "covr"
    AdvisoryEntry                     0x7274_6e67, // "rtng"
    RatingEntry                       0x7261_7465, // "rate"
    GroupingEntry                     0xa967_7270, // "©grp"
    MediaTypeEntry                    0x7374_696b, // "stik"
    PodcastEntry                      0x7063_7374, // "pcst"
    CategoryEntry                     0x6361_7467, // "catg"
    KeywordEntry                      0x6b65_7977, // "keyw"
    PodcastUrlEntry                   0x7075_726c, // "purl"
    PodcastGuidEntry                  0x6567_6964, // "egid"
    DescriptionEntry                  0x6465_7363, // "desc"
    LongDescriptionEntry              0x6c64_6573, // "ldes"
    LyricsEntry                       0xa96c_7972, // "©lyr"
    TVNetworkNameEntry                0x7476_6e6e, // "tvnn"
    TVShowNameEntry                   0x7476_7368, // "tvsh"
    TVEpisodeNameEntry                0x7476_656e, // "tven"
    TVSeasonNumberEntry               0x7476_736e, // "tvsn"
    TVEpisodeNumberEntry              0x7476_6573, // "tves"
    PurchaseDateEntry                 0x7075_7264, // "purd"
    GaplessPlaybackEntry              0x7067_6170, // "pgap"
    OwnerEntry                        0x6f77_6e72, // "ownr"
    HDVideoEntry                      0x6864_7664, // "hdvd"
    SortNameEntry                     0x736f_6e6d, // "sonm"
    SortAlbumEntry                    0x736f_616c, // "soal"
    SortArtistEntry                   0x736f_6172, // "soar"
    SortAlbumArtistEntry              0x736f_6161, // "soaa"
    SortComposerEntry                 0x736f_636f, // "soco"
);
<|endoftext|>