<commit_before>use std::ptr;
use CL::*;
use mem::*;
use std::mem;
use std::vec;
use std::libc::{size_t, c_void};

use hl::KernelArg;

pub struct Array3D<T> {
    width: uint,
    height: uint,
    depth: uint,
    dat: ~[T]
}

pub struct Array3D_cl<T> {
    width: uint,
    height: uint,
    depth: uint,
    buf: cl_mem,
}

impl<T: Clone> Array3D<T> {
    pub fn new(width: uint, height: uint, depth: uint, val: |uint, uint, uint| -> T) -> Array3D<T>
    {
        let mut dat: ~[T] = ~[];
        for x in range(0, width) {
            for y in range(0, height) {
                for z in range(0, depth) {
                    dat.push(val(x, y, z));
                }
            }
        }

        Array3D {
            width: width,
            height: height,
            depth: depth,
            dat: dat
        }
    }

    pub fn set(&mut self, x: uint, y: uint, z: uint, val: T)
    {
        self.dat[self.width*self.height*z + self.width*y + x] = val;
    }

    pub fn get(&self, x: uint, y: uint, z: uint) -> T
    {
        self.dat[self.width*self.height*z + self.width*y + x].clone()
    }
}

impl<'self, T> Put<Array3D<T>, Array3D_cl<T>> for &'self Array3D<T>
{
    fn put(&self, f: |ptr: *c_void, size: size_t| -> cl_mem) -> Array3D_cl<T>
    {
        let out = self.dat.as_imm_buf(|p, len| {
            f(p as *c_void, (len * mem::size_of::<T>()) as size_t)
        });

        Array3D_cl{
            width: self.width,
            height: self.height,
            depth: self.depth,
            buf: out
        }
    }
}

impl<T> Get<Array3D_cl<T>, Array3D<T>> for Array3D<T>
{
    fn get(arr: &Array3D_cl<T>, f: |offset: size_t, ptr: *mut c_void, size: size_t|) -> Array3D<T>
    {
        let mut v: ~[T] = vec::with_capacity(arr.len());
        unsafe {
            vec::raw::set_len(&mut v, arr.len());
        }

        v.as_mut_buf(|p, len| {
            f(0, p as *mut c_void, (len * mem::size_of::<T>()) as size_t)
        });

        Array3D {
            width: arr.width,
            height: arr.height,
            depth: arr.depth,
            dat: v
        }
    }
}

impl<T> Write for Array3D<T> {
    fn write(&self, f: |offset: size_t, ptr: *c_void, size: size_t|)
    {
        self.dat.as_imm_buf(|p, len| {
            f(0, p as *c_void, (len * mem::size_of::<T>()) as size_t)
        });
    }
}

impl<T> Read for Array3D<T> {
    fn read(&mut self, f: |offset: size_t, ptr: *mut c_void, size: size_t|)
    {
        self.dat.as_mut_buf(|p, len| {
            f(0, p as *mut c_void, (len * mem::size_of::<T>()) as size_t)
        });
    }
}

impl<T> Buffer<T> for Array3D_cl<T> {
    fn id_ptr(&self) -> *cl_mem {
        ptr::to_unsafe_ptr(&self.buf)
    }

    fn len(&self) -> uint {
        self.width * self.height * self.depth
    }
}

impl<T> KernelArg for Array3D_cl<T> {
    fn get_value(&self) -> (size_t, *c_void)
    {
        (mem::size_of::<cl_mem>() as size_t,
         self.id_ptr() as *c_void)
    }
}

pub struct Array2D<T> {
    width: uint,
    height: uint,
    dat: ~[T],
}

pub struct Array2D_cl<T> {
    width: uint,
    height: uint,
    buf: cl_mem,
}

impl<T: Clone> Array2D<T> {
    pub fn new(width: uint, height: uint, val: |uint, uint| -> T) -> Array2D<T>
    {
        let mut dat: ~[T] = ~[];
        for x in range(0, width) {
            for y in range(0, height) {
                dat.push(val(x, y));
            }
        }
        Array2D {
            width: width,
            height: height,
            dat: dat,
        }
    }

    pub fn set(&mut self, x: uint, y: uint, val: T) {
        self.dat[self.width*y + x] = val;
    }

    pub fn get(&self, x: uint, y: uint) -> T {
        self.dat[self.width*y + x].clone()
    }
}

impl<'self, T> Put<Array2D<T>, Array2D_cl<T>> for &'self Array2D<T>
{
    fn put(&self, f: |ptr: *c_void, size: size_t| -> cl_mem) -> Array2D_cl<T>
    {
        let out = self.dat.as_imm_buf(|p, len| {
            f(p as *c_void, (len * mem::size_of::<T>()) as size_t)
        });

        Array2D_cl{
            width: self.width,
            height: self.height,
            buf: out
        }
    }
}

impl<T> Get<Array2D_cl<T>, Array2D<T>> for Array2D<T>
{
    fn get(arr: &Array2D_cl<T>, f: |offset: size_t, ptr: *mut c_void, size: size_t|) -> Array2D<T>
    {
        let mut v: ~[T] = vec::with_capacity(arr.len());
        unsafe {
            vec::raw::set_len(&mut v, arr.len());
        }

        v.as_mut_buf(|p, len| {
            f(0, p as *mut c_void, (len * mem::size_of::<T>()) as size_t)
        });

        Array2D {
            width: arr.width,
            height: arr.height,
            dat: v
        }
    }
}

impl<T> Write for Array2D<T> {
    fn write(&self, f: |offset: size_t, ptr: *c_void, size: size_t|)
    {
        self.dat.as_imm_buf(|p, len| {
            f(0, p as *c_void, (len * mem::size_of::<T>()) as size_t)
        });
    }
}

impl<T> Read for Array2D<T> {
    fn read(&mut self, f: |offset: size_t, ptr: *mut c_void, size: size_t|)
    {
        self.dat.as_mut_buf(|p, len| {
            f(0, p as *mut c_void, (len * mem::size_of::<T>()) as size_t)
        });
    }
}

impl<T> Buffer<T> for Array2D_cl<T> {
    fn id_ptr(&self) -> *cl_mem {
        ptr::to_unsafe_ptr(&self.buf)
    }

    fn len(&self) -> uint {
        self.width * self.height
    }
}

impl<T> KernelArg for Array2D_cl<T> {
    fn get_value(&self) -> (size_t, *c_void)
    {
        (mem::size_of::<cl_mem>() as size_t,
         self.id_ptr() as *c_void)
    }
}
<commit_msg>add drop for Array2D/3D<commit_after>use std::ptr;
use CL::*;
use CL::ll::*;
use mem::*;
use std::mem;
use std::vec;
use std::libc::{size_t, c_void};

use hl::KernelArg;

pub struct Array3D<T> {
    width: uint,
    height: uint,
    depth: uint,
    dat: ~[T]
}

pub struct Array3D_cl<T> {
    width: uint,
    height: uint,
    depth: uint,
    buf: cl_mem,
}

impl<T: Clone> Array3D<T> {
    pub fn new(width: uint, height: uint, depth: uint, val: |uint, uint, uint| -> T) -> Array3D<T>
    {
        let mut dat: ~[T] = ~[];
        for x in range(0, width) {
            for y in range(0, height) {
                for z in range(0, depth) {
                    dat.push(val(x, y, z));
                }
            }
        }

        Array3D {
            width: width,
            height: height,
            depth: depth,
            dat: dat
        }
    }

    pub fn set(&mut self, x: uint, y: uint, z: uint, val: T)
    {
        self.dat[self.width*self.height*z + self.width*y + x] = val;
    }

    pub fn get(&self, x: uint, y: uint, z: uint) -> T
    {
        self.dat[self.width*self.height*z + self.width*y + x].clone()
    }
}

#[unsafe_destructor]
impl<T> Drop for Array3D_cl<T> {
    #[fixed_stack_segment] #[inline(never)]
    fn drop(&mut self) {
        unsafe {
            clReleaseMemObject(self.buf);
        }
    }
}

impl<'self, T> Put<Array3D<T>, Array3D_cl<T>> for &'self Array3D<T>
{
    fn put(&self, f: |ptr: *c_void, size: size_t| -> cl_mem) -> Array3D_cl<T>
    {
        let out = self.dat.as_imm_buf(|p, len| {
            f(p as *c_void, (len * mem::size_of::<T>()) as size_t)
        });

        Array3D_cl{
            width: self.width,
            height: self.height,
            depth: self.depth,
            buf: out
        }
    }
}

impl<T> Get<Array3D_cl<T>, Array3D<T>> for Array3D<T>
{
    fn get(arr: &Array3D_cl<T>, f: |offset: size_t, ptr: *mut c_void, size: size_t|) -> Array3D<T>
    {
        let mut v: ~[T] = vec::with_capacity(arr.len());
        unsafe {
            vec::raw::set_len(&mut v, arr.len());
        }

        v.as_mut_buf(|p, len| {
            f(0, p as *mut c_void, (len * mem::size_of::<T>()) as size_t)
        });

        Array3D {
            width: arr.width,
            height: arr.height,
            depth: arr.depth,
            dat: v
        }
    }
}

impl<T> Write for Array3D<T> {
    fn write(&self, f: |offset: size_t, ptr: *c_void, size: size_t|)
    {
        self.dat.as_imm_buf(|p, len| {
            f(0, p as *c_void, (len * mem::size_of::<T>()) as size_t)
        });
    }
}

impl<T> Read for Array3D<T> {
    fn read(&mut self, f: |offset: size_t, ptr: *mut c_void, size: size_t|)
    {
        self.dat.as_mut_buf(|p, len| {
            f(0, p as *mut c_void, (len * mem::size_of::<T>()) as size_t)
        });
    }
}

impl<T> Buffer<T> for Array3D_cl<T> {
    fn id_ptr(&self) -> *cl_mem {
        ptr::to_unsafe_ptr(&self.buf)
    }

    fn len(&self) -> uint {
        self.width * self.height * self.depth
    }
}

impl<T> KernelArg for Array3D_cl<T> {
    fn get_value(&self) -> (size_t, *c_void)
    {
        (mem::size_of::<cl_mem>() as size_t,
         self.id_ptr() as *c_void)
    }
}

pub struct Array2D<T> {
    width: uint,
    height: uint,
    dat: ~[T],
}

pub struct Array2D_cl<T> {
    width: uint,
    height: uint,
    buf: cl_mem,
}

impl<T: Clone> Array2D<T> {
    pub fn new(width: uint, height: uint, val: |uint, uint| -> T) -> Array2D<T>
    {
        let mut dat: ~[T] = ~[];
        for x in range(0, width) {
            for y in range(0, height) {
                dat.push(val(x, y));
            }
        }
        Array2D {
            width: width,
            height: height,
            dat: dat,
        }
    }

    pub fn set(&mut self, x: uint, y: uint, val: T) {
        self.dat[self.width*y + x] = val;
    }

    pub fn get(&self, x: uint, y: uint) -> T {
        self.dat[self.width*y + x].clone()
    }
}

#[unsafe_destructor]
impl<T> Drop for Array2D_cl<T> {
    #[fixed_stack_segment] #[inline(never)]
    fn drop(&mut self) {
        unsafe {
            clReleaseMemObject(self.buf);
        }
    }
}

impl<'self, T> Put<Array2D<T>, Array2D_cl<T>> for &'self Array2D<T>
{
    fn put(&self, f: |ptr: *c_void, size: size_t| -> cl_mem) -> Array2D_cl<T>
    {
        let out = self.dat.as_imm_buf(|p, len| {
            f(p as *c_void, (len * mem::size_of::<T>()) as size_t)
        });

        Array2D_cl{
            width: self.width,
            height: self.height,
            buf: out
        }
    }
}

impl<T> Get<Array2D_cl<T>, Array2D<T>> for Array2D<T>
{
    fn get(arr: &Array2D_cl<T>, f: |offset: size_t, ptr: *mut c_void, size: size_t|) -> Array2D<T>
    {
        let mut v: ~[T] = vec::with_capacity(arr.len());
        unsafe {
            vec::raw::set_len(&mut v, arr.len());
        }

        v.as_mut_buf(|p, len| {
            f(0, p as *mut c_void, (len * mem::size_of::<T>()) as size_t)
        });

        Array2D {
            width: arr.width,
            height: arr.height,
            dat: v
        }
    }
}

impl<T> Write for Array2D<T> {
    fn write(&self, f: |offset: size_t, ptr: *c_void, size: size_t|)
    {
        self.dat.as_imm_buf(|p, len| {
            f(0, p as *c_void, (len * mem::size_of::<T>()) as size_t)
        });
    }
}

impl<T> Read for Array2D<T> {
    fn read(&mut self, f: |offset: size_t, ptr: *mut c_void, size: size_t|)
    {
        self.dat.as_mut_buf(|p, len| {
            f(0, p as *mut c_void, (len * mem::size_of::<T>()) as size_t)
        });
    }
}

impl<T> Buffer<T> for Array2D_cl<T> {
    fn id_ptr(&self) -> *cl_mem {
        ptr::to_unsafe_ptr(&self.buf)
    }

    fn len(&self) -> uint {
        self.width * self.height
    }
}

impl<T> KernelArg for Array2D_cl<T> {
    fn get_value(&self) -> (size_t, *c_void)
    {
        (mem::size_of::<cl_mem>() as size_t,
         self.id_ptr() as *c_void)
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015 Benjamin Fry <benjaminfry@me.com>
 *
 * 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.
 */
#[cfg(feature = "openssl")]
use openssl::hash;

#[cfg(feature = "ring")]
use ring::digest;

use rr::dnssec::Algorithm;
use error::*;

#[cfg(any(feature = "openssl", feature = "ring"))]
use super::Digest;

/// This is the digest format for the
///
///```text
/// 0	Reserved	-	[RFC3658]
/// 1	SHA-1	MANDATORY	[RFC3658]
/// 2	SHA-256	MANDATORY	[RFC4509]
/// 3	GOST R 34.11-94	OPTIONAL	[RFC5933]
/// 4	SHA-384	OPTIONAL	[RFC6605]
/// 5 ED25519 [RFC draft-ietf-curdle-dnskey-eddsa-03]
/// 5-255	Unassigned	-
/// ```
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
pub enum DigestType {
    /// [RFC3658]
    SHA1,
    /// [RFC4509]
    SHA256, // [RFC4509]
    // GOSTR34_11_94, // [RFC5933]
    /// [RFC6605]
    SHA384,
    /// Undefined
    SHA512,
    /// This is a passthrough digest as ED25519 is self-packaged
    ED25519,
}

impl DigestType {
    /// http://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml
    pub fn from_u8(value: u8) -> DecodeResult<Self> {
        match value {
            1 => Ok(DigestType::SHA1),
            2 => Ok(DigestType::SHA256),
            //  3  => Ok(DigestType::GOSTR34_11_94),
            4 => Ok(DigestType::SHA384),
            5 => Ok(DigestType::ED25519),
            _ => Err(DecodeErrorKind::UnknownAlgorithmTypeValue(value).into()),
        }
    }

    /// The OpenSSL counterpart for the digest
    #[cfg(feature = "openssl")]
    pub fn to_openssl_digest(&self) -> DnsSecResult<hash::MessageDigest> {
        match *self {
            DigestType::SHA1 => Ok(hash::MessageDigest::sha1()),
            DigestType::SHA256 => Ok(hash::MessageDigest::sha256()),
            DigestType::SHA384 => Ok(hash::MessageDigest::sha384()),
            DigestType::SHA512 => Ok(hash::MessageDigest::sha512()),
            _ => {
                Err(DnsSecErrorKind::Msg(format!("digest not supported by openssl: {:?}", self))
                        .into())
            }
        }
    }

    /// The *ring* counterpart for the digest
    #[cfg(feature = "ring")]
    pub fn to_ring_digest_alg(&self) -> DnsSecResult<&'static digest::Algorithm> {
        match *self {
            DigestType::SHA1 => Ok(&digest::SHA1),
            DigestType::SHA256 => Ok(&digest::SHA256),
            DigestType::SHA384 => Ok(&digest::SHA384),
            DigestType::SHA512 => Ok(&digest::SHA512),
            _ =>
                Err(DnsSecErrorKind::Msg(format!("digest not supported by ring: {:?}", self))
                    .into())
        }
    }

    /// Hash the data
    #[cfg(all(not(feature = "ring"), feature = "openssl"))]
    pub fn hash(&self, data: &[u8]) -> DnsSecResult<Digest> {
        hash::hash2(try!(self.to_openssl_digest()), data).map_err(|e| e.into())
    }

    /// Hash the data
    #[cfg(feature = "ring")]
    pub fn hash(&self, data: &[u8]) -> DnsSecResult<Digest> {
        let alg = try!(self.to_ring_digest_alg());
        Ok(digest::digest(alg, data))
    }

    /// This will always error, enable openssl feature at compile time
    #[cfg(not(any(feature = "openssl", feature = "ring")))]
    pub fn hash(&self, _: &[u8]) -> DnsSecResult<Vec<u8>> {
        Err(DnsSecErrorKind::Message("openssl feature not enabled").into())
    }

    /// Digest all the data.
    #[cfg(all(not(feature = "ring"), feature = "openssl"))]
    pub fn digest_all(&self, data: &[&[u8]]) -> DnsSecResult<Digest> {
        use std::io::Write;

        let digest_type = try!(self.to_openssl_digest());
        hash::Hasher::new(digest_type)
            .map_err(|e| e.into())
            .and_then(|mut hasher| {
                for d in data {
                    try!(hasher.write_all(d));
                }
                hasher.finish2().map_err(|e| e.into())
            })
    }

    /// Digest all the data.
    #[cfg(feature = "ring")]
    pub fn digest_all(&self, data: &[&[u8]]) -> DnsSecResult<Digest> {
        let alg = try!(self.to_ring_digest_alg());
        let mut ctx = digest::Context::new(alg);
        for d in data {
            ctx.update(d);
        }
        Ok(ctx.finish())
    }
}

impl From<Algorithm> for DigestType {
    fn from(a: Algorithm) -> DigestType {
        match a {
            Algorithm::RSASHA1 |
            Algorithm::RSASHA1NSEC3SHA1 => DigestType::SHA1,
            Algorithm::RSASHA256 => DigestType::SHA256,
            Algorithm::RSASHA512 => DigestType::SHA512,
            Algorithm::ECDSAP256SHA256 => DigestType::SHA256,
            Algorithm::ECDSAP384SHA384 => DigestType::SHA384,
            Algorithm::ED25519 => DigestType::ED25519,
        }
    }
}

impl From<DigestType> for u8 {
    fn from(a: DigestType) -> u8 {
        match a {
            DigestType::SHA1 => 1,
            DigestType::SHA256 => 2,
            // DigestType::GOSTR34_11_94 => 3,
            DigestType::SHA384 => 4,
            DigestType::ED25519 => 5,
            DigestType::SHA512 => 255,
        }
    }
}
<commit_msg>Fix error message to mention *ring*.<commit_after>/*
 * Copyright (C) 2015 Benjamin Fry <benjaminfry@me.com>
 *
 * 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.
 */
#[cfg(feature = "openssl")]
use openssl::hash;

#[cfg(feature = "ring")]
use ring::digest;

use rr::dnssec::Algorithm;
use error::*;

#[cfg(any(feature = "openssl", feature = "ring"))]
use super::Digest;

/// This is the digest format for the
///
///```text
/// 0	Reserved	-	[RFC3658]
/// 1	SHA-1	MANDATORY	[RFC3658]
/// 2	SHA-256	MANDATORY	[RFC4509]
/// 3	GOST R 34.11-94	OPTIONAL	[RFC5933]
/// 4	SHA-384	OPTIONAL	[RFC6605]
/// 5 ED25519 [RFC draft-ietf-curdle-dnskey-eddsa-03]
/// 5-255	Unassigned	-
/// ```
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
pub enum DigestType {
    /// [RFC3658]
    SHA1,
    /// [RFC4509]
    SHA256, // [RFC4509]
    // GOSTR34_11_94, // [RFC5933]
    /// [RFC6605]
    SHA384,
    /// Undefined
    SHA512,
    /// This is a passthrough digest as ED25519 is self-packaged
    ED25519,
}

impl DigestType {
    /// http://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml
    pub fn from_u8(value: u8) -> DecodeResult<Self> {
        match value {
            1 => Ok(DigestType::SHA1),
            2 => Ok(DigestType::SHA256),
            //  3  => Ok(DigestType::GOSTR34_11_94),
            4 => Ok(DigestType::SHA384),
            5 => Ok(DigestType::ED25519),
            _ => Err(DecodeErrorKind::UnknownAlgorithmTypeValue(value).into()),
        }
    }

    /// The OpenSSL counterpart for the digest
    #[cfg(feature = "openssl")]
    pub fn to_openssl_digest(&self) -> DnsSecResult<hash::MessageDigest> {
        match *self {
            DigestType::SHA1 => Ok(hash::MessageDigest::sha1()),
            DigestType::SHA256 => Ok(hash::MessageDigest::sha256()),
            DigestType::SHA384 => Ok(hash::MessageDigest::sha384()),
            DigestType::SHA512 => Ok(hash::MessageDigest::sha512()),
            _ => {
                Err(DnsSecErrorKind::Msg(format!("digest not supported by openssl: {:?}", self))
                        .into())
            }
        }
    }

    /// The *ring* counterpart for the digest
    #[cfg(feature = "ring")]
    pub fn to_ring_digest_alg(&self) -> DnsSecResult<&'static digest::Algorithm> {
        match *self {
            DigestType::SHA1 => Ok(&digest::SHA1),
            DigestType::SHA256 => Ok(&digest::SHA256),
            DigestType::SHA384 => Ok(&digest::SHA384),
            DigestType::SHA512 => Ok(&digest::SHA512),
            _ =>
                Err(DnsSecErrorKind::Msg(format!("digest not supported by ring: {:?}", self))
                    .into())
        }
    }

    /// Hash the data
    #[cfg(all(not(feature = "ring"), feature = "openssl"))]
    pub fn hash(&self, data: &[u8]) -> DnsSecResult<Digest> {
        hash::hash2(try!(self.to_openssl_digest()), data).map_err(|e| e.into())
    }

    /// Hash the data
    #[cfg(feature = "ring")]
    pub fn hash(&self, data: &[u8]) -> DnsSecResult<Digest> {
        let alg = try!(self.to_ring_digest_alg());
        Ok(digest::digest(alg, data))
    }

    /// This will always error, enable openssl feature at compile time
    #[cfg(not(any(feature = "openssl", feature = "ring")))]
    pub fn hash(&self, _: &[u8]) -> DnsSecResult<Vec<u8>> {
        Err(DnsSecErrorKind::Message("The openssl and ring features are both disabled").into())
    }

    /// Digest all the data.
    #[cfg(all(not(feature = "ring"), feature = "openssl"))]
    pub fn digest_all(&self, data: &[&[u8]]) -> DnsSecResult<Digest> {
        use std::io::Write;

        let digest_type = try!(self.to_openssl_digest());
        hash::Hasher::new(digest_type)
            .map_err(|e| e.into())
            .and_then(|mut hasher| {
                for d in data {
                    try!(hasher.write_all(d));
                }
                hasher.finish2().map_err(|e| e.into())
            })
    }

    /// Digest all the data.
    #[cfg(feature = "ring")]
    pub fn digest_all(&self, data: &[&[u8]]) -> DnsSecResult<Digest> {
        let alg = try!(self.to_ring_digest_alg());
        let mut ctx = digest::Context::new(alg);
        for d in data {
            ctx.update(d);
        }
        Ok(ctx.finish())
    }
}

impl From<Algorithm> for DigestType {
    fn from(a: Algorithm) -> DigestType {
        match a {
            Algorithm::RSASHA1 |
            Algorithm::RSASHA1NSEC3SHA1 => DigestType::SHA1,
            Algorithm::RSASHA256 => DigestType::SHA256,
            Algorithm::RSASHA512 => DigestType::SHA512,
            Algorithm::ECDSAP256SHA256 => DigestType::SHA256,
            Algorithm::ECDSAP384SHA384 => DigestType::SHA384,
            Algorithm::ED25519 => DigestType::ED25519,
        }
    }
}

impl From<DigestType> for u8 {
    fn from(a: DigestType) -> u8 {
        match a {
            DigestType::SHA1 => 1,
            DigestType::SHA256 => 2,
            // DigestType::GOSTR34_11_94 => 3,
            DigestType::SHA384 => 4,
            DigestType::ED25519 => 5,
            DigestType::SHA512 => 255,
        }
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::io::{Read, Write};
use std::net;
use std::net::TcpStream;
use std::io::{ErrorKind};
use openssl::ssl::{SslStream, SslConnector,HandshakeError};

pub struct Transport {
    ssl: SslStream<TcpStream>,
    connector: SslConnector
}

impl Transport {
    pub fn new(addr: &str, connector: & SslConnector) -> io::Result<Transport> {
        let a: Vec<&str> = addr.split(':').collect();
        let res:Result< Result<Transport,HandshakeError<net::TcpStream>>,io::Error> =  net::TcpStream::connect(addr)
            .map(|socket|
                 connector.connect(a[0], socket)
                 .map(|sslsocket|
                    Transport {
                        ssl: sslsocket,
                        connector: connector.clone()
                    }
                 )
            );

        res.and_then(|res: Result<Transport,HandshakeError<net::TcpStream>>| {
        // transform `Ok(Result<Transport,HandshakeError<net::TcpStream>>)` into `Ok(Result<Transport, io::Error>)`
        res
        // transform n to Transport
        .map(|n: Transport| n )
        // transform `HandshakeError` into `'io::Error`
        .map_err(|e| io::Error::new(io::ErrorKind::Other,e))

        })
    }

    /// In opposite to `TcpStream`'s `try_clone` this method
    /// creates absolutely new connection - it gets an address
    /// of a peer from `Transport` and creates a new encrypted
    /// connection with a new TCP stream under hood.
    pub fn try_clone(&self) -> io::Result<Transport> {
        let addr = try!(self.ssl.get_ref().peer_addr());
        let ip_string = format!("{}", addr.ip());

        let res =  net::TcpStream::connect(addr)
            .map(|socket|
                  self.connector.connect(ip_string.as_str(), socket)
                      .map(|sslsocket| Transport {ssl: sslsocket, connector: self.connector.clone()}));

        res.and_then(|res| {
            res.map(|n: Transport| n ).map_err(|e| io::Error::new(io::ErrorKind::Other,e))
        })
    }

    pub fn close(&mut self, _close: net::Shutdown) -> io::Result<()> {
        self.ssl.shutdown().unwrap();
        return Ok(());
    }
}

impl Read for Transport {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        return self.ssl.read(buf);
    }
}

impl Write for Transport {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        return self.ssl.write(buf);
    }

    fn flush(&mut self) -> io::Result<()> {
        return self.ssl.flush();
    }
}
<commit_msg>one more unwrap removed<commit_after>use std::io;
use std::io::{Read, Write};
use std::net;
use std::net::TcpStream;
use openssl::ssl::{SslStream, SslConnector,HandshakeError};

pub struct Transport {
    ssl: SslStream<TcpStream>,
    connector: SslConnector
}

impl Transport {
    pub fn new(addr: &str, connector: & SslConnector) -> io::Result<Transport> {
        let a: Vec<&str> = addr.split(':').collect();
        let res:Result< Result<Transport,HandshakeError<net::TcpStream>>,io::Error> =  net::TcpStream::connect(addr)
            .map(|socket|
                 connector.connect(a[0], socket)
                 .map(|sslsocket|
                    Transport {
                        ssl: sslsocket,
                        connector: connector.clone()
                    }
                 )
            );

        res.and_then(|res: Result<Transport,HandshakeError<net::TcpStream>>| {
        // transform `Ok(Result<Transport,HandshakeError<net::TcpStream>>)` into `Ok(Result<Transport, io::Error>)`
        res
        // transform n to Transport
        .map(|n: Transport| n )
        // transform `HandshakeError` into `'io::Error`
        .map_err(|e| io::Error::new(io::ErrorKind::Other,e))

        })
    }

    /// In opposite to `TcpStream`'s `try_clone` this method
    /// creates absolutely new connection - it gets an address
    /// of a peer from `Transport` and creates a new encrypted
    /// connection with a new TCP stream under hood.
    pub fn try_clone(&self) -> io::Result<Transport> {
        let addr = try!(self.ssl.get_ref().peer_addr());
        let ip_string = format!("{}", addr.ip());

        let res =  net::TcpStream::connect(addr)
            .map(|socket|
                  self.connector.connect(ip_string.as_str(), socket)
                      .map(|sslsocket| Transport {ssl: sslsocket, connector: self.connector.clone()}));

        res.and_then(|res| {
            res.map(|n: Transport| n ).map_err(|e| io::Error::new(io::ErrorKind::Other,e))
        })
    }

    pub fn close(&mut self, _close: net::Shutdown) -> io::Result<()> {
        return self.ssl.shutdown().map_err(|e| io::Error::new(io::ErrorKind::Other,e)).and_then(|_| Ok(()));
    }
}

impl Read for Transport {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        return self.ssl.read(buf);
    }
}

impl Write for Transport {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        return self.ssl.write(buf);
    }

    fn flush(&mut self) -> io::Result<()> {
        return self.ssl.flush();
    }
}
<|endoftext|>


<commit_before>use std::cmp::max;
use std::f32::consts::PI;
use std::num::{signum, abs};
use calx::V2;

pub trait HexGeom {
    /// Hex distance represented by a vector.
    fn hex_dist(&self) -> int;

    /// The hexagonal base direction closest to this vector.
    fn dir6_towards(&self) -> V2<int>;
}

/// Hex grid geometry for vectors.
impl HexGeom for V2<int> {
    fn hex_dist(&self) -> int {
        let xd = self.0;
        let yd = self.1;
        if signum(xd) == signum(yd) {
            max(abs(xd), abs(yd))
        } else {
            abs(xd) + abs(yd)
        }
    }

    fn dir6_towards(&self) -> V2<int> {
        let hexadecant = {
            let width = PI / 8.0;
            let mut radian = (self.0 as f32).atan2(-self.1 as f32);
            if radian < 0.0 { radian += 2.0 * PI }
            (radian / width).floor() as int
        };

        DIR6[match hexadecant {
            14 | 15 => 0,
            0 | 1 | 2 | 3 => 1,
            4 | 5 => 2,
            6 | 7 => 3,
            8 | 9 | 10 | 11 => 4,
            12 | 13 => 5,
            _ => fail!("Bad hexadecant")
        }]
    }
}

/// The six directions of a hex grid in the default order.
pub static DIR6: [V2<int>, ..6] = [
    V2(-1, -1),
    V2( 0, -1),
    V2( 1,  0),
    V2( 1,  1),
    V2( 0,  1),
    V2(-1,  0),
];

/// The eight directions of a rectangle grid in the default order.
pub static DIR8: [V2<int>, ..8] = [
    V2(-1, -1),
    V2( 0, -1),
    V2( 1, -1),
    V2( 1,  0),
    V2( 1,  1),
    V2( 0,  1),
    V2(-1,  1),
    V2(-1,  0),
];
<commit_msg>Fix HexGeom doc comment placement<commit_after>use std::cmp::max;
use std::f32::consts::PI;
use std::num::{signum, abs};
use calx::V2;

/// Hex grid geometry for vectors.
pub trait HexGeom {
    /// Hex distance represented by a vector.
    fn hex_dist(&self) -> int;

    /// The hexagonal base direction closest to this vector.
    fn dir6_towards(&self) -> V2<int>;
}

impl HexGeom for V2<int> {
    fn hex_dist(&self) -> int {
        let xd = self.0;
        let yd = self.1;
        if signum(xd) == signum(yd) {
            max(abs(xd), abs(yd))
        } else {
            abs(xd) + abs(yd)
        }
    }

    fn dir6_towards(&self) -> V2<int> {
        let hexadecant = {
            let width = PI / 8.0;
            let mut radian = (self.0 as f32).atan2(-self.1 as f32);
            if radian < 0.0 { radian += 2.0 * PI }
            (radian / width).floor() as int
        };

        DIR6[match hexadecant {
            14 | 15 => 0,
            0 | 1 | 2 | 3 => 1,
            4 | 5 => 2,
            6 | 7 => 3,
            8 | 9 | 10 | 11 => 4,
            12 | 13 => 5,
            _ => fail!("Bad hexadecant")
        }]
    }
}

/// The six directions of a hex grid in the default order.
pub static DIR6: [V2<int>, ..6] = [
    V2(-1, -1),
    V2( 0, -1),
    V2( 1,  0),
    V2( 1,  1),
    V2( 0,  1),
    V2(-1,  0),
];

/// The eight directions of a rectangle grid in the default order.
pub static DIR8: [V2<int>, ..8] = [
    V2(-1, -1),
    V2( 0, -1),
    V2( 1, -1),
    V2( 1,  0),
    V2( 1,  1),
    V2( 0,  1),
    V2(-1,  1),
    V2(-1,  0),
];
<|endoftext|>


<commit_before>use termbox_simple::Termbox;
use term_input::Key;

use std::convert::From;
use std::rc::Rc;

use time::Tm;
use time;

use config::Style;
use config;
use trie::Trie;
use tui::exit_dialogue::ExitDialogue;
use tui::msg_area::MsgArea;
use tui::termbox;
use tui::text_field::TextField;
use tui::widget::{WidgetRet, Widget};

/// A messaging screen is just a text field to type messages and msg area to
/// show incoming/sent messages.
pub struct MessagingUI {
    /// Incoming and sent messages appear
    msg_area: MsgArea,

    /// Stacked user input fields. Topmost one handles keypresses.
    input_field: Vec<Box<Widget>>,

    width: i32,
    height: i32,

    // All nicks in the channel. Need to keep this up-to-date to be able to
    // properly highlight mentions.
    //
    // Rc to be able to share with dynamic messages.
    nicks: Rc<Trie>,

    current_nick: Option<Rc<String>>,
    draw_current_nick: bool,

    last_activity_line: Option<ActivityLine>,
    last_activity_ts: Option<Timestamp>,
}

/// Like `time::Tm`, but we only care about hour and minute parts.
#[derive(PartialEq, Eq, Clone, Copy)]
pub struct Timestamp {
    hour: i32,
    min: i32,
}

impl Timestamp {
    pub fn now() -> Timestamp {
        Timestamp::from(time::now())
    }

    fn stamp(&self, msg_area: &mut MsgArea) {
        msg_area.set_style(config::TIMESTAMP);
        msg_area.add_text(&format!("{:02}:{:02} ", self.hour, self.min));
    }
}

impl From<Tm> for Timestamp {
    fn from(tm: Tm) -> Timestamp {
        Timestamp { hour: tm.tm_hour, min: tm.tm_min }
    }
}

/// An activity line is just a line that we update on joins / leaves /
/// disconnects. We group activities that happen in the same minute to avoid
/// redundantly showing lines.
struct ActivityLine {
    ts: Timestamp,
    line_idx: usize,
}

impl MessagingUI {
    pub fn new(width : i32, height : i32) -> MessagingUI {
        MessagingUI {
            msg_area: MsgArea::new(width, height - 1),
            input_field: vec![Box::new(TextField::new(width))],
            width: width,
            height: height,
            nicks: Rc::new(Trie::new()),
            current_nick: None,
            draw_current_nick: true,
            last_activity_line: None,
            last_activity_ts: None,
        }
    }

    pub fn set_nick(&mut self, nick: Rc<String>) {
        self.current_nick = Some(nick);
    }

    pub fn get_nick(&self) -> Option<Rc<String>> {
        self.current_nick.clone()
    }

    pub fn draw(&self, tb: &mut Termbox, pos_x: i32, pos_y: i32) {
        self.msg_area.draw(tb, pos_x, pos_y);

        if let &Some(ref nick) = &self.current_nick {
            if self.draw_current_nick {
                let nick_color = self.get_nick_color(nick);
                let style = Style { fg: nick_color as u16, bg: config::USER_MSG.bg };
                termbox::print_chars(
                    tb,
                    pos_x,
                    pos_y + self.height - 1,
                    style,
                    &mut nick.chars());
                tb.change_cell(
                    pos_x + nick.len() as i32,
                    pos_y + self.height - 1,
                    ':',
                    config::USER_MSG.fg | config::TB_BOLD,
                    config::USER_MSG.bg);
                self.input_field.draw(
                    tb,
                    pos_x + nick.len() as i32 + 2,
                    pos_y + self.height - 1);
            } else {
                self.input_field.draw(tb, pos_x, pos_y + self.height - 1);
            }
        } else {
            self.input_field.draw(tb, pos_x, pos_y + self.height - 1);
        }
    }

    pub fn keypressed(&mut self, key : Key) -> WidgetRet {
        match key {
            Key::Ctrl('c') => {
                self.toggle_exit_dialogue();
                WidgetRet::KeyHandled
            },

            Key::Ctrl('u') => {
                self.msg_area.page_up();
                WidgetRet::KeyHandled
            },

            Key::Ctrl('d') => {
                self.msg_area.page_down();
                WidgetRet::KeyHandled
            },

            Key::PageUp => {
                self.msg_area.page_up();
                WidgetRet::KeyHandled
            },

            Key::PageDown => {
                self.msg_area.page_down();
                WidgetRet::KeyHandled
            },

            Key::ShiftUp => {
                self.msg_area.scroll_up();
                WidgetRet::KeyHandled
            },

            Key::ShiftDown => {
                self.msg_area.scroll_down();
                WidgetRet::KeyHandled
            },

            Key::Tab => {
                self.input_field.event(Box::new(self.nicks.clone()));
                WidgetRet::KeyHandled
            },

            key => {
                match self.input_field.keypressed(key) {
                    WidgetRet::Remove => {
                        self.input_field.pop();
                        WidgetRet::KeyHandled
                    },
                    ret => ret,
                }
            },
        }
    }

    pub fn resize(&mut self, width: i32, height: i32) {
        self.width = width;
        self.height = height;
        self.msg_area.resize(width, height - 1);

        let nick_width = match &self.current_nick {
            &None =>
                0,
            &Some(ref rc) =>
                // +2 for ": "
                rc.len() as i32 + 2,
        };

        self.draw_current_nick =
            (nick_width as f32) <= (width as f32) * (30f32 / 100f32);

        let widget_width =
            if self.draw_current_nick { width - nick_width } else { width };

        for w in &mut self.input_field {
            w.resize(widget_width, 1);
        }
    }

    fn toggle_exit_dialogue(&mut self) {
        assert!(self.input_field.len() > 0);
        // FIXME: This is a bit too fragile I think. Since we only stack an exit
        // dialogue on top of the input field at the moment, checking the len()
        // is fine. If we decide to stack more stuff it'll break.
        if self.input_field.len() == 1 {
            self.input_field.push(Box::new(ExitDialogue::new(self.width)));
        } else {
            self.input_field.pop();
        }
    }
}

////////////////////////////////////////////////////////////////////////////////
// Adding new messages

impl MessagingUI {

    fn add_timestamp(&mut self, ts: Timestamp) {
        if let Some(ts_) = self.last_activity_ts {
            if ts_ != ts {
                ts.stamp(&mut self.msg_area);
            }
        } else {
            ts.stamp(&mut self.msg_area);

        }
        self.last_activity_ts = Some(ts);
    }

    pub fn show_topic(&mut self, topic: &str, ts: Timestamp) {
        self.add_timestamp(ts);

        self.msg_area.set_style(config::TOPIC);
        self.msg_area.add_text(&format!("Channel topic is: \"{}\"", topic));

        self.msg_area.flush_line();
    }

    pub fn add_client_err_msg(&mut self, msg : &str) {
        self.reset_activity_line();

        self.msg_area.set_style(config::ERR_MSG);
        self.msg_area.add_text(msg);
        self.msg_area.flush_line();
    }

    pub fn add_client_msg(&mut self, msg : &str) {
        self.reset_activity_line();

        self.msg_area.set_style(config::USER_MSG);
        self.msg_area.add_text(msg);
        self.msg_area.flush_line();
        self.reset_activity_line();
    }

    pub fn add_privmsg(&mut self, sender: &str, msg: &str, ts: Timestamp, highlight: bool) {
        self.reset_activity_line();
        self.add_timestamp(ts);

        {
            let nick_color = self.get_nick_color(sender);
            let style = Style { fg: nick_color as u16, bg: config::USER_MSG.bg };
            self.msg_area.set_style(style);
            self.msg_area.add_text(sender);
        }

        self.msg_area.set_style(Style { fg: config::USER_MSG.fg | config::TB_BOLD, bg: config::USER_MSG.bg });
        self.msg_area.add_text(": ");

        self.msg_area.set_style(
            if highlight {
                config::HIGHLIGHT
            } else {
                config::USER_MSG
            });

        self.msg_area.add_text(msg);
        self.msg_area.flush_line();
    }

    pub fn add_msg(&mut self, msg: &str, ts: Timestamp) {
        self.reset_activity_line();

        self.add_timestamp(ts);
        self.msg_area.set_style(config::USER_MSG);
        self.msg_area.add_text(msg);
        self.msg_area.flush_line();
    }

    pub fn add_err_msg(&mut self, msg: &str, ts: Timestamp) {
        self.reset_activity_line();

        self.add_timestamp(ts);
        self.msg_area.set_style(config::ERR_MSG);
        self.msg_area.add_text(msg);
        self.msg_area.flush_line();
    }

    fn get_nick_color(&self, sender: &str) -> u8 {
        // Anything works as long as it's fast
        let mut hash: usize = 5381;
        for c in sender.chars() {
            hash = hash.wrapping_mul(33).wrapping_add(c as usize);
        }
        config::NICK_COLORS[hash % config::NICK_COLORS.len()]
    }
}

////////////////////////////////////////////////////////////////////////////////
// Keeping nick list up-to-date

impl MessagingUI {
    pub fn join(&mut self, nick: &str, ts: Option<Timestamp>) {
        Rc::get_mut(&mut self.nicks).unwrap().insert(nick);

        if let Some(ts) = ts {
            let line_idx = self.get_activity_line_idx(ts);
            self.msg_area.modify_line(line_idx, |line| {
                line.set_style(config::JOIN);
                line.add_char('+');
                line.set_style(config::FADED);
                line.add_text(nick);
                line.add_char(' ');
            });
        }
    }

    pub fn part(&mut self, nick: &str, ts: Option<Timestamp>) {
        Rc::get_mut(&mut self.nicks).unwrap().remove(nick);

        if let Some(ts) = ts {
            let line_idx = self.get_activity_line_idx(ts);
            self.msg_area.modify_line(line_idx, |line| {
                line.set_style(config::PART);
                line.add_char('-');
                line.set_style(config::FADED);
                line.add_text(nick);
                line.add_char(' ');
            });
        }
    }

    pub fn nick(&mut self, old_nick: &str, new_nick: &str, ts: Timestamp) {
        Rc::get_mut(&mut self.nicks).unwrap().remove(old_nick);
        Rc::get_mut(&mut self.nicks).unwrap().insert(new_nick);

        let line_idx = self.get_activity_line_idx(ts);
        self.msg_area.modify_line(line_idx, |line| {
            line.set_style(config::FADED);
            line.add_text(old_nick);
            line.set_style(config::NICK);
            line.add_text(">");
            line.set_style(config::FADED);
            line.add_text(new_nick);
            line.add_char(' ');
        });
    }

    pub fn has_nick(&self, nick : &str) -> bool {
        self.nicks.contains(nick)
    }

    fn reset_activity_line(&mut self) {
        self.last_activity_line = None;
    }

    fn get_activity_line_idx(&mut self, ts: Timestamp) -> usize {
        // borrow checker strikes again
        if let Some(ref mut l) = self.last_activity_line {
            if l.ts == ts {
                return l.line_idx;
            }
        }

        self.add_timestamp(ts);
        let line_idx = self.msg_area.flush_line();
        self.last_activity_line = Some(ActivityLine {
            ts: ts,
            line_idx: line_idx,
        });
        line_idx
    }
}
<commit_msg>Remove quotes etc. in topic line<commit_after>use termbox_simple::Termbox;
use term_input::Key;

use std::convert::From;
use std::rc::Rc;

use time::Tm;
use time;

use config::Style;
use config;
use trie::Trie;
use tui::exit_dialogue::ExitDialogue;
use tui::msg_area::MsgArea;
use tui::termbox;
use tui::text_field::TextField;
use tui::widget::{WidgetRet, Widget};

/// A messaging screen is just a text field to type messages and msg area to
/// show incoming/sent messages.
pub struct MessagingUI {
    /// Incoming and sent messages appear
    msg_area: MsgArea,

    /// Stacked user input fields. Topmost one handles keypresses.
    input_field: Vec<Box<Widget>>,

    width: i32,
    height: i32,

    // All nicks in the channel. Need to keep this up-to-date to be able to
    // properly highlight mentions.
    //
    // Rc to be able to share with dynamic messages.
    nicks: Rc<Trie>,

    current_nick: Option<Rc<String>>,
    draw_current_nick: bool,

    last_activity_line: Option<ActivityLine>,
    last_activity_ts: Option<Timestamp>,
}

/// Like `time::Tm`, but we only care about hour and minute parts.
#[derive(PartialEq, Eq, Clone, Copy)]
pub struct Timestamp {
    hour: i32,
    min: i32,
}

impl Timestamp {
    pub fn now() -> Timestamp {
        Timestamp::from(time::now())
    }

    fn stamp(&self, msg_area: &mut MsgArea) {
        msg_area.set_style(config::TIMESTAMP);
        msg_area.add_text(&format!("{:02}:{:02} ", self.hour, self.min));
    }
}

impl From<Tm> for Timestamp {
    fn from(tm: Tm) -> Timestamp {
        Timestamp { hour: tm.tm_hour, min: tm.tm_min }
    }
}

/// An activity line is just a line that we update on joins / leaves /
/// disconnects. We group activities that happen in the same minute to avoid
/// redundantly showing lines.
struct ActivityLine {
    ts: Timestamp,
    line_idx: usize,
}

impl MessagingUI {
    pub fn new(width : i32, height : i32) -> MessagingUI {
        MessagingUI {
            msg_area: MsgArea::new(width, height - 1),
            input_field: vec![Box::new(TextField::new(width))],
            width: width,
            height: height,
            nicks: Rc::new(Trie::new()),
            current_nick: None,
            draw_current_nick: true,
            last_activity_line: None,
            last_activity_ts: None,
        }
    }

    pub fn set_nick(&mut self, nick: Rc<String>) {
        self.current_nick = Some(nick);
    }

    pub fn get_nick(&self) -> Option<Rc<String>> {
        self.current_nick.clone()
    }

    pub fn draw(&self, tb: &mut Termbox, pos_x: i32, pos_y: i32) {
        self.msg_area.draw(tb, pos_x, pos_y);

        if let &Some(ref nick) = &self.current_nick {
            if self.draw_current_nick {
                let nick_color = self.get_nick_color(nick);
                let style = Style { fg: nick_color as u16, bg: config::USER_MSG.bg };
                termbox::print_chars(
                    tb,
                    pos_x,
                    pos_y + self.height - 1,
                    style,
                    &mut nick.chars());
                tb.change_cell(
                    pos_x + nick.len() as i32,
                    pos_y + self.height - 1,
                    ':',
                    config::USER_MSG.fg | config::TB_BOLD,
                    config::USER_MSG.bg);
                self.input_field.draw(
                    tb,
                    pos_x + nick.len() as i32 + 2,
                    pos_y + self.height - 1);
            } else {
                self.input_field.draw(tb, pos_x, pos_y + self.height - 1);
            }
        } else {
            self.input_field.draw(tb, pos_x, pos_y + self.height - 1);
        }
    }

    pub fn keypressed(&mut self, key : Key) -> WidgetRet {
        match key {
            Key::Ctrl('c') => {
                self.toggle_exit_dialogue();
                WidgetRet::KeyHandled
            },

            Key::Ctrl('u') => {
                self.msg_area.page_up();
                WidgetRet::KeyHandled
            },

            Key::Ctrl('d') => {
                self.msg_area.page_down();
                WidgetRet::KeyHandled
            },

            Key::PageUp => {
                self.msg_area.page_up();
                WidgetRet::KeyHandled
            },

            Key::PageDown => {
                self.msg_area.page_down();
                WidgetRet::KeyHandled
            },

            Key::ShiftUp => {
                self.msg_area.scroll_up();
                WidgetRet::KeyHandled
            },

            Key::ShiftDown => {
                self.msg_area.scroll_down();
                WidgetRet::KeyHandled
            },

            Key::Tab => {
                self.input_field.event(Box::new(self.nicks.clone()));
                WidgetRet::KeyHandled
            },

            key => {
                match self.input_field.keypressed(key) {
                    WidgetRet::Remove => {
                        self.input_field.pop();
                        WidgetRet::KeyHandled
                    },
                    ret => ret,
                }
            },
        }
    }

    pub fn resize(&mut self, width: i32, height: i32) {
        self.width = width;
        self.height = height;
        self.msg_area.resize(width, height - 1);

        let nick_width = match &self.current_nick {
            &None =>
                0,
            &Some(ref rc) =>
                // +2 for ": "
                rc.len() as i32 + 2,
        };

        self.draw_current_nick =
            (nick_width as f32) <= (width as f32) * (30f32 / 100f32);

        let widget_width =
            if self.draw_current_nick { width - nick_width } else { width };

        for w in &mut self.input_field {
            w.resize(widget_width, 1);
        }
    }

    fn toggle_exit_dialogue(&mut self) {
        assert!(self.input_field.len() > 0);
        // FIXME: This is a bit too fragile I think. Since we only stack an exit
        // dialogue on top of the input field at the moment, checking the len()
        // is fine. If we decide to stack more stuff it'll break.
        if self.input_field.len() == 1 {
            self.input_field.push(Box::new(ExitDialogue::new(self.width)));
        } else {
            self.input_field.pop();
        }
    }
}

////////////////////////////////////////////////////////////////////////////////
// Adding new messages

impl MessagingUI {

    fn add_timestamp(&mut self, ts: Timestamp) {
        if let Some(ts_) = self.last_activity_ts {
            if ts_ != ts {
                ts.stamp(&mut self.msg_area);
            }
        } else {
            ts.stamp(&mut self.msg_area);

        }
        self.last_activity_ts = Some(ts);
    }

    pub fn show_topic(&mut self, topic: &str, ts: Timestamp) {
        self.add_timestamp(ts);

        self.msg_area.set_style(config::TOPIC);
        self.msg_area.add_text(topic);

        self.msg_area.flush_line();
    }

    pub fn add_client_err_msg(&mut self, msg : &str) {
        self.reset_activity_line();

        self.msg_area.set_style(config::ERR_MSG);
        self.msg_area.add_text(msg);
        self.msg_area.flush_line();
    }

    pub fn add_client_msg(&mut self, msg : &str) {
        self.reset_activity_line();

        self.msg_area.set_style(config::USER_MSG);
        self.msg_area.add_text(msg);
        self.msg_area.flush_line();
        self.reset_activity_line();
    }

    pub fn add_privmsg(&mut self, sender: &str, msg: &str, ts: Timestamp, highlight: bool) {
        self.reset_activity_line();
        self.add_timestamp(ts);

        {
            let nick_color = self.get_nick_color(sender);
            let style = Style { fg: nick_color as u16, bg: config::USER_MSG.bg };
            self.msg_area.set_style(style);
            self.msg_area.add_text(sender);
        }

        self.msg_area.set_style(Style { fg: config::USER_MSG.fg | config::TB_BOLD, bg: config::USER_MSG.bg });
        self.msg_area.add_text(": ");

        self.msg_area.set_style(
            if highlight {
                config::HIGHLIGHT
            } else {
                config::USER_MSG
            });

        self.msg_area.add_text(msg);
        self.msg_area.flush_line();
    }

    pub fn add_msg(&mut self, msg: &str, ts: Timestamp) {
        self.reset_activity_line();

        self.add_timestamp(ts);
        self.msg_area.set_style(config::USER_MSG);
        self.msg_area.add_text(msg);
        self.msg_area.flush_line();
    }

    pub fn add_err_msg(&mut self, msg: &str, ts: Timestamp) {
        self.reset_activity_line();

        self.add_timestamp(ts);
        self.msg_area.set_style(config::ERR_MSG);
        self.msg_area.add_text(msg);
        self.msg_area.flush_line();
    }

    fn get_nick_color(&self, sender: &str) -> u8 {
        // Anything works as long as it's fast
        let mut hash: usize = 5381;
        for c in sender.chars() {
            hash = hash.wrapping_mul(33).wrapping_add(c as usize);
        }
        config::NICK_COLORS[hash % config::NICK_COLORS.len()]
    }
}

////////////////////////////////////////////////////////////////////////////////
// Keeping nick list up-to-date

impl MessagingUI {
    pub fn join(&mut self, nick: &str, ts: Option<Timestamp>) {
        Rc::get_mut(&mut self.nicks).unwrap().insert(nick);

        if let Some(ts) = ts {
            let line_idx = self.get_activity_line_idx(ts);
            self.msg_area.modify_line(line_idx, |line| {
                line.set_style(config::JOIN);
                line.add_char('+');
                line.set_style(config::FADED);
                line.add_text(nick);
                line.add_char(' ');
            });
        }
    }

    pub fn part(&mut self, nick: &str, ts: Option<Timestamp>) {
        Rc::get_mut(&mut self.nicks).unwrap().remove(nick);

        if let Some(ts) = ts {
            let line_idx = self.get_activity_line_idx(ts);
            self.msg_area.modify_line(line_idx, |line| {
                line.set_style(config::PART);
                line.add_char('-');
                line.set_style(config::FADED);
                line.add_text(nick);
                line.add_char(' ');
            });
        }
    }

    pub fn nick(&mut self, old_nick: &str, new_nick: &str, ts: Timestamp) {
        Rc::get_mut(&mut self.nicks).unwrap().remove(old_nick);
        Rc::get_mut(&mut self.nicks).unwrap().insert(new_nick);

        let line_idx = self.get_activity_line_idx(ts);
        self.msg_area.modify_line(line_idx, |line| {
            line.set_style(config::FADED);
            line.add_text(old_nick);
            line.set_style(config::NICK);
            line.add_text(">");
            line.set_style(config::FADED);
            line.add_text(new_nick);
            line.add_char(' ');
        });
    }

    pub fn has_nick(&self, nick : &str) -> bool {
        self.nicks.contains(nick)
    }

    fn reset_activity_line(&mut self) {
        self.last_activity_line = None;
    }

    fn get_activity_line_idx(&mut self, ts: Timestamp) -> usize {
        // borrow checker strikes again
        if let Some(ref mut l) = self.last_activity_line {
            if l.ts == ts {
                return l.line_idx;
            }
        }

        self.add_timestamp(ts);
        let line_idx = self.msg_area.flush_line();
        self.last_activity_line = Some(ActivityLine {
            ts: ts,
            line_idx: line_idx,
        });
        line_idx
    }
}
<|endoftext|>


<commit_before>use nom::{self, IResult, Needed};

use std::io::{self, Read};
use std::ptr;
use std::cmp;

use super::StreamProducer;

/// Represent the different kinds of errors.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum ErrorKind {
  /// Error from I/O.
  IO(io::ErrorKind),
  /// A parser stopped midway and need more bytes to consume.
  Incomplete(usize),
  /// A parser has completes and there is still more bytes to consume.
  Continue,
  /// A parser has completes and there is no more bytes to consume.
  EndOfInput,
  /// A non-specified error.
  Unknown,
  // Parser Error
  /// Failed parsing the "fLaC" header token.
  HeaderParser,
  /// Failed parsing a metadata header.
  MetadataHeaderParser,
  /// Failed parsing the metadata block `StreamInfo`.
  StreamInfoParser,
  /// Failed parsing the metadata block `Padding`.
  PaddingParser,
  /// Failed parsing the metadata block `Application`.
  ApplicationParser,
  /// Failed parsing the metadata block `SeekTable`.
  SeekTableParser,
  /// Failed parsing the metadata block `VorbisComment`.
  VorbisCommentParser,
  /// Failed parsing the metadata block `CueSheet`.
  CueSheetParser,
  /// Failed parsing the metadata block `Picture`.
  PictureParser,
  /// Failed parsing the metadata block `Unknown`.
  UnknownParser,
  /// Failed parsing the blocking strategy inside the frame header.
  BlockingStrategyParser,
  /// Failed parsing the blocking sample inside the frame header.
  BlockingSampleParser,
  /// Failed parsing the channel bits inside the frame header.
  ChannelBitsParser,
  /// Failed parsing the UTF-8 header inside the frame header.
  UTF8HeaderParser,
  /// Failed parsing the UTF-8 body inside the frame header.
  UTF8BodyParser,
  /// Failed parsing the CRC-8 inside the frame header.
  CRC8Parser,
  /// Failed parsing the frame footer, also known as the CRC-16.
  FrameFooterParser,
  SubframeHeaderParser,
  LeadingZerosParser,
  ConstantParser,
  VerbatimParser,
  FixedParser,
  LPCParser,
  // Invalid Error
  /// A block type, base on the number, that is outside the range (0-126).
  InvalidBlockType,
  /// An incorrect sync code with the frame header.
  InvalidSyncCode,
  /// A block sample that could cause sync-fooling.
  InvalidBlockSample,
  /// One or more bits are reserved values.
  InvalidChannelBits,
  /// An error occurred in building the UTF-8 value.
  InvalidUTF8,
  /// The stored CRC-8 doesn't match the one generated from the bytes within
  /// the frame header.
  InvalidCRC8,
  /// The stored CRC-16 doesn't match the one generated from the bytes
  /// within the entire frame.
  InvalidCRC16,
  InvalidSubframeHeader,
  // Not Found
  /// Some metadata block was not found with a specific filter.
  NotFound,
}

/// Structure that hold a slice of bytes.
pub struct ByteStream<'a> {
  offset: usize,
  bytes: &'a [u8],
}

impl<'a> ByteStream<'a> {
  /// Construct a `ByteStream` based on the passed in byte slice.
  pub fn new(bytes: &'a [u8]) -> Self {
    ByteStream {
      offset: 0,
      bytes: bytes,
    }
  }

  /// Return the number of bytes that haven't been consumed yet.
  #[inline]
  pub fn len(&self) -> usize {
    self.bytes.len() - self.offset
  }

  /// Return true if the stream contains no more bytes.
  #[inline]
  pub fn is_empty(&self) -> bool {
    self.len() == 0
  }
}

impl<'a> StreamProducer for ByteStream<'a> {
  fn parse<F, T>(&mut self, f: F) -> Result<T, ErrorKind>
   where F: FnOnce(&[u8]) -> IResult<&[u8], T, ErrorKind> {
    if self.is_empty() {
      return Err(ErrorKind::EndOfInput);
    }

    match f(&self.bytes[self.offset..]) {
      IResult::Done(i, o)    => {
        self.offset += self.len() - i.len();

        Ok(o)
      }
      IResult::Incomplete(n) => {
        let mut needed = self.len();

        if let Needed::Size(size) = n {
          needed = size;
        }

        Err(ErrorKind::Incomplete(needed))
      }
      IResult::Error(e)      => {
        match e {
          nom::Err::Code(k)               |
          nom::Err::Node(k, _)            |
          nom::Err::Position(k, _)        |
          nom::Err::NodePosition(k, _, _) => {
            if let nom::ErrorKind::Custom(kind) = k {
              Err(kind)
            } else {
              Err(ErrorKind::Unknown)
            }
          }
        }
      },
    }
  }
}

// Growable buffer of bytes.
//
// Mainly used to the `ReadStream` structure but can be used seperately for
// manually filling with some `Read` source.
pub struct Buffer {
  data: Vec<u8>,
  filled: usize,
  offset: usize,
}

impl Buffer {
  // Default constructor for `Buffer`
  pub fn new() -> Self {
    Self::with_capacity(1024)
  }

  // Explicitly set the buffer capacity.
  pub fn with_capacity(capacity: usize) -> Self {
    let mut buffer = Vec::with_capacity(capacity);

    unsafe {
      buffer.set_len(capacity);
    }

    Buffer {
      data: buffer,
      filled: 0,
      offset: 0,
    }
  }

  // Return the number of read bytes that haven't been consumed yet.
  #[inline]
  pub fn len(&self) -> usize {
    self.filled - self.offset
  }

  // Return true if buffer contains no more bytes.
  #[inline]
  pub fn is_empty(&self) -> bool {
    self.len() == 0
  }

  // The set length of the unlining buffer.
  #[inline]
  pub fn capacity(&self) -> usize {
    self.data.len()
  }

  // Return a reference to the slice of unread bytes.
  pub fn as_slice(&self) -> &[u8] {
    &self.data[self.offset..self.filled]
  }

  // Fill the buffer with bytes from a `Read` source.
  pub fn fill<R: Read>(&mut self, reader: &mut R) -> io::Result<usize> {
    reader.read(&mut self.data[self.filled..]).map(|consumed| {
      self.filled += consumed;

      consumed
    })
  }

  // Resize the current buffer
  //
  // This will only allocate data when the size requests is larger than the
  // current capacity of the buffer, otherwise it moves the currently filled
  // data to the beginning of the buffer.
  pub fn resize(&mut self, size: usize) {
    if size > self.data.capacity() {
      self.data.reserve(size);

      let capacity = self.data.capacity();

      unsafe {
        self.data.set_len(capacity);
      }
    }

    if self.data.len() - self.filled < size  {
      let length  = self.filled - self.offset;
      let mut_ptr = self.data.as_mut_ptr();

      unsafe {
        let offset_ptr  = self.data.as_ptr().offset(self.offset as isize);

        ptr::copy(offset_ptr, mut_ptr, length);
      }

      self.filled -= self.offset;
      self.offset  = 0;
    }
  }

  // Move the offset by the amount of consumed bytes.
  pub fn consume(&mut self, consumed: usize) {
    self.offset += consumed;
  }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum ParserState {
  Incomplete,
  EndOfInput,
}

fn fill<R: Read>(buffer: &mut Buffer, reader: &mut R, needed: usize)
                 -> io::Result<usize> {
  let mut read = 0;

  if buffer.len() < needed {
    buffer.resize(needed);

    while buffer.len() < needed {
      let size_read = try!(buffer.fill(reader));

      if size_read > 0 {
        read += size_read;
      } else {
        break;
      }
    }
  }

  Ok(read)
}

/// Structure that hold a reader for a source of bytes.
pub struct ReadStream<R: Read> {
  reader: R,
  buffer: Buffer,
  needed: usize,
  state: ParserState,
}

impl<R> ReadStream<R> where R: Read {
  /// Constructor for `ReadStream` based on a `Read` source.
  pub fn new(reader: R) -> Self {
    ReadStream {
      reader: reader,
      buffer: Buffer::new(),
      needed: 0,
      state: ParserState::Incomplete,
    }
  }

  // Fill the stream with bytes from a `Read` source.
  fn fill(&mut self) -> io::Result<usize> {
    let needed = cmp::max(1, self.needed);

    fill(&mut self.buffer, &mut self.reader, needed).map(|consumed| {
      if self.buffer.len() < needed {
        self.state = ParserState::EndOfInput;
      }

      consumed
    })
  }
}

fn from_iresult<T>(buffer: &Buffer, result: IResult<&[u8], T, ErrorKind>)
                   -> Result<(usize, T), ErrorKind> {
  match result {
    IResult::Done(i, o)    => Ok((buffer.len() - i.len(), o)),
    IResult::Incomplete(n) => {
      let mut needed = buffer.capacity() + 1024;

      if let Needed::Size(size) = n {
        needed = size;
      }

      Err(ErrorKind::Incomplete(needed))
    }
    IResult::Error(e)      => {
      match e {
        nom::Err::Code(k)               |
        nom::Err::Node(k, _)            |
        nom::Err::Position(k, _)        |
        nom::Err::NodePosition(k, _, _) => {
          if let nom::ErrorKind::Custom(kind) = k {
            Err(kind)
          } else {
            Err(ErrorKind::Unknown)
          }
        }
      }
    },
  }
}

impl<R> StreamProducer for ReadStream<R> where R: Read {
  fn parse<F, T>(&mut self, f: F) -> Result<T, ErrorKind>
   where F: FnOnce(&[u8]) -> IResult<&[u8], T, ErrorKind> {
    if self.state != ParserState::EndOfInput {
      try!(self.fill().map_err(|e| ErrorKind::IO(e.kind())));
    }

    let mut buffer = &mut self.buffer;

    if buffer.is_empty() {
      self.state = ParserState::EndOfInput;

      return Err(ErrorKind::EndOfInput);
    }

    let result = {
      let iresult = f(buffer.as_slice());

      from_iresult(&buffer, iresult)
    };

    match result {
      Ok((consumed, o)) => {
        buffer.consume(consumed);

        Ok(o)
      }
      Err(kind)         => {
        if let ErrorKind::Incomplete(needed) = kind {
          self.needed = needed;

          Err(ErrorKind::Continue)
        } else {
          Err(kind)
        }
      }
    }
  }
}

#[cfg(test)]
mod tests {
  use super::*;
  use utility::StreamProducer;
  use nom::{self, IResult};

  #[inline]
  fn be_u32(input: &[u8]) -> IResult<&[u8], u32, ErrorKind> {
    nom::be_u32(input).map_err(to_custom_error!(Unknown))
  }

  #[test]
  fn test_buffer() {
    let mut buffer = Buffer::new();
    let bytes      = b"Hello World";
    let mut reader = &bytes[..];

    assert!(buffer.is_empty());
    assert_eq!(buffer.capacity(), 1024);

    let bytes_read = buffer.fill(&mut reader).unwrap_or(0);
    let bytes_len  = bytes.len();

    assert_eq!(bytes_read, bytes_len);
    assert_eq!(buffer.len(), bytes_len);
    assert_eq!(buffer.as_slice(), bytes);

    buffer.resize(512);
    assert_eq!(buffer.capacity(), 1024);
  }

  #[test]
  fn test_byte_stream() {
    let bytes      = b"Hello World";
    let mut stream = ByteStream::new(bytes);

    assert_eq!(stream.len(), bytes.len());

    let result = stream.parse(be_u32).unwrap_or(0);

    assert_eq!(result, 1214606444);
    assert_eq!(stream.len(), 7);
  }

  #[test]
  fn test_read_stream() {
    let bytes      = b"Hello World";
    let mut stream = ReadStream::new(&bytes[..]);

    let result = stream.parse(be_u32).unwrap_or(0);

    assert_eq!(result, 1214606444)
  }
}
<commit_msg>Add documentation for parsers inside subframe<commit_after>use nom::{self, IResult, Needed};

use std::io::{self, Read};
use std::ptr;
use std::cmp;

use super::StreamProducer;

/// Represent the different kinds of errors.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum ErrorKind {
  /// Error from I/O.
  IO(io::ErrorKind),
  /// A parser stopped midway and need more bytes to consume.
  Incomplete(usize),
  /// A parser has completes and there is still more bytes to consume.
  Continue,
  /// A parser has completes and there is no more bytes to consume.
  EndOfInput,
  /// A non-specified error.
  Unknown,
  // Parser Error
  /// Failed parsing the "fLaC" header token.
  HeaderParser,
  /// Failed parsing a metadata header.
  MetadataHeaderParser,
  /// Failed parsing the metadata block `StreamInfo`.
  StreamInfoParser,
  /// Failed parsing the metadata block `Padding`.
  PaddingParser,
  /// Failed parsing the metadata block `Application`.
  ApplicationParser,
  /// Failed parsing the metadata block `SeekTable`.
  SeekTableParser,
  /// Failed parsing the metadata block `VorbisComment`.
  VorbisCommentParser,
  /// Failed parsing the metadata block `CueSheet`.
  CueSheetParser,
  /// Failed parsing the metadata block `Picture`.
  PictureParser,
  /// Failed parsing the metadata block `Unknown`.
  UnknownParser,
  /// Failed parsing the blocking strategy inside the frame header.
  BlockingStrategyParser,
  /// Failed parsing the blocking sample inside the frame header.
  BlockingSampleParser,
  /// Failed parsing the channel bits inside the frame header.
  ChannelBitsParser,
  /// Failed parsing the UTF-8 header inside the frame header.
  UTF8HeaderParser,
  /// Failed parsing the UTF-8 body inside the frame header.
  UTF8BodyParser,
  /// Failed parsing the CRC-8 inside the frame header.
  CRC8Parser,
  /// Failed parsing the frame footer, also known as the CRC-16.
  FrameFooterParser,
  /// Failed parsing the subframe header.
  SubframeHeaderParser,
  /// Failed parsing the leading zero for a unary value.
  LeadingZerosParser,
  /// Failed parsing a Constant subframe data.
  ConstantParser,
  /// Failed parsing a Verbatim subframe data.
  VerbatimParser,
  /// Failed parsing a Fixed subframe data.
  FixedParser,
  /// Failed parsing a LPC subframe data.
  LPCParser,
  // Invalid Error
  /// A block type, base on the number, that is outside the range (0-126).
  InvalidBlockType,
  /// An incorrect sync code with the frame header.
  InvalidSyncCode,
  /// A block sample that could cause sync-fooling.
  InvalidBlockSample,
  /// One or more bits are reserved values.
  InvalidChannelBits,
  /// An error occurred in building the UTF-8 value.
  InvalidUTF8,
  /// The stored CRC-8 doesn't match the one generated from the bytes within
  /// the frame header.
  InvalidCRC8,
  /// The stored CRC-16 doesn't match the one generated from the bytes
  /// within the entire frame.
  InvalidCRC16,
  InvalidSubframeHeader,
  // Not Found
  /// Some metadata block was not found with a specific filter.
  NotFound,
}

/// Structure that hold a slice of bytes.
pub struct ByteStream<'a> {
  offset: usize,
  bytes: &'a [u8],
}

impl<'a> ByteStream<'a> {
  /// Construct a `ByteStream` based on the passed in byte slice.
  pub fn new(bytes: &'a [u8]) -> Self {
    ByteStream {
      offset: 0,
      bytes: bytes,
    }
  }

  /// Return the number of bytes that haven't been consumed yet.
  #[inline]
  pub fn len(&self) -> usize {
    self.bytes.len() - self.offset
  }

  /// Return true if the stream contains no more bytes.
  #[inline]
  pub fn is_empty(&self) -> bool {
    self.len() == 0
  }
}

impl<'a> StreamProducer for ByteStream<'a> {
  fn parse<F, T>(&mut self, f: F) -> Result<T, ErrorKind>
   where F: FnOnce(&[u8]) -> IResult<&[u8], T, ErrorKind> {
    if self.is_empty() {
      return Err(ErrorKind::EndOfInput);
    }

    match f(&self.bytes[self.offset..]) {
      IResult::Done(i, o)    => {
        self.offset += self.len() - i.len();

        Ok(o)
      }
      IResult::Incomplete(n) => {
        let mut needed = self.len();

        if let Needed::Size(size) = n {
          needed = size;
        }

        Err(ErrorKind::Incomplete(needed))
      }
      IResult::Error(e)      => {
        match e {
          nom::Err::Code(k)               |
          nom::Err::Node(k, _)            |
          nom::Err::Position(k, _)        |
          nom::Err::NodePosition(k, _, _) => {
            if let nom::ErrorKind::Custom(kind) = k {
              Err(kind)
            } else {
              Err(ErrorKind::Unknown)
            }
          }
        }
      },
    }
  }
}

// Growable buffer of bytes.
//
// Mainly used to the `ReadStream` structure but can be used seperately for
// manually filling with some `Read` source.
pub struct Buffer {
  data: Vec<u8>,
  filled: usize,
  offset: usize,
}

impl Buffer {
  // Default constructor for `Buffer`
  pub fn new() -> Self {
    Self::with_capacity(1024)
  }

  // Explicitly set the buffer capacity.
  pub fn with_capacity(capacity: usize) -> Self {
    let mut buffer = Vec::with_capacity(capacity);

    unsafe {
      buffer.set_len(capacity);
    }

    Buffer {
      data: buffer,
      filled: 0,
      offset: 0,
    }
  }

  // Return the number of read bytes that haven't been consumed yet.
  #[inline]
  pub fn len(&self) -> usize {
    self.filled - self.offset
  }

  // Return true if buffer contains no more bytes.
  #[inline]
  pub fn is_empty(&self) -> bool {
    self.len() == 0
  }

  // The set length of the unlining buffer.
  #[inline]
  pub fn capacity(&self) -> usize {
    self.data.len()
  }

  // Return a reference to the slice of unread bytes.
  pub fn as_slice(&self) -> &[u8] {
    &self.data[self.offset..self.filled]
  }

  // Fill the buffer with bytes from a `Read` source.
  pub fn fill<R: Read>(&mut self, reader: &mut R) -> io::Result<usize> {
    reader.read(&mut self.data[self.filled..]).map(|consumed| {
      self.filled += consumed;

      consumed
    })
  }

  // Resize the current buffer
  //
  // This will only allocate data when the size requests is larger than the
  // current capacity of the buffer, otherwise it moves the currently filled
  // data to the beginning of the buffer.
  pub fn resize(&mut self, size: usize) {
    if size > self.data.capacity() {
      self.data.reserve(size);

      let capacity = self.data.capacity();

      unsafe {
        self.data.set_len(capacity);
      }
    }

    if self.data.len() - self.filled < size  {
      let length  = self.filled - self.offset;
      let mut_ptr = self.data.as_mut_ptr();

      unsafe {
        let offset_ptr  = self.data.as_ptr().offset(self.offset as isize);

        ptr::copy(offset_ptr, mut_ptr, length);
      }

      self.filled -= self.offset;
      self.offset  = 0;
    }
  }

  // Move the offset by the amount of consumed bytes.
  pub fn consume(&mut self, consumed: usize) {
    self.offset += consumed;
  }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum ParserState {
  Incomplete,
  EndOfInput,
}

fn fill<R: Read>(buffer: &mut Buffer, reader: &mut R, needed: usize)
                 -> io::Result<usize> {
  let mut read = 0;

  if buffer.len() < needed {
    buffer.resize(needed);

    while buffer.len() < needed {
      let size_read = try!(buffer.fill(reader));

      if size_read > 0 {
        read += size_read;
      } else {
        break;
      }
    }
  }

  Ok(read)
}

/// Structure that hold a reader for a source of bytes.
pub struct ReadStream<R: Read> {
  reader: R,
  buffer: Buffer,
  needed: usize,
  state: ParserState,
}

impl<R> ReadStream<R> where R: Read {
  /// Constructor for `ReadStream` based on a `Read` source.
  pub fn new(reader: R) -> Self {
    ReadStream {
      reader: reader,
      buffer: Buffer::new(),
      needed: 0,
      state: ParserState::Incomplete,
    }
  }

  // Fill the stream with bytes from a `Read` source.
  fn fill(&mut self) -> io::Result<usize> {
    let needed = cmp::max(1, self.needed);

    fill(&mut self.buffer, &mut self.reader, needed).map(|consumed| {
      if self.buffer.len() < needed {
        self.state = ParserState::EndOfInput;
      }

      consumed
    })
  }
}

fn from_iresult<T>(buffer: &Buffer, result: IResult<&[u8], T, ErrorKind>)
                   -> Result<(usize, T), ErrorKind> {
  match result {
    IResult::Done(i, o)    => Ok((buffer.len() - i.len(), o)),
    IResult::Incomplete(n) => {
      let mut needed = buffer.capacity() + 1024;

      if let Needed::Size(size) = n {
        needed = size;
      }

      Err(ErrorKind::Incomplete(needed))
    }
    IResult::Error(e)      => {
      match e {
        nom::Err::Code(k)               |
        nom::Err::Node(k, _)            |
        nom::Err::Position(k, _)        |
        nom::Err::NodePosition(k, _, _) => {
          if let nom::ErrorKind::Custom(kind) = k {
            Err(kind)
          } else {
            Err(ErrorKind::Unknown)
          }
        }
      }
    },
  }
}

impl<R> StreamProducer for ReadStream<R> where R: Read {
  fn parse<F, T>(&mut self, f: F) -> Result<T, ErrorKind>
   where F: FnOnce(&[u8]) -> IResult<&[u8], T, ErrorKind> {
    if self.state != ParserState::EndOfInput {
      try!(self.fill().map_err(|e| ErrorKind::IO(e.kind())));
    }

    let mut buffer = &mut self.buffer;

    if buffer.is_empty() {
      self.state = ParserState::EndOfInput;

      return Err(ErrorKind::EndOfInput);
    }

    let result = {
      let iresult = f(buffer.as_slice());

      from_iresult(&buffer, iresult)
    };

    match result {
      Ok((consumed, o)) => {
        buffer.consume(consumed);

        Ok(o)
      }
      Err(kind)         => {
        if let ErrorKind::Incomplete(needed) = kind {
          self.needed = needed;

          Err(ErrorKind::Continue)
        } else {
          Err(kind)
        }
      }
    }
  }
}

#[cfg(test)]
mod tests {
  use super::*;
  use utility::StreamProducer;
  use nom::{self, IResult};

  #[inline]
  fn be_u32(input: &[u8]) -> IResult<&[u8], u32, ErrorKind> {
    nom::be_u32(input).map_err(to_custom_error!(Unknown))
  }

  #[test]
  fn test_buffer() {
    let mut buffer = Buffer::new();
    let bytes      = b"Hello World";
    let mut reader = &bytes[..];

    assert!(buffer.is_empty());
    assert_eq!(buffer.capacity(), 1024);

    let bytes_read = buffer.fill(&mut reader).unwrap_or(0);
    let bytes_len  = bytes.len();

    assert_eq!(bytes_read, bytes_len);
    assert_eq!(buffer.len(), bytes_len);
    assert_eq!(buffer.as_slice(), bytes);

    buffer.resize(512);
    assert_eq!(buffer.capacity(), 1024);
  }

  #[test]
  fn test_byte_stream() {
    let bytes      = b"Hello World";
    let mut stream = ByteStream::new(bytes);

    assert_eq!(stream.len(), bytes.len());

    let result = stream.parse(be_u32).unwrap_or(0);

    assert_eq!(result, 1214606444);
    assert_eq!(stream.len(), 7);
  }

  #[test]
  fn test_read_stream() {
    let bytes      = b"Hello World";
    let mut stream = ReadStream::new(&bytes[..]);

    let result = stream.parse(be_u32).unwrap_or(0);

    assert_eq!(result, 1214606444)
  }
}
<|endoftext|>


<commit_before>macro_rules! e { ($e:expr) => { $e } }

macro_rules! sum {
    ($x:expr) => { $x };
    ($x:expr, $($y:expr),+) => { $x + sum!($($y),+) }
}

/// Macro for constructing a new vector type.
///
/// This can be used to construct fixed-sized vectors of whatever dimension
/// the user would like. While this crate only provides vectors of dimensons
/// 2 through 5, it's trivial to make vectors of arbitrary length using this
/// macro.
///
/// Another potential use of this macro is to create new vectors whose
/// subscripts have different names than those provided in this crate. The
/// vectors in `lin`  have subscripts named _x_, _y_, _z_, (as in Cartesian
/// coördinates), _w_, and _a_; but in some applications, these subscripts
/// might represent different quantities. Thus, users can use this macro to
/// create new vector types whose subscripts have names with semantic meanings
/// more appropriate to their individual use case.
///
/// # Arguments
///    - `$name`: The name of the new vector type
///    - `$dim`: the dimension (number of elements) of the new vector type
///    - `$sub`: the name of each subscript or element of the vector.
///              Note that the number of `$sub`s should be the same as the
///              length of the vector.
///
/// # Example
///   Consider the definition of `Vector3`:
///
///   ```
///   make_vector! { Vector3, length: 3, x, y, z }
///   ```
#[macro_export]
macro_rules! make_vector {
    ($name: ident, $dim:expr, $($sub: ident),+) => {
        #[cfg(not(simd))]
        #[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Debug, Default)]
        #[repr(C)]
        pub struct $name<N> {
            $(pub $sub: N),+
        }

        impl_rand! { $name, $($sub),+ }

        impl_ops! { $name, $($sub),+ }
        impl_converts! { $name, $dim }
        impl_index! { $name }

    }
}

macro_rules! impl_ops {
    ($ty: ident, $($sub: ident),+) => {
        impl_op! { Add for $ty, add, +, $($sub),+ }
        impl_op! { Sub for $ty, sub, -, $($sub),+ }
        impl_op! { Div for $ty, div, /, $($sub),+ }
        impl_op! { Rem for $ty, rem, %, $($sub),+ }

        #[cfg(features = "parallel")]
        impl<N> Mul<N> for $ty<N>
        where Self: Simdalize<Elem = N>
            , N: Mul<Output = N> {

            type Output = Self;
            fn mul(self, rhs: N) -> Output { self.simdalize() * N::splat(rhs) }
        }

        impl<N> Mul<N> for $ty<N>
        where N: Mul<Output = N>
            , N: Copy {

            type Output = Self;
            fn mul(self, rhs: N) -> Self {
                $ty { $($sub: self.$sub * rhs),+ }
            }

        }

        impl<N> Mul<$ty<N>> for $ty<N>
        where N: Mul<Output = N> + Add<Output = N>
            , N: Copy {

            type Output = N;
            fn mul(self, rhs: Self) -> N {
                sum!( $(self.$sub * rhs.$sub),+ )
            }
        }
    }
}

macro_rules! impl_op {
    ($name: ident for $ty:ident, $fun: ident, $op:tt, $($sub: ident),+) => {
        // implement the operation for vector & vectorI
        impl<N> $name<$ty<N>> for $ty<N>
        where N: $name<Output=N>
            , N: Copy {

            type Output = Self;
            fn $fun(self, rhs: Self) -> Self::Output {
                $ty { $($sub: e!(self.$sub $op rhs.$sub)),+ }
            }
        }

        // implement the operation for vector & scalar
        impl<N> $name<N> for $ty<N>
        where N: $name<Output=N>
            , N: Copy {

            type Output = Self;
            fn $fun(self, rhs: N) -> Self::Output {
                $ty { $($sub: e!(self.$sub $op rhs)),+ }
            }
        }

        #[cfg(features = "parallel")]
        impl<N> $name<N> for $ty<N>
        where Self: Simdalize<Elem = N>
            , N: $name<Output = N>
            , N: Copy {

            type Output = Self;
            fn $fun(self, rhs: N) -> Output {
                e!(self.simdalize() $op N::splat(rhs))
            }
        }

        #[cfg(features = "parallel")]
        impl<N> $name<N> for $ty<N>
        where Self: Simdalize<Elem = N>
            , N: $name<Output = N> {

            type Output = Self;
            fn $fun(self, rhs: Self) -> Output {
                e!(self.simdalize() $op rhs.simdalize())
            }
        }

    }
}

macro_rules! impl_index {
    ($($v: ident),+) => { $(
        impl<N> ops::Index<usize> for $v<N>
        where N: Copy {

            type Output = N;
            #[inline] fn index(&self, i: usize) -> &N {
                &self.as_ref()[i]
            }
        }

        impl<N> ops::IndexMut<usize> for $v<N>
        where N: Copy {

            #[inline] fn index_mut(&mut self, i: usize) -> &mut N {
                &mut self.as_mut()[i]
            }
        }

        impl<N> Columnar for $v<N>
        where N: Copy {

            type Column = $v<N>;
            #[inline] fn ncols(&self) -> usize { 1 }
            #[inline] fn column(&self, i: usize) -> Self::Column {
                if i == 0 { *self }
                else { panic!("Index out of bounds!") }
            }
            #[inline] fn column_mut(&mut self, i: usize) -> &mut Self::Column {
                if i == 0 { self }
                else { panic!("Index out of bounds!") }
            }

        }

        impl<N> Tabular for $v<N>
        where N: Copy {

            type Row = N;
            #[inline] fn nrows(&self) -> usize { 3 }
            #[inline] fn row(&self, i: usize) -> Self::Row {
                self.as_ref()[i]
            }
            #[inline] fn row_mut(&mut self, i: usize) -> &mut Self::Row {
                &mut self.as_mut()[i]
            }

        }
    )+}
}

#[cfg(features = "rand")]
macro_rules! impl_rand {
    ($ty: ident, $($sub: ident),+) => {
        impl<N> Rand for $ty<N>
        where N: Rand {

            fn rand<R: Rng>(rng: &mut R) -> Self {
                $ty { $($sub: N::rand(rng)),+ }
            }
        }
    }
}

macro_rules! impl_rand {
    ($ty: ident, $($sub: ident),+) => { }
}

macro_rules! impl_converts {
    ($($v: ident, $c: expr),+) => { $(
        impl<N> convert::AsRef<[N; $c]> for $v<N>
        where N: Copy {

            #[inline] fn as_ref(&self) -> &[N; $c] {
                unsafe { transmute(self) }
            }
        }
        impl<N> convert::AsMut<[N; $c]> for $v<N>
        where N: Copy {

            #[inline] fn as_mut(&mut self) -> &mut [N; $c] {
                unsafe { transmute(self) }
            }
        }
        impl<'a, N> convert::From<&'a [N; $c]> for &'a $v<N>
        where N: Copy {

            #[inline] fn from(a: &'a [N; $c]) -> &'a $v<N> {
                unsafe { transmute(a) }
            }
        }
        impl<'a, N> convert::From<&'a mut [N; $c]> for &'a mut $v<N>
        where N: Copy {

            #[inline] fn from(a: &'a mut [N; $c]) -> &'a mut $v<N> {
                unsafe { transmute(a) }
            }
        }
        // impl<N: ?Sized> From<[N; $c]> for $v<N>
        // where N: Numeric
        //     , N: Copy {
        //     #[inline]
        //     fn from(a: [N; $c]) -> $v<N> {
        //         unsafe { transmute(a) }
        //     }
        // }
    )+}
}
<commit_msg>[vector] Don't run `make_vector` example as doctest<commit_after>macro_rules! e { ($e:expr) => { $e } }

macro_rules! sum {
    ($x:expr) => { $x };
    ($x:expr, $($y:expr),+) => { $x + sum!($($y),+) }
}

/// Macro for constructing a new vector type.
///
/// This can be used to construct fixed-sized vectors of whatever dimension
/// the user would like. While this crate only provides vectors of dimensons
/// 2 through 5, it's trivial to make vectors of arbitrary length using this
/// macro.
///
/// Another potential use of this macro is to create new vectors whose
/// subscripts have different names than those provided in this crate. The
/// vectors in `lin`  have subscripts named _x_, _y_, _z_, (as in Cartesian
/// coördinates), _w_, and _a_; but in some applications, these subscripts
/// might represent different quantities. Thus, users can use this macro to
/// create new vector types whose subscripts have names with semantic meanings
/// more appropriate to their individual use case.
///
/// # Arguments
///    - `$name`: The name of the new vector type
///    - `$dim`: the dimension (number of elements) of the new vector type
///    - `$sub`: the name of each subscript or element of the vector.
///              Note that the number of `$sub`s should be the same as the
///              length of the vector.
///
/// # Example
///   Consider the definition of `Vector3`:
///
///   ```ignore
///   make_vector! { Vector3, length: 3, x, y, z }
///   ```
#[macro_export]
macro_rules! make_vector {
    ($name: ident, $dim:expr, $($sub: ident),+) => {
        #[cfg(not(simd))]
        #[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Debug, Default)]
        #[repr(C)]
        pub struct $name<N> {
            $(pub $sub: N),+
        }

        impl_rand! { $name, $($sub),+ }

        impl_ops! { $name, $($sub),+ }
        impl_converts! { $name, $dim }
        impl_index! { $name }

    }
}

macro_rules! impl_ops {
    ($ty: ident, $($sub: ident),+) => {
        impl_op! { Add for $ty, add, +, $($sub),+ }
        impl_op! { Sub for $ty, sub, -, $($sub),+ }
        impl_op! { Div for $ty, div, /, $($sub),+ }
        impl_op! { Rem for $ty, rem, %, $($sub),+ }

        #[cfg(features = "parallel")]
        impl<N> Mul<N> for $ty<N>
        where Self: Simdalize<Elem = N>
            , N: Mul<Output = N> {

            type Output = Self;
            fn mul(self, rhs: N) -> Output { self.simdalize() * N::splat(rhs) }
        }

        impl<N> Mul<N> for $ty<N>
        where N: Mul<Output = N>
            , N: Copy {

            type Output = Self;
            fn mul(self, rhs: N) -> Self {
                $ty { $($sub: self.$sub * rhs),+ }
            }

        }

        impl<N> Mul<$ty<N>> for $ty<N>
        where N: Mul<Output = N> + Add<Output = N>
            , N: Copy {

            type Output = N;
            fn mul(self, rhs: Self) -> N {
                sum!( $(self.$sub * rhs.$sub),+ )
            }
        }
    }
}

macro_rules! impl_op {
    ($name: ident for $ty:ident, $fun: ident, $op:tt, $($sub: ident),+) => {
        // implement the operation for vector & vectorI
        impl<N> $name<$ty<N>> for $ty<N>
        where N: $name<Output=N>
            , N: Copy {

            type Output = Self;
            fn $fun(self, rhs: Self) -> Self::Output {
                $ty { $($sub: e!(self.$sub $op rhs.$sub)),+ }
            }
        }

        // implement the operation for vector & scalar
        impl<N> $name<N> for $ty<N>
        where N: $name<Output=N>
            , N: Copy {

            type Output = Self;
            fn $fun(self, rhs: N) -> Self::Output {
                $ty { $($sub: e!(self.$sub $op rhs)),+ }
            }
        }

        #[cfg(features = "parallel")]
        impl<N> $name<N> for $ty<N>
        where Self: Simdalize<Elem = N>
            , N: $name<Output = N>
            , N: Copy {

            type Output = Self;
            fn $fun(self, rhs: N) -> Output {
                e!(self.simdalize() $op N::splat(rhs))
            }
        }

        #[cfg(features = "parallel")]
        impl<N> $name<N> for $ty<N>
        where Self: Simdalize<Elem = N>
            , N: $name<Output = N> {

            type Output = Self;
            fn $fun(self, rhs: Self) -> Output {
                e!(self.simdalize() $op rhs.simdalize())
            }
        }

    }
}

macro_rules! impl_index {
    ($($v: ident),+) => { $(
        impl<N> ops::Index<usize> for $v<N>
        where N: Copy {

            type Output = N;
            #[inline] fn index(&self, i: usize) -> &N {
                &self.as_ref()[i]
            }
        }

        impl<N> ops::IndexMut<usize> for $v<N>
        where N: Copy {

            #[inline] fn index_mut(&mut self, i: usize) -> &mut N {
                &mut self.as_mut()[i]
            }
        }

        impl<N> Columnar for $v<N>
        where N: Copy {

            type Column = $v<N>;
            #[inline] fn ncols(&self) -> usize { 1 }
            #[inline] fn column(&self, i: usize) -> Self::Column {
                if i == 0 { *self }
                else { panic!("Index out of bounds!") }
            }
            #[inline] fn column_mut(&mut self, i: usize) -> &mut Self::Column {
                if i == 0 { self }
                else { panic!("Index out of bounds!") }
            }

        }

        impl<N> Tabular for $v<N>
        where N: Copy {

            type Row = N;
            #[inline] fn nrows(&self) -> usize { 3 }
            #[inline] fn row(&self, i: usize) -> Self::Row {
                self.as_ref()[i]
            }
            #[inline] fn row_mut(&mut self, i: usize) -> &mut Self::Row {
                &mut self.as_mut()[i]
            }

        }
    )+}
}

#[cfg(features = "rand")]
macro_rules! impl_rand {
    ($ty: ident, $($sub: ident),+) => {
        impl<N> Rand for $ty<N>
        where N: Rand {

            fn rand<R: Rng>(rng: &mut R) -> Self {
                $ty { $($sub: N::rand(rng)),+ }
            }
        }
    }
}

macro_rules! impl_rand {
    ($ty: ident, $($sub: ident),+) => { }
}

macro_rules! impl_converts {
    ($($v: ident, $c: expr),+) => { $(
        impl<N> convert::AsRef<[N; $c]> for $v<N>
        where N: Copy {

            #[inline] fn as_ref(&self) -> &[N; $c] {
                unsafe { transmute(self) }
            }
        }
        impl<N> convert::AsMut<[N; $c]> for $v<N>
        where N: Copy {

            #[inline] fn as_mut(&mut self) -> &mut [N; $c] {
                unsafe { transmute(self) }
            }
        }
        impl<'a, N> convert::From<&'a [N; $c]> for &'a $v<N>
        where N: Copy {

            #[inline] fn from(a: &'a [N; $c]) -> &'a $v<N> {
                unsafe { transmute(a) }
            }
        }
        impl<'a, N> convert::From<&'a mut [N; $c]> for &'a mut $v<N>
        where N: Copy {

            #[inline] fn from(a: &'a mut [N; $c]) -> &'a mut $v<N> {
                unsafe { transmute(a) }
            }
        }
        // impl<N: ?Sized> From<[N; $c]> for $v<N>
        // where N: Numeric
        //     , N: Copy {
        //     #[inline]
        //     fn from(a: [N; $c]) -> $v<N> {
        //         unsafe { transmute(a) }
        //     }
        // }
    )+}
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013, David Renshaw (dwrenshaw@gmail.com)
 *
 * See the LICENSE file in the capnproto-rust root directory.
 */

use std;
use common::*;
use endian::*;
use message::*;

pub mod InputStreamMessageReader {

    use std;
    use endian::*;
    use message::*;

    pub fn new<U : std::rt::io::Reader, T>(inputStream : &mut U,
                                           options : ReaderOptions,
                                           cont : &fn(v : &mut MessageReader) -> T) -> T {

        let firstWord = inputStream.read_bytes(8);

        let segmentCount : u32 =
            unsafe {let p : *WireValue<u32> = std::cast::transmute(firstWord.unsafe_ref(0));
                    (*p).get() + 1
                   };

        let segment0Size =
            if (segmentCount == 0) { 0 } else {
            unsafe {let p : *WireValue<u32> = std::cast::transmute(firstWord.unsafe_ref(4));
                    (*p).get()
                   }
            };

        let mut totalWords = segment0Size;

        if (segmentCount >= 512) {
            fail!("too many segments");
        }

        let mut moreSizes : ~[u32] = std::vec::from_elem((segmentCount & !1) as uint, 0u32);

        if (segmentCount > 1) {
            let moreSizesRaw = inputStream.read_bytes((4 * (segmentCount & !1)) as uint);
            for ii in range(0, segmentCount as uint - 1) {
                moreSizes[ii] = unsafe {
                    let p : *WireValue<u32> =
                        std::cast::transmute(moreSizesRaw.unsafe_ref(ii * 4));
                    (*p).get()
                };
                totalWords += moreSizes[ii];
            }
        }

        //# Don't accept a message which the receiver couldn't possibly
        //# traverse without hitting the traversal limit. Without this
        //# check, a malicious client could transmit a very large
        //# segment size to make the receiver allocate excessive space
        //# and possibly crash.
        assert!(totalWords as u64 <= options.traversalLimitInWords);

        // TODO Is this guaranteed to be word-aligned?
        let ownedSpace : ~[u8] = inputStream.read_bytes(8 * totalWords as uint);

        // TODO lazy reading like in capnp-c++. Is that possible
        // within the std::io::Reader interface?

        let segment0 : &[u8] = ownedSpace.slice(0, 8 * segment0Size as uint);

        let mut segments : ~[&[u8]] = ~[segment0];

        if (segmentCount > 1) {
            let mut offset = segment0Size;

            for ii in range(0, segmentCount as uint - 1) {
                segments.push(ownedSpace.slice(offset as uint * 8,
                                               (offset + moreSizes[ii]) as uint * 8));
                offset += moreSizes[ii];
            }
        }

        let mut result = ~MessageReader::<'a> {
            segments : segments,
            options : options
        };

        cont(result)

    }
}

pub fn writeMessage<T: std::rt::io::Writer>(outputStream : &mut T,
                                            message : &MessageBuilder) {

    let tableSize : uint = ((message.segments.len() + 2) & (!1)) * (BYTES_PER_WORD / 2);

    let mut table : ~[u8] = std::vec::from_elem(tableSize, 0u8);

    WireValue::getFromBufMut(table, 0).set((message.segments.len() - 1) as u32);

    for i in range(0, message.segments.len()) {
        WireValue::getFromBufMut(table, (i + 1) * 4).set(
            message.segmentBuilders[i].pos as u32);
    }
    if (message.segments.len() % 2 == 0) {
        // Set padding.
        WireValue::getFromBufMut(table, (message.segments.len() + 1) * 4).set( 0 );
    }

    outputStream.write(table);

    for i in range(0, message.segments.len()) {
        let slice = message.segments[i].slice(0, message.segmentBuilders[i].pos * BYTES_PER_WORD);
        outputStream.write(slice);
    }
}
<commit_msg>fix memory corruption bug<commit_after>/*
 * Copyright (c) 2013, David Renshaw (dwrenshaw@gmail.com)
 *
 * See the LICENSE file in the capnproto-rust root directory.
 */

use std;
use common::*;
use endian::*;
use message::*;

pub mod InputStreamMessageReader {

    use std;
    use endian::*;
    use message::*;

    pub fn new<U : std::rt::io::Reader, T>(inputStream : &mut U,
                                           options : ReaderOptions,
                                           cont : &fn(v : &mut MessageReader) -> T) -> T {

        let firstWord = inputStream.read_bytes(8);

        let segmentCount : u32 =
            unsafe {let p : *WireValue<u32> = std::cast::transmute(firstWord.unsafe_ref(0));
                    (*p).get() + 1
                   };

        let segment0Size =
            if (segmentCount == 0) { 0 } else {
            unsafe {let p : *WireValue<u32> = std::cast::transmute(firstWord.unsafe_ref(4));
                    (*p).get()
                   }
            };

        let mut totalWords = segment0Size;

        if (segmentCount >= 512) {
            fail!("too many segments");
        }

        let mut moreSizes : ~[u32] = std::vec::from_elem((segmentCount & !1) as uint, 0u32);

        if (segmentCount > 1) {
            let moreSizesRaw = inputStream.read_bytes((4 * (segmentCount & !1)) as uint);
            for ii in range(0, segmentCount as uint - 1) {
                moreSizes[ii] = unsafe {
                    let p : *WireValue<u32> =
                        std::cast::transmute(moreSizesRaw.unsafe_ref(ii * 4));
                    (*p).get()
                };
                totalWords += moreSizes[ii];
            }
        }

        //# Don't accept a message which the receiver couldn't possibly
        //# traverse without hitting the traversal limit. Without this
        //# check, a malicious client could transmit a very large
        //# segment size to make the receiver allocate excessive space
        //# and possibly crash.
        assert!(totalWords as u64 <= options.traversalLimitInWords);

        // TODO Is this guaranteed to be word-aligned?
        let ownedSpace : ~[u8] = inputStream.read_bytes(8 * totalWords as uint);

        // TODO lazy reading like in capnp-c++. Is that possible
        // within the std::io::Reader interface?

        let segment0 : &[u8] = ownedSpace.slice(0, 8 * segment0Size as uint);

        let mut segments : ~[&[u8]] = ~[segment0];

        if (segmentCount > 1) {
            let mut offset = segment0Size;

            for ii in range(0, segmentCount as uint - 1) {
                segments.push(ownedSpace.slice(offset as uint * 8,
                                               (offset + moreSizes[ii]) as uint * 8));
                offset += moreSizes[ii];
            }
        }

        let mut result = ~MessageReader::<'a> {
            segments : segments,
            options : options
        };

        cont(result)

    }
}

pub fn writeMessage<T: std::rt::io::Writer>(outputStream : &mut T,
                                            message : &MessageBuilder) {

    let tableSize : uint = ((message.segments.len() + 2) & (!1)) * (BYTES_PER_WORD / 2);

    let mut table : ~[u8] = std::vec::from_elem(tableSize, 0u8);

    WireValue::getFromBufMut(table, 0).set((message.segments.len() - 1) as u32);

    for i in range(0, message.segments.len()) {
        WireValue::getFromBufMut(table, (i + 1) * 4).set(
            message.segmentBuilders[i].pos as u32);
    }
    if (message.segments.len() % 2 == 0) {
        // Set padding.
        WireValue::<u32>::getFromBufMut(table, (message.segments.len() + 1) * 4).set( 0 );
    }

    outputStream.write(table);

    for i in range(0, message.segments.len()) {
        let slice = message.segments[i].slice(0, message.segmentBuilders[i].pos * BYTES_PER_WORD);
        outputStream.write(slice);
    }
}
<|endoftext|>