<commit_before>// Copyright 2018 TiKV Project Authors. Licensed under Apache-2.0.

//! DO NOT MOVE THIS FILE. IT WILL BE PARSED BY `fuzz/cli.rs`. SEE `discover_fuzz_targets()`.

mod util;

use self::util::ReadLiteralExt;
use failure::Error;
use std::io::Cursor;

#[inline(always)]
pub fn fuzz_codec_bytes(data: &[u8]) -> Result<(), Error> {
    let _ = tikv_util::codec::bytes::encode_bytes(data);
    let _ = tikv_util::codec::bytes::encode_bytes_desc(data);
    let _ = tikv_util::codec::bytes::encoded_bytes_len(data, true);
    let _ = tikv_util::codec::bytes::encoded_bytes_len(data, false);
    Ok(())
}

#[inline(always)]
pub fn fuzz_codec_number(data: &[u8]) -> Result<(), Error> {
    use tikv_util::codec::number::NumberEncoder;
    {
        let mut cursor = Cursor::new(data);
        let n = cursor.read_as_u64()?;
        let mut buf = vec![];
        let _ = buf.encode_u64(n);
        let _ = buf.encode_u64_le(n);
        let _ = buf.encode_u64_desc(n);
        let _ = buf.encode_var_u64(n);
    }
    {
        let mut cursor = Cursor::new(data);
        let n = cursor.read_as_i64()?;
        let mut buf = vec![];
        let _ = buf.encode_i64(n);
        let _ = buf.encode_i64_le(n);
        let _ = buf.encode_i64_desc(n);
        let _ = buf.encode_var_i64(n);
    }
    {
        let mut cursor = Cursor::new(data);
        let n = cursor.read_as_f64()?;
        let mut buf = vec![];
        let _ = buf.encode_f64(n);
        let _ = buf.encode_f64_le(n);
        let _ = buf.encode_f64_desc(n);
    }
    {
        let mut cursor = Cursor::new(data);
        let n = cursor.read_as_u32()?;
        let mut buf = vec![];
        let _ = buf.encode_u32(n);
        let _ = buf.encode_u32_le(n);
    }
    {
        let mut cursor = Cursor::new(data);
        let n = cursor.read_as_i32()?;
        let mut buf = vec![];
        let _ = buf.encode_i32_le(n);
    }
    {
        let mut cursor = Cursor::new(data);
        let n = cursor.read_as_u16()?;
        let mut buf = vec![];
        let _ = buf.encode_u16(n);
        let _ = buf.encode_u16_le(n);
    }
    {
        let buf = data.to_owned();
        let _ = tikv_util::codec::number::decode_u64(&mut buf.as_slice());
        let _ = tikv_util::codec::number::decode_u64_desc(&mut buf.as_slice());
        let _ = tikv_util::codec::number::decode_u64_le(&mut buf.as_slice());
        let _ = tikv_util::codec::number::decode_i64(&mut buf.as_slice());
        let _ = tikv_util::codec::number::decode_i64_desc(&mut buf.as_slice());
        let _ = tikv_util::codec::number::decode_i64_le(&mut buf.as_slice());
        let _ = tikv_util::codec::number::decode_f64(&mut buf.as_slice());
        let _ = tikv_util::codec::number::decode_f64_desc(&mut buf.as_slice());
        let _ = tikv_util::codec::number::decode_f64_le(&mut buf.as_slice());
        let _ = tikv_util::codec::number::decode_u32(&mut buf.as_slice());
        let _ = tikv_util::codec::number::decode_u32_le(&mut buf.as_slice());
        let _ = tikv_util::codec::number::decode_i32_le(&mut buf.as_slice());
        let _ = tikv_util::codec::number::decode_u16(&mut buf.as_slice());
        let _ = tikv_util::codec::number::decode_u16_le(&mut buf.as_slice());
    }
    Ok(())
}

trait ReadAsDecimalRoundMode: ReadLiteralExt {
    fn read_as_decimal_round_mode(
        &mut self,
    ) -> Result<::tikv::coprocessor::codec::mysql::decimal::RoundMode, Error> {
        Ok(match self.read_as_u8()? % 3 {
            0 => tikv::coprocessor::codec::mysql::decimal::RoundMode::HalfEven,
            1 => tikv::coprocessor::codec::mysql::decimal::RoundMode::Truncate,
            _ => tikv::coprocessor::codec::mysql::decimal::RoundMode::Ceiling,
        })
    }
}

impl<T: ReadLiteralExt> ReadAsDecimalRoundMode for T {}

#[inline(always)]
pub fn fuzz_coprocessor_codec_decimal(data: &[u8]) -> Result<(), Error> {
    use tikv::coprocessor::codec::mysql::decimal::Decimal;

    fn fuzz(lhs: &Decimal, rhs: &Decimal, cursor: &mut Cursor<&[u8]>) -> Result<(), Error> {
        let _ = lhs.clone().abs();
        let _ = lhs.ceil();
        let _ = lhs.floor();
        let _ = lhs.prec_and_frac();

        let mode = cursor.read_as_decimal_round_mode()?;
        let frac = cursor.read_as_i8()?;
        let _ = lhs.clone().round(frac, mode.clone());

        let shift = cursor.read_as_u64()? as isize;
        let _ = lhs.clone().shift(shift);

        let _ = lhs.as_i64();
        let _ = lhs.as_u64();
        let _ = lhs.as_f64();
        let _ = lhs.is_zero();
        let _ = lhs.approximate_encoded_size();

        let _ = lhs > rhs;

        let _ = lhs + rhs;
        let _ = lhs - rhs;
        let _ = lhs * rhs;
        let _ = lhs.clone() / rhs.clone();
        let _ = lhs.clone() % rhs.clone();
        let _ = -lhs.clone();
        Ok(())
    }

    let mut cursor = Cursor::new(data);
    let decimal1 = Decimal::from_f64(cursor.read_as_f64()?)?;
    let decimal2 = Decimal::from_f64(cursor.read_as_f64()?)?;
    let _ = fuzz(&decimal1, &decimal2, &mut cursor);
    let _ = fuzz(&decimal2, &decimal1, &mut cursor);
    Ok(())
}

trait ReadAsTimeType: ReadLiteralExt {
    fn read_as_time_type(&mut self) -> Result<::tikv::coprocessor::codec::mysql::TimeType, Error> {
        Ok(match self.read_as_u8()? % 3 {
            0 => tikv::coprocessor::codec::mysql::TimeType::Date,
            1 => tikv::coprocessor::codec::mysql::TimeType::DateTime,
            _ => tikv::coprocessor::codec::mysql::TimeType::Timestamp,
        })
    }
}

impl<T: ReadLiteralExt> ReadAsTimeType for T {}

fn fuzz_time(
    t: tikv::coprocessor::codec::mysql::Time,
    mut cursor: Cursor<&[u8]>,
) -> Result<(), Error> {
    use tikv::coprocessor::codec::mysql::TimeEncoder;
    let _ = t.clone().set_time_type(cursor.read_as_time_type()?);
    let _ = t.is_zero();
    let _ = t.invalid_zero();
    let _ = t.to_decimal();
    let _ = t.to_f64();
    let _ = t.to_duration();
    let _ = t.to_packed_u64();
    let _ = t.clone().round_frac(cursor.read_as_i8()?);
    let _ = t.is_leap_year();
    let _ = t.last_day_of_month();
    let _ = t.to_string();
    let mut v = Vec::new();
    let _ = v.encode_time(&t);
    Ok(())
}

pub fn fuzz_coprocessor_codec_time_from_parse(data: &[u8]) -> Result<(), Error> {
    use std::io::Read;
    use tikv::coprocessor::codec::mysql::{Time, Tz};
    let mut cursor = Cursor::new(data);
    let tz = Tz::from_offset(cursor.read_as_i64()?).unwrap_or_else(Tz::utc);
    let fsp = cursor.read_as_i8()?;
    let mut buf: [u8; 32] = [b' '; 32];
    cursor.read_exact(&mut buf)?;
    let t = Time::parse_datetime(::std::str::from_utf8(&buf)?, fsp, &tz)?;
    fuzz_time(t, cursor)
}

pub fn fuzz_coprocessor_codec_time_from_u64(data: &[u8]) -> Result<(), Error> {
    use tikv::coprocessor::codec::mysql::{Time, Tz};
    let mut cursor = Cursor::new(data);
    let u = cursor.read_as_u64()?;
    let time_type = cursor.read_as_time_type()?;
    let tz = Tz::from_offset(cursor.read_as_i64()?).unwrap_or_else(Tz::utc);
    let fsp = cursor.read_as_i8()?;
    let t = Time::from_packed_u64(u, time_type, fsp, &tz)?;
    fuzz_time(t, cursor)
}
<commit_msg>[WIP] Add more fuzz tests (#4608)<commit_after>// Copyright 2018 TiKV Project Authors. Licensed under Apache-2.0.

//! DO NOT MOVE THIS FILE. IT WILL BE PARSED BY `fuzz/cli.rs`. SEE `discover_fuzz_targets()`.

mod util;

use self::util::ReadLiteralExt;
use failure::Error;
use std::io::Cursor;

#[inline(always)]
pub fn fuzz_codec_bytes(data: &[u8]) -> Result<(), Error> {
    let _ = tikv_util::codec::bytes::encode_bytes(data);
    let _ = tikv_util::codec::bytes::encode_bytes_desc(data);
    let _ = tikv_util::codec::bytes::encoded_bytes_len(data, true);
    let _ = tikv_util::codec::bytes::encoded_bytes_len(data, false);
    Ok(())
}

#[inline(always)]
pub fn fuzz_codec_number(data: &[u8]) -> Result<(), Error> {
    use tikv_util::codec::number::NumberEncoder;
    {
        let mut cursor = Cursor::new(data);
        let n = cursor.read_as_u64()?;
        let mut buf = vec![];
        let _ = buf.encode_u64(n);
        let _ = buf.encode_u64_le(n);
        let _ = buf.encode_u64_desc(n);
        let _ = buf.encode_var_u64(n);
    }
    {
        let mut cursor = Cursor::new(data);
        let n = cursor.read_as_i64()?;
        let mut buf = vec![];
        let _ = buf.encode_i64(n);
        let _ = buf.encode_i64_le(n);
        let _ = buf.encode_i64_desc(n);
        let _ = buf.encode_var_i64(n);
    }
    {
        let mut cursor = Cursor::new(data);
        let n = cursor.read_as_f64()?;
        let mut buf = vec![];
        let _ = buf.encode_f64(n);
        let _ = buf.encode_f64_le(n);
        let _ = buf.encode_f64_desc(n);
    }
    {
        let mut cursor = Cursor::new(data);
        let n = cursor.read_as_u32()?;
        let mut buf = vec![];
        let _ = buf.encode_u32(n);
        let _ = buf.encode_u32_le(n);
    }
    {
        let mut cursor = Cursor::new(data);
        let n = cursor.read_as_i32()?;
        let mut buf = vec![];
        let _ = buf.encode_i32_le(n);
    }
    {
        let mut cursor = Cursor::new(data);
        let n = cursor.read_as_u16()?;
        let mut buf = vec![];
        let _ = buf.encode_u16(n);
        let _ = buf.encode_u16_le(n);
    }
    {
        let buf = data.to_owned();
        let _ = tikv_util::codec::number::decode_u64(&mut buf.as_slice());
        let _ = tikv_util::codec::number::decode_u64_desc(&mut buf.as_slice());
        let _ = tikv_util::codec::number::decode_u64_le(&mut buf.as_slice());
        let _ = tikv_util::codec::number::decode_i64(&mut buf.as_slice());
        let _ = tikv_util::codec::number::decode_i64_desc(&mut buf.as_slice());
        let _ = tikv_util::codec::number::decode_i64_le(&mut buf.as_slice());
        let _ = tikv_util::codec::number::decode_f64(&mut buf.as_slice());
        let _ = tikv_util::codec::number::decode_f64_desc(&mut buf.as_slice());
        let _ = tikv_util::codec::number::decode_f64_le(&mut buf.as_slice());
        let _ = tikv_util::codec::number::decode_u32(&mut buf.as_slice());
        let _ = tikv_util::codec::number::decode_u32_le(&mut buf.as_slice());
        let _ = tikv_util::codec::number::decode_i32_le(&mut buf.as_slice());
        let _ = tikv_util::codec::number::decode_u16(&mut buf.as_slice());
        let _ = tikv_util::codec::number::decode_u16_le(&mut buf.as_slice());
    }
    Ok(())
}

trait ReadAsDecimalRoundMode: ReadLiteralExt {
    fn read_as_decimal_round_mode(
        &mut self,
    ) -> Result<::tikv::coprocessor::codec::mysql::decimal::RoundMode, Error> {
        Ok(match self.read_as_u8()? % 3 {
            0 => tikv::coprocessor::codec::mysql::decimal::RoundMode::HalfEven,
            1 => tikv::coprocessor::codec::mysql::decimal::RoundMode::Truncate,
            _ => tikv::coprocessor::codec::mysql::decimal::RoundMode::Ceiling,
        })
    }
}

impl<T: ReadLiteralExt> ReadAsDecimalRoundMode for T {}

#[inline(always)]
pub fn fuzz_coprocessor_codec_decimal(data: &[u8]) -> Result<(), Error> {
    use tikv::coprocessor::codec::mysql::decimal::Decimal;

    fn fuzz(lhs: &Decimal, rhs: &Decimal, cursor: &mut Cursor<&[u8]>) -> Result<(), Error> {
        let _ = lhs.clone().abs();
        let _ = lhs.ceil();
        let _ = lhs.floor();
        let _ = lhs.prec_and_frac();

        let mode = cursor.read_as_decimal_round_mode()?;
        let frac = cursor.read_as_i8()?;
        let _ = lhs.clone().round(frac, mode.clone());

        let shift = cursor.read_as_u64()? as isize;
        let _ = lhs.clone().shift(shift);

        let _ = lhs.as_i64();
        let _ = lhs.as_u64();
        let _ = lhs.as_f64();
        let _ = lhs.is_zero();
        let _ = lhs.approximate_encoded_size();

        let _ = lhs > rhs;

        let _ = lhs + rhs;
        let _ = lhs - rhs;
        let _ = lhs * rhs;
        let _ = lhs.clone() / rhs.clone();
        let _ = lhs.clone() % rhs.clone();
        let _ = -lhs.clone();
        Ok(())
    }

    let mut cursor = Cursor::new(data);
    let decimal1 = Decimal::from_f64(cursor.read_as_f64()?)?;
    let decimal2 = Decimal::from_f64(cursor.read_as_f64()?)?;
    let _ = fuzz(&decimal1, &decimal2, &mut cursor);
    let _ = fuzz(&decimal2, &decimal1, &mut cursor);
    Ok(())
}

trait ReadAsTimeType: ReadLiteralExt {
    fn read_as_time_type(&mut self) -> Result<::tikv::coprocessor::codec::mysql::TimeType, Error> {
        Ok(match self.read_as_u8()? % 3 {
            0 => tikv::coprocessor::codec::mysql::TimeType::Date,
            1 => tikv::coprocessor::codec::mysql::TimeType::DateTime,
            _ => tikv::coprocessor::codec::mysql::TimeType::Timestamp,
        })
    }
}

impl<T: ReadLiteralExt> ReadAsTimeType for T {}

fn fuzz_time(
    t: tikv::coprocessor::codec::mysql::Time,
    mut cursor: Cursor<&[u8]>,
) -> Result<(), Error> {
    use tikv::coprocessor::codec::mysql::TimeEncoder;
    let _ = t.clone().set_time_type(cursor.read_as_time_type()?);
    let _ = t.is_zero();
    let _ = t.invalid_zero();
    let _ = t.to_decimal();
    let _ = t.to_f64();
    let _ = t.to_duration();
    let _ = t.to_packed_u64();
    let _ = t.clone().round_frac(cursor.read_as_i8()?);
    let _ = t.is_leap_year();
    let _ = t.last_day_of_month();
    let _ = t.to_string();
    let mut v = Vec::new();
    let _ = v.encode_time(&t);
    Ok(())
}

pub fn fuzz_coprocessor_codec_time_from_parse(data: &[u8]) -> Result<(), Error> {
    use std::io::Read;
    use tikv::coprocessor::codec::mysql::{Time, Tz};
    let mut cursor = Cursor::new(data);
    let tz = Tz::from_offset(cursor.read_as_i64()?).unwrap_or_else(Tz::utc);
    let fsp = cursor.read_as_i8()?;
    let mut buf: [u8; 32] = [b' '; 32];
    cursor.read_exact(&mut buf)?;
    let t = Time::parse_datetime(::std::str::from_utf8(&buf)?, fsp, &tz)?;
    fuzz_time(t, cursor)
}

pub fn fuzz_coprocessor_codec_time_from_u64(data: &[u8]) -> Result<(), Error> {
    use tikv::coprocessor::codec::mysql::{Time, Tz};
    let mut cursor = Cursor::new(data);
    let u = cursor.read_as_u64()?;
    let time_type = cursor.read_as_time_type()?;
    let tz = Tz::from_offset(cursor.read_as_i64()?).unwrap_or_else(Tz::utc);
    let fsp = cursor.read_as_i8()?;
    let t = Time::from_packed_u64(u, time_type, fsp, &tz)?;
    fuzz_time(t, cursor)
}

// Duration
fn fuzz_duration(
    t: tikv::coprocessor::codec::mysql::Duration,
    mut cursor: Cursor<&[u8]>,
) -> Result<(), Error> {
    use tikv::coprocessor::codec::mysql::DurationEncoder;
    let _ = t.fsp();
    let mut u = t;
    u.set_fsp(cursor.read_as_u8()?);
    let _ = t.hours();
    let _ = t.minutes();
    let _ = t.secs();
    let _ = t.micro_secs();
    let _ = t.nano_secs();
    let _ = t.to_secs();
    let _ = t.is_zero();
    let _ = t.to_decimal();
    let u = t;
    u.round_frac(cursor.read_as_i8()?)?;
    let mut v = Vec::new();
    let _ = v.encode_duration(&t);
    Ok(())
}

pub fn fuzz_coprocessor_codec_duration_from_nanos(data: &[u8]) -> Result<(), Error> {
    use tikv::coprocessor::codec::mysql::Duration;
    let mut cursor = Cursor::new(data);
    let nanos = cursor.read_as_i64()?;
    let fsp = cursor.read_as_i8()?;
    fuzz_duration(Duration::from_nanos(nanos, fsp)?, cursor)
}

pub fn fuzz_coprocessor_codec_duration_from_parse(data: &[u8]) -> Result<(), Error> {
    use std::io::Read;
    use tikv::coprocessor::codec::mysql::Duration;
    let mut cursor = Cursor::new(data);
    let fsp = cursor.read_as_i8()?;
    let mut buf: [u8; 32] = [b' '; 32];
    cursor.read_exact(&mut buf)?;
    let d = Duration::parse(&buf, fsp)?;
    fuzz_duration(d, cursor)
}
<|endoftext|>


<commit_before>pub const LICENSE: &'static str = r#"
MIT License

// Copyright (c) 2016 Ansley Peduru

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE."#;

pub const VERSION: &'static str = env!("CARGO_PKG_VERSION");

pub const HELP: &'static str = r#""#;

pub const KEYWORDS: &'static [&'static str] = &["license", "exit", "help", "version"];
<commit_msg>Comment out unused constants<commit_after>// pub const LICENSE: &'static str = r#"
// MIT License

// Copyright (c) 2016 Ansley Peduru

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE."#;

pub const VERSION: &'static str = env!("CARGO_PKG_VERSION");

// pub const HELP: &'static str = r#""#;

// pub const KEYWORDS: &'static [&'static str] = &["license", "exit", "help", "version"];
<|endoftext|>


<commit_before>// Copyright 2015 Ilkka Rauta
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

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

use std::path::Path;
use libc::{c_uint,c_ulong};

#[allow(dead_code,non_camel_case_types,non_snake_case)]
mod enums {
    use super::ffi as ffi;

    include!(concat!(env!("OUT_DIR"), "/demux-enums.rs"));
}

pub use self::enums::{Input,Output,PesType};

pub struct Demux {
    device: DeviceFileDescriptor
}

use super::device::{DeviceFileDescriptor,BlockMode,ReadWriteMode,DeviceResult};

impl Demux {
    pub fn open(file: &Path, rw_mode: ReadWriteMode, block_mode: BlockMode) -> DeviceResult<Demux> {
        let device = try!(DeviceFileDescriptor::open(file, rw_mode, block_mode));
        Ok(Demux { device: device })
    }

    pub fn read(&self) -> DeviceResult<()> {
        unimplemented!();
    }

    // Should this even exist here?
    pub fn write(&self) -> DeviceResult<()> {
        unimplemented!();
    }

    pub fn start(&self) -> DeviceResult<()> {
        self.device.ioctl_argumentless(ffi::DMX_START as c_ulong)
    }

    pub fn stop(&self) -> DeviceResult<()> {
        self.device.ioctl_argumentless(ffi::DMX_STOP as c_ulong)
    }

    pub fn set_filter(&self) -> DeviceResult<()> {
        unimplemented!();
    }

    pub fn set_pes_filter(&self) -> DeviceResult<()> {
        unimplemented!();
    }

    pub fn set_buffer_size(&self, buffer_size: u32) -> DeviceResult<()> {
        let mut ffi_size = buffer_size as c_ulong;
        self.device.ioctl_pointer(ffi::DMX_SET_BUFFER_SIZE as c_ulong, &mut ffi_size)
    }

    pub fn get_system_time_counter(&self, num: u32) -> DeviceResult<SystemTimeCounter> {
        let mut ffi_stc = ffi::Struct_dmx_stc { num: num as c_uint, base: 0, stc: 0 };
        try!(self.device.ioctl_pointer(ffi::DMX_GET_STC as c_ulong, &mut ffi_stc));
        Ok(SystemTimeCounter { base: ffi_stc.base, counter: ffi_stc.stc })
    }

    pub fn get_pes_pids(&self) -> DeviceResult<[u16; 5]> {
        let mut ffi_pids = [0u16; 5];
        try!(self.device.ioctl_pointer(ffi::DMX_GET_PES_PIDS as c_ulong, ffi_pids.as_mut_ptr()));
        Ok(ffi_pids)
    }

    /// This function is undocumented in the official documentation, and doesn't seem to be
    /// actually in use. It is still nevertheless included here, if it is used by out-of-tree DVB
    /// drivers.
    pub fn get_caps(&self) -> DeviceResult<DemuxCaps> {
        let mut ffi_caps = ffi::Struct_dmx_caps { caps: 0, num_decoders: 0 };
        try!(self.device.ioctl_pointer(ffi::DMX_GET_CAPS as c_ulong, &mut ffi_caps));
        Ok(DemuxCaps { caps: ffi_caps.caps, num_decoders: ffi_caps.num_decoders as i32 })
    }

    /// Like get_caps(), this doesn't seem to be actively in use in Linux, but is still implemented.
    pub fn set_source(&self, source: enums::DemuxSource) -> DeviceResult<()> {
        let mut ffi_source: ffi::dmx_source_t =  source.into();
        self.device.ioctl_pointer(ffi::DMX_SET_SOURCE as c_ulong, &mut ffi_source)
    }

    pub fn add_pid(&self, pid: u16) -> DeviceResult<()> {
        let mut ffi_pid = pid;
        self.device.ioctl_pointer(ffi::DMX_ADD_PID as c_ulong, &mut ffi_pid)
    }

    pub fn remove_pid(&self, pid: u16) -> DeviceResult<()> {
        let mut ffi_pid = pid;
        self.device.ioctl_pointer(ffi::DMX_REMOVE_PID as c_ulong, &mut ffi_pid)
    }
}

pub struct DemuxCaps {
    pub caps: u32,
    pub num_decoders: i32
}

pub struct SystemTimeCounter {
    pub base: u32,
    pub counter: u64
}

pub struct DemuxFilter {
    pub filter: [u8; ffi::DMX_FILTER_SIZE as usize],
    pub mask: [u8; ffi::DMX_FILTER_SIZE as usize],
    pub mode: [u8; ffi::DMX_FILTER_SIZE as usize],
}

pub struct SectionFilterParams {
    pub pid: u16,
    pub filter: DemuxFilter,
    pub timeout: u32,
    pub flags: flags::SectionFilterFlags
}

pub struct PesFilterParams {
    pub pid: u16,
    pub input: Input,
    pub output: Output,
    pub pes_type: PesType,
    pub flags: flags::PesFilterFlags
}

#[allow(dead_code,non_upper_case_globals)]
pub mod flags {
    use super::ffi as ffi;
    bitflags!{
        flags SectionFilterFlags: u32 {
            const SecCheckCrC = ffi::DMX_CHECK_CRC,
            const SecOneShot = ffi::DMX_ONESHOT,
            const SecImmediateStart = ffi::DMX_IMMEDIATE_START
        }
    }

    bitflags!{
        flags PesFilterFlags: u32 {
            const PesImmediateStart = ffi::DMX_IMMEDIATE_START
        }
    }
}
<commit_msg>Implement demux set_filter() & set_pes_filter().<commit_after>// Copyright 2015 Ilkka Rauta
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

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

use std::path::Path;
use libc::{c_uint,c_ulong};

#[allow(dead_code,non_camel_case_types,non_snake_case)]
mod enums {
    use super::ffi as ffi;

    include!(concat!(env!("OUT_DIR"), "/demux-enums.rs"));
}

pub use self::enums::{Input,Output,PesType};

pub struct Demux {
    device: DeviceFileDescriptor
}

use super::device::{DeviceFileDescriptor,BlockMode,ReadWriteMode,DeviceResult};

impl Demux {
    pub fn open(file: &Path, rw_mode: ReadWriteMode, block_mode: BlockMode) -> DeviceResult<Demux> {
        let device = try!(DeviceFileDescriptor::open(file, rw_mode, block_mode));
        Ok(Demux { device: device })
    }

    pub fn read(&self) -> DeviceResult<()> {
        unimplemented!();
    }

    // Should this even exist here?
    pub fn write(&self) -> DeviceResult<()> {
        unimplemented!();
    }

    pub fn start(&self) -> DeviceResult<()> {
        self.device.ioctl_argumentless(ffi::DMX_START as c_ulong)
    }

    pub fn stop(&self) -> DeviceResult<()> {
        self.device.ioctl_argumentless(ffi::DMX_STOP as c_ulong)
    }

    pub fn set_filter(&self, filter_params: &SectionFilterParams) -> DeviceResult<()> {
        let mut ffi_params = ffi::Struct_dmx_sct_filter_params {
            pid: filter_params.pid,
            filter: ffi::Struct_dmx_filter {
                filter: filter_params.filter.filter,
                mask: filter_params.filter.mask,
                mode: filter_params.filter.mode,
            },
            timeout: filter_params.timeout,
            flags: filter_params.flags.bits()
        };
        self.device.ioctl_pointer(ffi::DMX_SET_FILTER as c_ulong, &mut ffi_params)
    }

    pub fn set_pes_filter(&self, filter_params: &PesFilterParams) -> DeviceResult<()> {
        let mut ffi_params = ffi::Struct_dmx_pes_filter_params {
            pid: filter_params.pid,
            input: filter_params.input.into(),
            output: filter_params.output.into(),
            pes_type: filter_params.pes_type.into(),
            flags: filter_params.flags.bits()
        };
        self.device.ioctl_pointer(ffi::DMX_SET_PES_FILTER as c_ulong, &mut ffi_params)
    }

    pub fn set_buffer_size(&self, buffer_size: u32) -> DeviceResult<()> {
        let mut ffi_size = buffer_size as c_ulong;
        self.device.ioctl_pointer(ffi::DMX_SET_BUFFER_SIZE as c_ulong, &mut ffi_size)
    }

    pub fn get_system_time_counter(&self, num: u32) -> DeviceResult<SystemTimeCounter> {
        let mut ffi_stc = ffi::Struct_dmx_stc { num: num as c_uint, base: 0, stc: 0 };
        try!(self.device.ioctl_pointer(ffi::DMX_GET_STC as c_ulong, &mut ffi_stc));
        Ok(SystemTimeCounter { base: ffi_stc.base, counter: ffi_stc.stc })
    }

    pub fn get_pes_pids(&self) -> DeviceResult<[u16; 5]> {
        let mut ffi_pids = [0u16; 5];
        try!(self.device.ioctl_pointer(ffi::DMX_GET_PES_PIDS as c_ulong, ffi_pids.as_mut_ptr()));
        Ok(ffi_pids)
    }

    /// This function is undocumented in the official documentation, and doesn't seem to be
    /// actually in use. It is still nevertheless included here, if it is used by out-of-tree DVB
    /// drivers.
    pub fn get_caps(&self) -> DeviceResult<DemuxCaps> {
        let mut ffi_caps = ffi::Struct_dmx_caps { caps: 0, num_decoders: 0 };
        try!(self.device.ioctl_pointer(ffi::DMX_GET_CAPS as c_ulong, &mut ffi_caps));
        Ok(DemuxCaps { caps: ffi_caps.caps, num_decoders: ffi_caps.num_decoders as i32 })
    }

    /// Like get_caps(), this doesn't seem to be actively in use in Linux, but is still implemented.
    pub fn set_source(&self, source: enums::DemuxSource) -> DeviceResult<()> {
        let mut ffi_source: ffi::dmx_source_t =  source.into();
        self.device.ioctl_pointer(ffi::DMX_SET_SOURCE as c_ulong, &mut ffi_source)
    }

    pub fn add_pid(&self, pid: u16) -> DeviceResult<()> {
        let mut ffi_pid = pid;
        self.device.ioctl_pointer(ffi::DMX_ADD_PID as c_ulong, &mut ffi_pid)
    }

    pub fn remove_pid(&self, pid: u16) -> DeviceResult<()> {
        let mut ffi_pid = pid;
        self.device.ioctl_pointer(ffi::DMX_REMOVE_PID as c_ulong, &mut ffi_pid)
    }
}

pub struct DemuxCaps {
    pub caps: u32,
    pub num_decoders: i32
}

pub struct SystemTimeCounter {
    pub base: u32,
    pub counter: u64
}

pub struct DemuxFilter {
    pub filter: [u8; ffi::DMX_FILTER_SIZE as usize],
    pub mask: [u8; ffi::DMX_FILTER_SIZE as usize],
    pub mode: [u8; ffi::DMX_FILTER_SIZE as usize],
}

pub struct SectionFilterParams {
    pub pid: u16,
    pub filter: DemuxFilter,
    pub timeout: u32,
    pub flags: flags::SectionFilterFlags
}

pub struct PesFilterParams {
    pub pid: u16,
    pub input: Input,
    pub output: Output,
    pub pes_type: PesType,
    pub flags: flags::PesFilterFlags
}

#[allow(dead_code,non_upper_case_globals)]
pub mod flags {
    use super::ffi as ffi;
    bitflags!{
        flags SectionFilterFlags: u32 {
            const SecCheckCrC = ffi::DMX_CHECK_CRC,
            const SecOneShot = ffi::DMX_ONESHOT,
            const SecImmediateStart = ffi::DMX_IMMEDIATE_START
        }
    }

    bitflags!{
        flags PesFilterFlags: u32 {
            const PesImmediateStart = ffi::DMX_IMMEDIATE_START
        }
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright 2017 Sreejith Krishnan R
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
*/

use super::{Drawable, BoundingBox, MeasureMode};
use ::layout::{Layout};
use ::paint::{Canvas, Point, Rect};
use ::platform::Context;
use ::props::{Color};

pub type ColorReader<T> = fn(&T) -> &Color;

pub enum LineParam {
    Fixed { start: Point, end: Point },
    Vertical { x: f32 },
    Horizontal { y: f32 },
}

pub struct Line<'a, T: Layout + 'a> {
    param: LineParam,

    element: &'a T,
    stroke_width: f32,
    color_reader: ColorReader<T>,

    bounding_box: BoundingBox,
    start: Point,
    end: Point,
}

impl<'a, T: Layout + 'a> Drawable for Line<'a, T> {
    fn draw(&self, canvas: &Canvas, pen_pos: &Point) {
        canvas.draw_line(
            &(&self.start+pen_pos),
            &(&self.end+pen_pos),
            (self.color_reader)(self.element),
            self.stroke_width,
        )
    }

    fn calculate(&mut self, _: &Context, width_mode: &MeasureMode, height_mode: &MeasureMode) {
        let (start, end) = match self.param {
            LineParam::Fixed { ref start, ref end } => {
                (start.clone(), end.clone())
            },
            LineParam::Vertical { x } => {
                (
                    Point::new(x, 0.),
                    Point::new(x, if let MeasureMode::UpTo(height) = *height_mode { height } else { 0. })
                )
            },
            LineParam::Horizontal { y } => {
                (
                    Point::new(0., y),
                    Point::new(if let MeasureMode::UpTo(width) = *width_mode { width } else { 0. }, y)
                )
            }
        };

        let stroke_width = self.stroke_width;

        let slope = (start.y()-end.y()).abs() / (start.x()-end.x()).abs();
        let angle = slope.atan();
        let x_diff = angle.sin()*stroke_width/2.;
        let y_diff = angle.cos()*stroke_width/2.;

        let mut width = (start.x()-end.x()).abs()+(x_diff*2.);
        let mut height = (start.y()-end.y()).abs()+(y_diff*2.);

        if width.is_nan() {
            width = 0.;
        }

        if height.is_nan() {
            height = 0.;
        }

        self.start = &start+&Point::new(x_diff, y_diff);
        self.end = &end+&Point::new(x_diff, y_diff);

        self.bounding_box = BoundingBox {
            rect: Rect::new(width, height),
            baseline: height/2.,
            axis: height/2.,
        }
    }

    fn bounding_box(&self) -> &BoundingBox {
        &self.bounding_box
    }
}

impl<'a, T: Layout + 'a> Line<'a, T> {
    pub fn new(param: LineParam, element: &'a T, stroke_width: f32,
               color_reader: ColorReader<T>) -> Line<'a, T> {
        Line {
            param,
            element,
            stroke_width,
            color_reader,
            bounding_box: BoundingBox::default(),
            start: Point::new(0., 0.),
            end: Point::new(0., 0.),
        }
    }
}

#[cfg(test)]
mod test {
    use std::any::Any;

    use super::*;
    use ::platform::test::test_context;
    use ::test::skia::Snapshot;

    struct MockElement;
    impl Layout for MockElement {
        fn layout<'a>(&'a self, _: &Context) -> Box<Drawable + 'a> {
            unimplemented!()
        }

        fn as_any(&self) -> &Any {
            unimplemented!()
        }
    }

    #[test]
    fn it_work_vertically() {
        let context = test_context();
        let element = MockElement {};
        let mut line = Line::new(
            LineParam::Vertical { x: 10. },
            &element,
            5.,
            |_| &Color::RGB(0, 0, 0)
        );

        line.calculate(&context, &MeasureMode::Wrap, &MeasureMode::UpTo(100.));

        assert_eq!(line.bounding_box().width(), 5.);
        assert_eq!(line.bounding_box().height(), 100.);
    }

    #[test]
    fn it_work_horizontally() {
        let context = test_context();
        let element = MockElement {};
        let mut line = Line::new(
            LineParam::Horizontal { y: 10. },
            &element,
            5.,
            |_| &Color::RGB(0, 0, 0)
        );

        line.calculate(&context, &MeasureMode::UpTo(100.), &MeasureMode::Wrap);

        assert_eq!(line.bounding_box().width(), 100.);
        assert_eq!(line.bounding_box().height(), 5.);
    }

    #[test]
    fn it_works_when_inclined() {
        let context = test_context();
        let element = MockElement {};
        let mut line = Line::new(
            LineParam::Fixed { start: Point::new(0., 0.), end: Point::new(10., 10.) },
            &element,
            5.,
            |_| &Color::RGB(0, 0, 0)
        );

        line.calculate(&context, &MeasureMode::Wrap, &MeasureMode::Wrap);

        assert_eq!(line.bounding_box().width(), 13.535534);
        assert_eq!(line.bounding_box().height(), 13.535534);
    }

    #[test]
    fn test_line() {
        let skia = Snapshot::default();

        let element = MockElement { };

        let mut line = Line::new(
            LineParam::Fixed { start: Point::new(0., 0.), end: Point::new(100., 100.) },
            &element,
            50.,
            |_| &Color::RGB(0, 0, 0)
        );

        skia.snap_drawable(&mut line, &MeasureMode::Wrap, &MeasureMode::Wrap,
                      "line_45deg");

        let mut line = Line::new(
            LineParam::Fixed { start: Point::new(0., 0.), end: Point::new(50., 100.) },
            &element,
            50.,
            |_| &Color::RGB(0, 0, 0)
        );

        skia.snap_drawable(&mut line, &MeasureMode::Wrap, &MeasureMode::Wrap,
                      "line_inclined");

        let mut line = Line::new(
            LineParam::Vertical { x: 0. },
            &element,
            50.,
            |_| &Color::RGB(0, 0, 0)
        );

        skia.snap_drawable(&mut line, &MeasureMode::Wrap, &MeasureMode::UpTo(100.),
                      "line_vertical");

        let mut line = Line::new(
            LineParam::Horizontal { y: 0. },
            &element,
            50.,
            |_| &Color::RGB(0, 0, 0)
        );

        skia.snap_drawable(&mut line, &MeasureMode::UpTo(100.), &MeasureMode::Wrap,
                      "line_horizontal");
    }
}<commit_msg>Center stroke<commit_after>/*
 * Copyright 2017 Sreejith Krishnan R
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
*/

use super::{Drawable, BoundingBox, MeasureMode};
use ::layout::{Layout};
use ::paint::{Canvas, Point, Rect};
use ::platform::Context;
use ::props::{Color};

pub type ColorReader<T> = fn(&T) -> &Color;

pub enum LineParam {
    Fixed { start: Point, end: Point },
    Vertical { x: f32 },
    Horizontal { y: f32 },
}

pub struct Line<'a, T: Layout + 'a> {
    param: LineParam,

    element: &'a T,
    stroke_width: f32,
    color_reader: ColorReader<T>,

    bounding_box: BoundingBox,
    start: Point,
    end: Point,
}

impl<'a, T: Layout + 'a> Drawable for Line<'a, T> {
    fn draw(&self, canvas: &Canvas, pen_pos: &Point) {
        canvas.draw_line(
            &(&self.start+pen_pos),
            &(&self.end+pen_pos),
            (self.color_reader)(self.element),
            self.stroke_width,
        )
    }

    fn calculate(&mut self, _: &Context, width_mode: &MeasureMode, height_mode: &MeasureMode) {
        let (start, end) = match self.param {
            LineParam::Fixed { ref start, ref end } => {
                (start.clone(), end.clone())
            },
            LineParam::Vertical { x } => {
                (
                    Point::new(x, 0.),
                    Point::new(x, if let MeasureMode::UpTo(height) = *height_mode { height } else { 0. })
                )
            },
            LineParam::Horizontal { y } => {
                (
                    Point::new(0., y),
                    Point::new(if let MeasureMode::UpTo(width) = *width_mode { width } else { 0. }, y)
                )
            }
        };

        let stroke_width = self.stroke_width;

        let slope = (start.y()-end.y()).abs() / (start.x()-end.x()).abs();
        let angle = slope.atan();
        let x_diff = angle.sin()*stroke_width/2.;
        let y_diff = angle.cos()*stroke_width/2.;

        let mut width = (start.x()-end.x()).abs()+(x_diff*2.);
        let mut height = (start.y()-end.y()).abs()+(y_diff*2.);

        if width.is_nan() {
            width = 0.;
        }

        if height.is_nan() {
            height = 0.;
        }

        self.start = &start+&Point::new(x_diff, y_diff+(stroke_width/2.));
        self.end = &end+&Point::new(x_diff, y_diff+(stroke_width/2.));

        self.bounding_box = BoundingBox {
            rect: Rect::new(width, height),
            baseline: height/2.,
            axis: height/2.,
        }
    }

    fn bounding_box(&self) -> &BoundingBox {
        &self.bounding_box
    }
}

impl<'a, T: Layout + 'a> Line<'a, T> {
    pub fn new(param: LineParam, element: &'a T, stroke_width: f32,
               color_reader: ColorReader<T>) -> Line<'a, T> {
        Line {
            param,
            element,
            stroke_width,
            color_reader,
            bounding_box: BoundingBox::default(),
            start: Point::new(0., 0.),
            end: Point::new(0., 0.),
        }
    }
}

#[cfg(test)]
mod test {
    use std::any::Any;

    use super::*;
    use ::platform::test::test_context;
    use ::test::skia::Snapshot;

    struct MockElement;
    impl Layout for MockElement {
        fn layout<'a>(&'a self, _: &Context) -> Box<Drawable + 'a> {
            unimplemented!()
        }

        fn as_any(&self) -> &Any {
            unimplemented!()
        }
    }

    #[test]
    fn it_work_vertically() {
        let context = test_context();
        let element = MockElement {};
        let mut line = Line::new(
            LineParam::Vertical { x: 10. },
            &element,
            5.,
            |_| &Color::RGB(0, 0, 0)
        );

        line.calculate(&context, &MeasureMode::Wrap, &MeasureMode::UpTo(100.));

        assert_eq!(line.bounding_box().width(), 5.);
        assert_eq!(line.bounding_box().height(), 100.);
    }

    #[test]
    fn it_work_horizontally() {
        let context = test_context();
        let element = MockElement {};
        let mut line = Line::new(
            LineParam::Horizontal { y: 10. },
            &element,
            5.,
            |_| &Color::RGB(0, 0, 0)
        );

        line.calculate(&context, &MeasureMode::UpTo(100.), &MeasureMode::Wrap);

        assert_eq!(line.bounding_box().width(), 100.);
        assert_eq!(line.bounding_box().height(), 5.);
    }

    #[test]
    fn it_works_when_inclined() {
        let context = test_context();
        let element = MockElement {};
        let mut line = Line::new(
            LineParam::Fixed { start: Point::new(0., 0.), end: Point::new(10., 10.) },
            &element,
            5.,
            |_| &Color::RGB(0, 0, 0)
        );

        line.calculate(&context, &MeasureMode::Wrap, &MeasureMode::Wrap);

        assert_eq!(line.bounding_box().width(), 13.535534);
        assert_eq!(line.bounding_box().height(), 13.535534);
    }

    #[test]
    fn test_line() {
        let skia = Snapshot::default();

        let element = MockElement { };

        let mut line = Line::new(
            LineParam::Fixed { start: Point::new(0., 0.), end: Point::new(100., 100.) },
            &element,
            50.,
            |_| &Color::RGB(0, 0, 0)
        );

        skia.snap_drawable(&mut line, &MeasureMode::Wrap, &MeasureMode::Wrap,
                      "line_45deg");

        let mut line = Line::new(
            LineParam::Fixed { start: Point::new(0., 0.), end: Point::new(50., 100.) },
            &element,
            50.,
            |_| &Color::RGB(0, 0, 0)
        );

        skia.snap_drawable(&mut line, &MeasureMode::Wrap, &MeasureMode::Wrap,
                      "line_inclined");

        let mut line = Line::new(
            LineParam::Vertical { x: 0. },
            &element,
            50.,
            |_| &Color::RGB(0, 0, 0)
        );

        skia.snap_drawable(&mut line, &MeasureMode::Wrap, &MeasureMode::UpTo(100.),
                      "line_vertical");

        let mut line = Line::new(
            LineParam::Horizontal { y: 0. },
            &element,
            50.,
            |_| &Color::RGB(0, 0, 0)
        );

        skia.snap_drawable(&mut line, &MeasureMode::UpTo(100.), &MeasureMode::Wrap,
                      "line_horizontal");
    }
}<|endoftext|>


<commit_before>use super::dsp::Dsp;
use super::super::apu::Apu;
use super::envelope::Envelope;
use super::brr_block_decoder::BrrBlockDecoder;
use super::dsp_helpers;

const RESAMPLE_BUFFER_LEN: usize = 4;

#[derive(Clone, Copy)]
pub struct VoiceOutput {
    pub left_out: i32,
    pub right_out: i32,
    pub last_voice_out: i32
}

impl VoiceOutput {
    pub fn default() -> VoiceOutput {
        VoiceOutput {
            left_out: 0,
            right_out: 0,
            last_voice_out: 0
        }
    }
}

pub const VOICE_BUFFER_LEN: usize = 128;

// TODO: If Rust had facilities for specifying arrray sizes with generic parameters,
// this could be removed in favor of a more generalized RingBuffer.
pub struct VoiceBuffer {
    pub buffer: Box<[VoiceOutput; VOICE_BUFFER_LEN]>,
    pub pos: i32
}

impl VoiceBuffer {
    pub fn new() -> VoiceBuffer {
        VoiceBuffer {
            buffer: Box::new([VoiceOutput::default(); VOICE_BUFFER_LEN]),
            pos: 0
        }
    }

    pub fn reset(&mut self) {
        for i in 0..VOICE_BUFFER_LEN {
            self.buffer[i] = VoiceOutput::default();
        }
        self.pos = 0;
    }

    pub fn write(&mut self, value: VoiceOutput) {
        self.buffer[self.pos as usize] = value;
        self.pos = (self.pos + 1) % (VOICE_BUFFER_LEN as i32);
    }
}

pub struct Voice {
    dsp: *mut Dsp,
    emulator: *mut Apu,

    pub envelope: Box<Envelope>,

    pub vol_left: u8,
    pub vol_right: u8,
    pub pitch_low: u8,
    pitch_high: u8,
    pub source: u8,
    pub pitch_mod: bool,
    pub noise_on: bool,
    pub echo_on: bool,

    sample_start_address: u32,
    loop_start_address: u32,
    brr_block_decoder: Box<BrrBlockDecoder>,
    sample_address: u32,
    sample_pos: i32,

    resample_buffer: [i32; RESAMPLE_BUFFER_LEN],
    resample_buffer_pos: usize,

    pub output_buffer: Box<VoiceBuffer>,
    pub is_muted: bool
}

impl Voice {
    pub fn new(dsp: *mut Dsp, emulator: *mut Apu) -> Voice {
        let mut ret = Voice {
            dsp: dsp,
            emulator: emulator,

            envelope: Box::new(Envelope::new(dsp)),

            vol_left: 0,
            vol_right: 0,
            pitch_low: 0,
            pitch_high: 0,
            source: 0,
            pitch_mod: false,
            noise_on: false,
            echo_on: false,

            sample_start_address: 0,
            loop_start_address: 0,
            brr_block_decoder: Box::new(BrrBlockDecoder::new()),
            sample_address: 0,
            sample_pos: 0,

            resample_buffer: [0; RESAMPLE_BUFFER_LEN],
            resample_buffer_pos: 0,

            output_buffer: Box::new(VoiceBuffer::new()),
            is_muted: false,
        };
        ret.reset();
        ret
    }

    #[inline]
    fn dsp(&self) -> &mut Dsp {
        unsafe {
            &mut (*self.dsp)
        }
    }

    #[inline]
    fn emulator(&self) -> &mut Apu {
        unsafe {
            &mut (*self.emulator)
        }
    }

    pub fn reset(&mut self) {
        self.envelope.reset();

        self.vol_left = 0;
        self.vol_right = 0;
        self.pitch_low = 0;
        self.pitch_high = 0x10;
        self.source = 0;
        self.pitch_mod = false;
        self.noise_on = false;

        self.sample_start_address = 0;
        self.loop_start_address = 0;
        self.brr_block_decoder.reset(0, 0);
        self.sample_address = 0;
        self.sample_pos = 0;

        for i in 0..RESAMPLE_BUFFER_LEN {
            self.resample_buffer[i] = 0;
        }
        self.resample_buffer_pos = 0;

        self.output_buffer.reset();
        self.is_muted = false;
    }

    pub fn render_sample(&mut self, last_voice_out: i32, noise: i32) -> VoiceOutput {
        let mut pitch = ((self.pitch_high as i32) << 8) | (self.pitch_low as i32);
        if self.pitch_mod {
            pitch += ((last_voice_out >> 5) * pitch) >> 10;
        }
        if pitch < 0 {
            pitch = 0;
        }
        if pitch > 0x3fff {
            pitch = 0x3fff;
        }

        let mut sample = if !self.noise_on {
            let p1 = self.sample_pos;
            let p2 = 0x1000 - p1;
            dsp_helpers::clamp((
                self.resample_buffer[self.resample_buffer_pos] * p1 +
                self.resample_buffer[(self.resample_buffer_pos + 1) % RESAMPLE_BUFFER_LEN] * p2) >> 12) & !1
        } else {
            ((noise * 2) as i16) as i32
        };

        self.envelope.tick();
        let env_level = self.envelope.level;

        sample = ((sample * env_level) >> 11) & !1;

        if self.brr_block_decoder.is_end && !self.brr_block_decoder.is_looping {
            self.envelope.key_off();
            self.envelope.level = 0;
        }

        self.sample_pos += pitch;
        while self.sample_pos >= 0x1000 {
            self.sample_pos -= 0x1000;
            self.read_next_sample();

            if self.brr_block_decoder.is_finished() {
                if self.brr_block_decoder.is_end && self.brr_block_decoder.is_looping {
                    self.read_entry();
                    self.sample_address = self.loop_start_address;
                }
                self.read_next_block();
            }
        }

        let ret =
            if !self.is_muted {
                VoiceOutput {
                    left_out: dsp_helpers::multiply_volume(sample, self.vol_left),
                    right_out: dsp_helpers::multiply_volume(sample, self.vol_right),
                    last_voice_out: sample
                }
            } else {
                VoiceOutput {
                    left_out: 0,
                    right_out: 0,
                    last_voice_out: 0
                }
            };
        self.output_buffer.write(ret);
        ret
    }

    pub fn set_pitch_high(&mut self, value: u8) {
        self.pitch_high = value & 0x3f;
    }

    pub fn key_on(&mut self) {
        self.read_entry();
        self.sample_address = self.sample_start_address;
        self.brr_block_decoder.reset(0, 0);
        self.read_next_block();
        self.sample_pos = 0;
        self.resample_buffer[self.resample_buffer_pos] = 0;
        self.read_next_sample();
        self.envelope.key_on();
    }

    pub fn key_off(&mut self) {
        self.envelope.key_off();
    }

    fn read_entry(&mut self) {
        self.sample_start_address = self.dsp().read_source_dir_start_address(self.source as i32);
        self.loop_start_address = self.dsp().read_source_dir_loop_address(self.source as i32);
    }

    fn read_next_block(&mut self) {
        let mut buf = [0; 9];
        for i in 0..9 {
            buf[i] = self.emulator().read_u8(self.sample_address + (i as u32));
        }
        self.brr_block_decoder.read(&buf);
        self.sample_address += 9;
    }

    fn read_next_sample(&mut self) {
        self.resample_buffer_pos = match self.resample_buffer_pos {
            0 => RESAMPLE_BUFFER_LEN - 1,
            x => x - 1
        };
        self.resample_buffer[self.resample_buffer_pos] = self.brr_block_decoder.read_next_sample() as i32;
    }
}
<commit_msg>Added ResamplingMode enum<commit_after>use super::dsp::Dsp;
use super::super::apu::Apu;
use super::envelope::Envelope;
use super::brr_block_decoder::BrrBlockDecoder;
use super::dsp_helpers;

const RESAMPLE_BUFFER_LEN: usize = 4;

pub enum ResamplingMode {
    Linear/*,
    Gaussian*/
}

#[derive(Clone, Copy)]
pub struct VoiceOutput {
    pub left_out: i32,
    pub right_out: i32,
    pub last_voice_out: i32
}

impl VoiceOutput {
    pub fn default() -> VoiceOutput {
        VoiceOutput {
            left_out: 0,
            right_out: 0,
            last_voice_out: 0
        }
    }
}

pub const VOICE_BUFFER_LEN: usize = 128;

// TODO: If Rust had facilities for specifying arrray sizes with generic parameters,
// this could be removed in favor of a more generalized RingBuffer.
pub struct VoiceBuffer {
    pub buffer: Box<[VoiceOutput; VOICE_BUFFER_LEN]>,
    pub pos: i32
}

impl VoiceBuffer {
    pub fn new() -> VoiceBuffer {
        VoiceBuffer {
            buffer: Box::new([VoiceOutput::default(); VOICE_BUFFER_LEN]),
            pos: 0
        }
    }

    pub fn reset(&mut self) {
        for i in 0..VOICE_BUFFER_LEN {
            self.buffer[i] = VoiceOutput::default();
        }
        self.pos = 0;
    }

    pub fn write(&mut self, value: VoiceOutput) {
        self.buffer[self.pos as usize] = value;
        self.pos = (self.pos + 1) % (VOICE_BUFFER_LEN as i32);
    }
}

pub struct Voice {
    dsp: *mut Dsp,
    emulator: *mut Apu,

    pub envelope: Box<Envelope>,

    pub vol_left: u8,
    pub vol_right: u8,
    pub pitch_low: u8,
    pitch_high: u8,
    pub source: u8,
    pub pitch_mod: bool,
    pub noise_on: bool,
    pub echo_on: bool,

    sample_start_address: u32,
    loop_start_address: u32,
    brr_block_decoder: Box<BrrBlockDecoder>,
    sample_address: u32,
    sample_pos: i32,

    resampling_mode: ResamplingMode,
    resample_buffer: [i32; RESAMPLE_BUFFER_LEN],
    resample_buffer_pos: usize,

    pub output_buffer: Box<VoiceBuffer>,
    pub is_muted: bool
}

impl Voice {
    pub fn new(dsp: *mut Dsp, emulator: *mut Apu) -> Voice {
        let mut ret = Voice {
            dsp: dsp,
            emulator: emulator,

            envelope: Box::new(Envelope::new(dsp)),

            vol_left: 0,
            vol_right: 0,
            pitch_low: 0,
            pitch_high: 0,
            source: 0,
            pitch_mod: false,
            noise_on: false,
            echo_on: false,

            sample_start_address: 0,
            loop_start_address: 0,
            brr_block_decoder: Box::new(BrrBlockDecoder::new()),
            sample_address: 0,
            sample_pos: 0,

            resampling_mode: ResamplingMode::Linear,
            resample_buffer: [0; RESAMPLE_BUFFER_LEN],
            resample_buffer_pos: 0,

            output_buffer: Box::new(VoiceBuffer::new()),
            is_muted: false,
        };
        ret.reset();
        ret
    }

    #[inline]
    fn dsp(&self) -> &mut Dsp {
        unsafe {
            &mut (*self.dsp)
        }
    }

    #[inline]
    fn emulator(&self) -> &mut Apu {
        unsafe {
            &mut (*self.emulator)
        }
    }

    pub fn reset(&mut self) {
        self.envelope.reset();

        self.vol_left = 0;
        self.vol_right = 0;
        self.pitch_low = 0;
        self.pitch_high = 0x10;
        self.source = 0;
        self.pitch_mod = false;
        self.noise_on = false;

        self.sample_start_address = 0;
        self.loop_start_address = 0;
        self.brr_block_decoder.reset(0, 0);
        self.sample_address = 0;
        self.sample_pos = 0;

        for i in 0..RESAMPLE_BUFFER_LEN {
            self.resample_buffer[i] = 0;
        }
        self.resample_buffer_pos = 0;

        self.output_buffer.reset();
        self.is_muted = false;
    }

    pub fn render_sample(&mut self, last_voice_out: i32, noise: i32) -> VoiceOutput {
        let mut pitch = ((self.pitch_high as i32) << 8) | (self.pitch_low as i32);
        if self.pitch_mod {
            pitch += ((last_voice_out >> 5) * pitch) >> 10;
        }
        if pitch < 0 {
            pitch = 0;
        }
        if pitch > 0x3fff {
            pitch = 0x3fff;
        }

        let mut sample = if !self.noise_on {
            match self.resampling_mode {
                ResamplingMode::Linear => {
                    let p1 = self.sample_pos;
                    let p2 = 0x1000 - p1;
                    dsp_helpers::clamp((
                        self.resample_buffer[self.resample_buffer_pos] * p1 +
                        self.resample_buffer[(self.resample_buffer_pos + 1) % RESAMPLE_BUFFER_LEN] * p2) >> 12) & !1
                }
            }
        } else {
            ((noise * 2) as i16) as i32
        };

        self.envelope.tick();
        let env_level = self.envelope.level;

        sample = ((sample * env_level) >> 11) & !1;

        if self.brr_block_decoder.is_end && !self.brr_block_decoder.is_looping {
            self.envelope.key_off();
            self.envelope.level = 0;
        }

        self.sample_pos += pitch;
        while self.sample_pos >= 0x1000 {
            self.sample_pos -= 0x1000;
            self.read_next_sample();

            if self.brr_block_decoder.is_finished() {
                if self.brr_block_decoder.is_end && self.brr_block_decoder.is_looping {
                    self.read_entry();
                    self.sample_address = self.loop_start_address;
                }
                self.read_next_block();
            }
        }

        let ret =
            if !self.is_muted {
                VoiceOutput {
                    left_out: dsp_helpers::multiply_volume(sample, self.vol_left),
                    right_out: dsp_helpers::multiply_volume(sample, self.vol_right),
                    last_voice_out: sample
                }
            } else {
                VoiceOutput {
                    left_out: 0,
                    right_out: 0,
                    last_voice_out: 0
                }
            };
        self.output_buffer.write(ret);
        ret
    }

    pub fn set_pitch_high(&mut self, value: u8) {
        self.pitch_high = value & 0x3f;
    }

    pub fn key_on(&mut self) {
        self.read_entry();
        self.sample_address = self.sample_start_address;
        self.brr_block_decoder.reset(0, 0);
        self.read_next_block();
        self.sample_pos = 0;
        self.resample_buffer[self.resample_buffer_pos] = 0;
        self.read_next_sample();
        self.envelope.key_on();
    }

    pub fn key_off(&mut self) {
        self.envelope.key_off();
    }

    fn read_entry(&mut self) {
        self.sample_start_address = self.dsp().read_source_dir_start_address(self.source as i32);
        self.loop_start_address = self.dsp().read_source_dir_loop_address(self.source as i32);
    }

    fn read_next_block(&mut self) {
        let mut buf = [0; 9];
        for i in 0..9 {
            buf[i] = self.emulator().read_u8(self.sample_address + (i as u32));
        }
        self.brr_block_decoder.read(&buf);
        self.sample_address += 9;
    }

    fn read_next_sample(&mut self) {
        self.resample_buffer_pos = match self.resample_buffer_pos {
            0 => RESAMPLE_BUFFER_LEN - 1,
            x => x - 1
        };
        self.resample_buffer[self.resample_buffer_pos] = self.brr_block_decoder.read_next_sample() as i32;
    }
}
<|endoftext|>


<commit_before>#![feature(test)]

extern crate puyocore;
extern crate test;

use test::Bencher;
use puyocore::bit_field::BitField;

#[bench]
fn simulate_19rensa(b: &mut Bencher) {
    let bf = BitField::from_str(concat!(
        ".G.BRG",
        "GBRRYR",
        "RRYYBY",
        "RGYRBR",
        "YGYRBY",
        "YGBGYR",
        "GRBGYR",
        "BRBYBY",
        "RYYBYY",
        "BRBYBR",
        "BGBYRR",
        "YGBGBG",
        "RBGBGG"));

    b.iter(|| {
        test::black_box(bf.clone().simulate())
    })
}

#[bench]
fn simulate_fast_19rensa(b: &mut Bencher) {
    let bf = BitField::from_str(concat!(
        ".G.BRG",
        "GBRRYR",
        "RRYYBY",
        "RGYRBR",
        "YGYRBY",
        "YGBGYR",
        "GRBGYR",
        "BRBYBY",
        "RYYBYY",
        "BRBYBR",
        "BGBYRR",
        "YGBGBG",
        "RBGBGG"));

    b.iter(|| {
        test::black_box(bf.clone().simulate_fast())
    })
}
<commit_msg>:green_heart: Fix bench build<commit_after>#![feature(test)]

extern crate puyocore;
extern crate test;

use test::Bencher;
use puyocore::field::BitField;

#[bench]
fn simulate_19rensa(b: &mut Bencher) {
    let bf = BitField::from_str(concat!(
        ".G.BRG",
        "GBRRYR",
        "RRYYBY",
        "RGYRBR",
        "YGYRBY",
        "YGBGYR",
        "GRBGYR",
        "BRBYBY",
        "RYYBYY",
        "BRBYBR",
        "BGBYRR",
        "YGBGBG",
        "RBGBGG"));

    b.iter(|| {
        test::black_box(bf.clone().simulate())
    })
}

#[bench]
fn simulate_fast_19rensa(b: &mut Bencher) {
    let bf = BitField::from_str(concat!(
        ".G.BRG",
        "GBRRYR",
        "RRYYBY",
        "RGYRBR",
        "YGYRBY",
        "YGBGYR",
        "GRBGYR",
        "BRBYBY",
        "RYYBYY",
        "BRBYBR",
        "BGBYRR",
        "YGBGBG",
        "RBGBGG"));

    b.iter(|| {
        test::black_box(bf.clone().simulate_fast())
    })
}
<|endoftext|>


<commit_before>/// HTTP message body parsing
///
/// See https://tools.ietf.org/html/rfc7230#section-3.3.3

use std::io;

use tokio_core::io::EasyBuf;

use httparse;

use super::Chunk;

pub enum BodyCodec {
    Length(Length),
    Chunked(Chunked),
    UntilClose(UntilClose),
}

impl BodyCodec {
    pub fn remaining(&self) -> bool {
        match *self {
            BodyCodec::Length(ref l) => l.remaining(),
            BodyCodec::Chunked(ref c) => c.remaining(),
            BodyCodec::UntilClose(ref u) => u.remaining(),
        }
    }

    pub fn decode(&mut self, buf: &mut EasyBuf) -> io::Result<Option<Chunk>> {
        match *self {
            BodyCodec::Length(ref mut l) => l.decode(buf),
            BodyCodec::Chunked(ref mut c) => c.decode(buf),
            BodyCodec::UntilClose(ref mut u) => u.decode(buf),
        }
    }
}

/// Body decoding based on a Content-Length header
#[derive(Debug)]
pub struct Length {
    length: usize,
    remaining: usize,
}

impl Length {
    pub fn new(length: usize) -> Length {
        Length {
            length: length,
            remaining: length,
        }
    }

    pub fn remaining(&self) -> bool {
        self.remaining > 0
    }

    pub fn decode(&mut self, buf: &mut EasyBuf) -> io::Result<Option<Chunk>> {
        if buf.len() == 0 {
            return Ok(None);
        }

        if self.remaining <= 0 {
            return Err(io::Error::new(io::ErrorKind::Other, "No more body bytes remaining."));
        }

        // TODO make sure that content length is not > usize::MAX. does parse do this?
        let len = ::std::cmp::min(self.length, buf.len());
        self.remaining -= len;
        debug!("Content length remaining {}", self.remaining);

        let body = buf.drain_to(len);

        Ok(
            Some(
                Chunk(Vec::from(body.as_ref()))
            )
        )
    }
}

#[derive(Eq, PartialEq, Debug)]
pub enum ChunkedState {
    Header,
    Body(u64),
    Trailer,
    End,
}

/// Chunked Transfer Coding
///
/// See https://tools.ietf.org/html/rfc7230#section-4
pub struct Chunked {
    state: ChunkedState,
}

impl Chunked {
    pub fn new() -> Chunked {
        Chunked {
            state: ChunkedState::Header,
        }
    }

    pub fn remaining(&self) -> bool {
        self.state != ChunkedState::End
    }

    pub fn decode(&mut self, buf: &mut EasyBuf) -> io::Result<Option<Chunk>> {
        trace!("chunked decode");
        let mut body: Option<Chunk> = None;
        loop {
            match self.state {
                ChunkedState::Header => {
                    trace!("chunk state header");
                    match httparse::parse_chunk_size(buf.as_ref()) {
                        Ok(httparse::Status::Complete((i, len))) => {
                            debug!("Found chunk size of {}", len);

                            let header = buf.drain_to(i);

                            if body.is_some() {
                                let mut chunk = body.take().expect("Chunk is None");
                                chunk.0.extend_from_slice(header.as_ref());
                                body = Some(chunk);
                            } else {
                                body = Some(Chunk(Vec::from(header.as_ref())));
                            }

                            if len > 0 {
                                self.state = ChunkedState::Body(len);
                            } else {
                                debug!("Found last chunk");
                                if buf.as_ref().starts_with(b"\r\n") {
                                    self.state = ChunkedState::End;
                                } else {
                                    self.state = ChunkedState::Trailer;
                                }
                            }
                        }
                        Ok(httparse::Status::Partial) => return Ok(body),
                        Err(e) => {
                            debug!("Invalid chunk size: {:?}", e);
                            return Err(io::Error::new(io::ErrorKind::InvalidInput, "Invalid chunk size"));
                        }
                    }
                }
                ChunkedState::Body(len) => {
                    trace!("chunk state body");

                    if buf.len() == 0 {
                        return Ok(body);
                    }

                    // ensure that the buffer contains the crlf too
                    // TODO check for overflow
                    let len: usize = len as usize + 2;

                    if len > buf.len() {
                        debug!("partial body chunk + crlf len = {}, buf len = {}", len, buf.len());
                        let l = buf.len();
                        let b = buf.drain_to(l);

                        if body.is_some() {
                            let mut chunk = body.take().expect("Chunk is None");
                            chunk.0.extend_from_slice(b.as_ref());
                            body = Some(chunk);
                        } else {
                            body = Some(Chunk(Vec::from(b.as_ref())));
                        }

                        let new_len: u64 = (len - l - 2) as u64;
                        self.state = ChunkedState::Body(new_len);
                    } else {
                        let b = buf.drain_to(len);

                        if body.is_some() {
                            let mut chunk = body.take().expect("Chunk is None");
                            chunk.0.extend_from_slice(b.as_ref());
                            body = Some(chunk);
                        } else {
                            body = Some(Chunk(Vec::from(b.as_ref())));
                        }

                        self.state = ChunkedState::Header;
                    }
                }
                ChunkedState::Trailer => {
                    trace!("chunk state trailer");
                    let mut headers = [httparse::EMPTY_HEADER; 16];
                    match httparse::parse_headers(buf.as_ref(), &mut headers) {
                        Ok(httparse::Status::Complete((i, _))) => {
                            let h = buf.drain_to(i);

                            if body.is_some() {
                                let mut chunk = body.take().expect("Chunk is None");
                                chunk.0.extend_from_slice(h.as_ref());
                                body = Some(chunk);
                            } else {
                                body = Some(Chunk(Vec::from(h.as_ref())));
                            }

                            self.state = ChunkedState::End;
                        }
                        Ok(httparse::Status::Partial) => return Ok(body),
                        Err(e) => {
                            debug!("Invalid header format: {:?}", e);
                            return Err(io::Error::new(io::ErrorKind::InvalidInput, "Invalid header format"));
                        }
                    }
                }
                ChunkedState::End => {
                    trace!("chunk state end");
                    if buf.len() < 2 {
                        return Ok(body);
                    }

                    let h = buf.drain_to(2);
                    if body.is_some() {
                        let mut chunk = body.take().expect("Chunk is None");
                        chunk.0.extend_from_slice(h.as_ref());
                        body = Some(chunk);
                    } else {
                        body = Some(Chunk(Vec::from(h.as_ref())));
                    }
                    break;
                }
            }
        }

        Ok(body)
    }
}

pub struct UntilClose {
    is_closed: bool,
}

impl UntilClose {

    pub fn new() -> UntilClose {
        UntilClose {
            is_closed: false,
        }
    }

    pub fn remaining(&self) -> bool {
        self.is_closed
    }

    pub fn decode(&mut self, buf: &mut EasyBuf) -> io::Result<Option<Chunk>> {
        if buf.len() == 0 {
            self.is_closed = true;
            return Ok(None);
        }

        let len = buf.len();
        trace!("UntilClose decode {} bytes", len);

        let body = buf.drain_to(len);

        Ok(
            Some(
                Chunk(Vec::from(body.as_ref()))
            )
        )
    }
}

#[cfg(test)]
mod tests {
    use tokio_core::io::EasyBuf;
    use super::*;

    fn mock_buf_with_data(data: &[u8]) -> EasyBuf {
        let mut buf = EasyBuf::with_capacity(data.len());
        buf.get_mut().extend_from_slice(data);
        buf
    }

    fn extend_mock_buf(buf: &mut EasyBuf, len: usize) {
        let mut data = (0u8..len as u8).map(|_| 0).collect::<Vec<u8>>();
        buf.get_mut().append(&mut data);
    }

    #[test]
    fn test_decode_length_buf_len_zero() {
        let mut buf = EasyBuf::with_capacity(0);
        assert_eq!(0, buf.len());
        let mut codec = Length::new(1);
        assert!(codec.decode(&mut buf).unwrap().is_none());
    }

    #[test]
    fn test_decode_length_buf_len_equals_content_length() {
        let mut buf = mock_buf_with_data(&[0u8; 64]);
        let mut codec = Length::new(64);
        assert_eq!(64, codec.decode(&mut buf).unwrap().unwrap().0.len());
        assert_eq!(0, buf.len());
    }

    #[test]
    fn test_decode_length_buf_len_greater_than_content_length() {
        let mut buf = mock_buf_with_data(&[0u8; 65]);
        let mut codec = Length::new(64);
        assert_eq!(64, codec.decode(&mut buf).unwrap().unwrap().0.len());
        assert_eq!(1, buf.len());

        assert!(codec.decode(&mut buf).is_err());
    }

    #[test]
    fn test_decode_length_buf_len_less_than_content_length() {
        let mut buf = mock_buf_with_data(&[0u8; 20]);
        let mut codec = Length::new(64);
        assert_eq!(20, codec.decode(&mut buf).unwrap().unwrap().0.len());
        assert_eq!(44, codec.remaining);
        assert_eq!(0, buf.len());

        extend_mock_buf(&mut buf, 40);
        assert_eq!(40, codec.decode(&mut buf).unwrap().unwrap().0.len());
        assert_eq!(4, codec.remaining);
        assert_eq!(0, buf.len());

        extend_mock_buf(&mut buf, 4);
        assert_eq!(4, codec.decode(&mut buf).unwrap().unwrap().0.len());
        assert_eq!(0, codec.remaining);
        assert_eq!(0, buf.len());
    }

    #[test]
    fn test_decode_chunked_buf_len_zero() {
        let mut buf = EasyBuf::with_capacity(0);
        assert_eq!(0, buf.len());
        let mut codec = Chunked::new();
        assert!(codec.decode(&mut buf).unwrap().is_none());
    }

    #[test]
    fn test_decode_chunked() {
        let body =
            b"7\r\n\
              Mozilla\r\n\
              9\r\n\
              Developer\r\n\
              7\r\n\
              Network\r\n\
              0\r\n\
              \r\n";

        let mut buf = mock_buf_with_data(body.as_ref());

        let mut codec = Chunked::new();
        assert_eq!(body.len(), codec.decode(&mut buf).unwrap().unwrap().0.len());
        assert_eq!(0, buf.len());
        assert_eq!(ChunkedState::End, codec.state);
    }

    #[test]
    fn test_decode_chunked_buf_len_greater_than_chunk() {
        let body =
            b"7\r\n\
              Mozilla\r\n\
              0\r\n\
              \r\nx";

        let mut buf = mock_buf_with_data(body.as_ref());

        let mut codec = Chunked::new();
        assert_eq!(body.len() - 1, codec.decode(&mut buf).unwrap().unwrap().0.len());
        assert_eq!(1, buf.len());
        assert_eq!(ChunkedState::End, codec.state);
    }

    #[test]
    fn test_decode_chunked_buf_len_less_than_chunk() {
        let body =
            b"7\r\n\
              Mozi";

        let mut buf = mock_buf_with_data(body.as_ref());

        let mut codec = Chunked::new();
        assert_eq!(7, codec.decode(&mut buf).unwrap().unwrap().0.len());
        assert_eq!(0, buf.len());
        assert_eq!(ChunkedState::Body(3), codec.state);

        let body = b"lla\r\n";
        buf.get_mut().extend_from_slice(body.as_ref());

        assert_eq!(5, codec.decode(&mut buf).unwrap().unwrap().0.len());
        assert_eq!(0, buf.len());
        assert_eq!(ChunkedState::Header, codec.state);
    }
}
<commit_msg>tests written<commit_after>/// HTTP message body parsing
///
/// See https://tools.ietf.org/html/rfc7230#section-3.3.3

use std::io;

use tokio_core::io::EasyBuf;

use httparse;

use super::Chunk;

pub enum BodyCodec {
    Length(Length),
    Chunked(Chunked),
    UntilClose(UntilClose),
}

impl BodyCodec {
    pub fn remaining(&self) -> bool {
        match *self {
            BodyCodec::Length(ref l) => l.remaining(),
            BodyCodec::Chunked(ref c) => c.remaining(),
            BodyCodec::UntilClose(ref u) => u.remaining(),
        }
    }

    pub fn decode(&mut self, buf: &mut EasyBuf) -> io::Result<Option<Chunk>> {
        match *self {
            BodyCodec::Length(ref mut l) => l.decode(buf),
            BodyCodec::Chunked(ref mut c) => c.decode(buf),
            BodyCodec::UntilClose(ref mut u) => u.decode(buf),
        }
    }
}

/// Body decoding based on a Content-Length header
#[derive(Debug)]
pub struct Length {
    length: usize,
    remaining: usize,
}

impl Length {
    pub fn new(length: usize) -> Length {
        Length {
            length: length,
            remaining: length,
        }
    }

    pub fn remaining(&self) -> bool {
        self.remaining > 0
    }

    pub fn decode(&mut self, buf: &mut EasyBuf) -> io::Result<Option<Chunk>> {
        if buf.len() == 0 {
            return Ok(None);
        }

        if self.remaining <= 0 {
            return Err(io::Error::new(io::ErrorKind::Other, "No more body bytes remaining."));
        }

        // TODO make sure that content length is not > usize::MAX. does parse do this?
        let len = ::std::cmp::min(self.length, buf.len());
        self.remaining -= len;
        debug!("Content length remaining {}", self.remaining);

        let body = buf.drain_to(len);

        Ok(
            Some(
                Chunk(Vec::from(body.as_ref()))
            )
        )
    }
}

#[derive(Eq, PartialEq, Debug)]
pub enum ChunkedState {
    Header,
    Body(u64),
    Trailer,
    End,
}

/// Chunked Transfer Coding
///
/// See https://tools.ietf.org/html/rfc7230#section-4
pub struct Chunked {
    state: ChunkedState,
}

impl Chunked {
    pub fn new() -> Chunked {
        Chunked {
            state: ChunkedState::Header,
        }
    }

    pub fn remaining(&self) -> bool {
        self.state != ChunkedState::End
    }

    pub fn decode(&mut self, buf: &mut EasyBuf) -> io::Result<Option<Chunk>> {
        trace!("chunked decode");
        let mut body: Option<Chunk> = None;
        loop {
            match self.state {
                ChunkedState::Header => {
                    trace!("chunk state header");
                    match httparse::parse_chunk_size(buf.as_ref()) {
                        Ok(httparse::Status::Complete((i, len))) => {
                            debug!("Found chunk size of {}", len);

                            let header = buf.drain_to(i);

                            if body.is_some() {
                                let mut chunk = body.take().expect("Chunk is None");
                                chunk.0.extend_from_slice(header.as_ref());
                                body = Some(chunk);
                            } else {
                                body = Some(Chunk(Vec::from(header.as_ref())));
                            }

                            if len > 0 {
                                self.state = ChunkedState::Body(len);
                            } else {
                                debug!("Found last chunk");
                                if buf.as_ref().starts_with(b"\r\n") {
                                    self.state = ChunkedState::End;
                                } else {
                                    self.state = ChunkedState::Trailer;
                                }
                            }
                        }
                        Ok(httparse::Status::Partial) => return Ok(body),
                        Err(e) => {
                            debug!("Invalid chunk size: {:?}", e);
                            return Err(io::Error::new(io::ErrorKind::InvalidInput, "Invalid chunk size"));
                        }
                    }
                }
                ChunkedState::Body(len) => {
                    trace!("chunk state body");

                    if buf.len() == 0 {
                        return Ok(body);
                    }

                    // ensure that the buffer contains the crlf too
                    // TODO check for overflow
                    let len: usize = len as usize + 2;

                    if len > buf.len() {
                        debug!("partial body chunk + crlf len = {}, buf len = {}", len, buf.len());
                        let l = buf.len();
                        let b = buf.drain_to(l);

                        if body.is_some() {
                            let mut chunk = body.take().expect("Chunk is None");
                            chunk.0.extend_from_slice(b.as_ref());
                            body = Some(chunk);
                        } else {
                            body = Some(Chunk(Vec::from(b.as_ref())));
                        }

                        let new_len: u64 = (len - l - 2) as u64;
                        self.state = ChunkedState::Body(new_len);
                    } else {
                        let b = buf.drain_to(len);

                        if body.is_some() {
                            let mut chunk = body.take().expect("Chunk is None");
                            chunk.0.extend_from_slice(b.as_ref());
                            body = Some(chunk);
                        } else {
                            body = Some(Chunk(Vec::from(b.as_ref())));
                        }

                        self.state = ChunkedState::Header;
                    }
                }
                ChunkedState::Trailer => {
                    trace!("chunk state trailer");
                    let mut headers = [httparse::EMPTY_HEADER; 16];
                    match httparse::parse_headers(buf.as_ref(), &mut headers) {
                        Ok(httparse::Status::Complete((i, _))) => {
                            let h = buf.drain_to(i);

                            if body.is_some() {
                                let mut chunk = body.take().expect("Chunk is None");
                                chunk.0.extend_from_slice(h.as_ref());
                                body = Some(chunk);
                            } else {
                                body = Some(Chunk(Vec::from(h.as_ref())));
                            }

                            self.state = ChunkedState::End;
                        }
                        Ok(httparse::Status::Partial) => return Ok(body),
                        Err(e) => {
                            debug!("Invalid header format: {:?}", e);
                            return Err(io::Error::new(io::ErrorKind::InvalidInput, "Invalid header format"));
                        }
                    }
                }
                ChunkedState::End => {
                    trace!("chunk state end");
                    if buf.len() < 2 {
                        return Ok(body);
                    }

                    let h = buf.drain_to(2);
                    if body.is_some() {
                        let mut chunk = body.take().expect("Chunk is None");
                        chunk.0.extend_from_slice(h.as_ref());
                        body = Some(chunk);
                    } else {
                        body = Some(Chunk(Vec::from(h.as_ref())));
                    }
                    break;
                }
            }
        }

        Ok(body)
    }
}

pub struct UntilClose {
    is_closed: bool,
}

impl UntilClose {

    pub fn new() -> UntilClose {
        UntilClose {
            is_closed: false,
        }
    }

    pub fn remaining(&self) -> bool {
        self.is_closed == false
    }

    pub fn decode(&mut self, buf: &mut EasyBuf) -> io::Result<Option<Chunk>> {
        if buf.len() == 0 {
            self.is_closed = true;
            return Ok(None);
        }

        let len = buf.len();
        trace!("UntilClose decode {} bytes", len);

        let body = buf.drain_to(len);

        Ok(
            Some(
                Chunk(Vec::from(body.as_ref()))
            )
        )
    }
}

#[cfg(test)]
mod tests {
    use tokio_core::io::EasyBuf;
    use super::*;

    fn mock_buf(data: &[u8]) -> EasyBuf {
        let mut buf = EasyBuf::with_capacity(data.len());
        buf.get_mut().extend_from_slice(data);
        buf
    }

    fn extend_mock_buf(buf: &mut EasyBuf, len: usize) {
        let mut data = (0u8..len as u8).map(|_| 0).collect::<Vec<u8>>();
        buf.get_mut().append(&mut data);
    }

    #[test]
    fn test_decode_length_buf_len_zero() {
        let mut buf = mock_buf(&[]);
        assert_eq!(0, buf.len());
        let mut codec = Length::new(1);
        assert!(codec.decode(&mut buf).unwrap().is_none());
    }

    #[test]
    fn test_decode_length_buf_len_equals_content_length() {
        let mut buf = mock_buf(&[0u8; 64]);
        let mut codec = Length::new(64);
        assert_eq!(64, codec.decode(&mut buf).unwrap().unwrap().0.len());
        assert_eq!(0, buf.len());
    }

    #[test]
    fn test_decode_length_buf_len_greater_than_content_length() {
        let mut buf = mock_buf(&[0u8; 65]);
        let mut codec = Length::new(64);
        assert_eq!(64, codec.decode(&mut buf).unwrap().unwrap().0.len());
        assert_eq!(1, buf.len());

        assert!(codec.decode(&mut buf).is_err());
    }

    #[test]
    fn test_decode_length_buf_len_less_than_content_length() {
        let mut buf = mock_buf(&[0u8; 20]);
        let mut codec = Length::new(64);
        assert_eq!(20, codec.decode(&mut buf).unwrap().unwrap().0.len());
        assert_eq!(44, codec.remaining);
        assert_eq!(0, buf.len());

        extend_mock_buf(&mut buf, 40);
        assert_eq!(40, codec.decode(&mut buf).unwrap().unwrap().0.len());
        assert_eq!(4, codec.remaining);
        assert_eq!(0, buf.len());

        extend_mock_buf(&mut buf, 4);
        assert_eq!(4, codec.decode(&mut buf).unwrap().unwrap().0.len());
        assert_eq!(0, codec.remaining);
        assert_eq!(0, buf.len());
    }

    #[test]
    fn test_decode_chunked_buf_len_zero() {
        let mut buf = mock_buf(&[]);
        assert_eq!(0, buf.len());
        let mut codec = Chunked::new();
        assert!(codec.decode(&mut buf).unwrap().is_none());
    }

    #[test]
    fn test_decode_chunked() {
        let body =
            b"7\r\n\
              Mozilla\r\n\
              9\r\n\
              Developer\r\n\
              7\r\n\
              Network\r\n\
              0\r\n\
              \r\n";

        let mut buf = mock_buf(body.as_ref());

        let mut codec = Chunked::new();
        assert_eq!(body.len(), codec.decode(&mut buf).unwrap().unwrap().0.len());
        assert_eq!(0, buf.len());
        assert_eq!(ChunkedState::End, codec.state);
    }

    #[test]
    fn test_decode_chunked_buf_len_greater_than_chunk() {
        let body =
            b"7\r\n\
              Mozilla\r\n\
              0\r\n\
              \r\nx";

        let mut buf = mock_buf(body.as_ref());

        let mut codec = Chunked::new();
        assert_eq!(body.len() - 1, codec.decode(&mut buf).unwrap().unwrap().0.len());
        assert_eq!(1, buf.len());
        assert_eq!(ChunkedState::End, codec.state);
    }

    #[test]
    fn test_decode_chunked_buf_len_less_than_chunk() {
        let body =
            b"7\r\n\
              Mozi";

        let mut buf = mock_buf(body.as_ref());

        let mut codec = Chunked::new();
        assert_eq!(7, codec.decode(&mut buf).unwrap().unwrap().0.len());
        assert_eq!(0, buf.len());
        assert_eq!(ChunkedState::Body(3), codec.state);

        let body = b"lla\r\n";
        buf.get_mut().extend_from_slice(body.as_ref());

        assert_eq!(5, codec.decode(&mut buf).unwrap().unwrap().0.len());
        assert_eq!(0, buf.len());
        assert_eq!(ChunkedState::Header, codec.state);
    }

    #[test]
    fn test_decode_until_close_buf_len_zero() {
        let mut buf = mock_buf(&[]);
        assert_eq!(0, buf.len());
        let mut codec = UntilClose::new();
        assert!(codec.decode(&mut buf).unwrap().is_none());
        assert_eq!(false, codec.remaining());
    }

    #[test]
    fn test_decode_until_close_buf_len_greater_than_zero() {
        let mut buf = mock_buf(&[0u8; 64]);
        assert_eq!(64, buf.len());
        let mut codec = UntilClose::new();
        assert_eq!(buf.len(), codec.decode(&mut buf).unwrap().unwrap().0.len());
        assert_eq!(true, codec.remaining());
        assert!(codec.decode(&mut buf).unwrap().is_none());
        assert_eq!(false, codec.remaining());
    }
}
<|endoftext|>


<commit_before>use voodoo::color::ColorValue;
use voodoo::window::{FormattedString, Point, Window};

use program::{Ability, Program};

pub struct InfoView {
    window: Window,
    ability_list: Vec<(String, Ability)>,
    selected_ability: Option<(usize, Ability)>,
}

impl InfoView {
    pub fn new(mut window: Window) -> InfoView {
        let mut f: FormattedString = "     End Turn     ".into();
        f.bg = Some(ColorValue::Magenta);
        window.print_at(Point::new(2, 23), f);

        InfoView {
            window: window,
            ability_list: Vec::new(),
            selected_ability: None,
        }
    }

    pub fn from_global_frame(&self, p: Point) -> Option<Point> {
        self.window.position.from_global_frame(p)
    }

    pub fn refresh(&mut self, stdout: &mut ::std::io::Stdout) {
        self.window.refresh(stdout);
    }

    pub fn clear(&mut self) {
        self.ability_list.clear();
        self.selected_ability = None;
        self.window.clear();
        self.window.border();
        let mut f: FormattedString = "     End Turn     ".into();
        f.bg = Some(ColorValue::Magenta);
        self.window.print_at(Point::new(2, 23), f);
    }

    pub fn display_abilities(&mut self) {
        let mut y = 5;
        for (ability_number, &(ref name, _)) in self.ability_list.iter().enumerate() {
            let mut f: FormattedString = name.into();
            f.bg = if let Some((offset, _)) = self.selected_ability {
                if offset == ability_number {
                    Some(ColorValue::Red)
                }
                else {
                    Some(ColorValue::Magenta)
                }
            } else { Some(ColorValue::Magenta) };
            self.window.print_at(Point::new(2, y), f);
            y += 1;
        }
    }

    // TODO: take a ProgramRef and store it (maybe a weak reference)
    pub fn display_program(&mut self, program: &Program) {
        self.window.print_at(Point::new(2, 2), &program.name);

        self.window.print_at(Point::new(2, 4), "Abilities:");
        self.ability_list.extend(program.abilities.iter().cloned());

        self.display_abilities();
    }

    // TODO: return the ability range or something? Ability descriptor
    pub fn translate_click(&mut self, click: Point) -> Option<Ability> {
        for (offset, &(_, ability)) in self.ability_list.iter().enumerate() {
            if click.y == 5 + offset as u16 {
                self.selected_ability = Some((offset, ability));
                break;
            }
        }
        self.display_abilities();

        self.selected_ability.map(|(_, ability)| ability)
    }

    pub fn clear_ability(&mut self) {
        self.selected_ability = None;
        self.display_abilities();
    }
}
<commit_msg>feat: add 'moves' text to info view<commit_after>use voodoo::color::ColorValue;
use voodoo::window::{FormattedString, Point, Window};

use program::{Ability, Program};

pub struct InfoView {
    window: Window,
    ability_list: Vec<(String, Ability)>,
    selected_ability: Option<(usize, Ability)>,
}

impl InfoView {
    pub fn new(mut window: Window) -> InfoView {
        let mut f: FormattedString = "     End Turn     ".into();
        f.bg = Some(ColorValue::Magenta);
        window.print_at(Point::new(2, 23), f);

        InfoView {
            window: window,
            ability_list: Vec::new(),
            selected_ability: None,
        }
    }

    pub fn from_global_frame(&self, p: Point) -> Option<Point> {
        self.window.position.from_global_frame(p)
    }

    pub fn refresh(&mut self, stdout: &mut ::std::io::Stdout) {
        self.window.refresh(stdout);
    }

    pub fn clear(&mut self) {
        self.ability_list.clear();
        self.selected_ability = None;
        self.window.clear();
        self.window.border();
        let mut f: FormattedString = "     End Turn     ".into();
        f.bg = Some(ColorValue::Magenta);
        self.window.print_at(Point::new(2, 23), f);
    }

    pub fn display_abilities(&mut self) {
        let mut y = 6;
        for (ability_number, &(ref name, _)) in self.ability_list.iter().enumerate() {
            let mut f: FormattedString = name.into();
            f.bg = if let Some((offset, _)) = self.selected_ability {
                if offset == ability_number {
                    Some(ColorValue::Red)
                }
                else {
                    Some(ColorValue::Magenta)
                }
            } else { Some(ColorValue::Magenta) };
            self.window.print_at(Point::new(2, y), f);
            y += 1;
        }
    }

    // TODO: take a ProgramRef and store it (maybe a weak reference)
    pub fn display_program(&mut self, program: &Program) {
        self.window.print_at(Point::new(2, 2), &program.name);
        self.window.print_at(Point::new(2, 3), "Moves: 3/3");

        self.window.print_at(Point::new(2, 4), "Abilities:");
        self.ability_list.extend(program.abilities.iter().cloned());

        self.display_abilities();
    }

    // TODO: return the ability range or something? Ability descriptor
    pub fn translate_click(&mut self, click: Point) -> Option<Ability> {
        for (offset, &(_, ability)) in self.ability_list.iter().enumerate() {
            if click.y == 6 + offset as u16 {
                self.selected_ability = Some((offset, ability));
                break;
            }
        }
        self.display_abilities();

        self.selected_ability.map(|(_, ability)| ability)
    }

    pub fn clear_ability(&mut self) {
        self.selected_ability = None;
        self.display_abilities();
    }
}
<|endoftext|>