<commit_before>use num::{self, Num, NumCast};

pub trait Unit: Copy + Num {
    fn unit_radius() -> (Self, Self);
    fn unit_width() -> (Self, Self);
}

macro_rules! unit {
    (integer => $($t:ty),*) => {$(
        impl Unit for $t {
            fn unit_radius() -> (Self, Self) {
                use num::{One, Zero};
                (Self::zero(), Self::one() + Self::one())
            }

            fn unit_width() -> (Self, Self) {
                use num::{One, Zero};
                (Self::zero(), Self::one())
            }
        }
    )*};
    (real => $($t:ty),*) => {$(
        impl Unit for $t {
            fn unit_radius() -> (Self, Self) {
                use num::One;
                (-Self::one(), Self::one())
            }

            fn unit_width() -> (Self, Self) {
                use num::One;
                let half = Self::one() / (Self::one() + Self::one());
                (-half, half)
            }
        }
    )*};
}
unit!(integer => i8, i16, i32, i64, u8, u16, u32, u64);
unit!(real => f32, f64);

pub trait Interpolate<T = Self>: Sized {
    type Output;

    fn lerp(self, other: T, f: f64) -> Self::Output;

    fn midpoint(self, other: T) -> Self::Output {
        self.lerp(other, 0.5)
    }
}

impl<T> Interpolate for (T, T)
where
    T: Copy + Num + NumCast,
{
    type Output = Self;

    fn lerp(self, other: Self, f: f64) -> Self::Output {
        (lerp(self.0, other.0, f), lerp(self.1, other.1, f))
    }
}

impl<T> Interpolate for (T, T, T)
where
    T: Copy + Num + NumCast,
{
    type Output = Self;

    fn lerp(self, other: Self, f: f64) -> Self::Output {
        (
            lerp(self.0, other.0, f),
            lerp(self.1, other.1, f),
            lerp(self.2, other.2, f),
        )
    }
}

fn lerp<T>(a: T, b: T, f: f64) -> T
where
    T: Num + NumCast,
{
    let f = num::clamp(f, 0.0, 1.0);
    let af = <f64 as NumCast>::from(a).unwrap() * (1.0 - f);
    let bf = <f64 as NumCast>::from(b).unwrap() * f;
    <T as NumCast>::from(af + bf).unwrap()
}
<commit_msg>Implement geometry traits for nalgebra types.<commit_after>use num::{self, Num, NumCast};

pub trait Unit: Copy + Num {
    fn unit_radius() -> (Self, Self);
    fn unit_width() -> (Self, Self);
}

macro_rules! unit {
    (integer => $($t:ty),*) => {$(
        impl Unit for $t {
            fn unit_radius() -> (Self, Self) {
                use num::{One, Zero};
                (Self::zero(), Self::one() + Self::one())
            }

            fn unit_width() -> (Self, Self) {
                use num::{One, Zero};
                (Self::zero(), Self::one())
            }
        }
    )*};
    (real => $($t:ty),*) => {$(
        impl Unit for $t {
            fn unit_radius() -> (Self, Self) {
                use num::One;
                (-Self::one(), Self::one())
            }

            fn unit_width() -> (Self, Self) {
                use num::One;
                let half = Self::one() / (Self::one() + Self::one());
                (-half, half)
            }
        }
    )*};
}
unit!(integer => i8, i16, i32, i64, u8, u16, u32, u64);
unit!(real => f32, f64);

pub trait Interpolate<T = Self>: Sized {
    type Output;

    fn lerp(self, other: T, f: f64) -> Self::Output;

    fn midpoint(self, other: T) -> Self::Output {
        self.lerp(other, 0.5)
    }
}

impl<T> Interpolate for (T, T)
where
    T: Copy + Num + NumCast,
{
    type Output = Self;

    fn lerp(self, other: Self, f: f64) -> Self::Output {
        (lerp(self.0, other.0, f), lerp(self.1, other.1, f))
    }
}

impl<T> Interpolate for (T, T, T)
where
    T: Copy + Num + NumCast,
{
    type Output = Self;

    fn lerp(self, other: Self, f: f64) -> Self::Output {
        (
            lerp(self.0, other.0, f),
            lerp(self.1, other.1, f),
            lerp(self.2, other.2, f),
        )
    }
}

fn lerp<T>(a: T, b: T, f: f64) -> T
where
    T: Num + NumCast,
{
    let f = num::clamp(f, 0.0, 1.0);
    let af = <f64 as NumCast>::from(a).unwrap() * (1.0 - f);
    let bf = <f64 as NumCast>::from(b).unwrap() * f;
    <T as NumCast>::from(af + bf).unwrap()
}

#[cfg(feature = "geometry-nalgebra")]
mod feature {
    use nalgebra::{Point2, Point3, Scalar, Vector2, Vector3};

    use super::*;

    impl<T> Interpolate for Point2<T>
    where
        T: NumCast + Scalar + Unit,
    {
        type Output = Self;

        fn lerp(self, other: Self, f: f64) -> Self::Output {
            Point2::new(lerp(self.x, other.x, f), lerp(self.y, other.y, f))
        }
    }

    impl<T> Interpolate for Point3<T>
    where
        T: NumCast + Scalar + Unit,
    {
        type Output = Self;

        fn lerp(self, other: Self, f: f64) -> Self::Output {
            Point3::new(
                lerp(self.x, other.x, f),
                lerp(self.y, other.y, f),
                lerp(self.z, other.z, f),
            )
        }
    }

    impl<T> Interpolate for Vector2<T>
    where
        T: NumCast + Scalar + Unit,
    {
        type Output = Self;

        fn lerp(self, other: Self, f: f64) -> Self::Output {
            Vector2::new(lerp(self.x, other.x, f), lerp(self.y, other.y, f))
        }
    }

    impl<T> Interpolate for Vector3<T>
    where
        T: NumCast + Scalar + Unit,
    {
        type Output = Self;

        fn lerp(self, other: Self, f: f64) -> Self::Output {
            Vector3::new(
                lerp(self.x, other.x, f),
                lerp(self.y, other.y, f),
                lerp(self.z, other.z, f),
            )
        }
    }
}

#[cfg(not(feature = "geometry-nalgebra"))]
mod feature {}

pub use self::feature::*;
<|endoftext|>


<commit_before>use std::collections::{BTreeMap, HashMap};

use crate::context::Context;
use crate::error::RenderError;
use crate::helpers::HelperDef;
use crate::json::value::{PathAndJson, ScopedJson};
use crate::registry::Registry;
use crate::render::{Helper, RenderContext};

use rhai::ser::to_dynamic;
use rhai::{Dynamic, Engine, Scope, AST};

use serde_json::value::{Map, Number, Value as Json};

pub struct ScriptHelper {
    pub(crate) script: AST,
}

#[inline]
fn call_script_helper<'reg: 'rc, 'rc>(
    params: &Vec<PathAndJson<'reg, 'rc>>,
    hash: &BTreeMap<&'reg str, PathAndJson<'reg, 'rc>>,
    engine: &Engine,
    script: &AST,
) -> Result<Option<ScopedJson<'reg, 'rc>>, RenderError> {
    let params: Dynamic = to_dynamic(params.iter().map(|p| p.value()).collect::<Vec<&Json>>())?;

    let hash: Dynamic = to_dynamic(
        hash.iter()
            .map(|(k, v)| ((*k).to_owned(), v.value()))
            .collect::<HashMap<String, &Json>>(),
    )?;

    let mut scope = Scope::new();
    scope.push_dynamic("params", params);
    scope.push_dynamic("hash", hash);

    let result = engine
        .eval_ast_with_scope::<Dynamic>(&mut scope, script)
        .map_err(RenderError::from)?;

    let result_json = to_json(&result);

    Ok(Some(ScopedJson::Derived(result_json)))
}

impl HelperDef for ScriptHelper {
    fn call_inner<'reg: 'rc, 'rc>(
        &self,
        h: &Helper<'reg, 'rc>,
        reg: &'reg Registry<'reg>,
        _ctx: &'rc Context,
        _rc: &mut RenderContext<'reg, 'rc>,
    ) -> Result<Option<ScopedJson<'reg, 'rc>>, RenderError> {
        call_script_helper(h.params(), h.hash(), &reg.engine, &self.script)
    }
}

fn to_json(d: &Dynamic) -> Json {
    if let Ok(s) = d.as_str() {
        return Json::String(s.to_owned());
    }
    if let Ok(i) = d.as_int() {
        return Json::Number(Number::from(i));
    }
    if let Ok(b) = d.as_bool() {
        return Json::Bool(b);
    }

    if d.type_name() == "array" {
        let v = d
            .downcast_ref::<Vec<Dynamic>>()
            .unwrap()
            .iter()
            .map(to_json)
            .collect::<Vec<Json>>();
        return Json::Array(v);
    }

    if d.type_name() == "map" {
        let m = d
            .downcast_ref::<HashMap<String, Dynamic>>()
            .unwrap()
            .iter()
            .map(|(k, v)| (k.clone(), to_json(v)))
            .collect::<Map<String, Json>>();

        return Json::Object(m);
    }

    // FIXME: more types
    return Json::Null;
}

#[cfg(test)]
mod test {
    use super::*;
    use crate::json::value::{PathAndJson, ScopedJson};
    use rhai::Engine;

    #[test]
    fn test_dynamic_convert() {
        let j0 = json! {
            [{"name": "tomcat"}, {"name": "jetty"}]
        };

        let d0 = to_dynamic(&j0).unwrap();
        assert_eq!("array", d0.type_name());

        let j1 = json!({
            "name": "tomcat",
            "value": 4000,
        });

        let d1 = to_dynamic(&j1).unwrap();
        assert_eq!("map", d1.type_name());
    }

    #[test]
    fn test_to_json() {
        let d0 = Dynamic::from("tomcat".to_owned());

        assert_eq!(Json::String("tomcat".to_owned()), to_json(&d0));
    }

    #[test]
    fn test_script_helper_value_access() {
        let engine = Engine::new();

        let script = "let plen = len(params); let p0 = params[0]; let hlen = len(hash); let hme = hash[\"me\"]; plen + \",\" + p0 + \",\" + hlen + \",\" + hme";
        let ast = engine.compile(&script).unwrap();

        let params = vec![PathAndJson::new(None, ScopedJson::Derived(json!(true)))];
        let hash = btreemap! {
            "me" => PathAndJson::new(None, ScopedJson::Derived(json!("no"))),
            "you" => PathAndJson::new(None, ScopedJson::Derived(json!("yes"))),
        };

        let result = call_script_helper(&params, &hash, &engine, &ast)
            .unwrap()
            .unwrap()
            .render();
        assert_eq!("1,true,2,no", &result);
    }
}
<commit_msg>(feat) use rhai 0.17 deserialize function<commit_after>use std::collections::{BTreeMap, HashMap};

use crate::context::Context;
use crate::error::RenderError;
use crate::helpers::HelperDef;
use crate::json::value::{PathAndJson, ScopedJson};
use crate::registry::Registry;
use crate::render::{Helper, RenderContext};

use rhai::de::from_dynamic;
use rhai::ser::to_dynamic;
use rhai::{Dynamic, Engine, Scope, AST};

use serde_json::value::Value as Json;

pub struct ScriptHelper {
    pub(crate) script: AST,
}

#[inline]
fn call_script_helper<'reg: 'rc, 'rc>(
    params: &Vec<PathAndJson<'reg, 'rc>>,
    hash: &BTreeMap<&'reg str, PathAndJson<'reg, 'rc>>,
    engine: &Engine,
    script: &AST,
) -> Result<Option<ScopedJson<'reg, 'rc>>, RenderError> {
    let params: Dynamic = to_dynamic(params.iter().map(|p| p.value()).collect::<Vec<&Json>>())?;

    let hash: Dynamic = to_dynamic(
        hash.iter()
            .map(|(k, v)| ((*k).to_owned(), v.value()))
            .collect::<HashMap<String, &Json>>(),
    )?;

    let mut scope = Scope::new();
    scope.push_dynamic("params", params);
    scope.push_dynamic("hash", hash);

    let result = engine
        .eval_ast_with_scope::<Dynamic>(&mut scope, script)
        .map_err(RenderError::from)?;

    let result_json: Json = from_dynamic(&result)?;

    Ok(Some(ScopedJson::Derived(result_json)))
}

impl HelperDef for ScriptHelper {
    fn call_inner<'reg: 'rc, 'rc>(
        &self,
        h: &Helper<'reg, 'rc>,
        reg: &'reg Registry<'reg>,
        _ctx: &'rc Context,
        _rc: &mut RenderContext<'reg, 'rc>,
    ) -> Result<Option<ScopedJson<'reg, 'rc>>, RenderError> {
        call_script_helper(h.params(), h.hash(), &reg.engine, &self.script)
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use crate::json::value::{PathAndJson, ScopedJson};
    use rhai::Engine;

    #[test]
    fn test_dynamic_convert() {
        let j0 = json! {
            [{"name": "tomcat"}, {"name": "jetty"}]
        };

        let d0 = to_dynamic(&j0).unwrap();
        assert_eq!("array", d0.type_name());

        let j1 = json!({
            "name": "tomcat",
            "value": 4000,
        });

        let d1 = to_dynamic(&j1).unwrap();
        assert_eq!("map", d1.type_name());
    }

    #[test]
    fn test_to_json() {
        let d0 = Dynamic::from("tomcat".to_owned());

        assert_eq!(
            Json::String("tomcat".to_owned()),
            from_dynamic::<Json>(&d0).unwrap()
        );
    }

    #[test]
    fn test_script_helper_value_access() {
        let engine = Engine::new();

        let script = "let plen = len(params); let p0 = params[0]; let hlen = len(hash); let hme = hash[\"me\"]; plen + \",\" + p0 + \",\" + hlen + \",\" + hme";
        let ast = engine.compile(&script).unwrap();

        let params = vec![PathAndJson::new(None, ScopedJson::Derived(json!(true)))];
        let hash = btreemap! {
            "me" => PathAndJson::new(None, ScopedJson::Derived(json!("no"))),
            "you" => PathAndJson::new(None, ScopedJson::Derived(json!("yes"))),
        };

        let result = call_script_helper(&params, &hash, &engine, &ast)
            .unwrap()
            .unwrap()
            .render();
        assert_eq!("1,true,2,no", &result);
    }
}
<|endoftext|>


<commit_before>extern crate winapi;

use std::{mem, ptr, slice};
use std::ffi::OsString;
use std::os::windows::ffi::OsStringExt;
use std::sync::Mutex;
use std::io::{Write, stderr};
use std::thread::sleep;
use std::time::Duration;
use memalloc::{allocate, deallocate};

use self::winapi::shared::basetsd::{DWORD_PTR, UINT_PTR};
use self::winapi::shared::minwindef::{DWORD, UINT};

use self::winapi::um::mmeapi::{midiInAddBuffer, midiInClose, midiInGetDevCapsW, midiInGetNumDevs,
                               midiInOpen, midiInPrepareHeader, midiInReset, midiInStart,
                               midiInStop, midiInUnprepareHeader, midiOutClose,
                               midiOutGetDevCapsW, midiOutGetNumDevs, midiOutLongMsg, midiOutOpen,
                               midiOutPrepareHeader, midiOutReset, midiOutShortMsg,
                               midiOutUnprepareHeader};

use self::winapi::um::mmsystem::{CALLBACK_FUNCTION, CALLBACK_NULL, HMIDIIN, HMIDIOUT, LPMIDIHDR,
                                 MIDIERR_NOTREADY, MIDIERR_STILLPLAYING, MIDIHDR, MIDIINCAPSW,
                                 MIDIOUTCAPSW, MMSYSERR_BADDEVICEID, MMSYSERR_NOERROR};

use {Ignore, MidiMessage};
use errors::*;

mod handler;

const RT_SYSEX_BUFFER_SIZE: usize = 1024;
const RT_SYSEX_BUFFER_COUNT: usize = 4;

// helper for string conversion
fn from_wide_ptr(ptr: *const u16, max_len: usize) -> OsString {
    unsafe {
        assert!(!ptr.is_null());
        let len = (0..max_len as isize).position(|i| *ptr.offset(i) == 0).unwrap();
        let slice = slice::from_raw_parts(ptr, len);
        OsString::from_wide(slice)
    }
}

#[derive(Debug)]
pub struct MidiInput {
    ignore_flags: Ignore
}

pub struct MidiInputConnection<T> {
    handler_data: Box<HandlerData<T>>,
}

/// This is all the data that is stored on the heap as long as a connection
/// is opened and passed to the callback handler.
///
/// It is important that `user_data` is the last field to not influence
/// offsets after monomorphization.
struct HandlerData<T> {
    message: MidiMessage,
    sysex_buffer: [LPMIDIHDR; RT_SYSEX_BUFFER_COUNT],
    in_handle: Option<Mutex<HMIDIIN>>,
    ignore_flags: Ignore,
    callback: Box<FnMut(u64, &[u8], &mut T) + Send + 'static>,
    user_data: Option<T>
}

impl MidiInput {
    pub fn new(_client_name: &str) -> Result<Self, InitError> {
        Ok(MidiInput { ignore_flags: Ignore::None })
    }

    pub fn ignore(&mut self, flags: Ignore) {
        self.ignore_flags = flags;
    }

    pub fn port_count(&self) -> usize {
        unsafe { midiInGetNumDevs() as usize }
    }

    pub fn port_name(&self, port_number: usize) -> Result<String, PortInfoError> {
        let mut device_caps: MIDIINCAPSW = unsafe { mem::uninitialized() };
        let result = unsafe { midiInGetDevCapsW(port_number as UINT_PTR, &mut device_caps, mem::size_of::<MIDIINCAPSW>() as u32) };
        if result == MMSYSERR_BADDEVICEID {
            return Err(PortInfoError::PortNumberOutOfRange)
        } else if result != MMSYSERR_NOERROR {
            return Err(PortInfoError::CannotRetrievePortName)
        }
        let output = from_wide_ptr(device_caps.szPname.as_ptr(), device_caps.szPname.len()).to_string_lossy().into_owned();
        Ok(output)
    }

    pub fn connect<F, T: Send>(
        self, port_number: usize, _port_name: &str, callback: F, data: T
    ) -> Result<MidiInputConnection<T>, ConnectError<MidiInput>>
        where F: FnMut(u64, &[u8], &mut T) + Send + 'static {

        let mut handler_data = Box::new(HandlerData {
            message: MidiMessage::new(),
            sysex_buffer: unsafe { mem::uninitialized() },
            in_handle: None,
            ignore_flags: self.ignore_flags,
            callback: Box::new(callback),
            user_data: Some(data)
        });

        let mut in_handle: HMIDIIN = unsafe { mem::uninitialized() };
        let handler_data_ptr: *mut HandlerData<T> = &mut *handler_data;
        let result = unsafe { midiInOpen(&mut in_handle,
                        port_number as UINT,
                        handler::handle_input::<T> as DWORD_PTR,
                        handler_data_ptr as DWORD_PTR,
                        CALLBACK_FUNCTION) };
        if result == MMSYSERR_BADDEVICEID {
            return Err(ConnectError::new(ConnectErrorKind::PortNumberOutOfRange, self));
        } else if result != MMSYSERR_NOERROR {
            return Err(ConnectError::other("could not create Windows MM MIDI input port", self));
        }

        // Allocate and init the sysex buffers.
        for i in 0..RT_SYSEX_BUFFER_COUNT {
            handler_data.sysex_buffer[i] = Box::into_raw(Box::new(MIDIHDR {
                lpData: unsafe { allocate(RT_SYSEX_BUFFER_SIZE/*, mem::align_of::<u8>()*/) } as *mut i8,
                dwBufferLength: RT_SYSEX_BUFFER_SIZE as u32,
                dwBytesRecorded: 0,
                dwUser: i as DWORD_PTR, // We use the dwUser parameter as buffer indicator
                dwFlags: 0,
                lpNext: ptr::null_mut(),
                reserved: 0,
                dwOffset: 0,
                dwReserved: [0; 4],
            }));

            // TODO: are those buffers ever freed if an error occurs here (altough these calls probably only fail with out-of-memory)?
            // TODO: close port in case of error?

            let result = unsafe { midiInPrepareHeader(in_handle, handler_data.sysex_buffer[i], mem::size_of::<MIDIHDR>() as u32) };
            if result != MMSYSERR_NOERROR {
                return Err(ConnectError::other("could not initialize Windows MM MIDI input port (PrepareHeader)", self));
            }

            // Register the buffer.
            let result = unsafe { midiInAddBuffer(in_handle, handler_data.sysex_buffer[i], mem::size_of::<MIDIHDR>() as u32) };
            if result != MMSYSERR_NOERROR {
                return Err(ConnectError::other("could not initialize Windows MM MIDI input port (AddBuffer)", self));
            }
        }

        handler_data.in_handle = Some(Mutex::new(in_handle));

        // We can safely access (a copy of) `in_handle` here, although
        // it has been copied into the Mutex already, because the callback
        // has not been called yet.
        let result = unsafe { midiInStart(in_handle) };
        if result != MMSYSERR_NOERROR {
            unsafe { midiInClose(in_handle) };
            return Err(ConnectError::other("could not start Windows MM MIDI input port", self));
        }

        Ok(MidiInputConnection {
            handler_data: handler_data
        })
    }
}

impl<T> MidiInputConnection<T> {
    pub fn close(mut self) -> (MidiInput, T) {
        self.close_internal();

        (MidiInput {
            ignore_flags: self.handler_data.ignore_flags,
        }, self.handler_data.user_data.take().unwrap())
    }

    fn close_internal(&mut self) {
        // for information about his lock, see https://groups.google.com/forum/#!topic/mididev/6OUjHutMpEo
        let in_handle_lock = self.handler_data.in_handle.as_ref().unwrap().lock().unwrap();

        // TODO: Call both reset and stop here? The difference seems to be that
        //       reset "returns all pending input buffers to the callback function"
        unsafe {
            midiInReset(*in_handle_lock);
            midiInStop(*in_handle_lock);
        }

        for i in 0..RT_SYSEX_BUFFER_COUNT {
            let result;
            unsafe {
                result = midiInUnprepareHeader(*in_handle_lock, self.handler_data.sysex_buffer[i], mem::size_of::<MIDIHDR>() as u32);
                deallocate((*self.handler_data.sysex_buffer[i]).lpData as *mut u8, RT_SYSEX_BUFFER_SIZE/*, mem::align_of::<u8>()*/);
                // recreate the Box so that it will be dropped/deallocated at the end of this scope
                let _ = Box::from_raw(self.handler_data.sysex_buffer[i]);
            }

            if result != MMSYSERR_NOERROR {
                let _ = writeln!(stderr(), "Warning: Ignoring error shutting down Windows MM input port (UnprepareHeader).");
            }
        }

        unsafe { midiInClose(*in_handle_lock) };
    }
}

impl<T> Drop for MidiInputConnection<T> {
    fn drop(&mut self) {
        // If user_data has been emptied, we know that we already have closed the connection
        if self.handler_data.user_data.is_some() {
            self.close_internal()
        }
    }
}

#[derive(Debug)]
pub struct MidiOutput;

pub struct MidiOutputConnection {
    out_handle: HMIDIOUT,
}

unsafe impl Send for MidiOutputConnection {}

impl MidiOutput {
    pub fn new(_client_name: &str) -> Result<Self, InitError> {
        Ok(MidiOutput)
    }

    pub fn port_count(&self) -> usize {
        unsafe { midiOutGetNumDevs() as usize }
    }

    pub fn port_name(&self, port_number: usize) -> Result<String, PortInfoError> {
        let mut device_caps: MIDIOUTCAPSW = unsafe { mem::uninitialized() };
        let result = unsafe { midiOutGetDevCapsW(port_number as UINT_PTR, &mut device_caps, mem::size_of::<MIDIINCAPSW>() as u32) };
        if result == MMSYSERR_BADDEVICEID {
            return Err(PortInfoError::PortNumberOutOfRange)
        } else if result != MMSYSERR_NOERROR {
            return Err(PortInfoError::CannotRetrievePortName)
        }
        let output = from_wide_ptr(device_caps.szPname.as_ptr(), device_caps.szPname.len()).to_string_lossy().into_owned();
        Ok(output)
    }

    pub fn connect(self, port_number: usize, _port_name: &str) -> Result<MidiOutputConnection, ConnectError<MidiOutput>> {
        let mut out_handle = unsafe { mem::uninitialized() };

        let result = unsafe { midiOutOpen(&mut out_handle, port_number as UINT, 0, 0, CALLBACK_NULL) };
        if result == MMSYSERR_BADDEVICEID {
            return Err(ConnectError::new(ConnectErrorKind::PortNumberOutOfRange, self));
        } else if result != MMSYSERR_NOERROR {
            return Err(ConnectError::other("could not create Windows MM MIDI output port", self));
        }

        Ok(MidiOutputConnection {
            out_handle: out_handle
        })
    }
}

impl MidiOutputConnection {
    pub fn close(self) -> MidiOutput {
        // The actual closing is done by the implementation of Drop
        MidiOutput // In this API this is a noop
    }

    pub fn send(&mut self, message: &[u8]) -> Result<(), SendError> {
        let nbytes = message.len();
        if nbytes == 0 {
            return Err(SendError::InvalidData("message to be sent must not be empty"));
        }

        if message[0] == 0xF0 { // Sysex message
            // Allocate buffer for sysex data and copy message
            let mut buffer = message.to_vec();

            // Create and prepare MIDIHDR structure.
            let mut sysex = MIDIHDR {
                lpData: buffer.as_mut_ptr() as *mut i8,
                dwBufferLength: nbytes as u32,
                dwBytesRecorded: 0,
                dwUser: 0,
                dwFlags: 0,
                lpNext: ptr::null_mut(),
                reserved: 0,
                dwOffset: 0,
                dwReserved: [0; 4],
            };

            let result = unsafe { midiOutPrepareHeader(self.out_handle, &mut sysex, mem::size_of::<MIDIHDR>() as u32) };

            if result != MMSYSERR_NOERROR {
                return Err(SendError::Other("preparation for sending sysex message failed (OutPrepareHeader)"));
            }

            // Send the message.
            loop {
                let result = unsafe { midiOutLongMsg(self.out_handle, &mut sysex, mem::size_of::<MIDIHDR>() as u32) };
                if result == MIDIERR_NOTREADY {
                    sleep(Duration::from_millis(1));
                    continue;
                } else {
                    if result != MMSYSERR_NOERROR {
                        return Err(SendError::Other("sending sysex message failed"));
                    }
                    break;
                }
            }

            loop {
                let result = unsafe { midiOutUnprepareHeader(self.out_handle, &mut sysex, mem::size_of::<MIDIHDR>() as u32) };
                if result == MIDIERR_STILLPLAYING {
                    sleep(Duration::from_millis(1));
                    continue;
                } else { break; }
            }
        } else { // Channel or system message.
            // Make sure the message size isn't too big.
            if nbytes > 3 {
                return Err(SendError::InvalidData("non-sysex message must not be longer than 3 bytes"));
            }

            // Pack MIDI bytes into double word.
            let packet: DWORD = 0;
            let ptr = &packet as *const u32 as *mut u8;
            for i in 0..nbytes {
                unsafe { *ptr.offset(i as isize) = message[i] };
            }

            // Send the message immediately.
            loop {
                let result = unsafe { midiOutShortMsg(self.out_handle, packet) };
                if result == MIDIERR_NOTREADY {
                    sleep(Duration::from_millis(1));
                    continue;
                } else {
                    if result != MMSYSERR_NOERROR {
                        return Err(SendError::Other("sending non-sysex message failed"));
                    }
                    break;
                }
            }
        }

        Ok(())
    }
}

impl Drop for MidiOutputConnection {
    fn drop(&mut self) {
        unsafe {
            midiOutReset(self.out_handle);
            midiOutClose(self.out_handle);
        }
    }
}<commit_msg>Small fix in WinMM backend<commit_after>extern crate winapi;

use std::{mem, ptr, slice};
use std::ffi::OsString;
use std::os::windows::ffi::OsStringExt;
use std::sync::Mutex;
use std::io::{Write, stderr};
use std::thread::sleep;
use std::time::Duration;
use memalloc::{allocate, deallocate};

use self::winapi::shared::basetsd::{DWORD_PTR, UINT_PTR};
use self::winapi::shared::minwindef::{DWORD, UINT};

use self::winapi::um::mmeapi::{midiInAddBuffer, midiInClose, midiInGetDevCapsW, midiInGetNumDevs,
                               midiInOpen, midiInPrepareHeader, midiInReset, midiInStart,
                               midiInStop, midiInUnprepareHeader, midiOutClose,
                               midiOutGetDevCapsW, midiOutGetNumDevs, midiOutLongMsg, midiOutOpen,
                               midiOutPrepareHeader, midiOutReset, midiOutShortMsg,
                               midiOutUnprepareHeader};

use self::winapi::um::mmsystem::{CALLBACK_FUNCTION, CALLBACK_NULL, HMIDIIN, HMIDIOUT, LPMIDIHDR,
                                 MIDIERR_NOTREADY, MIDIERR_STILLPLAYING, MIDIHDR, MIDIINCAPSW,
                                 MIDIOUTCAPSW, MMSYSERR_BADDEVICEID, MMSYSERR_NOERROR};

use {Ignore, MidiMessage};
use errors::*;

mod handler;

const RT_SYSEX_BUFFER_SIZE: usize = 1024;
const RT_SYSEX_BUFFER_COUNT: usize = 4;

// helper for string conversion
fn from_wide_ptr(ptr: *const u16, max_len: usize) -> OsString {
    unsafe {
        assert!(!ptr.is_null());
        let len = (0..max_len as isize).position(|i| *ptr.offset(i) == 0).unwrap();
        let slice = slice::from_raw_parts(ptr, len);
        OsString::from_wide(slice)
    }
}

#[derive(Debug)]
pub struct MidiInput {
    ignore_flags: Ignore
}

pub struct MidiInputConnection<T> {
    handler_data: Box<HandlerData<T>>,
}

/// This is all the data that is stored on the heap as long as a connection
/// is opened and passed to the callback handler.
///
/// It is important that `user_data` is the last field to not influence
/// offsets after monomorphization.
struct HandlerData<T> {
    message: MidiMessage,
    sysex_buffer: [LPMIDIHDR; RT_SYSEX_BUFFER_COUNT],
    in_handle: Option<Mutex<HMIDIIN>>,
    ignore_flags: Ignore,
    callback: Box<FnMut(u64, &[u8], &mut T) + Send + 'static>,
    user_data: Option<T>
}

impl MidiInput {
    pub fn new(_client_name: &str) -> Result<Self, InitError> {
        Ok(MidiInput { ignore_flags: Ignore::None })
    }

    pub fn ignore(&mut self, flags: Ignore) {
        self.ignore_flags = flags;
    }

    pub fn port_count(&self) -> usize {
        unsafe { midiInGetNumDevs() as usize }
    }

    pub fn port_name(&self, port_number: usize) -> Result<String, PortInfoError> {
        let mut device_caps: MIDIINCAPSW = unsafe { mem::uninitialized() };
        let result = unsafe { midiInGetDevCapsW(port_number as UINT_PTR, &mut device_caps, mem::size_of::<MIDIINCAPSW>() as u32) };
        if result == MMSYSERR_BADDEVICEID {
            return Err(PortInfoError::PortNumberOutOfRange)
        } else if result != MMSYSERR_NOERROR {
            return Err(PortInfoError::CannotRetrievePortName)
        }
        let output = from_wide_ptr(device_caps.szPname.as_ptr(), device_caps.szPname.len()).to_string_lossy().into_owned();
        Ok(output)
    }

    pub fn connect<F, T: Send>(
        self, port_number: usize, _port_name: &str, callback: F, data: T
    ) -> Result<MidiInputConnection<T>, ConnectError<MidiInput>>
        where F: FnMut(u64, &[u8], &mut T) + Send + 'static {

        let mut handler_data = Box::new(HandlerData {
            message: MidiMessage::new(),
            sysex_buffer: unsafe { mem::uninitialized() },
            in_handle: None,
            ignore_flags: self.ignore_flags,
            callback: Box::new(callback),
            user_data: Some(data)
        });

        let mut in_handle: HMIDIIN = unsafe { mem::uninitialized() };
        let handler_data_ptr: *mut HandlerData<T> = &mut *handler_data;
        let result = unsafe { midiInOpen(&mut in_handle,
                        port_number as UINT,
                        handler::handle_input::<T> as DWORD_PTR,
                        handler_data_ptr as DWORD_PTR,
                        CALLBACK_FUNCTION) };
        if result == MMSYSERR_BADDEVICEID {
            return Err(ConnectError::new(ConnectErrorKind::PortNumberOutOfRange, self));
        } else if result != MMSYSERR_NOERROR {
            return Err(ConnectError::other("could not create Windows MM MIDI input port", self));
        }

        // Allocate and init the sysex buffers.
        for i in 0..RT_SYSEX_BUFFER_COUNT {
            handler_data.sysex_buffer[i] = Box::into_raw(Box::new(MIDIHDR {
                lpData: unsafe { allocate(RT_SYSEX_BUFFER_SIZE/*, mem::align_of::<u8>()*/) } as *mut i8,
                dwBufferLength: RT_SYSEX_BUFFER_SIZE as u32,
                dwBytesRecorded: 0,
                dwUser: i as DWORD_PTR, // We use the dwUser parameter as buffer indicator
                dwFlags: 0,
                lpNext: ptr::null_mut(),
                reserved: 0,
                dwOffset: 0,
                dwReserved: [0; 4],
            }));

            // TODO: are those buffers ever freed if an error occurs here (altough these calls probably only fail with out-of-memory)?
            // TODO: close port in case of error?

            let result = unsafe { midiInPrepareHeader(in_handle, handler_data.sysex_buffer[i], mem::size_of::<MIDIHDR>() as u32) };
            if result != MMSYSERR_NOERROR {
                return Err(ConnectError::other("could not initialize Windows MM MIDI input port (PrepareHeader)", self));
            }

            // Register the buffer.
            let result = unsafe { midiInAddBuffer(in_handle, handler_data.sysex_buffer[i], mem::size_of::<MIDIHDR>() as u32) };
            if result != MMSYSERR_NOERROR {
                return Err(ConnectError::other("could not initialize Windows MM MIDI input port (AddBuffer)", self));
            }
        }

        handler_data.in_handle = Some(Mutex::new(in_handle));

        // We can safely access (a copy of) `in_handle` here, although
        // it has been copied into the Mutex already, because the callback
        // has not been called yet.
        let result = unsafe { midiInStart(in_handle) };
        if result != MMSYSERR_NOERROR {
            unsafe { midiInClose(in_handle) };
            return Err(ConnectError::other("could not start Windows MM MIDI input port", self));
        }

        Ok(MidiInputConnection {
            handler_data: handler_data
        })
    }
}

impl<T> MidiInputConnection<T> {
    pub fn close(mut self) -> (MidiInput, T) {
        self.close_internal();

        (MidiInput {
            ignore_flags: self.handler_data.ignore_flags,
        }, self.handler_data.user_data.take().unwrap())
    }

    fn close_internal(&mut self) {
        // for information about his lock, see https://groups.google.com/forum/#!topic/mididev/6OUjHutMpEo
        let in_handle_lock = self.handler_data.in_handle.as_ref().unwrap().lock().unwrap();

        // TODO: Call both reset and stop here? The difference seems to be that
        //       reset "returns all pending input buffers to the callback function"
        unsafe {
            midiInReset(*in_handle_lock);
            midiInStop(*in_handle_lock);
        }

        for i in 0..RT_SYSEX_BUFFER_COUNT {
            let result;
            unsafe {
                result = midiInUnprepareHeader(*in_handle_lock, self.handler_data.sysex_buffer[i], mem::size_of::<MIDIHDR>() as u32);
                deallocate((*self.handler_data.sysex_buffer[i]).lpData as *mut u8, RT_SYSEX_BUFFER_SIZE/*, mem::align_of::<u8>()*/);
                // recreate the Box so that it will be dropped/deallocated at the end of this scope
                let _ = Box::from_raw(self.handler_data.sysex_buffer[i]);
            }

            if result != MMSYSERR_NOERROR {
                let _ = writeln!(stderr(), "Warning: Ignoring error shutting down Windows MM input port (UnprepareHeader).");
            }
        }

        unsafe { midiInClose(*in_handle_lock) };
    }
}

impl<T> Drop for MidiInputConnection<T> {
    fn drop(&mut self) {
        // If user_data has been emptied, we know that we already have closed the connection
        if self.handler_data.user_data.is_some() {
            self.close_internal()
        }
    }
}

#[derive(Debug)]
pub struct MidiOutput;

pub struct MidiOutputConnection {
    out_handle: HMIDIOUT,
}

unsafe impl Send for MidiOutputConnection {}

impl MidiOutput {
    pub fn new(_client_name: &str) -> Result<Self, InitError> {
        Ok(MidiOutput)
    }

    pub fn port_count(&self) -> usize {
        unsafe { midiOutGetNumDevs() as usize }
    }

    pub fn port_name(&self, port_number: usize) -> Result<String, PortInfoError> {
        let mut device_caps: MIDIOUTCAPSW = unsafe { mem::uninitialized() };
        let result = unsafe { midiOutGetDevCapsW(port_number as UINT_PTR, &mut device_caps, mem::size_of::<MIDIOUTCAPSW>() as u32) };
        if result == MMSYSERR_BADDEVICEID {
            return Err(PortInfoError::PortNumberOutOfRange)
        } else if result != MMSYSERR_NOERROR {
            return Err(PortInfoError::CannotRetrievePortName)
        }
        let output = from_wide_ptr(device_caps.szPname.as_ptr(), device_caps.szPname.len()).to_string_lossy().into_owned();
        Ok(output)
    }

    pub fn connect(self, port_number: usize, _port_name: &str) -> Result<MidiOutputConnection, ConnectError<MidiOutput>> {
        let mut out_handle = unsafe { mem::uninitialized() };

        let result = unsafe { midiOutOpen(&mut out_handle, port_number as UINT, 0, 0, CALLBACK_NULL) };
        if result == MMSYSERR_BADDEVICEID {
            return Err(ConnectError::new(ConnectErrorKind::PortNumberOutOfRange, self));
        } else if result != MMSYSERR_NOERROR {
            return Err(ConnectError::other("could not create Windows MM MIDI output port", self));
        }

        Ok(MidiOutputConnection {
            out_handle: out_handle
        })
    }
}

impl MidiOutputConnection {
    pub fn close(self) -> MidiOutput {
        // The actual closing is done by the implementation of Drop
        MidiOutput // In this API this is a noop
    }

    pub fn send(&mut self, message: &[u8]) -> Result<(), SendError> {
        let nbytes = message.len();
        if nbytes == 0 {
            return Err(SendError::InvalidData("message to be sent must not be empty"));
        }

        if message[0] == 0xF0 { // Sysex message
            // Allocate buffer for sysex data and copy message
            let mut buffer = message.to_vec();

            // Create and prepare MIDIHDR structure.
            let mut sysex = MIDIHDR {
                lpData: buffer.as_mut_ptr() as *mut i8,
                dwBufferLength: nbytes as u32,
                dwBytesRecorded: 0,
                dwUser: 0,
                dwFlags: 0,
                lpNext: ptr::null_mut(),
                reserved: 0,
                dwOffset: 0,
                dwReserved: [0; 4],
            };

            let result = unsafe { midiOutPrepareHeader(self.out_handle, &mut sysex, mem::size_of::<MIDIHDR>() as u32) };

            if result != MMSYSERR_NOERROR {
                return Err(SendError::Other("preparation for sending sysex message failed (OutPrepareHeader)"));
            }

            // Send the message.
            loop {
                let result = unsafe { midiOutLongMsg(self.out_handle, &mut sysex, mem::size_of::<MIDIHDR>() as u32) };
                if result == MIDIERR_NOTREADY {
                    sleep(Duration::from_millis(1));
                    continue;
                } else {
                    if result != MMSYSERR_NOERROR {
                        return Err(SendError::Other("sending sysex message failed"));
                    }
                    break;
                }
            }

            loop {
                let result = unsafe { midiOutUnprepareHeader(self.out_handle, &mut sysex, mem::size_of::<MIDIHDR>() as u32) };
                if result == MIDIERR_STILLPLAYING {
                    sleep(Duration::from_millis(1));
                    continue;
                } else { break; }
            }
        } else { // Channel or system message.
            // Make sure the message size isn't too big.
            if nbytes > 3 {
                return Err(SendError::InvalidData("non-sysex message must not be longer than 3 bytes"));
            }

            // Pack MIDI bytes into double word.
            let packet: DWORD = 0;
            let ptr = &packet as *const u32 as *mut u8;
            for i in 0..nbytes {
                unsafe { *ptr.offset(i as isize) = message[i] };
            }

            // Send the message immediately.
            loop {
                let result = unsafe { midiOutShortMsg(self.out_handle, packet) };
                if result == MIDIERR_NOTREADY {
                    sleep(Duration::from_millis(1));
                    continue;
                } else {
                    if result != MMSYSERR_NOERROR {
                        return Err(SendError::Other("sending non-sysex message failed"));
                    }
                    break;
                }
            }
        }

        Ok(())
    }
}

impl Drop for MidiOutputConnection {
    fn drop(&mut self) {
        unsafe {
            midiOutReset(self.out_handle);
            midiOutClose(self.out_handle);
        }
    }
}<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

//! Constants for the binary format.
//!
//! Definition for the constants of the binary format, used by the serializer and the deserializer.
//! This module also offers helpers for the serialization and deserialization of certain
//! integer indexes.
//!
//! We use LEB128 for integer compression. LEB128 is a representation from the DWARF3 spec,
//! http://dwarfstd.org/Dwarf3Std.php or https://en.wikipedia.org/wiki/LEB128.
//! It's used to compress mostly indexes into the main binary tables.
use byteorder::ReadBytesExt;
use failure::*;
use std::{
    io::Cursor,
    mem::{size_of, transmute},
};

/// Constant values for the binary format header.
///
/// The binary header is magic +  version info + table count.
pub enum BinaryConstants {}
impl BinaryConstants {
    /// The blob that must start a binary.
    pub const LIBRA_MAGIC_SIZE: usize = 8;
    pub const LIBRA_MAGIC: [u8; BinaryConstants::LIBRA_MAGIC_SIZE] =
        [b'L', b'I', b'B', b'R', b'A', b'V', b'M', b'\n'];
    /// The `LIBRA_MAGIC` size, 1 byte for major version, 1 byte for minor version and 1 byte
    /// for table count.
    pub const HEADER_SIZE: usize = BinaryConstants::LIBRA_MAGIC_SIZE + 3;
    /// A (Table Type, Start Offset, Byte Count) size, which is 1 byte for the type and
    /// 4 bytes for the offset/count.
    pub const TABLE_HEADER_SIZE: u32 = size_of::<u32>() as u32 * 2 + 1;
}

/// Constants for table types in the binary.
///
/// The binary contains a subset of those tables. A table specification is a tuple (table type,
/// start offset, byte count) for a given table.
#[rustfmt::skip]
#[allow(non_camel_case_types)]
#[repr(u8)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum TableType {
    MODULE_HANDLES          = 0x1,
    STRUCT_HANDLES          = 0x2,
    FUNCTION_HANDLES        = 0x3,
    ADDRESS_POOL            = 0x4,
    STRING_POOL             = 0x5,
    BYTE_ARRAY_POOL         = 0x6,
    MAIN                    = 0x7,
    STRUCT_DEFS             = 0x8,
    FIELD_DEFS              = 0x9,
    FUNCTION_DEFS           = 0xA,
    TYPE_SIGNATURES         = 0xB,
    FUNCTION_SIGNATURES     = 0xC,
    LOCALS_SIGNATURES       = 0xD,
}

/// Constants for signature kinds (type, function, locals). Those values start a signature blob.
#[rustfmt::skip]
#[allow(non_camel_case_types)]
#[repr(u8)]
#[derive(Clone, Copy, Debug)]
pub enum SignatureType {
    TYPE_SIGNATURE          = 0x1,
    FUNCTION_SIGNATURE      = 0x2,
    LOCAL_SIGNATURE         = 0x3,
}

/// Constants for signature blob values.
#[rustfmt::skip]
#[allow(non_camel_case_types)]
#[repr(u8)]
#[derive(Clone, Copy, Debug)]
pub enum SerializedType {
    BOOL                    = 0x1,
    INTEGER                 = 0x2,
    STRING                  = 0x3,
    ADDRESS                 = 0x4,
    REFERENCE               = 0x5,
    MUTABLE_REFERENCE       = 0x6,
    STRUCT                  = 0x7,
    BYTEARRAY               = 0x8,
}

/// List of opcodes constants.
#[rustfmt::skip]
#[allow(non_camel_case_types)]
#[repr(u8)]
#[derive(Clone, Copy, Debug)]
pub enum Opcodes {
    POP                     = 0x01,
    RET                     = 0x02,
    BR_TRUE                 = 0x03,
    BR_FALSE                = 0x04,
    BRANCH                  = 0x05,
    LD_CONST                = 0x06,
    LD_ADDR                 = 0x07,
    LD_STR                  = 0x08,
    LD_TRUE                 = 0x09,
    LD_FALSE                = 0x0A,
    COPY_LOC                = 0x0B,
    MOVE_LOC                = 0x0C,
    ST_LOC                  = 0x0D,
    LD_REF_LOC              = 0x0E,
    LD_REF_FIELD            = 0x0F,
    LD_BYTEARRAY            = 0x10,
    CALL                    = 0x11,
    PACK                    = 0x12,
    UNPACK                  = 0x13,
    READ_REF                = 0x14,
    WRITE_REF               = 0x15,
    ADD                     = 0x16,
    SUB                     = 0x17,
    MUL                     = 0x18,
    MOD                     = 0x19,
    DIV                     = 0x1A,
    BIT_OR                  = 0x1B,
    BIT_AND                 = 0x1C,
    XOR                     = 0x1D,
    OR                      = 0x1E,
    AND                     = 0x1F,
    NOT                     = 0x20,
    EQ                      = 0x21,
    NEQ                     = 0x22,
    LT                      = 0x23,
    GT                      = 0x24,
    LE                      = 0x25,
    GE                      = 0x26,
    ASSERT                  = 0x27,
    GET_TXN_GAS_UNIT_PRICE  = 0x28,
    GET_TXN_MAX_GAS_UNITS   = 0x29,
    GET_GAS_REMAINING       = 0x2A,
    GET_TXN_SENDER          = 0x2B,
    EXISTS                  = 0x2C,
    BORROW_REF              = 0x2D,
    RELEASE_REF             = 0x2E,
    MOVE_FROM               = 0x2F,
    MOVE_TO                 = 0x30,
    CREATE_ACCOUNT          = 0x31,
    EMIT_EVENT              = 0x32,
    GET_TXN_SEQUENCE_NUMBER = 0x33,
    GET_TXN_PUBLIC_KEY      = 0x34,
    FREEZE_REF              = 0x35,
}

/// Take a `Vec<u8>` and a value to write to that vector and applies LEB128 logic to
/// compress the u16.
pub fn write_u16_as_uleb128(binary: &mut Vec<u8>, value: u16) {
    write_u32_as_uleb128(binary, u32::from(value));
}

/// Take a `Vec<u8>` and a value to write to that vector and applies LEB128 logic to
/// compress the u32.
pub fn write_u32_as_uleb128(binary: &mut Vec<u8>, value: u32) {
    let mut val = value;
    loop {
        let v: u8 = (val & 0x7f) as u8;
        if u32::from(v) != val {
            binary.push(v | 0x80);
            val >>= 7;
        } else {
            binary.push(v);
            break;
        }
    }
}

/// Write a `u16` in Little Endian format.
pub fn write_u16(binary: &mut Vec<u8>, value: u16) {
    let bytes: [u8; 2] = unsafe { transmute(value.to_le()) };
    for byte in &bytes {
        binary.push(*byte);
    }
}

/// Write a `u32` in Little Endian format.
pub fn write_u32(binary: &mut Vec<u8>, value: u32) {
    let bytes: [u8; 4] = unsafe { transmute(value.to_le()) };
    for byte in &bytes {
        binary.push(*byte);
    }
}

/// Write a `u64` in Little Endian format.
pub fn write_u64(binary: &mut Vec<u8>, value: u64) {
    let bytes: [u8; 8] = unsafe { transmute(value.to_le()) };
    for byte in &bytes {
        binary.push(*byte);
    }
}

/// Reads a `u16` in ULEB128 format from a `binary`.
///
/// Takes a `&mut Cursor<&[u8]>` and returns a pair:
///
/// u16 - value read
///
/// Return an error on an invalid representation.
pub fn read_uleb128_as_u16(cursor: &mut Cursor<&[u8]>) -> Result<u16> {
    let mut value: u16 = 0;
    let mut shift: u8 = 0;
    while let Ok(byte) = cursor.read_u8() {
        let val = byte & 0x7f;
        value |= u16::from(val) << shift;
        if val == byte {
            return Ok(value);
        }
        shift += 7;
        if shift > 14 {
            break;
        }
    }
    bail!("invalid ULEB128 representation for u16")
}

/// Reads a `u32` in ULEB128 format from a `binary`.
///
/// Takes a `&mut Cursor<&[u8]>` and returns a pair:
///
/// u32 - value read
///
/// Return an error on an invalid representation.
pub fn read_uleb128_as_u32(cursor: &mut Cursor<&[u8]>) -> Result<u32> {
    let mut value: u32 = 0;
    let mut shift: u8 = 0;
    while let Ok(byte) = cursor.read_u8() {
        let val = byte & 0x7f;
        value |= u32::from(val) << shift;
        if val == byte {
            return Ok(value);
        }
        shift += 7;
        if shift > 28 {
            break;
        }
    }
    bail!("invalid ULEB128 representation for u32")
}
<commit_msg>Remove uses of unsafe from file_format_common<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

//! Constants for the binary format.
//!
//! Definition for the constants of the binary format, used by the serializer and the deserializer.
//! This module also offers helpers for the serialization and deserialization of certain
//! integer indexes.
//!
//! We use LEB128 for integer compression. LEB128 is a representation from the DWARF3 spec,
//! http://dwarfstd.org/Dwarf3Std.php or https://en.wikipedia.org/wiki/LEB128.
//! It's used to compress mostly indexes into the main binary tables.
use byteorder::ReadBytesExt;
use failure::*;
use std::{io::Cursor, mem::size_of};

/// Constant values for the binary format header.
///
/// The binary header is magic +  version info + table count.
pub enum BinaryConstants {}
impl BinaryConstants {
    /// The blob that must start a binary.
    pub const LIBRA_MAGIC_SIZE: usize = 8;
    pub const LIBRA_MAGIC: [u8; BinaryConstants::LIBRA_MAGIC_SIZE] =
        [b'L', b'I', b'B', b'R', b'A', b'V', b'M', b'\n'];
    /// The `LIBRA_MAGIC` size, 1 byte for major version, 1 byte for minor version and 1 byte
    /// for table count.
    pub const HEADER_SIZE: usize = BinaryConstants::LIBRA_MAGIC_SIZE + 3;
    /// A (Table Type, Start Offset, Byte Count) size, which is 1 byte for the type and
    /// 4 bytes for the offset/count.
    pub const TABLE_HEADER_SIZE: u32 = size_of::<u32>() as u32 * 2 + 1;
}

/// Constants for table types in the binary.
///
/// The binary contains a subset of those tables. A table specification is a tuple (table type,
/// start offset, byte count) for a given table.
#[rustfmt::skip]
#[allow(non_camel_case_types)]
#[repr(u8)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum TableType {
    MODULE_HANDLES          = 0x1,
    STRUCT_HANDLES          = 0x2,
    FUNCTION_HANDLES        = 0x3,
    ADDRESS_POOL            = 0x4,
    STRING_POOL             = 0x5,
    BYTE_ARRAY_POOL         = 0x6,
    MAIN                    = 0x7,
    STRUCT_DEFS             = 0x8,
    FIELD_DEFS              = 0x9,
    FUNCTION_DEFS           = 0xA,
    TYPE_SIGNATURES         = 0xB,
    FUNCTION_SIGNATURES     = 0xC,
    LOCALS_SIGNATURES       = 0xD,
}

/// Constants for signature kinds (type, function, locals). Those values start a signature blob.
#[rustfmt::skip]
#[allow(non_camel_case_types)]
#[repr(u8)]
#[derive(Clone, Copy, Debug)]
pub enum SignatureType {
    TYPE_SIGNATURE          = 0x1,
    FUNCTION_SIGNATURE      = 0x2,
    LOCAL_SIGNATURE         = 0x3,
}

/// Constants for signature blob values.
#[rustfmt::skip]
#[allow(non_camel_case_types)]
#[repr(u8)]
#[derive(Clone, Copy, Debug)]
pub enum SerializedType {
    BOOL                    = 0x1,
    INTEGER                 = 0x2,
    STRING                  = 0x3,
    ADDRESS                 = 0x4,
    REFERENCE               = 0x5,
    MUTABLE_REFERENCE       = 0x6,
    STRUCT                  = 0x7,
    BYTEARRAY               = 0x8,
}

/// List of opcodes constants.
#[rustfmt::skip]
#[allow(non_camel_case_types)]
#[repr(u8)]
#[derive(Clone, Copy, Debug)]
pub enum Opcodes {
    POP                     = 0x01,
    RET                     = 0x02,
    BR_TRUE                 = 0x03,
    BR_FALSE                = 0x04,
    BRANCH                  = 0x05,
    LD_CONST                = 0x06,
    LD_ADDR                 = 0x07,
    LD_STR                  = 0x08,
    LD_TRUE                 = 0x09,
    LD_FALSE                = 0x0A,
    COPY_LOC                = 0x0B,
    MOVE_LOC                = 0x0C,
    ST_LOC                  = 0x0D,
    LD_REF_LOC              = 0x0E,
    LD_REF_FIELD            = 0x0F,
    LD_BYTEARRAY            = 0x10,
    CALL                    = 0x11,
    PACK                    = 0x12,
    UNPACK                  = 0x13,
    READ_REF                = 0x14,
    WRITE_REF               = 0x15,
    ADD                     = 0x16,
    SUB                     = 0x17,
    MUL                     = 0x18,
    MOD                     = 0x19,
    DIV                     = 0x1A,
    BIT_OR                  = 0x1B,
    BIT_AND                 = 0x1C,
    XOR                     = 0x1D,
    OR                      = 0x1E,
    AND                     = 0x1F,
    NOT                     = 0x20,
    EQ                      = 0x21,
    NEQ                     = 0x22,
    LT                      = 0x23,
    GT                      = 0x24,
    LE                      = 0x25,
    GE                      = 0x26,
    ASSERT                  = 0x27,
    GET_TXN_GAS_UNIT_PRICE  = 0x28,
    GET_TXN_MAX_GAS_UNITS   = 0x29,
    GET_GAS_REMAINING       = 0x2A,
    GET_TXN_SENDER          = 0x2B,
    EXISTS                  = 0x2C,
    BORROW_REF              = 0x2D,
    RELEASE_REF             = 0x2E,
    MOVE_FROM               = 0x2F,
    MOVE_TO                 = 0x30,
    CREATE_ACCOUNT          = 0x31,
    EMIT_EVENT              = 0x32,
    GET_TXN_SEQUENCE_NUMBER = 0x33,
    GET_TXN_PUBLIC_KEY      = 0x34,
    FREEZE_REF              = 0x35,
}

/// Take a `Vec<u8>` and a value to write to that vector and applies LEB128 logic to
/// compress the u16.
pub fn write_u16_as_uleb128(binary: &mut Vec<u8>, value: u16) {
    write_u32_as_uleb128(binary, u32::from(value));
}

/// Take a `Vec<u8>` and a value to write to that vector and applies LEB128 logic to
/// compress the u32.
pub fn write_u32_as_uleb128(binary: &mut Vec<u8>, value: u32) {
    let mut val = value;
    loop {
        let v: u8 = (val & 0x7f) as u8;
        if u32::from(v) != val {
            binary.push(v | 0x80);
            val >>= 7;
        } else {
            binary.push(v);
            break;
        }
    }
}

/// Write a `u16` in Little Endian format.
pub fn write_u16(binary: &mut Vec<u8>, value: u16) {
    binary.extend(&value.to_le_bytes());
}

/// Write a `u32` in Little Endian format.
pub fn write_u32(binary: &mut Vec<u8>, value: u32) {
    binary.extend(&value.to_le_bytes());
}

/// Write a `u64` in Little Endian format.
pub fn write_u64(binary: &mut Vec<u8>, value: u64) {
    binary.extend(&value.to_le_bytes());
}

/// Reads a `u16` in ULEB128 format from a `binary`.
///
/// Takes a `&mut Cursor<&[u8]>` and returns a pair:
///
/// u16 - value read
///
/// Return an error on an invalid representation.
pub fn read_uleb128_as_u16(cursor: &mut Cursor<&[u8]>) -> Result<u16> {
    let mut value: u16 = 0;
    let mut shift: u8 = 0;
    while let Ok(byte) = cursor.read_u8() {
        let val = byte & 0x7f;
        value |= u16::from(val) << shift;
        if val == byte {
            return Ok(value);
        }
        shift += 7;
        if shift > 14 {
            break;
        }
    }
    bail!("invalid ULEB128 representation for u16")
}

/// Reads a `u32` in ULEB128 format from a `binary`.
///
/// Takes a `&mut Cursor<&[u8]>` and returns a pair:
///
/// u32 - value read
///
/// Return an error on an invalid representation.
pub fn read_uleb128_as_u32(cursor: &mut Cursor<&[u8]>) -> Result<u32> {
    let mut value: u32 = 0;
    let mut shift: u8 = 0;
    while let Ok(byte) = cursor.read_u8() {
        let val = byte & 0x7f;
        value |= u32::from(val) << shift;
        if val == byte {
            return Ok(value);
        }
        shift += 7;
        if shift > 28 {
            break;
        }
    }
    bail!("invalid ULEB128 representation for u32")
}
<|endoftext|>


<commit_before>extern crate matroska;
extern crate av_format;
extern crate av_data;
extern crate circular;
extern crate nom;

use nom::{Err, Offset};
use circular::Buffer;
use std::env;
use std::io::Read;
use std::fs::File;

use matroska::ebml::ebml_header;
use matroska::elements::{segment, segment_element, SegmentElement};

fn main() {
    let mut args = env::args();
    let _ = args.next().expect("first arg is program path");
    let filename = args.next().expect("expected file path");

    //println!("filename: {}", filename);
    run(&filename).expect("should parse file correctly");
}

fn run(filename: &str) -> std::io::Result<()> {
    let mut file = File::open(filename)?;

    let capacity = 16384;
    let mut b = Buffer::with_capacity(capacity);

    // we write into the `&mut[u8]` returned by `space()`
    let sz = file.read(b.space()).expect("should write");
    b.fill(sz);
    //eprintln!("write {:#?}", sz);

    let length = {
        let res = ebml_header(b.data());
        if let Ok((remaining, header)) = res {
            //eprintln!("parsed header: {:#?}", h);
            println!("+ EBML head");
            println!("|+ EBML version: {}", header.version);
            println!("|+ EBML read version: {}", header.read_version);
            println!("|+ EBML maximum ID length: {}", header.max_id_length);
            println!("|+ EBML maximum size length: {}", header.max_size_length);
            println!("|+ Doc type: {}", header.doc_type);
            println!("|+ Doc type read version: {}", header.doc_type_read_version);

            b.data().offset(remaining)
        } else {
            panic!("couldn't parse header");
        }
    };

    let mut _consumed = length;
    //println!("consumed {} bytes", length);
    b.consume(length);

    let length = {
        let res = segment(b.data());
        if let Ok((remaining, segment)) = res {
            //eprintln!("parsed segment: {:#?}", h);
            println!("+ Segment, size {}", segment.1.unwrap_or(0));

            b.data().offset(remaining)
        } else {
            panic!("couldn't parse header");
        }
    };

    //eprintln!("consumed {} bytes", length);
    b.consume(length);

    // handle first elements
    let mut seek_head = None;
    let mut info = None;
    let mut tracks = None;

    loop {
        if seek_head.is_some() && info.is_some() && tracks.is_some() {
            break;
        }

        // refill the buffer
        let sz = file.read(b.space()).expect("should write");
        b.fill(sz);
        /*
        eprintln!(
            "refill: {} more bytes, available data: {} bytes, consumed: {} bytes",
            sz,
            b.available_data(),
            consumed
        );
        */

        // if there's no more available data in the buffer after a write, that means we reached
        // the end of the file
        if b.available_data() == 0 {
            panic!("no more data to read or parse, stopping the reading loop");
        }

        let offset = {
            let (i, element) = match segment_element(b.data()) {
                Ok((i, o)) => (i, o),
                Err(Err::Error(e)) |
                Err(Err::Failure(e)) => panic!("failed parsing: {:?}", e),
                Err(Err::Incomplete(_)) => continue,
            };

            match element {
                SegmentElement::SeekHead(s) => {
                    //eprintln!("got seek head: {:#?}", s);
                    println!("|+ Seek head");
                    if seek_head.is_some() {
                        panic!("already got a SeekHead element");
                    } else {
                        seek_head = Some(s);
                    }
                },
                SegmentElement::Info(i) => {
                    println!("|+ Segment Information");
                    println!("| + timestamp scale: {}", i.timecode_scale);
                    println!("| + multiplexing application: {}", i.muxing_app);
                    println!("| + writing application: {}", i.writing_app);
                    println!("| + segment UID: {:?}", i.segment_uid.as_ref().unwrap_or(&Vec::new()));
                    println!("| + duration: {}s", i.duration.unwrap_or(0f64) / 1000f64);
                    if info.is_some() {
                        panic!("already got an Info element");
                    } else {
                        info = Some(i);
                    }
                },
                SegmentElement::Tracks(t) => {
                    //eprintln!("got tracks: {:#?}", t);
                    println!("|+ Segment tracks");
                    for tr in t.tracks.iter() {
                      println!("| + A track");
                      println!("|  + Track number: {}", tr.track_number);
                      println!("|  + Track UID: {}", tr.track_uid);
                      println!("|  + Track type: {}", tr.track_type);
                      println!("|  + Lacing flag: {}", tr.flag_lacing.unwrap_or(0));
                      println!("|  + Default flag: {}", tr.flag_default.unwrap_or(0));
                      println!("|  + Language: {}", tr.language.as_ref().unwrap_or(&"".to_string()));
                      println!("|  + Codec ID: {}", tr.codec_id);
                      println!("|  + Codec private: length {}", tr.codec_private.as_ref().map(|v| v.len()).unwrap_or(0));

                      if let Some(ref v) = tr.video {
                        println!("|  + Video track");
                        println!("|    + Pixel width: {}", v.pixel_width);
                        println!("|    + Pixel height: {}", v.pixel_height);
                        if let Some(inter) = v.flag_interlaced {
                          println!("|    + Interlaced: {}", inter);
                        }
                        if let Some(width) = v.display_width {
                          println!("|    + Display width: {}", width);
                        }
                        if let Some(height) = v.display_height {
                          println!("|    + Display height: {}", height);
                        }
                        if let Some(unit) = v.display_unit {
                          println!("|    + Display unit: {}", unit);
                        }
                      }

                      if let Some(ref a) = tr.audio {
                        println!("|  + Audio track");
                        println!("|    + Sampling frequency: {}", a.sampling_frequency);
                        if let Some(frequency) = a.output_sampling_frequency {
                          println!("|    + Output sampling freqeuncy: {}", frequency);
                        }
                        println!("|    + Channels: {}", a.channels);
                        if let Some(ref channel_positions) = a.channel_positions {
                          println!("|    + Channel position: {:?}", channel_positions);
                        }
                        if let Some(bit_depth) = a.bit_depth {
                          println!("|    + Bit depth: {}", bit_depth);
                        }
                      }
                    }
                    if tracks.is_some() {
                        panic!("already got a Tracks element");
                    } else {
                        tracks = Some(t);
                    }
                }
                SegmentElement::Cluster(_) => {
                    println!("|+ Cluster");
                    //eprintln!("got a cluster: {:#?}", c);
                },
                SegmentElement::Void => {
                    println!("|+ EbmlVoid");
                },
                el => {
                    panic!("got unexpected element: {:#?}", el);
                }
            }

            b.data().offset(i)
        };
        _consumed += offset;
        //eprintln!("consumed {} bytes", length);
        b.consume(offset);
    }

    loop {
        // refill the buffer
        let sz = file.read(b.space()).expect("should write");
        b.fill(sz);
        /*
        eprintln!(
            "refill: {} more bytes, available data: {} bytes, consumed: {} bytes",
            sz,
            b.available_data(),
            consumed
        );
        */

        // if there's no more available data in the buffer after a write, that means we reached
        // the end of the file
        if b.available_data() == 0 {
            //panic!("no more data to read or parse, stopping the reading loop");
            break;
        }

        let offset = {
            let (i, element) = match segment_element(b.data()) {
                Ok((i, o)) => (i, o),
                Err(Err::Error(e)) |
                Err(Err::Failure(e)) => panic!("failed parsing: {:?}", e),
                Err(Err::Incomplete(_)) => continue,
            };

            match element {
                SegmentElement::SeekHead(_) | SegmentElement::Info(_) | SegmentElement::Tracks(_) => {
                  panic!("unexpected seek head, info or tracks element");
                },
                SegmentElement::Cluster(c) => {
                  println!("|+ Cluster");
                  eprintln!("got a cluster: {:#?}", c);
                },
                SegmentElement::Void => {
                  println!("|+ EbmlVoid");
                },
                SegmentElement::Tags(_) => {
                  println!("|+ Tags");
                }
                SegmentElement::Cues(_) => {
                  println!("|+ Cues");
                }
                el => {
                    panic!("got unexpected element: {:#?}", el);
                }
            }

            b.data().offset(i)
        };
        _consumed += offset;
        //eprintln!("consumed {} bytes", length);
        b.consume(offset);
    }

    Ok(())
}
<commit_msg>fix matroska_info<commit_after>extern crate matroska;
extern crate av_format;
extern crate av_data;
extern crate circular;
extern crate nom;

use nom::{Err, Offset};
use circular::Buffer;
use std::env;
use std::io::Read;
use std::fs::File;

use matroska::ebml::ebml_header;
use matroska::elements::{segment, segment_element, SegmentElement};

fn main() {
    let mut args = env::args();
    let _ = args.next().expect("first arg is program path");
    let filename = args.next().expect("expected file path");

    //println!("filename: {}", filename);
    run(&filename).expect("should parse file correctly");
}

fn run(filename: &str) -> std::io::Result<()> {
    let mut file = File::open(filename)?;

    let capacity = 5242880;
    let mut b = Buffer::with_capacity(capacity);

    // we write into the `&mut[u8]` returned by `space()`
    let sz = file.read(b.space()).expect("should write");
    b.fill(sz);
    //eprintln!("write {:#?}", sz);

    let length = {
        let res = ebml_header(b.data());
        if let Ok((remaining, header)) = res {
            //eprintln!("parsed header: {:#?}", h);
            println!("+ EBML head");
            println!("|+ EBML version: {}", header.version);
            println!("|+ EBML read version: {}", header.read_version);
            println!("|+ EBML maximum ID length: {}", header.max_id_length);
            println!("|+ EBML maximum size length: {}", header.max_size_length);
            println!("|+ Doc type: {}", header.doc_type);
            println!("|+ Doc type read version: {}", header.doc_type_read_version);

            b.data().offset(remaining)
        } else {
            panic!("couldn't parse header");
        }
    };

    let mut _consumed = length;
    //println!("consumed {} bytes", length);
    b.consume(length);

    let length = {
        let res = segment(b.data());
        if let Ok((remaining, segment)) = res {
            //eprintln!("parsed segment: {:#?}", h);
            println!("+ Segment, size {}", segment.1.unwrap_or(0));

            b.data().offset(remaining)
        } else {
            panic!("couldn't parse header");
        }
    };

    //eprintln!("consumed {} bytes", length);
    b.consume(length);

    // handle first elements
    let mut seek_head = None;
    let mut info = None;
    let mut tracks = None;

    loop {
        if seek_head.is_some() && info.is_some() && tracks.is_some() {
            break;
        }

        // refill the buffer
        let sz = file.read(b.space()).expect("should read");
        b.fill(sz);
        /*
        eprintln!(
            "refill: {} more bytes, available data: {} bytes, consumed: {} bytes",
            sz,
            b.available_data(),
            consumed
        );
        */

        // if there's no more available data in the buffer after a write, that means we reached
        // the end of the file
        if b.available_data() == 0 {
            panic!("no more data to read or parse, stopping the reading loop");
        }

        let offset = {
            let (i, element) = match segment_element(b.data()) {
                Ok((i, o)) => (i, o),
                Err(Err::Error(e)) |
                Err(Err::Failure(e)) => panic!("failed parsing: {:?}", e),
                Err(Err::Incomplete(_)) => continue,
            };

            match element {
                SegmentElement::SeekHead(s) => {
                    //eprintln!("got seek head: {:#?}", s);
                    println!("|+ Seek head");
                    if seek_head.is_some() {
                        panic!("already got a SeekHead element");
                    } else {
                        seek_head = Some(s);
                    }
                },
                SegmentElement::Info(i) => {
                    println!("|+ Segment Information");
                    println!("| + timestamp scale: {}", i.timecode_scale);
                    println!("| + multiplexing application: {}", i.muxing_app);
                    println!("| + writing application: {}", i.writing_app);
                    println!("| + segment UID: {:?}", i.segment_uid.as_ref().unwrap_or(&Vec::new()));
                    println!("| + duration: {}s", i.duration.unwrap_or(0f64) / 1000f64);
                    if info.is_some() {
                        panic!("already got an Info element");
                    } else {
                        info = Some(i);
                    }
                },
                SegmentElement::Tracks(t) => {
                    //eprintln!("got tracks: {:#?}", t);
                    println!("|+ Segment tracks");
                    for tr in t.tracks.iter() {
                      println!("| + A track");
                      println!("|  + Track number: {}", tr.track_number);
                      println!("|  + Track UID: {}", tr.track_uid);
                      println!("|  + Track type: {}", tr.track_type);
                      println!("|  + Lacing flag: {}", tr.flag_lacing.unwrap_or(0));
                      println!("|  + Default flag: {}", tr.flag_default.unwrap_or(0));
                      println!("|  + Language: {}", tr.language.as_ref().unwrap_or(&"".to_string()));
                      println!("|  + Codec ID: {}", tr.codec_id);
                      println!("|  + Codec private: length {}", tr.codec_private.as_ref().map(|v| v.len()).unwrap_or(0));

                      if let Some(ref v) = tr.video {
                        println!("|  + Video track");
                        println!("|    + Pixel width: {}", v.pixel_width);
                        println!("|    + Pixel height: {}", v.pixel_height);
                        if let Some(inter) = v.flag_interlaced {
                          println!("|    + Interlaced: {}", inter);
                        }
                        if let Some(width) = v.display_width {
                          println!("|    + Display width: {}", width);
                        }
                        if let Some(height) = v.display_height {
                          println!("|    + Display height: {}", height);
                        }
                        if let Some(unit) = v.display_unit {
                          println!("|    + Display unit: {}", unit);
                        }
                      }

                      if let Some(ref a) = tr.audio {
                        println!("|  + Audio track");
                        println!("|    + Sampling frequency: {}", a.sampling_frequency);
                        if let Some(frequency) = a.output_sampling_frequency {
                          println!("|    + Output sampling freqeuncy: {}", frequency);
                        }
                        println!("|    + Channels: {}", a.channels);
                        if let Some(ref channel_positions) = a.channel_positions {
                          println!("|    + Channel position: {:?}", channel_positions);
                        }
                        if let Some(bit_depth) = a.bit_depth {
                          println!("|    + Bit depth: {}", bit_depth);
                        }
                      }
                    }
                    if tracks.is_some() {
                        panic!("already got a Tracks element");
                    } else {
                        tracks = Some(t);
                    }
                },
                /*SegmentElement::Cluster(c) => {
                    println!("|+ Cluster");
                    eprintln!("got a cluster: {:#?}", c);
                },*/
                SegmentElement::Void => {
                    println!("|+ EbmlVoid");
                },
                el => {
                    panic!("got unexpected element: {:#?}", el);
                }
            }

            b.data().offset(i)
        };
        _consumed += offset;
        //eprintln!("consumed {} bytes", length);
        b.consume(offset);
    }

    loop {
        if b.available_space() == 0 {
          b.shift();
          if b.available_space() == 0 {
            println!("buffer is already full,  cannot refill");
            break;
          }
        }

        // refill the buffer
        let sz = file.read(b.space()).expect("should read");
        b.fill(sz);

        /*
        eprintln!(
            "refill: {} more bytes, available data: {} bytes, consumed: {} bytes",
            sz,
            b.available_data(),
            consumed
        );
        */

        // if there's no more available data in the buffer after a write, that means we reached
        // the end of the file
        if b.available_data() == 0 {
            //panic!("no more data to read or parse, stopping the reading loop");
            break;
        }

        let offset = {
            let (i, element) = match segment_element(b.data()) {
                Ok((i, o)) => (i, o),
                Err(Err::Error(e)) |
                Err(Err::Failure(e)) => panic!("failed parsing: {:?}", e),
                Err(Err::Incomplete(_)) => continue,
            };

            match element {
                SegmentElement::SeekHead(_) | SegmentElement::Info(_) | SegmentElement::Tracks(_) => {
                  panic!("unexpected seek head, info or tracks element: {:?}", element);
                },
                SegmentElement::Cluster(c) => {
                  println!("|+ Cluster");
                  //eprintln!("got a cluster: {:#?}", c);
                },
                SegmentElement::Void => {
                  println!("|+ EbmlVoid");
                },
                SegmentElement::Tags(_) => {
                  println!("|+ Tags");
                }
                SegmentElement::Cues(_) => {
                  println!("|+ Cues");
                }
                el => {
                    panic!("got unexpected element: {:#?}", el);
                }
            }

            b.data().offset(i)
        };
        _consumed += offset;
        //eprintln!("consumed {} bytes", length);
        b.consume(offset);
    }

    Ok(())
}
<|endoftext|>


<commit_before>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

//! Implementation of the install aspects of the compiler.
//!
//! This module is responsible for installing the standard library,
//! compiler, and documentation.

use std::env;
use std::fs;
use std::path::{Path, PathBuf, Component};
use std::process::Command;

use Build;
use dist::{sanitize_sh, tmpdir};

/// Installs everything.
pub fn install(build: &Build, stage: u32, host: &str) {
    let prefix_default = PathBuf::from("/usr/local");
    let docdir_default = PathBuf::from("share/doc/rust");
    let mandir_default = PathBuf::from("share/man");
    let libdir_default = PathBuf::from("lib");
    let prefix = build.config.prefix.as_ref().unwrap_or(&prefix_default);
    let docdir = build.config.docdir.as_ref().unwrap_or(&docdir_default);
    let libdir = build.config.libdir.as_ref().unwrap_or(&libdir_default);
    let mandir = build.config.mandir.as_ref().unwrap_or(&mandir_default);

    let docdir = prefix.join(docdir);
    let libdir = prefix.join(libdir);
    let mandir = prefix.join(mandir);

    let destdir = env::var_os("DESTDIR").map(PathBuf::from);

    let prefix = add_destdir(&prefix, &destdir);
    let docdir = add_destdir(&docdir, &destdir);
    let libdir = add_destdir(&libdir, &destdir);
    let mandir = add_destdir(&mandir, &destdir);

    let empty_dir = build.out.join("tmp/empty_dir");
    t!(fs::create_dir_all(&empty_dir));
    if build.config.docs {
        install_sh(&build, "docs", "rust-docs", &build.rust_package_vers(),
                   stage, host, &prefix, &docdir, &libdir, &mandir, &empty_dir);
    }

    for target in build.config.target.iter() {
        install_sh(&build, "std", "rust-std", &build.rust_package_vers(), stage, target, &prefix,
                   &docdir, &libdir, &mandir, &empty_dir);
    }

    install_sh(&build, "rustc", "rustc", &build.rust_package_vers(), stage, host, &prefix,
               &docdir, &libdir, &mandir, &empty_dir);
    t!(fs::remove_dir_all(&empty_dir));
}

fn install_sh(build: &Build, package: &str, name: &str, version: &str, stage: u32, host: &str,
              prefix: &Path, docdir: &Path, libdir: &Path, mandir: &Path, empty_dir: &Path) {
    println!("Install {} stage{} ({})", package, stage, host);
    let package_name = format!("{}-{}-{}", name, version, host);

    let mut cmd = Command::new("sh");
    cmd.current_dir(empty_dir)
       .arg(sanitize_sh(&tmpdir(build).join(&package_name).join("install.sh")))
       .arg(format!("--prefix={}", sanitize_sh(prefix)))
       .arg(format!("--docdir={}", sanitize_sh(docdir)))
       .arg(format!("--libdir={}", sanitize_sh(libdir)))
       .arg(format!("--mandir={}", sanitize_sh(mandir)))
       .arg("--disable-ldconfig");
    build.run(&mut cmd);
}

fn add_destdir(path: &Path, destdir: &Option<PathBuf>) -> PathBuf {
    let mut ret = match *destdir {
        Some(ref dest) => dest.clone(),
        None => return path.to_path_buf(),
    };
    for part in path.components() {
        match part {
            Component::Normal(s) => ret.push(s),
            _ => {}
        }
    }
    return ret
}
<commit_msg>rustbuild: install cargo and rls when extended build is enabled<commit_after>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

//! Implementation of the install aspects of the compiler.
//!
//! This module is responsible for installing the standard library,
//! compiler, and documentation.

use std::env;
use std::fs;
use std::path::{Path, PathBuf, Component};
use std::process::Command;

use Build;
use dist::{sanitize_sh, tmpdir};

/// Installs everything.
pub fn install(build: &Build, stage: u32, host: &str) {
    let prefix_default = PathBuf::from("/usr/local");
    let docdir_default = PathBuf::from("share/doc/rust");
    let mandir_default = PathBuf::from("share/man");
    let libdir_default = PathBuf::from("lib");
    let prefix = build.config.prefix.as_ref().unwrap_or(&prefix_default);
    let docdir = build.config.docdir.as_ref().unwrap_or(&docdir_default);
    let libdir = build.config.libdir.as_ref().unwrap_or(&libdir_default);
    let mandir = build.config.mandir.as_ref().unwrap_or(&mandir_default);

    let docdir = prefix.join(docdir);
    let libdir = prefix.join(libdir);
    let mandir = prefix.join(mandir);

    let destdir = env::var_os("DESTDIR").map(PathBuf::from);

    let prefix = add_destdir(&prefix, &destdir);
    let docdir = add_destdir(&docdir, &destdir);
    let libdir = add_destdir(&libdir, &destdir);
    let mandir = add_destdir(&mandir, &destdir);

    let empty_dir = build.out.join("tmp/empty_dir");
    t!(fs::create_dir_all(&empty_dir));
    if build.config.docs {
        install_sh(&build, "docs", "rust-docs", &build.rust_package_vers(),
                   stage, host, &prefix, &docdir, &libdir, &mandir, &empty_dir);
    }

    for target in build.config.target.iter() {
        install_sh(&build, "std", "rust-std", &build.rust_package_vers(),
                   stage, target, &prefix, &docdir, &libdir, &mandir, &empty_dir);
    }

    install_sh(&build, "rustc", "rustc", &build.rust_package_vers(),
               stage, host, &prefix, &docdir, &libdir, &mandir, &empty_dir);

    if build.config.extended {
        install_sh(&build, "cargo", "cargo", &build.cargo_package_vers(),
                   stage, host, &prefix, &docdir, &libdir, &mandir, &empty_dir);
        install_sh(&build, "rls", "rls", &build.rls_package_vers(),
                   stage, host, &prefix, &docdir, &libdir, &mandir, &empty_dir);
    }

    t!(fs::remove_dir_all(&empty_dir));
}

fn install_sh(build: &Build, package: &str, name: &str, version: &str, stage: u32, host: &str,
              prefix: &Path, docdir: &Path, libdir: &Path, mandir: &Path, empty_dir: &Path) {
    println!("Install {} stage{} ({})", package, stage, host);
    let package_name = format!("{}-{}-{}", name, version, host);

    let mut cmd = Command::new("sh");
    cmd.current_dir(empty_dir)
       .arg(sanitize_sh(&tmpdir(build).join(&package_name).join("install.sh")))
       .arg(format!("--prefix={}", sanitize_sh(prefix)))
       .arg(format!("--docdir={}", sanitize_sh(docdir)))
       .arg(format!("--libdir={}", sanitize_sh(libdir)))
       .arg(format!("--mandir={}", sanitize_sh(mandir)))
       .arg("--disable-ldconfig");
    build.run(&mut cmd);
}

fn add_destdir(path: &Path, destdir: &Option<PathBuf>) -> PathBuf {
    let mut ret = match *destdir {
        Some(ref dest) => dest.clone(),
        None => return path.to_path_buf(),
    };
    for part in path.components() {
        match part {
            Component::Normal(s) => ret.push(s),
            _ => {}
        }
    }
    return ret
}
<|endoftext|>


<commit_before>extern crate regex;

use std::ascii::AsciiExt;
use std::error::Error;
use std::fs::File;
use std::io;
use std::io::BufReader;
use std::io::prelude::*;
use std::path::Path;
use std::collections::HashMap;
use std::collections::HashSet;
use regex::Regex;

fn load_dictionary(dictionary_path: &Path) -> Vec<String> {
    let display = dictionary_path.display();

    let file = match File::open(dictionary_path) {
        Err(why) => panic!("couldn't open {}: {}",
                           display,
                           Error::description(&why)),
        Ok(file) => file,
    };
    let reader = BufReader::new(file);
    let mut words = Vec::new();

    for readline in reader.lines() {
        let line = match readline {
            Err(why) => panic!("couldn't read from {}: {}",
                                display,
                                Error::description(&why)),
            Ok(readline) => readline,
        };

        words.push(line.trim().to_string());
    }
    return words;
}

fn build_maps(words: &Vec<String>) -> (
        HashMap<(char, usize, usize), HashSet<&str>>,
        HashMap<usize, HashSet<&str>>) {
    let mut ch_position_length_map :
        HashMap<(char, usize, usize), HashSet<&str>> = HashMap::new();
    let mut length_map : HashMap<usize, HashSet<&str>> = HashMap::new();

    for word in words.iter() {
        for (index, ch) in word.to_ascii_lowercase().chars().enumerate() {
            let key = (ch, index, word.len());

            ch_position_length_map.entry(key).or_insert(
                HashSet::new()).insert(word);
            length_map.entry(word.len()).or_insert(
                HashSet::new()).insert(word);
        }
    }
    (ch_position_length_map, length_map)
}

fn match_pattern<'a>(pattern : &str,
         ch_position_length_map : &HashMap<(char, usize, usize), HashSet<&'a str>>,
         length_map : &HashMap<usize, HashSet<&'a str>>) -> Vec<&'a str> {
    let pattern_parser = Regex::new(
        r"(?P<number>\d+)|(?P<letter>[A-Za-z])").unwrap();

    let mut pattern_length: usize = 0;
    let mut ch_and_index = Vec::new();

    for number_or_letter in pattern_parser.captures_iter(
            &pattern.to_ascii_lowercase()) {
        if number_or_letter.name("number").is_some() {
            let number_as_string = number_or_letter.name("number").unwrap();
            let number: usize = number_as_string.parse().unwrap();
            pattern_length += number;
        } else {
            let match_word = number_or_letter.name("letter").unwrap();
            let ch = match_word.char_indices().next().unwrap().1;
            ch_and_index.push((ch, pattern_length));
            pattern_length += 1;
        }
    }

    if ch_and_index.is_empty() {
        if length_map.contains_key(&pattern_length) {
            return length_map.get(
                &pattern_length).unwrap().iter().cloned().collect();
        } else {
            return Vec::new();
        }
    }

    let mut word_sets : Vec<&HashSet<&str>> = Vec::new();
    for &(ch, index) in ch_and_index.iter() {
        let key = (ch, index as usize, pattern_length as usize);
        if ch_position_length_map.contains_key(&key) {
            word_sets.push(ch_position_length_map.get(&key).unwrap());
        } else {
            // There are no words of pattern_length that ch at index.
            return Vec::new();
        }
    }

    assert!(!word_sets.is_empty());
    if word_sets.len() == 1 {
        return word_sets.get(0).unwrap().iter().cloned().collect();
    }

    word_sets.sort_by(|a, b| a.len().cmp(&b.len()));
    let mut refined_word_set : HashSet<&str> =
        word_sets.get(0).unwrap().intersection(
            word_sets.get(1).unwrap()).cloned().collect();

    for word_set in word_sets.iter().skip(2) {
        refined_word_set = refined_word_set.intersection(
            word_set).cloned().collect();
    }

    return refined_word_set.iter().cloned().collect();
}

fn print_matches(words : Vec<&str>) {
    if words.is_empty() {
        println!("\t<No Results>");
    } else {
        let mut sorted_words : Vec<&str> = words.into_iter().collect();
        sorted_words.sort();
        for word in sorted_words {
            println!("\t{}", word);
        }
    }
}

fn main() {
    let dictionary_path = Path::new("/usr/share/dict/words");
    let words = load_dictionary(&dictionary_path);
    let (ch_position_length_map, length_map) = build_maps(&words);

    let stdin = io::stdin();
    for line in stdin.lock().lines() {
        let matches = match_pattern(&line.unwrap(),
                                    &ch_position_length_map,
                                    &length_map);
        print_matches(matches);
    }
}<commit_msg>Add unit tests<commit_after>extern crate regex;

use std::ascii::AsciiExt;
use std::error::Error;
use std::fs::File;
use std::io;
use std::io::BufReader;
use std::io::prelude::*;
use std::path::Path;
use std::collections::HashMap;
use std::collections::HashSet;
use regex::Regex;

fn load_dictionary(dictionary_path: &Path) -> Vec<String> {
    let display = dictionary_path.display();

    let file = match File::open(dictionary_path) {
        Err(why) => panic!("couldn't open {}: {}",
                           display,
                           Error::description(&why)),
        Ok(file) => file,
    };
    let reader = BufReader::new(file);
    let mut words = Vec::new();

    for readline in reader.lines() {
        let line = match readline {
            Err(why) => panic!("couldn't read from {}: {}",
                                display,
                                Error::description(&why)),
            Ok(readline) => readline,
        };

        words.push(line.trim().to_string());
    }
    return words;
}

fn build_maps(words: &Vec<String>) -> (
        HashMap<(char, usize, usize), HashSet<&str>>,
        HashMap<usize, HashSet<&str>>) {
    let mut ch_position_length_map :
        HashMap<(char, usize, usize), HashSet<&str>> = HashMap::new();
    let mut length_map : HashMap<usize, HashSet<&str>> = HashMap::new();

    for word in words.iter() {
        for (index, ch) in word.to_ascii_lowercase().chars().enumerate() {
            let key = (ch, index, word.len());

            ch_position_length_map.entry(key).or_insert(
                HashSet::new()).insert(word);
            length_map.entry(word.len()).or_insert(
                HashSet::new()).insert(word);
        }
    }
    (ch_position_length_map, length_map)
}

fn match_pattern<'a>(pattern : &str,
         ch_position_length_map : &HashMap<(char, usize, usize), HashSet<&'a str>>,
         length_map : &HashMap<usize, HashSet<&'a str>>) -> Vec<&'a str> {
    let pattern_parser = Regex::new(
        r"(?P<number>\d+)|(?P<letter>[A-Za-z])").unwrap();

    let mut pattern_length: usize = 0;
    let mut ch_and_index = Vec::new();

    for number_or_letter in pattern_parser.captures_iter(
            &pattern.to_ascii_lowercase()) {
        if number_or_letter.name("number").is_some() {
            let number_as_string = number_or_letter.name("number").unwrap();
            let number: usize = number_as_string.parse().unwrap();
            pattern_length += number;
        } else {
            let match_word = number_or_letter.name("letter").unwrap();
            let ch = match_word.char_indices().next().unwrap().1;
            ch_and_index.push((ch, pattern_length));
            pattern_length += 1;
        }
    }

    if ch_and_index.is_empty() {
        if length_map.contains_key(&pattern_length) {
            return length_map.get(
                &pattern_length).unwrap().iter().cloned().collect();
        } else {
            return Vec::new();
        }
    }

    let mut word_sets : Vec<&HashSet<&str>> = Vec::new();
    for &(ch, index) in ch_and_index.iter() {
        let key = (ch, index as usize, pattern_length as usize);
        if ch_position_length_map.contains_key(&key) {
            word_sets.push(ch_position_length_map.get(&key).unwrap());
        } else {
            // There are no words of pattern_length that ch at index.
            return Vec::new();
        }
    }

    assert!(!word_sets.is_empty());
    if word_sets.len() == 1 {
        return word_sets.get(0).unwrap().iter().cloned().collect();
    }

    word_sets.sort_by(|a, b| a.len().cmp(&b.len()));
    let mut refined_word_set : HashSet<&str> =
        word_sets.get(0).unwrap().intersection(
            word_sets.get(1).unwrap()).cloned().collect();

    for word_set in word_sets.iter().skip(2) {
        refined_word_set = refined_word_set.intersection(
            word_set).cloned().collect();
    }

    return refined_word_set.iter().cloned().collect();
}

fn print_matches(words : Vec<&str>) {
    if words.is_empty() {
        println!("\t<No Results>");
    } else {
        let mut sorted_words : Vec<&str> = words.into_iter().collect();
        sorted_words.sort();
        for word in sorted_words {
            println!("\t{}", word);
        }
    }
}

#[test]
fn match_number_only() {
    let words = vec![
            "cat".to_string(),
            "intercrystallization".to_string(),
            "parallelogrammatical".to_string(),
            "pseudoanthropological".to_string()];
    let (ch_position_length_map, length_map) = build_maps(&words);
    let mut matches = match_pattern("20",
                                    &ch_position_length_map,
                                    &length_map);
    matches.sort();
    assert_eq!(matches, ["intercrystallization", "parallelogrammatical"]);
}

#[test]
fn match_letters_only() {
    let words = vec![
            "cat".to_string(),
            "intercrystallization".to_string(),
            "parallelogrammatical".to_string(),
            "pseudoanthropological".to_string()];
    let (ch_position_length_map, length_map) = build_maps(&words);
    let mut matches = match_pattern("parallelogrammatical",
                                    &ch_position_length_map,
                                    &length_map);
    matches.sort();
    assert_eq!(matches, ["parallelogrammatical"]);
}

#[test]
fn match_letter_number_letter() {
    let words = vec![
            "i18n".to_string(),
            "in".to_string(),
            "intercrystallization".to_string(),
            "internationalization".to_string(),
            "internationalizationy".to_string()];
    let (ch_position_length_map, length_map) = build_maps(&words);
    let mut matches = match_pattern("i18n",
                                    &ch_position_length_map,
                                    &length_map);
    matches.sort();
    assert_eq!(matches, ["intercrystallization", "internationalization"]);
}

#[test]
fn match_letter_number_letter_number_letter() {
    let words = vec![
            "institutionalization".to_string(),
            "intercrystallization".to_string(),
            "internationalization".to_string(),
            "internationalizationy".to_string()];
    let (ch_position_length_map, length_map) = build_maps(&words);
    let mut matches = match_pattern("i1t16n",
                                    &ch_position_length_map,
                                    &length_map);
    matches.sort();
    assert_eq!(matches, ["intercrystallization", "internationalization"]);
}

#[test]
fn match_number_letter_number_letter_number() {
    let words = vec![
            "antianthropomorphism".to_string(),
            "institutionalization".to_string(),
            "intercrystallization".to_string(),
            "internationalization".to_string(),
            "internationalizationy".to_string()];
    let (ch_position_length_map, length_map) = build_maps(&words);
    let mut matches = match_pattern("2t2n14",
                                    &ch_position_length_map,
                                    &length_map);
    matches.sort();
    assert_eq!(matches, ["antianthropomorphism", "internationalization"]);
}

#[test]
fn match_ignores_case() {
    let words = vec![
            "Cat".to_string(),
            "cat".to_string(),
            "cot".to_string(),
            "dog".to_string()];
    let (ch_position_length_map, length_map) = build_maps(&words);
    let mut matches = match_pattern("c1t",
                                    &ch_position_length_map,
                                    &length_map);
    matches.sort();
    assert_eq!(matches, ["Cat", "cat", "cot"]);
}

#[allow(dead_code)]
fn main() {
    let dictionary_path = Path::new("/usr/share/dict/words");
    let words = load_dictionary(&dictionary_path);
    let (ch_position_length_map, length_map) = build_maps(&words);

    let stdin = io::stdin();
    for line in stdin.lock().lines() {
        let matches = match_pattern(&line.unwrap(),
                                    &ch_position_length_map,
                                    &length_map);
        print_matches(matches);
    }
}<|endoftext|>


<commit_before>extern crate gcc;

fn main() {
    let target = std::env::var("TARGET").unwrap();

    let mut config = gcc::Config::new();
    config.file("mdb/libraries/liblmdb/mdb.c")
          .file("mdb/libraries/liblmdb/midl.c");

    if target.contains("dragonfly") {
        config.flag("-DMDB_DSYNC=O_SYNC");
        config.flag("-DMDB_FDATASYNC=fsync");
    }

    config.compile("liblmdb.a");
}
<commit_msg>Build sys crate with opt-level 2<commit_after>extern crate gcc;

fn main() {
    let target = std::env::var("TARGET").unwrap();

    let mut config = gcc::Config::new();
    config.file("mdb/libraries/liblmdb/mdb.c")
          .file("mdb/libraries/liblmdb/midl.c");
    config.opt_level(2);

    if target.contains("dragonfly") {
        config.flag("-DMDB_DSYNC=O_SYNC");
        config.flag("-DMDB_FDATASYNC=fsync");
    }

    config.compile("liblmdb.a");
}
<|endoftext|>