<commit_before>//! Serialize a Rust data structure into UBJSON data.

use std::io::Write;

use byteorder::{BigEndian, ByteOrder, WriteBytesExt};
use serde::ser::{self, Serialize};

use error::{Error, Result};

/// Serialize the given value as a UBJSON byte vector.
pub fn to_vec<T>(value: &T) -> Result<Vec<u8>>
    where T: Serialize
{
    let mut serializer = Serializer::new(Vec::new());
    value.serialize(&mut serializer)?;
    Ok(serializer.into_inner())
}

/// Serialize the given value as UBJSON into the IO stream.
pub fn to_writer<T, W>(writer: W, value: &T) -> Result<()>
    where W: Write,
          T: Serialize
{
    let mut serializer = Serializer::new(writer);
    value.serialize(&mut serializer)?;
    Ok(())
}

/// Structure for serializing Rust values into UBJSON.
pub struct Serializer<W> {
    inner: W,
}

impl<W> Serializer<W>
    where W: Write
{
    /// Creates a new UBJSON serializer.
    pub fn new(writer: W) -> Self {
        Serializer { inner: writer }
    }

    /// Consumes the serializer and returns the writer it wrapped.
    fn into_inner(self) -> W {
        self.inner
    }
}

impl<'a, W> ser::Serializer for &'a mut Serializer<W> {
    type Ok = ();
    type Error = Error;

    fn serialize_bool(self, v: bool) -> Result<()> {
        self.inner
            .write_u8(match v {
                          true => b'T',
                          false => b'F',
                      })
            .map_err(|err| Error::Io(err))
    }

    fn serialize_i8(self, v: i8) -> Result<()> {
        self.inner
            .write_u8(b'i')
            .and_then(|_| self.inner.write_i8(v))
            .map_err(|err| Error::Io(err))
    }

    fn serialize_i16(self, v: i16) -> Result<()> {
        if (i8::min_value() as i16 <= v) && (v <= i8::max_value() as i16) {
            self.serialize_i8(v as i8)
        } else {
            self.inner
                .write_u8(b'I')
                .and_then(|_| self.inner.write_i16::<BigEndian>(v))
                .map_err(|err| Error::Io(err))
        }
    }

    fn serialize_i32(self, v: i32) -> Result<()> {
        if (i16::min_value() as i32 <= v) && (v <= i16::max_value() as i32) {
            self.serialize_i16(v as i16)
        } else {
            self.inner
                .write_u8(b'l')
                .and_then(|_| self.inner.write_i32::<BigEndian>(v))
                .map_err(|err| Error::Io(err))
        }
    }

    fn serialize_i64(self, v: i64) -> Result<()> {
        if (i32::min_value() as i64 <= v) && (v <= i32::max_value() as i64) {
            self.serialize_i32(v as i32)
        } else {
            self.inner
                .write_u8(b'L')
                .and_then(|_| self.inner.write_i64::<BigEndian>(v))
                .map_err(|err| Error::io(err))
        }
    }

    fn serialize_u8(self, v: u8) -> Result<()> {
        self.inner
            .write_u8(b'U')
            .and_then(|_| self.inner.write_u8(v))
            .map_err(|err| Error::Io(err))
    }

    fn serialize_u16(self, v: u16) -> Result<()> {
        if v <= u8::max_value() as u16 {
            self.serialize_u8(v as u8)
        } else if v <= i16::max_value() as u16 {
            self.serialize_i16(v as i16)
        } else {
            self.serialize_i32(v as i32)
        }
    }

    fn serialize_u32(self, v: u32) -> Result<()> {
        if v <= u16::max_value() as u32 {
            self.serialize_u16(v as u16)
        } else if v <= i32::max_value() as u32 {
            self.serialize_i32(v as i32)
        } else {
            self.serialize_i64(v as i64)
        }
    }

    fn serialize_u64(self, v: u64) -> Result<()> {
        if v <= u32::max_value() as u64 {
            self.serialize_u32(v as u32)
        } else if v <= i64::max_value() as u64 {
            self.serialize_i64(v as i64)
        } else {
            let v = v.to_string();
            self.inner
                .write_u8(b'H')
                .map_err(|err| Error::Io(err))
                .and_then(|_| self.serialize_u64(v.len()))
                .and_then(|_| self.inner.write(v.as_bytes()).map_err(|err| Error::Io(err)))
        }
    }

    fn serialize_f32(self, v: f32) -> Result<()> {
        self.inner
            .write_u8(b'd')
            .and_then(|_| self.inner.write_f32::<BigEndian>(v))
            .map_err(|err| Error::Io(err))
    }

    fn serialize_f64(self, v: f64) -> Result<()> {
        self.inner
            .write_u8(b'D')
            .and_then(|_| self.inner.write_f64::<BigEndian>(v))
            .map_err(|err| Error::Io(err))
    }

    fn serialize_char(self, v: char) -> Result<()> {
        let v: u32 = v.into();
        if v <= u8::max_value() as u32 {
            self.inner
                .write_u8(b'C')
                .and_then(|_| self.inner.write_u8(v as u8))
                .map_err(|err| Error::Io(err))
        } else {
            self.serialize_u32(v)
        }
    }

    fn serialize_str(self, v: &str) -> Result<()> {
        self.inner
            .write_u8(b'S')
            .map_err(|err| Error::Io(err))
            .and_then(|_| self.serialize_u64(v.len() as u64))
            .and_then(|_| {
                          self.inner
                              .write(v.as_bytes())
                              .map(|_| ())
                              .map_err(|err| Error::Io(err))
                      })
    }

    fn serialize_bytes(self, v: &[u8]) -> Result<()> {
        self.inner
            .write(b"[$U#")
            .map(|_| ())
            .map_err(|err| Error::Io(err))
            .and_then(|_| self.serialize_u64(v.len() as u64))
            .and_then(|_| {
                          self.inner
                              .write(v)
                              .map(|_| ())
                              .map_err(|err| Error::Io(err))
                      })
    }

    fn serialize_none(self) -> Result<()> {
        self.inner.write_u8(b'Z').map_err(|err| Error::Io(err))
    }

    fn serialize_some<T: ?Sized>(self, value: &T) -> Result<()>
        where T: Serialize
    {
        value.serialize(self)
    }

    fn serialize_unit(self) -> Result<()> {
        self.serialize_none()
    }

    fn serialize_unit_struct(self, name: &'static str) -> Result<()> {
        unimplemented!()
    }

    fn serialize_unit_variant(self,
                              name: &'static str,
                              variant_index: u32,
                              variant: &'static str)
                              -> Result<()> {
        unimplemented!()
    }

    fn serialize_newtype_struct<T: ?Sized>(self, name: &'static str, value: &T) -> Result<()>
        where T: Serialize
    {
        unimplemented!()
    }

    fn serialize_newtype_variant<T: ?Sized>(self,
                                            name: &'static str,
                                            variant_index: u32,
                                            variant: &'static str,
                                            value: &T)
                                            -> Result<()>
        where T: Serialize
    {
        unimplemented!()
    }
}
<commit_msg>Fix error handling<commit_after>//! Serialize a Rust data structure into UBJSON data.

use std::io::Write;

use byteorder::{BigEndian, ByteOrder, WriteBytesExt};
use serde::ser::{self, Serialize};

use error::{Error, Result};

/// Serialize the given value as a UBJSON byte vector.
pub fn to_vec<T>(value: &T) -> Result<Vec<u8>>
    where T: Serialize
{
    let mut serializer = Serializer::new(Vec::new());
    value.serialize(&mut serializer)?;
    Ok(serializer.into_inner())
}

/// Serialize the given value as UBJSON into the IO stream.
pub fn to_writer<T, W>(writer: W, value: &T) -> Result<()>
    where W: Write,
          T: Serialize
{
    let mut serializer = Serializer::new(writer);
    value.serialize(&mut serializer)?;
    Ok(())
}

/// Structure for serializing Rust values into UBJSON.
pub struct Serializer<W> {
    inner: W,
}

impl<W> Serializer<W>
    where W: Write
{
    /// Creates a new UBJSON serializer.
    pub fn new(writer: W) -> Self {
        Serializer { inner: writer }
    }

    /// Consumes the serializer and returns the writer it wrapped.
    fn into_inner(self) -> W {
        self.inner
    }
}

impl<'a, W> ser::Serializer for &'a mut Serializer<W> {
    type Ok = ();
    type Error = Error;

    fn serialize_bool(self, v: bool) -> Result<()> {
        self.inner
            .write_u8(match v {
                          true => b'T',
                          false => b'F',
                      })
            .map_err(Error::Io)
    }

    fn serialize_i8(self, v: i8) -> Result<()> {
        self.inner
            .write_u8(b'i')
            .and_then(|_| self.inner.write_i8(v))
            .map_err(Error::Io)
    }

    fn serialize_i16(self, v: i16) -> Result<()> {
        if (i8::min_value() as i16 <= v) && (v <= i8::max_value() as i16) {
            self.serialize_i8(v as i8)
        } else {
            self.inner
                .write_u8(b'I')
                .and_then(|_| self.inner.write_i16::<BigEndian>(v))
                .map_err(Error::Io)
        }
    }

    fn serialize_i32(self, v: i32) -> Result<()> {
        if (i16::min_value() as i32 <= v) && (v <= i16::max_value() as i32) {
            self.serialize_i16(v as i16)
        } else {
            self.inner
                .write_u8(b'l')
                .and_then(|_| self.inner.write_i32::<BigEndian>(v))
                .map_err(Error::Io)
        }
    }

    fn serialize_i64(self, v: i64) -> Result<()> {
        if (i32::min_value() as i64 <= v) && (v <= i32::max_value() as i64) {
            self.serialize_i32(v as i32)
        } else {
            self.inner
                .write_u8(b'L')
                .and_then(|_| self.inner.write_i64::<BigEndian>(v))
                .map_err(|err| Error::io(err))
        }
    }

    fn serialize_u8(self, v: u8) -> Result<()> {
        self.inner
            .write_u8(b'U')
            .and_then(|_| self.inner.write_u8(v))
            .map_err(Error::Io)
    }

    fn serialize_u16(self, v: u16) -> Result<()> {
        if v <= u8::max_value() as u16 {
            self.serialize_u8(v as u8)
        } else if v <= i16::max_value() as u16 {
            self.serialize_i16(v as i16)
        } else {
            self.serialize_i32(v as i32)
        }
    }

    fn serialize_u32(self, v: u32) -> Result<()> {
        if v <= u16::max_value() as u32 {
            self.serialize_u16(v as u16)
        } else if v <= i32::max_value() as u32 {
            self.serialize_i32(v as i32)
        } else {
            self.serialize_i64(v as i64)
        }
    }

    fn serialize_u64(self, v: u64) -> Result<()> {
        if v <= u32::max_value() as u64 {
            self.serialize_u32(v as u32)
        } else if v <= i64::max_value() as u64 {
            self.serialize_i64(v as i64)
        } else {
            let v = v.to_string();
            self.inner
                .write_u8(b'H')
                .map_err(Error::Io)
                .and_then(|_| self.serialize_u64(v.len()))
                .and_then(|_| self.inner.write_all(v.as_bytes()).map_err(Error::Io))
        }
    }

    fn serialize_f32(self, v: f32) -> Result<()> {
        self.inner
            .write_u8(b'd')
            .and_then(|_| self.inner.write_f32::<BigEndian>(v))
            .map_err(Error::Io)
    }

    fn serialize_f64(self, v: f64) -> Result<()> {
        self.inner
            .write_u8(b'D')
            .and_then(|_| self.inner.write_f64::<BigEndian>(v))
            .map_err(Error::Io)
    }

    fn serialize_char(self, v: char) -> Result<()> {
        let v: u32 = v.into();
        if v <= u8::max_value() as u32 {
            self.inner
                .write_u8(b'C')
                .and_then(|_| self.inner.write_u8(v as u8))
                .map_err(Error::Io)
        } else {
            self.serialize_u32(v)
        }
    }

    fn serialize_str(self, v: &str) -> Result<()> {
        self.inner
            .write_u8(b'S')
            .map_err(Error::Io)
            .and_then(|_| self.serialize_u64(v.len() as u64))
            .and_then(|_| {
                          self.inner
                              .write_all(v.as_bytes())
                              .map_err(Error::Io)
                      })
    }

    fn serialize_bytes(self, v: &[u8]) -> Result<()> {
        self.inner
            .write_all(b"[$U#")
            .map_err(Error::Io)
            .and_then(|_| self.serialize_u64(v.len() as u64))
            .and_then(|_| {
                          self.inner
                              .write_all(v.as_bytes())
                              .map_err(Error::Io)
                      })
    }

    fn serialize_none(self) -> Result<()> {
        self.inner.write_u8(b'Z').map_err(Error::Io)
    }

    fn serialize_some<T: ?Sized>(self, value: &T) -> Result<()>
        where T: Serialize
    {
        value.serialize(self)
    }

    fn serialize_unit(self) -> Result<()> {
        self.serialize_none()
    }

    fn serialize_unit_struct(self, name: &'static str) -> Result<()> {
        unimplemented!()
    }

    fn serialize_unit_variant(self,
                              name: &'static str,
                              variant_index: u32,
                              variant: &'static str)
                              -> Result<()> {
        unimplemented!()
    }

    fn serialize_newtype_struct<T: ?Sized>(self, name: &'static str, value: &T) -> Result<()>
        where T: Serialize
    {
        unimplemented!()
    }

    fn serialize_newtype_variant<T: ?Sized>(self,
                                            name: &'static str,
                                            variant_index: u32,
                                            variant: &'static str,
                                            value: &T)
                                            -> Result<()>
        where T: Serialize
    {
        unimplemented!()
    }
}
<|endoftext|>


<commit_before>
/// This module is copied from `libstd/sys/common/stack.rs`.

#[allow(dead_code)]

pub mod stack {
    pub const RED_ZONE: usize = 20 * 1024;

    #[inline(always)]
    pub unsafe fn record_rust_managed_stack_bounds(stack_lo: usize, stack_hi: usize) {
        // When the old runtime had segmented stacks, it used a calculation that was
        // "limit + RED_ZONE + FUDGE". The red zone was for things like dynamic
        // symbol resolution, llvm function calls, etc. In theory this red zone
        // value is 0, but it matters far less when we have gigantic stacks because
        // we don't need to be so exact about our stack budget. The "fudge factor"
        // was because LLVM doesn't emit a stack check for functions < 256 bytes in
        // size. Again though, we have giant stacks, so we round all these
        // calculations up to the nice round number of 20k.
        record_sp_limit(stack_lo + RED_ZONE);

        return target_record_stack_bounds(stack_lo, stack_hi);

        #[cfg(not(windows))] #[inline(always)]
        unsafe fn target_record_stack_bounds(_stack_lo: usize, _stack_hi: usize) {}

        #[cfg(all(windows, target_arch = "x86"))] #[inline(always)]
        unsafe fn target_record_stack_bounds(stack_lo: usize, stack_hi: usize) {
            // stack range is at TIB: %fs:0x04 (top) and %fs:0x08 (bottom)
            asm!("mov $0, %fs:0x04" :: "r"(stack_hi) :: "volatile");
            asm!("mov $0, %fs:0x08" :: "r"(stack_lo) :: "volatile");
        }
        #[cfg(all(windows, target_arch = "x86_64"))] #[inline(always)]
        unsafe fn target_record_stack_bounds(stack_lo: usize, stack_hi: usize) {
            // stack range is at TIB: %gs:0x08 (top) and %gs:0x10 (bottom)
            asm!("mov $0, %gs:0x08" :: "r"(stack_hi) :: "volatile");
            asm!("mov $0, %gs:0x10" :: "r"(stack_lo) :: "volatile");
        }
    }

    /// Records the current limit of the stack as specified by `end`.
    ///
    /// This is stored in an OS-dependent location, likely inside of the thread
    /// local storage. The location that the limit is stored is a pre-ordained
    /// location because it's where LLVM has emitted code to check.
    ///
    /// Note that this cannot be called under normal circumstances. This function is
    /// changing the stack limit, so upon returning any further function calls will
    /// possibly be triggering the morestack logic if you're not careful.
    ///
    /// Also note that this and all of the inside functions are all flagged as
    /// "inline(always)" because they're messing around with the stack limits.  This
    /// would be unfortunate for the functions themselves to trigger a morestack
    /// invocation (if they were an actual function call).
    #[inline(always)]
    pub unsafe fn record_sp_limit(limit: usize) {
        return target_record_sp_limit(limit);

        // x86-64
        #[cfg(all(target_arch = "x86_64",
                  any(target_os = "macos", target_os = "ios")))]
        #[inline(always)]
        unsafe fn target_record_sp_limit(limit: usize) {
            asm!("movq $$0x60+90*8, %rsi
                  movq $0, %gs:(%rsi)" :: "r"(limit) : "rsi" : "volatile")
        }
        #[cfg(all(target_arch = "x86_64", target_os = "linux"))] #[inline(always)]
        unsafe fn target_record_sp_limit(limit: usize) {
            asm!("movq $0, %fs:112" :: "r"(limit) :: "volatile")
        }
        #[cfg(all(target_arch = "x86_64", target_os = "windows"))] #[inline(always)]
        unsafe fn target_record_sp_limit(_: usize) {
        }
        #[cfg(all(target_arch = "x86_64", target_os = "freebsd"))] #[inline(always)]
        unsafe fn target_record_sp_limit(limit: usize) {
            asm!("movq $0, %fs:24" :: "r"(limit) :: "volatile")
        }
        #[cfg(all(target_arch = "x86_64", target_os = "dragonfly"))]
        #[inline(always)]
        unsafe fn target_record_sp_limit(limit: usize) {
            asm!("movq $0, %fs:32" :: "r"(limit) :: "volatile")
        }

        // x86
        #[cfg(all(target_arch = "x86",
                  any(target_os = "macos", target_os = "ios")))]
        #[inline(always)]
        unsafe fn target_record_sp_limit(limit: usize) {
            asm!("movl $$0x48+90*4, %eax
                  movl $0, %gs:(%eax)" :: "r"(limit) : "eax" : "volatile")
        }
        #[cfg(all(target_arch = "x86",
                  any(target_os = "linux", target_os = "freebsd")))]
        #[inline(always)]
        unsafe fn target_record_sp_limit(limit: usize) {
            asm!("movl $0, %gs:48" :: "r"(limit) :: "volatile")
        }
        #[cfg(all(target_arch = "x86", target_os = "windows"))] #[inline(always)]
        unsafe fn target_record_sp_limit(_: usize) {
        }

        // mips, arm - Some brave soul can port these to inline asm, but it's over
        //             my head personally
        #[cfg(any(target_arch = "mips",
                  target_arch = "mipsel",
                  all(target_arch = "arm", not(target_os = "ios"))))]
        #[inline(always)]
        unsafe fn target_record_sp_limit(limit: usize) {
            use libc::c_void;
            return record_sp_limit(limit as *const c_void);
            extern {
                fn record_sp_limit(limit: *const c_void);
            }
        }

        // aarch64 - FIXME(AARCH64): missing...
        // powerpc - FIXME(POWERPC): missing...
        // arm-ios - iOS segmented stack is disabled for now, see related notes
        // openbsd - segmented stack is disabled
        #[cfg(any(target_arch = "aarch64",
                  target_arch = "powerpc",
                  all(target_arch = "arm", target_os = "ios"),
                  target_os = "bitrig",
                  target_os = "openbsd"))]
        unsafe fn target_record_sp_limit(_: usize) {
        }
    }

    /// The counterpart of the function above, this function will fetch the current
    /// stack limit stored in TLS.
    ///
    /// Note that all of these functions are meant to be exact counterparts of their
    /// brethren above, except that the operands are reversed.
    ///
    /// As with the setter, this function does not have a __morestack header and can
    /// therefore be called in a "we're out of stack" situation.
    #[inline(always)]
    pub unsafe fn get_sp_limit() -> usize {
        return target_get_sp_limit();

        // x86-64
        #[cfg(all(target_arch = "x86_64",
                  any(target_os = "macos", target_os = "ios")))]
        #[inline(always)]
        unsafe fn target_get_sp_limit() -> usize {
            let limit;
            asm!("movq $$0x60+90*8, %rsi
                  movq %gs:(%rsi), $0" : "=r"(limit) :: "rsi" : "volatile");
            return limit;
        }
        #[cfg(all(target_arch = "x86_64", target_os = "linux"))] #[inline(always)]
        unsafe fn target_get_sp_limit() -> usize {
            let limit;
            asm!("movq %fs:112, $0" : "=r"(limit) ::: "volatile");
            return limit;
        }
        #[cfg(all(target_arch = "x86_64", target_os = "windows"))] #[inline(always)]
        unsafe fn target_get_sp_limit() -> usize {
            return 1024;
        }
        #[cfg(all(target_arch = "x86_64", target_os = "freebsd"))] #[inline(always)]
        unsafe fn target_get_sp_limit() -> usize {
            let limit;
            asm!("movq %fs:24, $0" : "=r"(limit) ::: "volatile");
            return limit;
        }
        #[cfg(all(target_arch = "x86_64", target_os = "dragonfly"))]
        #[inline(always)]
        unsafe fn target_get_sp_limit() -> usize {
            let limit;
            asm!("movq %fs:32, $0" : "=r"(limit) ::: "volatile");
            return limit;
        }

        // x86
        #[cfg(all(target_arch = "x86",
                  any(target_os = "macos", target_os = "ios")))]
        #[inline(always)]
        unsafe fn target_get_sp_limit() -> usize {
            let limit;
            asm!("movl $$0x48+90*4, %eax
                  movl %gs:(%eax), $0" : "=r"(limit) :: "eax" : "volatile");
            return limit;
        }
        #[cfg(all(target_arch = "x86",
                  any(target_os = "linux", target_os = "freebsd")))]
        #[inline(always)]
        unsafe fn target_get_sp_limit() -> usize {
            let limit;
            asm!("movl %gs:48, $0" : "=r"(limit) ::: "volatile");
            return limit;
        }
        #[cfg(all(target_arch = "x86", target_os = "windows"))] #[inline(always)]
        unsafe fn target_get_sp_limit() -> usize {
            return 1024;
        }

        // mips, arm - Some brave soul can port these to inline asm, but it's over
        //             my head personally
        #[cfg(any(target_arch = "mips",
                  target_arch = "mipsel",
                  all(target_arch = "arm", not(target_os = "ios"))))]
        #[inline(always)]
        unsafe fn target_get_sp_limit() -> usize {
            use libc::c_void;
            return get_sp_limit() as usize;
            extern {
                fn get_sp_limit() -> *const c_void;
            }
        }

        // aarch64 - FIXME(AARCH64): missing...
        // powerpc - FIXME(POWERPC): missing...
        // arm-ios - iOS doesn't support segmented stacks yet.
        // openbsd - OpenBSD doesn't support segmented stacks.
        //
        // This function might be called by runtime though
        // so it is unsafe to unreachable, let's return a fixed constant.
        #[cfg(any(target_arch = "aarch64",
                  target_arch = "powerpc",
                  all(target_arch = "arm", target_os = "ios"),
                  target_os = "bitrig",
                  target_os = "openbsd"))]
        #[inline(always)]
        unsafe fn target_get_sp_limit() -> usize {
            1024
        }
    }
}
<commit_msg>NetBSD tweaks taken from rustc 1.3.0<commit_after>
/// This module is copied from `libstd/sys/common/stack.rs`.

#[allow(dead_code)]

pub mod stack {
    pub const RED_ZONE: usize = 20 * 1024;

    #[inline(always)]
    pub unsafe fn record_rust_managed_stack_bounds(stack_lo: usize, stack_hi: usize) {
        // When the old runtime had segmented stacks, it used a calculation that was
        // "limit + RED_ZONE + FUDGE". The red zone was for things like dynamic
        // symbol resolution, llvm function calls, etc. In theory this red zone
        // value is 0, but it matters far less when we have gigantic stacks because
        // we don't need to be so exact about our stack budget. The "fudge factor"
        // was because LLVM doesn't emit a stack check for functions < 256 bytes in
        // size. Again though, we have giant stacks, so we round all these
        // calculations up to the nice round number of 20k.
        record_sp_limit(stack_lo + RED_ZONE);

        return target_record_stack_bounds(stack_lo, stack_hi);

        #[cfg(not(windows))] #[inline(always)]
        unsafe fn target_record_stack_bounds(_stack_lo: usize, _stack_hi: usize) {}

        #[cfg(all(windows, target_arch = "x86"))] #[inline(always)]
        unsafe fn target_record_stack_bounds(stack_lo: usize, stack_hi: usize) {
            // stack range is at TIB: %fs:0x04 (top) and %fs:0x08 (bottom)
            asm!("mov $0, %fs:0x04" :: "r"(stack_hi) :: "volatile");
            asm!("mov $0, %fs:0x08" :: "r"(stack_lo) :: "volatile");
        }
        #[cfg(all(windows, target_arch = "x86_64"))] #[inline(always)]
        unsafe fn target_record_stack_bounds(stack_lo: usize, stack_hi: usize) {
            // stack range is at TIB: %gs:0x08 (top) and %gs:0x10 (bottom)
            asm!("mov $0, %gs:0x08" :: "r"(stack_hi) :: "volatile");
            asm!("mov $0, %gs:0x10" :: "r"(stack_lo) :: "volatile");
        }
    }

    /// Records the current limit of the stack as specified by `end`.
    ///
    /// This is stored in an OS-dependent location, likely inside of the thread
    /// local storage. The location that the limit is stored is a pre-ordained
    /// location because it's where LLVM has emitted code to check.
    ///
    /// Note that this cannot be called under normal circumstances. This function is
    /// changing the stack limit, so upon returning any further function calls will
    /// possibly be triggering the morestack logic if you're not careful.
    ///
    /// Also note that this and all of the inside functions are all flagged as
    /// "inline(always)" because they're messing around with the stack limits.  This
    /// would be unfortunate for the functions themselves to trigger a morestack
    /// invocation (if they were an actual function call).
    #[inline(always)]
    pub unsafe fn record_sp_limit(limit: usize) {
        return target_record_sp_limit(limit);

        #[cfg(all(target_arch = "x86_64",
                  any(target_os = "macos", target_os = "ios")))]
        #[inline(always)]
        unsafe fn target_record_sp_limit(limit: usize) {
            asm!("movq $$0x60+90*8, %rsi
                  movq $0, %gs:(%rsi)" :: "r"(limit) : "rsi" : "volatile")
        }
        #[cfg(all(target_arch = "x86_64", target_os = "linux"))] #[inline(always)]
        unsafe fn target_record_sp_limit(limit: usize) {
            asm!("movq $0, %fs:112" :: "r"(limit) :: "volatile")
        }
        #[cfg(all(target_arch = "x86_64", target_os = "windows"))] #[inline(always)]
        unsafe fn target_record_sp_limit(_: usize) {
        }
        #[cfg(all(target_arch = "x86_64", target_os = "freebsd"))] #[inline(always)]
        unsafe fn target_record_sp_limit(limit: usize) {
            asm!("movq $0, %fs:24" :: "r"(limit) :: "volatile")
        }
        #[cfg(all(target_arch = "x86_64", target_os = "dragonfly"))]
        #[inline(always)]
        unsafe fn target_record_sp_limit(limit: usize) {
            asm!("movq $0, %fs:32" :: "r"(limit) :: "volatile")
        }

        #[cfg(all(target_arch = "x86",
                  any(target_os = "macos", target_os = "ios")))]
        #[inline(always)]
        unsafe fn target_record_sp_limit(limit: usize) {
            asm!("movl $$0x48+90*4, %eax
                  movl $0, %gs:(%eax)" :: "r"(limit) : "eax" : "volatile")
        }
        #[cfg(all(target_arch = "x86", target_os = "linux"))]
        #[inline(always)]
        unsafe fn target_record_sp_limit(limit: usize) {
            asm!("movl $0, %gs:48" :: "r"(limit) :: "volatile")
        }
        #[cfg(all(target_arch = "x86", target_os = "windows"))] #[inline(always)]
        unsafe fn target_record_sp_limit(_: usize) {
        }

        // mips, arm - The implementations are a bit big for inline asm!
        //             They can be found in src/rt/arch/$target_arch/record_sp.S
        #[cfg(any(target_arch = "mips",
                  target_arch = "mipsel",
                  all(target_arch = "arm", not(target_os = "ios"))))]
        #[inline(always)]
        unsafe fn target_record_sp_limit(limit: usize) {
            use libc::c_void;
            return record_sp_limit(limit as *const c_void);
            extern {
                fn record_sp_limit(limit: *const c_void);
            }
        }

        // aarch64 - FIXME(AARCH64): missing...
        // powerpc - FIXME(POWERPC): missing...
        // arm-ios - iOS segmented stack is disabled for now, see related notes
        // openbsd/bitrig/netbsd - no segmented stacks.
        // x86-freebsd - no segmented stacks.
        #[cfg(any(target_arch = "aarch64",
                  target_arch = "powerpc",
                  all(target_arch = "arm", target_os = "ios"),
                  all(target_arch = "x86", target_os = "freebsd"),
                  target_os = "bitrig",
                  target_os = "netbsd",
                  target_os = "openbsd"))]
        unsafe fn target_record_sp_limit(_: usize) {
        }
    }

    /// The counterpart of the function above, this function will fetch the current
    /// stack limit stored in TLS.
    ///
    /// Note that all of these functions are meant to be exact counterparts of their
    /// brethren above, except that the operands are reversed.
    ///
    /// As with the setter, this function does not have a __morestack header and can
    /// therefore be called in a "we're out of stack" situation.
    #[inline(always)]
    pub unsafe fn get_sp_limit() -> usize {
        return target_get_sp_limit();

        #[cfg(all(target_arch = "x86_64",
                  any(target_os = "macos", target_os = "ios")))]
        #[inline(always)]
        unsafe fn target_get_sp_limit() -> usize {
            let limit;
            asm!("movq $$0x60+90*8, %rsi
                  movq %gs:(%rsi), $0" : "=r"(limit) :: "rsi" : "volatile");
            return limit;
        }
        #[cfg(all(target_arch = "x86_64", target_os = "linux"))] #[inline(always)]
        unsafe fn target_get_sp_limit() -> usize {
            let limit;
            asm!("movq %fs:112, $0" : "=r"(limit) ::: "volatile");
            return limit;
        }
        #[cfg(all(target_arch = "x86_64", target_os = "windows"))] #[inline(always)]
        unsafe fn target_get_sp_limit() -> usize {
            return 1024;
        }
        #[cfg(all(target_arch = "x86_64", target_os = "freebsd"))] #[inline(always)]
        unsafe fn target_get_sp_limit() -> usize {
            let limit;
            asm!("movq %fs:24, $0" : "=r"(limit) ::: "volatile");
            return limit;
        }
        #[cfg(all(target_arch = "x86_64", target_os = "dragonfly"))]
        #[inline(always)]
        unsafe fn target_get_sp_limit() -> usize {
            let limit;
            asm!("movq %fs:32, $0" : "=r"(limit) ::: "volatile");
            return limit;
        }

        #[cfg(all(target_arch = "x86",
                  any(target_os = "macos", target_os = "ios")))]
        #[inline(always)]
        unsafe fn target_get_sp_limit() -> usize {
            let limit;
            asm!("movl $$0x48+90*4, %eax
                  movl %gs:(%eax), $0" : "=r"(limit) :: "eax" : "volatile");
            return limit;
        }
        #[cfg(all(target_arch = "x86", target_os = "linux"))]
        #[inline(always)]
        unsafe fn target_get_sp_limit() -> usize {
            let limit;
            asm!("movl %gs:48, $0" : "=r"(limit) ::: "volatile");
            return limit;
        }
        #[cfg(all(target_arch = "x86", target_os = "windows"))] #[inline(always)]
        unsafe fn target_get_sp_limit() -> usize {
            return 1024;
        }

        // mips, arm - The implementations are a bit big for inline asm!
        //             They can be found in src/rt/arch/$target_arch/record_sp.S
        #[cfg(any(target_arch = "mips",
                  target_arch = "mipsel",
                  all(target_arch = "arm", not(target_os = "ios"))))]
        #[inline(always)]
        unsafe fn target_get_sp_limit() -> usize {
            use libc::c_void;
            return get_sp_limit() as usize;
            extern {
                fn get_sp_limit() -> *const c_void;
            }
        }

        // aarch64 - FIXME(AARCH64): missing...
        // powerpc - FIXME(POWERPC): missing...
        // arm-ios - no segmented stacks.
        // openbsd/bitrig/netbsd - no segmented stacks.
        // x86-freebsd - no segmented stacks..
        //
        // This function might be called by runtime though
        // so it is unsafe to unreachable, let's return a fixed constant.
        #[cfg(any(target_arch = "aarch64",
                  target_arch = "powerpc",
                  all(target_arch = "arm", target_os = "ios"),
                  all(target_arch = "x86", target_os = "freebsd"),
                  target_os = "bitrig",
                  target_os = "netbsd",
                  target_os = "openbsd"))]
        #[inline(always)]
        unsafe fn target_get_sp_limit() -> usize {
            1024
        }
    }
}
<|endoftext|>


<commit_before>use std::iter::*;
use std::sync::atomic::*;
use atomic_option::*;
use types::*;
use config::*;
use player::*;
use field::*;

struct UctNode {
  wins: AtomicUsize,
  draws: AtomicUsize,
  visits: AtomicUsize,
  pos: Pos,
  child: AtomicOption<UctNode>,
  sibling: Option<Box<UctNode>>
}

impl UctNode {
  pub fn new() -> UctNode {
    UctNode {
      wins: AtomicUsize::new(0),
      draws: AtomicUsize::new(0),
      visits: AtomicUsize::new(0),
      pos: 0,
      child: AtomicOption::empty(),
      sibling: None
    }
  }
}

pub struct UctRoot {
  node: Option<Box<UctNode>>,
  moves: Vec<Pos>,
  moves_field: Vec<Pos>,
  player: Option<Player>,
  moves_count: usize,
  hash: u64
}

impl UctRoot {
  fn clear(&mut self) {
    self.node = None;
    self.moves.clear();
    for i in self.moves_field.iter_mut() {
      *i = 0;
    }
    self.player = None;
    self.moves_count = 0;
    self.hash = 0;
  }

  fn init(&mut self, field: &Field) {
    self.node = Some(Box::new(UctNode::new()));
    self.player = None;
    let width = field.width();
    for &start_pos in field.points_seq() {
      wave(width, start_pos, |pos| {
        if self.moves_field[pos] != start_pos && field.is_putting_allowed(pos) && manhattan(width, start_pos, pos) <= UCT_RADIUS {
          self.moves_field[pos] = start_pos;
          true
        } else {
          false
        }
      });
    }
  }

  fn update(&mut self, field: &Field, player: Player) {
    if !self.node.is_none() && field.hash_at(self.moves_count) != Some(self.hash) {
      self.clear();
    }
    loop {

    }
  }

  pub fn new(length: Pos) -> UctRoot {
    UctRoot {
      node: None,
      moves: Vec::new(),
      moves_field: repeat(0).take(length).collect(),
      player: None,
      moves_count: 0,
      hash: 0
    }
  }

  pub fn best_move(&mut self) -> Pos {
    0
  }

  //pub fn estimates
}
<commit_msg>Fix in UCT init.<commit_after>use std::iter::*;
use std::sync::atomic::*;
use atomic_option::*;
use types::*;
use config::*;
use player::*;
use field::*;

struct UctNode {
  wins: AtomicUsize,
  draws: AtomicUsize,
  visits: AtomicUsize,
  pos: Pos,
  child: AtomicOption<UctNode>,
  sibling: Option<Box<UctNode>>
}

impl UctNode {
  pub fn new() -> UctNode {
    UctNode {
      wins: AtomicUsize::new(0),
      draws: AtomicUsize::new(0),
      visits: AtomicUsize::new(0),
      pos: 0,
      child: AtomicOption::empty(),
      sibling: None
    }
  }
}

pub struct UctRoot {
  node: Option<Box<UctNode>>,
  moves: Vec<Pos>,
  moves_field: Vec<Pos>,
  player: Option<Player>,
  moves_count: usize,
  hash: u64
}

impl UctRoot {
  fn clear(&mut self) {
    self.node = None;
    self.moves.clear();
    for i in self.moves_field.iter_mut() {
      *i = 0;
    }
    self.player = None;
    self.moves_count = 0;
    self.hash = 0;
  }

  fn init(&mut self, field: &Field) {
    self.node = Some(Box::new(UctNode::new()));
    self.player = None;
    let width = field.width();
    for &start_pos in field.points_seq() {
      wave(width, start_pos, |pos| {
        if self.moves_field[pos] != start_pos && field.is_putting_allowed(pos) && manhattan(width, start_pos, pos) <= UCT_RADIUS {
          if self.moves_field[pos] == 0 {
            self.moves.push(pos);
          }
          self.moves_field[pos] = start_pos;
          true
        } else {
          false
        }
      });
    }
  }

  fn update(&mut self, field: &Field, player: Player) {
    if !self.node.is_none() && field.hash_at(self.moves_count) != Some(self.hash) {
      self.clear();
    }
    loop {

    }
  }

  pub fn new(length: Pos) -> UctRoot {
    UctRoot {
      node: None,
      moves: Vec::new(),
      moves_field: repeat(0).take(length).collect(),
      player: None,
      moves_count: 0,
      hash: 0
    }
  }

  pub fn best_move(&mut self) -> Pos {
    0
  }

  //pub fn estimates
}
<|endoftext|>


<commit_before><commit_msg>Remove CowRcStr APIs that might allocate and used to never do so.<commit_after><|endoftext|>


<commit_before>import ptr::addr_of;
import comm::{port, chan, methods};
import result::{result, ok, err};
import std::net::ip::{
    get_addr, format_addr, ipv4, ipv6, ip_addr,
    ip_get_addr_err
};
import std::net::tcp::{connect, tcp_socket};
import std::uv_global_loop;
import comm::{methods};
import connection::{
    Connection, ConnectionFactory, UvConnectionFactory,
    MockConnection, MockConnectionFactory
};
import parser::{Parser, ParserCallbacks};

const timeout: uint = 2000;

/**
A quick hack URI type
*/
type Uri = {
    host: ~str,
    path: ~str
};

/// HTTP status codes
enum StatusCode {
    StatusOk = 200,
    StatusUnknown
}

/// HTTP request error conditions
enum RequestError {
    ErrorDnsResolution,
    ErrorConnect,
    ErrorMisc
}

/// Request
enum RequestEvent {
    Status(StatusCode),
    Payload(~mut option<~[u8]>),
    Error(RequestError)
}

type DnsResolver = fn@(host: ~str) -> result<~[ip_addr], ip_get_addr_err>;

fn uv_dns_resolver() -> DnsResolver {
    |host| {
        let iotask = uv_global_loop::get();
        get_addr(host, iotask)
    }
}

fn uv_http_request(+uri: Uri) -> HttpRequest<tcp_socket, UvConnectionFactory> {
    HttpRequest(uv_dns_resolver(), UvConnectionFactory, uri)
}

class HttpRequest<C: Connection, CF: ConnectionFactory<C>> {

    let resolve_ip_addr: DnsResolver;
    let connection_factory: CF;
    let uri: Uri;
    let parser: Parser;

    new(resolver: DnsResolver, +connection_factory: CF, +uri: Uri) {
        self.resolve_ip_addr = resolver;
        self.connection_factory = connection_factory;
        self.uri = uri;

        self.parser = Parser();
    }

    fn begin(cb: fn(+RequestEvent)) {
        #debug("http_client: looking up uri %?", self.uri);
        let ip_addr = {
            let ip_addrs = self.resolve_ip_addr(self.uri.host);
            if ip_addrs.is_ok() {
                let ip_addrs = result::unwrap(ip_addrs);
                // FIXME: This log crashes
                //#debug("http_client: got IP addresses for %?: %?", self.uri, ip_addrs);
                if ip_addrs.is_not_empty() {
                    // FIXME: Which address should we really pick?
                    let best_ip = do ip_addrs.find |ip| {
                        alt ip {
                          ipv4(*) { true }
                          ipv6(*) { false }
                        }
                    };

                    if best_ip.is_some() {
                        option::unwrap(best_ip)
                    } else {
                        // FIXME: Need test
                        cb(Error(ErrorMisc));
                        ret;
                    }
                } else {
                    #debug("http_client: got no IP addresses for %?", self.uri);
                    // FIXME: Need test
                    cb(Error(ErrorMisc));
                    ret;
                }
            } else {
                #debug("http_client: DNS lookup failure: %?", ip_addrs.get_err());
                cb(Error(ErrorDnsResolution));
                ret;
            }
        };

        #debug("http_client: using IP %? for %?", format_addr(ip_addr), self.uri);

        let socket = {
            #debug("http_client: connecting to %?", ip_addr);
            let socket = self.connection_factory.connect(copy ip_addr, 80);
            if socket.is_ok() {
                result::unwrap(socket)
            } else {
                #debug("http_client: unable to connect to %?: %?", ip_addr, socket);
                cb(Error(ErrorConnect));
                ret;
            }
        };

        #debug("http_client: got socket for %?", ip_addr);

        let request_header = #fmt("GET %s HTTP/1.0\u000D\u000AHost: %s\u000D\u000A\u000D\u000A",
                                  self.uri.path, self.uri.host);
        #debug("http_client: writing request header: %?", request_header);
        let request_header_bytes = str::bytes(request_header);
        alt socket.write_(request_header_bytes) {
          result::ok(*) { }
          result::err(e) {
            // FIXME: Need test
            cb(Error(ErrorMisc));
            ret;
          }
        }

        let read_port = {
            let read_port = socket.read_start_();
            if read_port.is_ok() {
                result::unwrap(read_port)
            } else {
                cb(Error(ErrorMisc));
                ret;
            }
        };

        // This unsafety is unfortunate but we can't capture self
        // into shared closures
        let unsafe_self = addr_of(self);
        let callbacks: ParserCallbacks = unsafe {{
            on_message_begin: || (*unsafe_self).on_message_begin(),
            on_url: |data| (*unsafe_self).on_url(data),
            on_header_field: |data| (*unsafe_self).on_header_field(data),
            on_header_value: |data| (*unsafe_self).on_header_value(data),
            on_headers_complete: || (*unsafe_self).on_headers_complete(),
            on_body: |data| (*unsafe_self).on_body(data),
            on_message_complete: || (*unsafe_self).on_message_complete()
        }};

        loop {
            let next_data = read_port.recv();

            if next_data.is_ok() {
                let next_data = result::unwrap(next_data);
                self.parser.execute(next_data, &callbacks);
                let the_payload = Payload(~mut some(next_data));
                cb(the_payload);
            } else {
                #debug("http_client: read error: %?", next_data);

                // This method of detecting EOF is lame
                alt next_data {
                  result::err({err_name: ~"EOF", _}) {
                    break;
                  }
                  _ {
                    // FIXME: Need tests and error handling
                    socket.read_stop_(read_port);
                    cb(Error(ErrorMisc));
                    ret;
                  }
                }
            }
        }
        socket.read_stop_(read_port);
    }

    fn on_message_begin() -> bool {
        #debug("on_message_begin");
        true
    }

    fn on_url(+data: ~[u8]) -> bool {
        #debug("on_url");
        true
    }

    fn on_header_field(+data: ~[u8]) -> bool {
        #debug("on_header_field");
        true
    }

    fn on_header_value(+data: ~[u8]) -> bool {
        #debug("on_header_value");
        true
    }

    fn on_headers_complete() -> bool {
        #debug("on_headers_complete");
        true
    }

    fn on_body(+data: ~[u8]) -> bool {
        #debug("on_body");
        true
    }

    fn on_message_complete() -> bool {
        #debug("on_message_complete");
        true
    }
}

fn sequence<C: Connection, CF: ConnectionFactory<C>>(request: HttpRequest<C, CF>) -> ~[RequestEvent] {
    let mut events = ~[];
    do request.begin |event| {
        vec::push(events, event)
    }
    ret events;
}

#[test]
fn test_resolve_error() {
    let uri = {
        host: ~"example.com_not_real",
        path: ~"/"
    };

    let request = uv_http_request(uri);
    let events = sequence(request);

    assert events == ~[
        Error(ErrorDnsResolution),
    ];
}

#[test]
fn test_connect_error() {
    let uri = {
        // This address is invalid because the first octet
        // of a class A address cannot be 0
        host: ~"0.42.42.42",
        path: ~"/"
    };

    let request = uv_http_request(uri);
    let events = sequence(request);

    assert events == ~[
        Error(ErrorConnect),
    ];
}

#[test]
fn test_connect_success() {
    let uri = {
        host: ~"example.com",
        path: ~"/"
    };

    let request = uv_http_request(uri);
    let events = sequence(request);

    for events.each |ev| {
        alt ev {
          Error(*) { fail }
          _ { }
        }
    }
}

#[test]
#[ignore(reason = "ICE")]
fn test_simple_response() {
    let uri = {
        host: ~"whatever",
        path: ~"/"
    };

    let mock_connection: MockConnection = {
        write_fn: |data| { ok(()) },
        read_start_fn: || {
            let port = port();
            let chan = port.chan();

            let response = ~"HTTP/1.0 200 OK\
                            \
                            Test";
            chan.send(ok(str::bytes(response)));

            ok(port)
        },
        read_stop_fn: |_port| { ok(()) }
    };

    let mock_connection_factory: MockConnectionFactory = {
        connect_fn: |ip, port| {

            // FIXME this doesn't work
            fail;//ok(mock_connection)
        }
    };
}<commit_msg>Extract get_ip from HttpRequest<commit_after>import ptr::addr_of;
import comm::{port, chan, methods};
import result::{result, ok, err};
import std::net::ip::{
    get_addr, format_addr, ipv4, ipv6, ip_addr,
    ip_get_addr_err
};
import std::net::tcp::{connect, tcp_socket};
import std::uv_global_loop;
import comm::{methods};
import connection::{
    Connection, ConnectionFactory, UvConnectionFactory,
    MockConnection, MockConnectionFactory
};
import parser::{Parser, ParserCallbacks};

const timeout: uint = 2000;

/**
A quick hack URI type
*/
type Uri = {
    host: ~str,
    path: ~str
};

/// HTTP status codes
enum StatusCode {
    StatusOk = 200,
    StatusUnknown
}

/// HTTP request error conditions
enum RequestError {
    ErrorDnsResolution,
    ErrorConnect,
    ErrorMisc
}

/// Request
enum RequestEvent {
    Status(StatusCode),
    Payload(~mut option<~[u8]>),
    Error(RequestError)
}

type DnsResolver = fn@(host: ~str) -> result<~[ip_addr], ip_get_addr_err>;

fn uv_dns_resolver() -> DnsResolver {
    |host| {
        let iotask = uv_global_loop::get();
        get_addr(host, iotask)
    }
}

fn uv_http_request(+uri: Uri) -> HttpRequest<tcp_socket, UvConnectionFactory> {
    HttpRequest(uv_dns_resolver(), UvConnectionFactory, uri)
}

class HttpRequest<C: Connection, CF: ConnectionFactory<C>> {

    let resolve_ip_addr: DnsResolver;
    let connection_factory: CF;
    let uri: Uri;
    let parser: Parser;

    new(resolver: DnsResolver, +connection_factory: CF, +uri: Uri) {
        self.resolve_ip_addr = resolver;
        self.connection_factory = connection_factory;
        self.uri = uri;

        self.parser = Parser();
    }

    fn begin(cb: fn(+RequestEvent)) {
        #debug("http_client: looking up uri %?", self.uri);
        let ip_addr = alt self.get_ip() {
          ok(ip_addr) { ip_addr }
          err(e) { cb(Error(e)); ret }
        };

        #debug("http_client: using IP %? for %?", format_addr(ip_addr), self.uri);

        let socket = {
            #debug("http_client: connecting to %?", ip_addr);
            let socket = self.connection_factory.connect(copy ip_addr, 80);
            if socket.is_ok() {
                result::unwrap(socket)
            } else {
                #debug("http_client: unable to connect to %?: %?", ip_addr, socket);
                cb(Error(ErrorConnect));
                ret;
            }
        };

        #debug("http_client: got socket for %?", ip_addr);

        let request_header = #fmt("GET %s HTTP/1.0\u000D\u000AHost: %s\u000D\u000A\u000D\u000A",
                                  self.uri.path, self.uri.host);
        #debug("http_client: writing request header: %?", request_header);
        let request_header_bytes = str::bytes(request_header);
        alt socket.write_(request_header_bytes) {
          result::ok(*) { }
          result::err(e) {
            // FIXME: Need test
            cb(Error(ErrorMisc));
            ret;
          }
        }

        let read_port = {
            let read_port = socket.read_start_();
            if read_port.is_ok() {
                result::unwrap(read_port)
            } else {
                cb(Error(ErrorMisc));
                ret;
            }
        };

        // This unsafety is unfortunate but we can't capture self
        // into shared closures
        let unsafe_self = addr_of(self);
        let callbacks: ParserCallbacks = unsafe {{
            on_message_begin: || (*unsafe_self).on_message_begin(),
            on_url: |data| (*unsafe_self).on_url(data),
            on_header_field: |data| (*unsafe_self).on_header_field(data),
            on_header_value: |data| (*unsafe_self).on_header_value(data),
            on_headers_complete: || (*unsafe_self).on_headers_complete(),
            on_body: |data| (*unsafe_self).on_body(data),
            on_message_complete: || (*unsafe_self).on_message_complete()
        }};

        loop {
            let next_data = read_port.recv();

            if next_data.is_ok() {
                let next_data = result::unwrap(next_data);
                self.parser.execute(next_data, &callbacks);
                let the_payload = Payload(~mut some(next_data));
                cb(the_payload);
            } else {
                #debug("http_client: read error: %?", next_data);

                // This method of detecting EOF is lame
                alt next_data {
                  result::err({err_name: ~"EOF", _}) {
                    break;
                  }
                  _ {
                    // FIXME: Need tests and error handling
                    socket.read_stop_(read_port);
                    cb(Error(ErrorMisc));
                    ret;
                  }
                }
            }
        }
        socket.read_stop_(read_port);
    }

    fn get_ip() -> result<ip_addr, RequestError> {
        let ip_addrs = self.resolve_ip_addr(self.uri.host);
        if ip_addrs.is_ok() {
            let ip_addrs = result::unwrap(ip_addrs);
            // FIXME: This log crashes
            //#debug("http_client: got IP addresses for %?: %?", self.uri, ip_addrs);
            if ip_addrs.is_not_empty() {
                // FIXME: Which address should we really pick?
                let best_ip = do ip_addrs.find |ip| {
                    alt ip {
                      ipv4(*) { true }
                      ipv6(*) { false }
                    }
                };

                if best_ip.is_some() {
                    ret ok(option::unwrap(best_ip));
                } else {
                    // FIXME: Need test
                    ret err(ErrorMisc);
                }
            } else {
                #debug("http_client: got no IP addresses for %?", self.uri);
                // FIXME: Need test
                ret err(ErrorMisc);
            }
        } else {
            #debug("http_client: DNS lookup failure: %?", ip_addrs.get_err());
            ret err(ErrorDnsResolution);
        }
    }

    fn on_message_begin() -> bool {
        #debug("on_message_begin");
        true
    }

    fn on_url(+data: ~[u8]) -> bool {
        #debug("on_url");
        true
    }

    fn on_header_field(+data: ~[u8]) -> bool {
        #debug("on_header_field");
        true
    }

    fn on_header_value(+data: ~[u8]) -> bool {
        #debug("on_header_value");
        true
    }

    fn on_headers_complete() -> bool {
        #debug("on_headers_complete");
        true
    }

    fn on_body(+data: ~[u8]) -> bool {
        #debug("on_body");
        true
    }

    fn on_message_complete() -> bool {
        #debug("on_message_complete");
        true
    }
}

fn sequence<C: Connection, CF: ConnectionFactory<C>>(request: HttpRequest<C, CF>) -> ~[RequestEvent] {
    let mut events = ~[];
    do request.begin |event| {
        vec::push(events, event)
    }
    ret events;
}

#[test]
fn test_resolve_error() {
    let uri = {
        host: ~"example.com_not_real",
        path: ~"/"
    };

    let request = uv_http_request(uri);
    let events = sequence(request);

    assert events == ~[
        Error(ErrorDnsResolution),
    ];
}

#[test]
fn test_connect_error() {
    let uri = {
        // This address is invalid because the first octet
        // of a class A address cannot be 0
        host: ~"0.42.42.42",
        path: ~"/"
    };

    let request = uv_http_request(uri);
    let events = sequence(request);

    assert events == ~[
        Error(ErrorConnect),
    ];
}

#[test]
fn test_connect_success() {
    let uri = {
        host: ~"example.com",
        path: ~"/"
    };

    let request = uv_http_request(uri);
    let events = sequence(request);

    for events.each |ev| {
        alt ev {
          Error(*) { fail }
          _ { }
        }
    }
}

#[test]
#[ignore(reason = "ICE")]
fn test_simple_response() {
    let uri = {
        host: ~"whatever",
        path: ~"/"
    };

    let mock_connection: MockConnection = {
        write_fn: |data| { ok(()) },
        read_start_fn: || {
            let port = port();
            let chan = port.chan();

            let response = ~"HTTP/1.0 200 OK\
                            \
                            Test";
            chan.send(ok(str::bytes(response)));

            ok(port)
        },
        read_stop_fn: |_port| { ok(()) }
    };

    let mock_connection_factory: MockConnectionFactory = {
        connect_fn: |ip, port| {

            // FIXME this doesn't work
            fail;//ok(mock_connection)
        }
    };
}<|endoftext|>


<commit_before><commit_msg>Add GAUniformSelector. Remove sort_basis from select(), add to GARankSelector.<commit_after><|endoftext|>


<commit_before>use std::io;
use std::fmt;
use std::error;
use std::vec::Vec;
use byteorder;
use byteorder::{BigEndian,ReadBytesExt,WriteBytesExt};

#[derive(Debug)]
pub enum Error {
	Io(byteorder::Error),
	InvalidValue,
	InvalidType
}

impl From<byteorder::Error> for Error {
	fn from(err: byteorder::Error) -> Error { Error::Io(err) }
}

impl From<Error> for byteorder::Error {
	fn from(err: Error) -> byteorder::Error {
		match err {
			Error::Io(err) => err,
			Error::InvalidValue => byteorder::Error::Io(io::Error::new(io::ErrorKind::Other, "Invalid value")),
			Error::InvalidType => byteorder::Error::Io(io::Error::new(io::ErrorKind::Other, "Invalid type")),
		}
	}
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
	        match *self {
				Error::InvalidValue => write!(f, "Invalid value."),
				Error::InvalidType => write!(f, "Invalid type."),
				Error::Io(ref err) => err.fmt(f),
			}
	}
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::InvalidValue => "Invalid value.",
            Error::InvalidType => "Invalid type.",
            Error::Io(ref err) => error::Error::description(err),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::InvalidValue => None,
            Error::InvalidType => None,
            Error::Io(ref err) => err.cause(),
        }
    }
}

pub struct XdrReader {
	reader : io::Cursor<Vec<u8>>
}

pub struct XdrWriter {
	writer : io::Cursor<Vec<u8>>
}

impl XdrWriter {
	pub fn new() -> XdrWriter {
		let v : Vec<u8>= Vec::new();
		XdrWriter{ writer: io::Cursor::new(v)}
	}

	pub fn get_buffer(self) -> Vec<u8> {
		self.writer.into_inner()
	}

	pub fn pack<T:XdrPrimitive>(&mut self, x:T) {
		XdrPrimitive::write_to_xdr(self, x)
	}

}
pub trait XdrPrimitive {
	fn read_from_xdr(x: &mut XdrReader) -> Result<Self, Error>;
	fn write_to_xdr(x: &mut XdrWriter, v: Self);
}

impl XdrPrimitive for u32 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<u32, Error>{
		match x.reader.read_u32::<byteorder::BigEndian>() {
			Ok(v) => Ok(v),
			Err(v) => Err(Error::Io(v))
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_u32::<byteorder::BigEndian>(v).unwrap();
	}
}
impl XdrPrimitive for u16 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<u16, Error>{
		match x.reader.read_u32::<byteorder::BigEndian>() {
			Ok(v) => Ok(v as u16),
			Err(v) => Err(Error::Io(v))
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_u32::<byteorder::BigEndian>(v as u32).unwrap();
	}
}
impl XdrPrimitive for u8 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<u8, Error>{
		match x.reader.read_u32::<byteorder::BigEndian>() {
			Ok(v) => Ok(v as u8),
			Err(v) => Err(Error::Io(v))
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_u32::<byteorder::BigEndian>(v as u32).unwrap();
	}
}
impl XdrPrimitive for i8 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<i8, Error>{
		match x.reader.read_i32::<byteorder::BigEndian>() {
			Ok(v) => Ok(v as i8),
			Err(v) => Err(Error::Io(v))
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_i32::<byteorder::BigEndian>(v as i32).unwrap();
	}
}
impl XdrPrimitive for i16 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<i16, Error>{
		match x.reader.read_i32::<byteorder::BigEndian>() {
			Ok(v) => Ok(v as i16),
			Err(v) => Err(Error::Io(v))
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_i32::<byteorder::BigEndian>(v as i32).unwrap();
	}
}
impl XdrPrimitive for i32 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<i32, Error>{
		match x.reader.read_i32::<byteorder::BigEndian>() {
			Ok(v) => Ok(v),
			Err(v) => Err(Error::Io(v))
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_i32::<byteorder::BigEndian>(v).unwrap();
	}
}
impl XdrPrimitive for i64 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<i64, Error>{
		match x.reader.read_i64::<byteorder::BigEndian>() {
			Ok(v) => Ok(v),
			Err(v) => Err(Error::Io(v))
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_i64::<byteorder::BigEndian>(v).unwrap();
	}
}
impl XdrPrimitive for u64 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<u64, Error>{
		match x.reader.read_u64::<byteorder::BigEndian>() {
			Ok(v) => Ok(v),
			Err(v) => Err(Error::Io(v))
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_u64::<byteorder::BigEndian>(v).unwrap();
	}

}

impl XdrPrimitive for f32 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<f32, Error>{
		match x.reader.read_f32::<byteorder::BigEndian>() {
			Ok(v) => Ok(v),
			Err(v) => Err(Error::Io(v))
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_f32::<byteorder::BigEndian>(v).unwrap();
	}
}
impl XdrPrimitive for f64 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<f64, Error>{
		match x.reader.read_f64::<byteorder::BigEndian>() {
			Ok(v) => Ok(v),
			Err(v) => Err(Error::Io(v))
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_f64::<byteorder::BigEndian>(v).unwrap();
	}
}

<commit_msg>implement XdrPrimitive for bool type<commit_after>use std::io;
use std::fmt;
use std::error;
use std::vec::Vec;
use byteorder;
use byteorder::{BigEndian,ReadBytesExt,WriteBytesExt};

#[derive(Debug)]
pub enum Error {
	Io(byteorder::Error),
	InvalidValue,
	InvalidType
}

impl From<byteorder::Error> for Error {
	fn from(err: byteorder::Error) -> Error { Error::Io(err) }
}

impl From<Error> for byteorder::Error {
	fn from(err: Error) -> byteorder::Error {
		match err {
			Error::Io(err) => err,
			Error::InvalidValue => byteorder::Error::Io(io::Error::new(io::ErrorKind::Other, "Invalid value")),
			Error::InvalidType => byteorder::Error::Io(io::Error::new(io::ErrorKind::Other, "Invalid type")),
		}
	}
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
	        match *self {
				Error::InvalidValue => write!(f, "Invalid value."),
				Error::InvalidType => write!(f, "Invalid type."),
				Error::Io(ref err) => err.fmt(f),
			}
	}
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::InvalidValue => "Invalid value.",
            Error::InvalidType => "Invalid type.",
            Error::Io(ref err) => error::Error::description(err),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::InvalidValue => None,
            Error::InvalidType => None,
            Error::Io(ref err) => err.cause(),
        }
    }
}

pub struct XdrReader {
	reader : io::Cursor<Vec<u8>>
}

pub struct XdrWriter {
	writer : io::Cursor<Vec<u8>>
}

impl XdrWriter {
	pub fn new() -> XdrWriter {
		let v : Vec<u8>= Vec::new();
		XdrWriter{ writer: io::Cursor::new(v)}
	}

	pub fn get_buffer(self) -> Vec<u8> {
		self.writer.into_inner()
	}

	pub fn pack<T:XdrPrimitive>(&mut self, x:T) {
		XdrPrimitive::write_to_xdr(self, x)
	}

}
pub trait XdrPrimitive {
	fn read_from_xdr(x: &mut XdrReader) -> Result<Self, Error>;
	fn write_to_xdr(x: &mut XdrWriter, v: Self);
}

impl XdrPrimitive for u32 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<u32, Error>{
		match x.reader.read_u32::<byteorder::BigEndian>() {
			Ok(v) => Ok(v),
			Err(v) => Err(Error::Io(v))
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_u32::<byteorder::BigEndian>(v).unwrap();
	}
}
impl XdrPrimitive for u16 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<u16, Error>{
		match x.reader.read_u32::<byteorder::BigEndian>() {
			Ok(v) => Ok(v as u16),
			Err(v) => Err(Error::Io(v))
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_u32::<byteorder::BigEndian>(v as u32).unwrap();
	}
}
impl XdrPrimitive for u8 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<u8, Error>{
		match x.reader.read_u32::<byteorder::BigEndian>() {
			Ok(v) => Ok(v as u8),
			Err(v) => Err(Error::Io(v))
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_u32::<byteorder::BigEndian>(v as u32).unwrap();
	}
}
impl XdrPrimitive for i8 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<i8, Error>{
		match x.reader.read_i32::<byteorder::BigEndian>() {
			Ok(v) => Ok(v as i8),
			Err(v) => Err(Error::Io(v))
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_i32::<byteorder::BigEndian>(v as i32).unwrap();
	}
}
impl XdrPrimitive for i16 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<i16, Error>{
		match x.reader.read_i32::<byteorder::BigEndian>() {
			Ok(v) => Ok(v as i16),
			Err(v) => Err(Error::Io(v))
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_i32::<byteorder::BigEndian>(v as i32).unwrap();
	}
}
impl XdrPrimitive for i32 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<i32, Error>{
		match x.reader.read_i32::<byteorder::BigEndian>() {
			Ok(v) => Ok(v),
			Err(v) => Err(Error::Io(v))
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_i32::<byteorder::BigEndian>(v).unwrap();
	}
}
impl XdrPrimitive for i64 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<i64, Error>{
		match x.reader.read_i64::<byteorder::BigEndian>() {
			Ok(v) => Ok(v),
			Err(v) => Err(Error::Io(v))
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_i64::<byteorder::BigEndian>(v).unwrap();
	}
}
impl XdrPrimitive for u64 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<u64, Error>{
		match x.reader.read_u64::<byteorder::BigEndian>() {
			Ok(v) => Ok(v),
			Err(v) => Err(Error::Io(v))
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_u64::<byteorder::BigEndian>(v).unwrap();
	}

}

impl XdrPrimitive for f32 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<f32, Error>{
		match x.reader.read_f32::<byteorder::BigEndian>() {
			Ok(v) => Ok(v),
			Err(v) => Err(Error::Io(v))
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_f32::<byteorder::BigEndian>(v).unwrap();
	}
}
impl XdrPrimitive for f64 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<f64, Error>{
		match x.reader.read_f64::<byteorder::BigEndian>() {
			Ok(v) => Ok(v),
			Err(v) => Err(Error::Io(v))
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_f64::<byteorder::BigEndian>(v).unwrap();
	}
}

impl XdrPrimitive for bool {
	fn read_from_xdr(x: &mut XdrReader) -> Result<bool, Error>{
		match x.reader.read_u32::<byteorder::BigEndian>() {
			Ok(0) => Ok(false),
			Ok(1) => Ok(true),
			Ok(_) => Err(Error::InvalidValue),
			Err(v) => Err(Error::Io(v))
		}
	}

	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		match v {
			true => x.writer.write_u32::<byteorder::BigEndian>(1).unwrap(),
			false => x.writer.write_u32::<byteorder::BigEndian>(0).unwrap(),
		}
	}
}
<|endoftext|>


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

use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::BlobBinding::BlobMethods;
use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
use dom::bindings::codegen::Bindings::FileReaderBinding::{self, FileReaderConstants, FileReaderMethods};
use dom::bindings::error::{Error, ErrorResult, Fallible};
use dom::bindings::global::GlobalRef;
use dom::bindings::inheritance::Castable;
use dom::bindings::js::{JS, MutNullableHeap, Root};
use dom::bindings::refcounted::Trusted;
use dom::bindings::reflector::{Reflectable, reflect_dom_object};
use dom::bindings::str::DOMString;
use dom::blob::Blob;
use dom::domexception::{DOMErrorName, DOMException};
use dom::event::{Event, EventBubbles, EventCancelable};
use dom::eventtarget::EventTarget;
use dom::progressevent::ProgressEvent;
use encoding::all::UTF_8;
use encoding::label::encoding_from_whatwg_label;
use encoding::types::{DecoderTrap, EncodingRef};
use hyper::mime::{Attr, Mime};
use rustc_serialize::base64::{CharacterSet, Config, Newline, ToBase64};
use script_runtime::ScriptThreadEventCategory::FileRead;
use script_runtime::{ScriptChan, CommonScriptMsg};
use script_thread::Runnable;
use std::cell::Cell;
use std::sync::Arc;
use string_cache::Atom;
use util::thread::spawn_named;

#[derive(PartialEq, Clone, Copy, JSTraceable, HeapSizeOf)]
pub enum FileReaderFunction {
    ReadAsText,
    ReadAsDataUrl,
}

pub type TrustedFileReader = Trusted<FileReader>;

#[derive(Clone, HeapSizeOf)]
pub struct ReadMetaData {
    pub blobtype: String,
    pub label: Option<String>,
    pub function: FileReaderFunction
}

impl ReadMetaData {
    pub fn new(blobtype: String,
               label: Option<String>, function: FileReaderFunction) -> ReadMetaData {
        ReadMetaData {
            blobtype: blobtype,
            label: label,
            function: function,
        }
    }
}

#[derive(PartialEq, Clone, Copy, JSTraceable, HeapSizeOf)]
pub struct GenerationId(u32);

#[repr(u16)]
#[derive(Copy, Clone, Debug, PartialEq, JSTraceable, HeapSizeOf)]
pub enum FileReaderReadyState {
    Empty = FileReaderConstants::EMPTY,
    Loading = FileReaderConstants::LOADING,
    Done = FileReaderConstants::DONE,
}

#[dom_struct]
pub struct FileReader {
    eventtarget: EventTarget,
    ready_state: Cell<FileReaderReadyState>,
    error: MutNullableHeap<JS<DOMException>>,
    result: DOMRefCell<Option<DOMString>>,
    generation_id: Cell<GenerationId>,
}

impl FileReader {
    pub fn new_inherited() -> FileReader {
        FileReader {
            eventtarget: EventTarget::new_inherited(),
            ready_state: Cell::new(FileReaderReadyState::Empty),
            error: MutNullableHeap::new(None),
            result: DOMRefCell::new(None),
            generation_id: Cell::new(GenerationId(0)),
        }
    }

    pub fn new(global: GlobalRef) -> Root<FileReader> {
        reflect_dom_object(box FileReader::new_inherited(),
                           global, FileReaderBinding::Wrap)
    }

    pub fn Constructor(global: GlobalRef) -> Fallible<Root<FileReader>> {
        Ok(FileReader::new(global))
    }

    //https://w3c.github.io/FileAPI/#dfn-error-steps
    pub fn process_read_error(filereader: TrustedFileReader, gen_id: GenerationId, error: DOMErrorName) {
        let fr = filereader.root();

        macro_rules! return_on_abort(
            () => (
                if gen_id != fr.generation_id.get() {
                    return
                }
            );
        );

        return_on_abort!();
        // Step 1
        fr.change_ready_state(FileReaderReadyState::Done);
        *fr.result.borrow_mut() = None;

        let global = fr.r().global();
        let exception = DOMException::new(global.r(), error);
        fr.error.set(Some(&exception));

        fr.dispatch_progress_event(atom!("error"), 0, None);
        return_on_abort!();
        // Step 3
        fr.dispatch_progress_event(atom!("loadend"), 0, None);
        return_on_abort!();
        // Step 4
        fr.terminate_ongoing_reading();
    }

    // https://w3c.github.io/FileAPI/#dfn-readAsText
    pub fn process_read_data(filereader: TrustedFileReader, gen_id: GenerationId) {
        let fr = filereader.root();

        macro_rules! return_on_abort(
            () => (
                if gen_id != fr.generation_id.get() {
                    return
                }
            );
        );
        return_on_abort!();
        //FIXME Step 7 send current progress
        fr.dispatch_progress_event(atom!("progress"), 0, None);
    }

    // https://w3c.github.io/FileAPI/#dfn-readAsText
    pub fn process_read(filereader: TrustedFileReader, gen_id: GenerationId) {
        let fr = filereader.root();

        macro_rules! return_on_abort(
            () => (
                if gen_id != fr.generation_id.get() {
                    return
                }
            );
        );
        return_on_abort!();
        // Step 6
        fr.dispatch_progress_event(atom!("loadstart"), 0, None);
    }

    // https://w3c.github.io/FileAPI/#dfn-readAsText
    pub fn process_read_eof(filereader: TrustedFileReader, gen_id: GenerationId,
                            data: ReadMetaData, blob_contents: Arc<Vec<u8>>) {
        let fr = filereader.root();

        macro_rules! return_on_abort(
            () => (
                if gen_id != fr.generation_id.get() {
                    return
                }
            );
        );

        return_on_abort!();
        // Step 8.1
        fr.change_ready_state(FileReaderReadyState::Done);
        // Step 8.2

        let output = match data.function {
            FileReaderFunction::ReadAsDataUrl =>
                FileReader::perform_readasdataurl(data, &blob_contents),
            FileReaderFunction::ReadAsText =>
                FileReader::perform_readastext(data, &blob_contents),
        };

        *fr.result.borrow_mut() = Some(output);

        // Step 8.3
        fr.dispatch_progress_event(atom!("load"), 0, None);
        return_on_abort!();
        // Step 8.4
        if fr.ready_state.get() != FileReaderReadyState::Loading {
            fr.dispatch_progress_event(atom!("loadend"), 0, None);
        }
        return_on_abort!();
        // Step 9
        fr.terminate_ongoing_reading();
    }

    // https://w3c.github.io/FileAPI/#dfn-readAsText
    fn perform_readastext(data: ReadMetaData, blob_bytes: &[u8])
        -> DOMString {
        let blob_label = &data.label;
        let blob_type = &data.blobtype;

        //https://w3c.github.io/FileAPI/#encoding-determination
        // Steps 1 & 2 & 3
        let mut encoding = blob_label.as_ref()
            .map(|string| &**string)
            .and_then(encoding_from_whatwg_label);

        // Step 4 & 5
        encoding = encoding.or_else(|| {
            let resultmime = blob_type.parse::<Mime>().ok();
            resultmime.and_then(|Mime(_, _, ref parameters)| {
                parameters.iter()
                    .find(|&&(ref k, _)| &Attr::Charset == k)
                    .and_then(|&(_, ref v)| encoding_from_whatwg_label(&v.to_string()))
            })
        });

        // Step 6
        let enc = encoding.unwrap_or(UTF_8 as EncodingRef);

        let convert = blob_bytes;
        // Step 7
        let output = enc.decode(convert, DecoderTrap::Replace).unwrap();
        DOMString::from(output)
    }

    //https://w3c.github.io/FileAPI/#dfn-readAsDataURL
    fn perform_readasdataurl(data: ReadMetaData, bytes: &[u8])
        -> DOMString {
        let config = Config {
            char_set: CharacterSet::UrlSafe,
            newline: Newline::LF,
            pad: true,
            line_length: None
        };
        let base64 = bytes.to_base64(config);

        let output = if data.blobtype.is_empty() {
            format!("data:base64,{}", base64)
        } else {
            format!("data:{};base64,{}", data.blobtype, base64)
        };

        DOMString::from(output)
    }
}

impl FileReaderMethods for FileReader {
    // https://w3c.github.io/FileAPI/#dfn-onloadstart
    event_handler!(loadstart, GetOnloadstart, SetOnloadstart);

    // https://w3c.github.io/FileAPI/#dfn-onprogress
    event_handler!(progress, GetOnprogress, SetOnprogress);

    // https://w3c.github.io/FileAPI/#dfn-onload
    event_handler!(load, GetOnload, SetOnload);

    // https://w3c.github.io/FileAPI/#dfn-onabort
    event_handler!(abort, GetOnabort, SetOnabort);

    // https://w3c.github.io/FileAPI/#dfn-onerror
    event_handler!(error, GetOnerror, SetOnerror);

    // https://w3c.github.io/FileAPI/#dfn-onloadend
    event_handler!(loadend, GetOnloadend, SetOnloadend);

    //TODO https://w3c.github.io/FileAPI/#dfn-readAsArrayBuffer
    // https://w3c.github.io/FileAPI/#dfn-readAsDataURL
    fn ReadAsDataURL(&self, blob: &Blob) -> ErrorResult {
        self.read(FileReaderFunction::ReadAsDataUrl, blob, None)
    }

    // https://w3c.github.io/FileAPI/#dfn-readAsText
    fn ReadAsText(&self, blob: &Blob, label: Option<DOMString>) -> ErrorResult {
        self.read(FileReaderFunction::ReadAsText, blob, label)
    }

    // https://w3c.github.io/FileAPI/#dfn-abort
    fn Abort(&self) {
        // Step 2
        if self.ready_state.get() == FileReaderReadyState::Loading {
            self.change_ready_state(FileReaderReadyState::Done);
        }
        // Steps 1 & 3
        *self.result.borrow_mut() = None;

        let global = self.global();
        let exception = DOMException::new(global.r(), DOMErrorName::AbortError);
        self.error.set(Some(&exception));

        self.terminate_ongoing_reading();
        // Steps 5 & 6
        self.dispatch_progress_event(atom!("abort"), 0, None);
        self.dispatch_progress_event(atom!("loadend"), 0, None);
    }

    // https://w3c.github.io/FileAPI/#dfn-error
    fn GetError(&self) -> Option<Root<DOMException>> {
        self.error.get()
    }

    // https://w3c.github.io/FileAPI/#dfn-result
    fn GetResult(&self) -> Option<DOMString> {
        self.result.borrow().clone()
    }

    // https://w3c.github.io/FileAPI/#dfn-readyState
    fn ReadyState(&self) -> u16 {
        self.ready_state.get() as u16
    }
}

impl FileReader {
    fn dispatch_progress_event(&self, type_: Atom, loaded: u64, total: Option<u64>) {
        let global = self.global();
        let progressevent = ProgressEvent::new(global.r(),
            type_, EventBubbles::DoesNotBubble, EventCancelable::NotCancelable,
            total.is_some(), loaded, total.unwrap_or(0));
        progressevent.upcast::<Event>().fire(self.upcast());
    }

    fn terminate_ongoing_reading(&self) {
        let GenerationId(prev_id) = self.generation_id.get();
        self.generation_id.set(GenerationId(prev_id + 1));
    }

    fn read(&self, function: FileReaderFunction, blob: &Blob, label: Option<DOMString>) -> ErrorResult {
        // Step 1
        if self.ready_state.get() == FileReaderReadyState::Loading {
            return Err(Error::InvalidState);
        }
        // Step 2
        if blob.IsClosed() {
            let global = self.global();
            let exception = DOMException::new(global.r(), DOMErrorName::InvalidStateError);
            self.error.set(Some(&exception));

            self.dispatch_progress_event(atom!("error"), 0, None);
            return Ok(());
        }

        // Step 3
        self.change_ready_state(FileReaderReadyState::Loading);

        // Step 4
        let blob_contents = Arc::new(blob.get_bytes().unwrap_or(vec![]));

        let type_ = blob.Type();

        let load_data = ReadMetaData::new(String::from(type_), label.map(String::from), function);

        let fr = Trusted::new(self);
        let gen_id = self.generation_id.get();

        let script_chan = self.global().r().file_reading_task_source();

        spawn_named("file reader async operation".to_owned(), move || {
            perform_annotated_read_operation(gen_id, load_data, blob_contents, fr, script_chan)
        });
        Ok(())
    }

    fn change_ready_state(&self, state: FileReaderReadyState) {
        self.ready_state.set(state);
    }
}

#[derive(Clone)]
pub enum FileReaderEvent {
    ProcessRead(TrustedFileReader, GenerationId),
    ProcessReadData(TrustedFileReader, GenerationId),
    ProcessReadError(TrustedFileReader, GenerationId, DOMErrorName),
    ProcessReadEOF(TrustedFileReader, GenerationId, ReadMetaData, Arc<Vec<u8>>)
}

impl Runnable for FileReaderEvent {
    fn handler(self: Box<FileReaderEvent>) {
        let file_reader_event = *self;
        match file_reader_event {
            FileReaderEvent::ProcessRead(filereader, gen_id) => {
                FileReader::process_read(filereader, gen_id);
            },
            FileReaderEvent::ProcessReadData(filereader, gen_id) => {
                FileReader::process_read_data(filereader, gen_id);
            },
            FileReaderEvent::ProcessReadError(filereader, gen_id, error) => {
                FileReader::process_read_error(filereader, gen_id, error);
            },
            FileReaderEvent::ProcessReadEOF(filereader, gen_id, data, blob_contents) => {
                FileReader::process_read_eof(filereader, gen_id, data, blob_contents);
            }
        }
    }
}

// https://w3c.github.io/FileAPI/#thread-read-operation
fn perform_annotated_read_operation(gen_id: GenerationId, data: ReadMetaData, blob_contents: Arc<Vec<u8>>,
    filereader: TrustedFileReader, script_chan: Box<ScriptChan + Send>) {
    let chan = &script_chan;
    // Step 4
    let thread = box FileReaderEvent::ProcessRead(filereader.clone(), gen_id);
    chan.send(CommonScriptMsg::RunnableMsg(FileRead, thread)).unwrap();

    let thread = box FileReaderEvent::ProcessReadData(filereader.clone(), gen_id);
    chan.send(CommonScriptMsg::RunnableMsg(FileRead, thread)).unwrap();

    let thread = box FileReaderEvent::ProcessReadEOF(filereader, gen_id, data, blob_contents);
    chan.send(CommonScriptMsg::RunnableMsg(FileRead, thread)).unwrap();
}
<commit_msg>Implements name method for FilerReader event from trait Runnable<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::BlobBinding::BlobMethods;
use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
use dom::bindings::codegen::Bindings::FileReaderBinding::{self, FileReaderConstants, FileReaderMethods};
use dom::bindings::error::{Error, ErrorResult, Fallible};
use dom::bindings::global::GlobalRef;
use dom::bindings::inheritance::Castable;
use dom::bindings::js::{JS, MutNullableHeap, Root};
use dom::bindings::refcounted::Trusted;
use dom::bindings::reflector::{Reflectable, reflect_dom_object};
use dom::bindings::str::DOMString;
use dom::blob::Blob;
use dom::domexception::{DOMErrorName, DOMException};
use dom::event::{Event, EventBubbles, EventCancelable};
use dom::eventtarget::EventTarget;
use dom::progressevent::ProgressEvent;
use encoding::all::UTF_8;
use encoding::label::encoding_from_whatwg_label;
use encoding::types::{DecoderTrap, EncodingRef};
use hyper::mime::{Attr, Mime};
use rustc_serialize::base64::{CharacterSet, Config, Newline, ToBase64};
use script_runtime::ScriptThreadEventCategory::FileRead;
use script_runtime::{ScriptChan, CommonScriptMsg};
use script_thread::Runnable;
use std::cell::Cell;
use std::sync::Arc;
use string_cache::Atom;
use util::thread::spawn_named;

#[derive(PartialEq, Clone, Copy, JSTraceable, HeapSizeOf)]
pub enum FileReaderFunction {
    ReadAsText,
    ReadAsDataUrl,
}

pub type TrustedFileReader = Trusted<FileReader>;

#[derive(Clone, HeapSizeOf)]
pub struct ReadMetaData {
    pub blobtype: String,
    pub label: Option<String>,
    pub function: FileReaderFunction
}

impl ReadMetaData {
    pub fn new(blobtype: String,
               label: Option<String>, function: FileReaderFunction) -> ReadMetaData {
        ReadMetaData {
            blobtype: blobtype,
            label: label,
            function: function,
        }
    }
}

#[derive(PartialEq, Clone, Copy, JSTraceable, HeapSizeOf)]
pub struct GenerationId(u32);

#[repr(u16)]
#[derive(Copy, Clone, Debug, PartialEq, JSTraceable, HeapSizeOf)]
pub enum FileReaderReadyState {
    Empty = FileReaderConstants::EMPTY,
    Loading = FileReaderConstants::LOADING,
    Done = FileReaderConstants::DONE,
}

#[dom_struct]
pub struct FileReader {
    eventtarget: EventTarget,
    ready_state: Cell<FileReaderReadyState>,
    error: MutNullableHeap<JS<DOMException>>,
    result: DOMRefCell<Option<DOMString>>,
    generation_id: Cell<GenerationId>,
}

impl FileReader {
    pub fn new_inherited() -> FileReader {
        FileReader {
            eventtarget: EventTarget::new_inherited(),
            ready_state: Cell::new(FileReaderReadyState::Empty),
            error: MutNullableHeap::new(None),
            result: DOMRefCell::new(None),
            generation_id: Cell::new(GenerationId(0)),
        }
    }

    pub fn new(global: GlobalRef) -> Root<FileReader> {
        reflect_dom_object(box FileReader::new_inherited(),
                           global, FileReaderBinding::Wrap)
    }

    pub fn Constructor(global: GlobalRef) -> Fallible<Root<FileReader>> {
        Ok(FileReader::new(global))
    }

    //https://w3c.github.io/FileAPI/#dfn-error-steps
    pub fn process_read_error(filereader: TrustedFileReader, gen_id: GenerationId, error: DOMErrorName) {
        let fr = filereader.root();

        macro_rules! return_on_abort(
            () => (
                if gen_id != fr.generation_id.get() {
                    return
                }
            );
        );

        return_on_abort!();
        // Step 1
        fr.change_ready_state(FileReaderReadyState::Done);
        *fr.result.borrow_mut() = None;

        let global = fr.r().global();
        let exception = DOMException::new(global.r(), error);
        fr.error.set(Some(&exception));

        fr.dispatch_progress_event(atom!("error"), 0, None);
        return_on_abort!();
        // Step 3
        fr.dispatch_progress_event(atom!("loadend"), 0, None);
        return_on_abort!();
        // Step 4
        fr.terminate_ongoing_reading();
    }

    // https://w3c.github.io/FileAPI/#dfn-readAsText
    pub fn process_read_data(filereader: TrustedFileReader, gen_id: GenerationId) {
        let fr = filereader.root();

        macro_rules! return_on_abort(
            () => (
                if gen_id != fr.generation_id.get() {
                    return
                }
            );
        );
        return_on_abort!();
        //FIXME Step 7 send current progress
        fr.dispatch_progress_event(atom!("progress"), 0, None);
    }

    // https://w3c.github.io/FileAPI/#dfn-readAsText
    pub fn process_read(filereader: TrustedFileReader, gen_id: GenerationId) {
        let fr = filereader.root();

        macro_rules! return_on_abort(
            () => (
                if gen_id != fr.generation_id.get() {
                    return
                }
            );
        );
        return_on_abort!();
        // Step 6
        fr.dispatch_progress_event(atom!("loadstart"), 0, None);
    }

    // https://w3c.github.io/FileAPI/#dfn-readAsText
    pub fn process_read_eof(filereader: TrustedFileReader, gen_id: GenerationId,
                            data: ReadMetaData, blob_contents: Arc<Vec<u8>>) {
        let fr = filereader.root();

        macro_rules! return_on_abort(
            () => (
                if gen_id != fr.generation_id.get() {
                    return
                }
            );
        );

        return_on_abort!();
        // Step 8.1
        fr.change_ready_state(FileReaderReadyState::Done);
        // Step 8.2

        let output = match data.function {
            FileReaderFunction::ReadAsDataUrl =>
                FileReader::perform_readasdataurl(data, &blob_contents),
            FileReaderFunction::ReadAsText =>
                FileReader::perform_readastext(data, &blob_contents),
        };

        *fr.result.borrow_mut() = Some(output);

        // Step 8.3
        fr.dispatch_progress_event(atom!("load"), 0, None);
        return_on_abort!();
        // Step 8.4
        if fr.ready_state.get() != FileReaderReadyState::Loading {
            fr.dispatch_progress_event(atom!("loadend"), 0, None);
        }
        return_on_abort!();
        // Step 9
        fr.terminate_ongoing_reading();
    }

    // https://w3c.github.io/FileAPI/#dfn-readAsText
    fn perform_readastext(data: ReadMetaData, blob_bytes: &[u8])
        -> DOMString {
        let blob_label = &data.label;
        let blob_type = &data.blobtype;

        //https://w3c.github.io/FileAPI/#encoding-determination
        // Steps 1 & 2 & 3
        let mut encoding = blob_label.as_ref()
            .map(|string| &**string)
            .and_then(encoding_from_whatwg_label);

        // Step 4 & 5
        encoding = encoding.or_else(|| {
            let resultmime = blob_type.parse::<Mime>().ok();
            resultmime.and_then(|Mime(_, _, ref parameters)| {
                parameters.iter()
                    .find(|&&(ref k, _)| &Attr::Charset == k)
                    .and_then(|&(_, ref v)| encoding_from_whatwg_label(&v.to_string()))
            })
        });

        // Step 6
        let enc = encoding.unwrap_or(UTF_8 as EncodingRef);

        let convert = blob_bytes;
        // Step 7
        let output = enc.decode(convert, DecoderTrap::Replace).unwrap();
        DOMString::from(output)
    }

    //https://w3c.github.io/FileAPI/#dfn-readAsDataURL
    fn perform_readasdataurl(data: ReadMetaData, bytes: &[u8])
        -> DOMString {
        let config = Config {
            char_set: CharacterSet::UrlSafe,
            newline: Newline::LF,
            pad: true,
            line_length: None
        };
        let base64 = bytes.to_base64(config);

        let output = if data.blobtype.is_empty() {
            format!("data:base64,{}", base64)
        } else {
            format!("data:{};base64,{}", data.blobtype, base64)
        };

        DOMString::from(output)
    }
}

impl FileReaderMethods for FileReader {
    // https://w3c.github.io/FileAPI/#dfn-onloadstart
    event_handler!(loadstart, GetOnloadstart, SetOnloadstart);

    // https://w3c.github.io/FileAPI/#dfn-onprogress
    event_handler!(progress, GetOnprogress, SetOnprogress);

    // https://w3c.github.io/FileAPI/#dfn-onload
    event_handler!(load, GetOnload, SetOnload);

    // https://w3c.github.io/FileAPI/#dfn-onabort
    event_handler!(abort, GetOnabort, SetOnabort);

    // https://w3c.github.io/FileAPI/#dfn-onerror
    event_handler!(error, GetOnerror, SetOnerror);

    // https://w3c.github.io/FileAPI/#dfn-onloadend
    event_handler!(loadend, GetOnloadend, SetOnloadend);

    //TODO https://w3c.github.io/FileAPI/#dfn-readAsArrayBuffer
    // https://w3c.github.io/FileAPI/#dfn-readAsDataURL
    fn ReadAsDataURL(&self, blob: &Blob) -> ErrorResult {
        self.read(FileReaderFunction::ReadAsDataUrl, blob, None)
    }

    // https://w3c.github.io/FileAPI/#dfn-readAsText
    fn ReadAsText(&self, blob: &Blob, label: Option<DOMString>) -> ErrorResult {
        self.read(FileReaderFunction::ReadAsText, blob, label)
    }

    // https://w3c.github.io/FileAPI/#dfn-abort
    fn Abort(&self) {
        // Step 2
        if self.ready_state.get() == FileReaderReadyState::Loading {
            self.change_ready_state(FileReaderReadyState::Done);
        }
        // Steps 1 & 3
        *self.result.borrow_mut() = None;

        let global = self.global();
        let exception = DOMException::new(global.r(), DOMErrorName::AbortError);
        self.error.set(Some(&exception));

        self.terminate_ongoing_reading();
        // Steps 5 & 6
        self.dispatch_progress_event(atom!("abort"), 0, None);
        self.dispatch_progress_event(atom!("loadend"), 0, None);
    }

    // https://w3c.github.io/FileAPI/#dfn-error
    fn GetError(&self) -> Option<Root<DOMException>> {
        self.error.get()
    }

    // https://w3c.github.io/FileAPI/#dfn-result
    fn GetResult(&self) -> Option<DOMString> {
        self.result.borrow().clone()
    }

    // https://w3c.github.io/FileAPI/#dfn-readyState
    fn ReadyState(&self) -> u16 {
        self.ready_state.get() as u16
    }
}

impl FileReader {
    fn dispatch_progress_event(&self, type_: Atom, loaded: u64, total: Option<u64>) {
        let global = self.global();
        let progressevent = ProgressEvent::new(global.r(),
            type_, EventBubbles::DoesNotBubble, EventCancelable::NotCancelable,
            total.is_some(), loaded, total.unwrap_or(0));
        progressevent.upcast::<Event>().fire(self.upcast());
    }

    fn terminate_ongoing_reading(&self) {
        let GenerationId(prev_id) = self.generation_id.get();
        self.generation_id.set(GenerationId(prev_id + 1));
    }

    fn read(&self, function: FileReaderFunction, blob: &Blob, label: Option<DOMString>) -> ErrorResult {
        // Step 1
        if self.ready_state.get() == FileReaderReadyState::Loading {
            return Err(Error::InvalidState);
        }
        // Step 2
        if blob.IsClosed() {
            let global = self.global();
            let exception = DOMException::new(global.r(), DOMErrorName::InvalidStateError);
            self.error.set(Some(&exception));

            self.dispatch_progress_event(atom!("error"), 0, None);
            return Ok(());
        }

        // Step 3
        self.change_ready_state(FileReaderReadyState::Loading);

        // Step 4
        let blob_contents = Arc::new(blob.get_bytes().unwrap_or(vec![]));

        let type_ = blob.Type();

        let load_data = ReadMetaData::new(String::from(type_), label.map(String::from), function);

        let fr = Trusted::new(self);
        let gen_id = self.generation_id.get();

        let script_chan = self.global().r().file_reading_task_source();

        spawn_named("file reader async operation".to_owned(), move || {
            perform_annotated_read_operation(gen_id, load_data, blob_contents, fr, script_chan)
        });
        Ok(())
    }

    fn change_ready_state(&self, state: FileReaderReadyState) {
        self.ready_state.set(state);
    }
}

#[derive(Clone)]
pub enum FileReaderEvent {
    ProcessRead(TrustedFileReader, GenerationId),
    ProcessReadData(TrustedFileReader, GenerationId),
    ProcessReadError(TrustedFileReader, GenerationId, DOMErrorName),
    ProcessReadEOF(TrustedFileReader, GenerationId, ReadMetaData, Arc<Vec<u8>>)
}

impl Runnable for FileReaderEvent {
    fn name(&self) -> &'static str { "FileReaderEvent" }

    fn handler(self: Box<FileReaderEvent>) {
        let file_reader_event = *self;
        match file_reader_event {
            FileReaderEvent::ProcessRead(filereader, gen_id) => {
                FileReader::process_read(filereader, gen_id);
            },
            FileReaderEvent::ProcessReadData(filereader, gen_id) => {
                FileReader::process_read_data(filereader, gen_id);
            },
            FileReaderEvent::ProcessReadError(filereader, gen_id, error) => {
                FileReader::process_read_error(filereader, gen_id, error);
            },
            FileReaderEvent::ProcessReadEOF(filereader, gen_id, data, blob_contents) => {
                FileReader::process_read_eof(filereader, gen_id, data, blob_contents);
            }
        }
    }
}

// https://w3c.github.io/FileAPI/#thread-read-operation
fn perform_annotated_read_operation(gen_id: GenerationId, data: ReadMetaData, blob_contents: Arc<Vec<u8>>,
    filereader: TrustedFileReader, script_chan: Box<ScriptChan + Send>) {
    let chan = &script_chan;
    // Step 4
    let thread = box FileReaderEvent::ProcessRead(filereader.clone(), gen_id);
    chan.send(CommonScriptMsg::RunnableMsg(FileRead, thread)).unwrap();

    let thread = box FileReaderEvent::ProcessReadData(filereader.clone(), gen_id);
    chan.send(CommonScriptMsg::RunnableMsg(FileRead, thread)).unwrap();

    let thread = box FileReaderEvent::ProcessReadEOF(filereader, gen_id, data, blob_contents);
    chan.send(CommonScriptMsg::RunnableMsg(FileRead, thread)).unwrap();
}
<|endoftext|>