<commit_before>// This module implements Identifier, a short-optimized string allowed to
// contain only the ASCII characters hyphen, dot, 0-9, A-Z, a-z.
//
// As of mid-2021, the distribution of pre-release lengths on crates.io is:
//
//     length  count         length  count         length  count
//        0  355929            11      81            24       2
//        1     208            12      48            25       6
//        2     236            13      55            26      10
//        3    1909            14      25            27       4
//        4    1284            15      15            28       1
//        5    1742            16      35            30       1
//        6    3440            17       9            31       5
//        7    5624            18       6            32       1
//        8    1321            19      12            36       2
//        9     179            20       2            37     379
//       10      65            23      11
//
// and the distribution of build metadata lengths is:
//
//     length  count         length  count         length  count
//        0  364445             8    7725            18       1
//        1      72             9      16            19       1
//        2       7            10      85            20       1
//        3      28            11      17            22       4
//        4       9            12      10            26       1
//        5      68            13       9            27       1
//        6      73            14      10            40       5
//        7      53            15       6
//
// Therefore it really behooves us to be able to use the entire 8 bytes of a
// pointer for inline storage. For both pre-release and build metadata there are
// vastly more strings with length exactly 8 bytes than the sum over all lengths
// longer than 8 bytes.
//
// To differentiate the inline representation from the heap allocated long
// representation, we'll allocate heap pointers with 2-byte alignment so that
// they are guaranteed to have an unset least significant bit. Then in the repr
// we store for pointers, we rotate a 1 into the most significant bit of the
// most significant byte, which is never set for an ASCII byte.
//
// Inline repr:
//
//     0xxxxxxx 0xxxxxxx 0xxxxxxx 0xxxxxxx 0xxxxxxx 0xxxxxxx 0xxxxxxx 0xxxxxxx
//
// Heap allocated repr:
//
//     1ppppppp pppppppp pppppppp pppppppp pppppppp pppppppp pppppppp pppppppp 0
//     ^ most significant bit   least significant bit of orig ptr, rotated out ^
//
// Since the most significant bit doubles as a sign bit for the similarly sized
// signed integer type, the CPU has an efficient instruction for inspecting it,
// meaning we can differentiate between an inline repr and a heap allocated repr
// in one instruction. Effectively an inline repr always looks like a positive
// i64 while a heap allocated repr always looks like a negative i64.
//
// For the inline repr, we store \0 padding on the end of the stored characters,
// and thus the string length is readily determined efficiently by a cttz (count
// trailing zeros) or bsf (bit scan forward) instruction.
//
// For the heap allocated repr, the length is encoded as a base-128 varint at
// the head of the allocation.
//
// Empty strings are stored as an all-1 bit pattern, corresponding to -1i64.
// Consequently the all-0 bit pattern is never a legal representation in any
// repr, leaving it available as a niche for downstream code. For example this
// allows size_of::<Version>() == size_of::<Option<Version>>().

use std::alloc::{alloc, dealloc, Layout};
use std::mem;
use std::num::{NonZeroU64, NonZeroUsize};
use std::ptr;
use std::slice;
use std::str;

#[repr(transparent)]
pub(crate) struct Identifier {
    repr: NonZeroU64,
}

impl Identifier {
    const EMPTY: NonZeroU64 = unsafe { NonZeroU64::new_unchecked(!0) };

    pub(crate) const fn empty() -> Self {
        // `mov rax, -1`
        Identifier { repr: Self::EMPTY }
    }

    pub(crate) unsafe fn new_unchecked(string: &str) -> Self {
        let len = string.len();
        let repr = match len as u64 {
            0 => Self::EMPTY,
            1..=8 => {
                let mut bytes = [0u8; 8];
                unsafe { ptr::copy_nonoverlapping(string.as_ptr(), bytes.as_mut_ptr(), len) };
                unsafe { NonZeroU64::new_unchecked(u64::from_ne_bytes(bytes)) }
            }
            9..=0xff_ffff_ffff_ffff => {
                let size = bytes_for_varint(unsafe { NonZeroUsize::new_unchecked(len) }) + len;
                let align = 2;
                let layout = unsafe { Layout::from_size_align_unchecked(size, align) };
                let ptr = unsafe { alloc(layout) };
                let mut write = ptr;
                let mut varint_remaining = len;
                while varint_remaining > 0 {
                    unsafe { ptr::write(write, varint_remaining as u8 | 0x80) };
                    varint_remaining >>= 7;
                    write = unsafe { write.add(1) };
                }
                unsafe { ptr::copy_nonoverlapping(string.as_ptr(), write, len) };
                ptr_to_repr(ptr)
            }
            0x100_0000_0000_0000..=0xffff_ffff_ffff_ffff => {
                unreachable!("please refrain from storing >64 petabytes of text in semver version");
            }
        };
        Identifier { repr }
    }

    pub(crate) fn is_empty(&self) -> bool {
        // `cmp rdi, -1` -- basically: `repr as i64 == -1`
        self.repr == Self::EMPTY
    }

    fn is_inline(&self) -> bool {
        // `test rdi, rdi` -- basically: `repr as i64 >= 0`
        self.repr.get() >> 63 == 0
    }

    fn is_empty_or_inline(&self) -> bool {
        // `cmp rdi, -2` -- basically: `repr as i64 > -2`
        self.is_empty() || self.is_inline()
    }

    pub(crate) fn as_str(&self) -> &str {
        if self.is_empty() {
            ""
        } else if self.is_inline() {
            unsafe { inline_as_str(&self.repr) }
        } else {
            unsafe { ptr_as_str(&self.repr) }
        }
    }
}

impl Clone for Identifier {
    fn clone(&self) -> Self {
        let repr = if self.is_empty_or_inline() {
            self.repr
        } else {
            let ptr = repr_to_ptr(self.repr);
            let len = unsafe { decode_len(ptr) };
            let size = bytes_for_varint(len) + len.get();
            let align = 2;
            let layout = unsafe { Layout::from_size_align_unchecked(size, align) };
            let clone = unsafe { alloc(layout) };
            unsafe { ptr::copy_nonoverlapping(ptr, clone, size) }
            ptr_to_repr(clone)
        };
        Identifier { repr }
    }
}

impl Drop for Identifier {
    fn drop(&mut self) {
        if self.is_empty_or_inline() {
            return;
        }
        let ptr = repr_to_ptr_mut(self.repr);
        let len = unsafe { decode_len(ptr) };
        let size = bytes_for_varint(len) + len.get();
        let align = 2;
        let layout = unsafe { Layout::from_size_align_unchecked(size, align) };
        unsafe { dealloc(ptr, layout) }
    }
}

impl PartialEq for Identifier {
    fn eq(&self, rhs: &Self) -> bool {
        if self.is_empty_or_inline() {
            // Fast path (most common)
            self.repr == rhs.repr
        } else if rhs.is_empty_or_inline() {
            false
        } else {
            unsafe { ptr_as_str(&self.repr) == ptr_as_str(&rhs.repr) }
        }
    }
}

// We use heap pointers that are 2-byte aligned, meaning they have an
// insignificant 0 in the least significant bit. We take advantage of that
// unneeded bit to rotate a 1 into the most significant bit to make the repr
// distinguishable from ASCII bytes.
fn ptr_to_repr(ptr: *mut u8) -> NonZeroU64 {
    // `mov eax, 1`
    // `shld rax, rdi, 63`
    let repr = (ptr as u64 | 1).rotate_right(1);

    unsafe { NonZeroU64::new_unchecked(repr) }
}

// Shift out the 1 previously placed into the most significant bit of the least
// significant byte. Shift in a low 0 bit to reconstruct the original 2-byte
// aligned pointer.
fn repr_to_ptr(repr: NonZeroU64) -> *const u8 {
    // `lea rax, [rdi + rdi]`
    (repr.get() << 1) as *const u8
}

fn repr_to_ptr_mut(repr: NonZeroU64) -> *mut u8 {
    repr_to_ptr(repr) as *mut u8
}

// Compute the length of the inline string, assuming the argument is in short
// string representation. Short strings are stored as 1 to 8 nonzero ASCII
// bytes, followed by \0 padding for the remaining bytes.
fn inline_len(repr: NonZeroU64) -> NonZeroUsize {
    #[cfg(target_endian = "little")]
    let zero_bits_on_string_end = repr.leading_zeros();
    #[cfg(target_endian = "big")]
    let zero_bits_on_string_end = repr.trailing_zeros();

    let nonzero_bytes = 8 - zero_bits_on_string_end as usize / 8;

    unsafe { NonZeroUsize::new_unchecked(nonzero_bytes) }
}

unsafe fn inline_as_str(repr: &NonZeroU64) -> &str {
    let ptr = repr as *const NonZeroU64 as *const u8;
    let len = inline_len(*repr).get();
    let slice = unsafe { slice::from_raw_parts(ptr, len) };
    unsafe { str::from_utf8_unchecked(slice) }
}

// Decode varint. Varints consist of between one and eight base-128 digits, each
// of which is stored in a byte with most significant bit set. Adjacent to the
// varint in memory there is guaranteed to be at least 9 ASCII bytes, each of
// which has an unset most significant bit.
unsafe fn decode_len(ptr: *const u8) -> NonZeroUsize {
    let [first, second] = unsafe { ptr::read(ptr as *const [u8; 2]) };
    if second < 0x80 {
        unsafe { NonZeroUsize::new_unchecked((first & 0x7f) as usize) }
    } else {
        return unsafe { decode_len_cold(ptr) };

        // Identifiers 128 bytes or longer. This is not exercised by any crate
        // version currently published to crates.io.
        #[cold]
        #[inline(never)]
        unsafe fn decode_len_cold(mut ptr: *const u8) -> NonZeroUsize {
            let mut len = 0;
            let mut shift = 0;
            loop {
                let byte = unsafe { *ptr };
                if byte < 0x80 {
                    return unsafe { NonZeroUsize::new_unchecked(len) };
                }
                ptr = unsafe { ptr.add(1) };
                len += ((byte & 0x7f) as usize) << shift;
                shift += 7;
            }
        }
    }
}

unsafe fn ptr_as_str(repr: &NonZeroU64) -> &str {
    let ptr = repr_to_ptr(*repr);
    let len = unsafe { decode_len(ptr) };
    let header = bytes_for_varint(len);
    let slice = unsafe { slice::from_raw_parts(ptr.add(header), len.get()) };
    unsafe { str::from_utf8_unchecked(slice) }
}

// Number of base-128 digits required for the varint representation of a length.
fn bytes_for_varint(len: NonZeroUsize) -> usize {
    let usize_bits = mem::size_of::<usize>() * 8;
    let len_bits = usize_bits - len.leading_zeros() as usize;
    (len_bits + 6) / 7
}
<commit_msg>Document safety of identifier implementation<commit_after>// This module implements Identifier, a short-optimized string allowed to
// contain only the ASCII characters hyphen, dot, 0-9, A-Z, a-z.
//
// As of mid-2021, the distribution of pre-release lengths on crates.io is:
//
//     length  count         length  count         length  count
//        0  355929            11      81            24       2
//        1     208            12      48            25       6
//        2     236            13      55            26      10
//        3    1909            14      25            27       4
//        4    1284            15      15            28       1
//        5    1742            16      35            30       1
//        6    3440            17       9            31       5
//        7    5624            18       6            32       1
//        8    1321            19      12            36       2
//        9     179            20       2            37     379
//       10      65            23      11
//
// and the distribution of build metadata lengths is:
//
//     length  count         length  count         length  count
//        0  364445             8    7725            18       1
//        1      72             9      16            19       1
//        2       7            10      85            20       1
//        3      28            11      17            22       4
//        4       9            12      10            26       1
//        5      68            13       9            27       1
//        6      73            14      10            40       5
//        7      53            15       6
//
// Therefore it really behooves us to be able to use the entire 8 bytes of a
// pointer for inline storage. For both pre-release and build metadata there are
// vastly more strings with length exactly 8 bytes than the sum over all lengths
// longer than 8 bytes.
//
// To differentiate the inline representation from the heap allocated long
// representation, we'll allocate heap pointers with 2-byte alignment so that
// they are guaranteed to have an unset least significant bit. Then in the repr
// we store for pointers, we rotate a 1 into the most significant bit of the
// most significant byte, which is never set for an ASCII byte.
//
// Inline repr:
//
//     0xxxxxxx 0xxxxxxx 0xxxxxxx 0xxxxxxx 0xxxxxxx 0xxxxxxx 0xxxxxxx 0xxxxxxx
//
// Heap allocated repr:
//
//     1ppppppp pppppppp pppppppp pppppppp pppppppp pppppppp pppppppp pppppppp 0
//     ^ most significant bit   least significant bit of orig ptr, rotated out ^
//
// Since the most significant bit doubles as a sign bit for the similarly sized
// signed integer type, the CPU has an efficient instruction for inspecting it,
// meaning we can differentiate between an inline repr and a heap allocated repr
// in one instruction. Effectively an inline repr always looks like a positive
// i64 while a heap allocated repr always looks like a negative i64.
//
// For the inline repr, we store \0 padding on the end of the stored characters,
// and thus the string length is readily determined efficiently by a cttz (count
// trailing zeros) or bsf (bit scan forward) instruction.
//
// For the heap allocated repr, the length is encoded as a base-128 varint at
// the head of the allocation.
//
// Empty strings are stored as an all-1 bit pattern, corresponding to -1i64.
// Consequently the all-0 bit pattern is never a legal representation in any
// repr, leaving it available as a niche for downstream code. For example this
// allows size_of::<Version>() == size_of::<Option<Version>>().

use std::alloc::{alloc, dealloc, Layout};
use std::mem;
use std::num::{NonZeroU64, NonZeroUsize};
use std::ptr;
use std::slice;
use std::str;

#[repr(transparent)]
pub(crate) struct Identifier {
    repr: NonZeroU64,
}

impl Identifier {
    const EMPTY: NonZeroU64 = unsafe { NonZeroU64::new_unchecked(!0) };

    pub(crate) const fn empty() -> Self {
        // `mov rax, -1`
        Identifier { repr: Self::EMPTY }
    }

    // SAFETY: string must be ASCII and not contain \0 bytes.
    pub(crate) unsafe fn new_unchecked(string: &str) -> Self {
        let len = string.len();
        let repr = match len as u64 {
            0 => Self::EMPTY,
            1..=8 => {
                let mut bytes = [0u8; 8];
                // SAFETY: string is big enough to read len bytes, bytes is big
                // enough to write len bytes, and they do not overlap.
                unsafe { ptr::copy_nonoverlapping(string.as_ptr(), bytes.as_mut_ptr(), len) };
                // SAFETY: it's nonzero because the input string was at least 1
                // byte of ASCII and did not contain \0.
                unsafe { NonZeroU64::new_unchecked(u64::from_ne_bytes(bytes)) }
            }
            9..=0xff_ffff_ffff_ffff => {
                // SAFETY: len is in a range that does not contain 0.
                let size = bytes_for_varint(unsafe { NonZeroUsize::new_unchecked(len) }) + len;
                let align = 2;
                // SAFETY: align is not zero, align is a power of two, and
                // rounding size up to align does not overflow usize::MAX.
                let layout = unsafe { Layout::from_size_align_unchecked(size, align) };
                // SAFETY: layout's size is nonzero.
                let ptr = unsafe { alloc(layout) };
                let mut write = ptr;
                let mut varint_remaining = len;
                while varint_remaining > 0 {
                    // SAFETY: size is bytes_for_varint(len) bytes + len bytes.
                    // This is writing the first bytes_for_variant(len) bytes.
                    unsafe { ptr::write(write, varint_remaining as u8 | 0x80) };
                    varint_remaining >>= 7;
                    // SAFETY: still in bounds of the same allocation.
                    write = unsafe { write.add(1) };
                }
                // SAFETY: size is bytes_for_varint(len) bytes + len bytes. This
                // is writing to the last len bytes.
                unsafe { ptr::copy_nonoverlapping(string.as_ptr(), write, len) };
                ptr_to_repr(ptr)
            }
            0x100_0000_0000_0000..=0xffff_ffff_ffff_ffff => {
                unreachable!("please refrain from storing >64 petabytes of text in semver version");
            }
        };
        Identifier { repr }
    }

    pub(crate) fn is_empty(&self) -> bool {
        // `cmp rdi, -1` -- basically: `repr as i64 == -1`
        self.repr == Self::EMPTY
    }

    fn is_inline(&self) -> bool {
        // `test rdi, rdi` -- basically: `repr as i64 >= 0`
        self.repr.get() >> 63 == 0
    }

    fn is_empty_or_inline(&self) -> bool {
        // `cmp rdi, -2` -- basically: `repr as i64 > -2`
        self.is_empty() || self.is_inline()
    }

    pub(crate) fn as_str(&self) -> &str {
        if self.is_empty() {
            ""
        } else if self.is_inline() {
            // SAFETY: repr is in the inline representation.
            unsafe { inline_as_str(&self.repr) }
        } else {
            // SAFETY: repr is in the heap allocated representation.
            unsafe { ptr_as_str(&self.repr) }
        }
    }
}

impl Clone for Identifier {
    fn clone(&self) -> Self {
        let repr = if self.is_empty_or_inline() {
            self.repr
        } else {
            let ptr = repr_to_ptr(self.repr);
            // SAFETY: ptr is one of our own heap allocations.
            let len = unsafe { decode_len(ptr) };
            let size = bytes_for_varint(len) + len.get();
            let align = 2;
            // SAFETY: align is not zero, align is a power of two, and rounding
            // size up to align does not overflow usize::MAX. This is just
            // duplicating a previous allocation where all of these guarantees
            // were already made.
            let layout = unsafe { Layout::from_size_align_unchecked(size, align) };
            // SAFETY: layout's size is nonzero.
            let clone = unsafe { alloc(layout) };
            // SAFETY: new allocation cannot overlap the previous one (this was
            // not a realloc). The argument ptrs are readable/writeable
            // respectively for size bytes.
            unsafe { ptr::copy_nonoverlapping(ptr, clone, size) }
            ptr_to_repr(clone)
        };
        Identifier { repr }
    }
}

impl Drop for Identifier {
    fn drop(&mut self) {
        if self.is_empty_or_inline() {
            return;
        }
        let ptr = repr_to_ptr_mut(self.repr);
        // SAFETY: ptr is one of our own heap allocations.
        let len = unsafe { decode_len(ptr) };
        let size = bytes_for_varint(len) + len.get();
        let align = 2;
        // SAFETY: align is not zero, align is a power of two, and rounding
        // size up to align does not overflow usize::MAX. These guarantees were
        // made when originally allocating this memory.
        let layout = unsafe { Layout::from_size_align_unchecked(size, align) };
        // SAFETY: ptr was previously allocated by the same allocator with the
        // same layout.
        unsafe { dealloc(ptr, layout) }
    }
}

impl PartialEq for Identifier {
    fn eq(&self, rhs: &Self) -> bool {
        if self.is_empty_or_inline() {
            // Fast path (most common)
            self.repr == rhs.repr
        } else if rhs.is_empty_or_inline() {
            false
        } else {
            // SAFETY: both reprs are in the heap allocated representation.
            unsafe { ptr_as_str(&self.repr) == ptr_as_str(&rhs.repr) }
        }
    }
}

// We use heap pointers that are 2-byte aligned, meaning they have an
// insignificant 0 in the least significant bit. We take advantage of that
// unneeded bit to rotate a 1 into the most significant bit to make the repr
// distinguishable from ASCII bytes.
fn ptr_to_repr(ptr: *mut u8) -> NonZeroU64 {
    // `mov eax, 1`
    // `shld rax, rdi, 63`
    let repr = (ptr as u64 | 1).rotate_right(1);

    // SAFETY: the most significant bit of repr is known to be set, so the value
    // is not zero.
    unsafe { NonZeroU64::new_unchecked(repr) }
}

// Shift out the 1 previously placed into the most significant bit of the least
// significant byte. Shift in a low 0 bit to reconstruct the original 2-byte
// aligned pointer.
fn repr_to_ptr(repr: NonZeroU64) -> *const u8 {
    // `lea rax, [rdi + rdi]`
    (repr.get() << 1) as *const u8
}

fn repr_to_ptr_mut(repr: NonZeroU64) -> *mut u8 {
    repr_to_ptr(repr) as *mut u8
}

// Compute the length of the inline string, assuming the argument is in short
// string representation. Short strings are stored as 1 to 8 nonzero ASCII
// bytes, followed by \0 padding for the remaining bytes.
fn inline_len(repr: NonZeroU64) -> NonZeroUsize {
    #[cfg(target_endian = "little")]
    let zero_bits_on_string_end = repr.leading_zeros();
    #[cfg(target_endian = "big")]
    let zero_bits_on_string_end = repr.trailing_zeros();

    let nonzero_bytes = 8 - zero_bits_on_string_end as usize / 8;

    // SAFETY: repr is nonzero, so it has at most 63 zero bits on either end,
    // thus at least one nonzero byte.
    unsafe { NonZeroUsize::new_unchecked(nonzero_bytes) }
}

// SAFETY: repr must be in the inline representation, i.e. at least 1 and at
// most 8 nonzero ASCII bytes padded on the end with \0 bytes.
unsafe fn inline_as_str(repr: &NonZeroU64) -> &str {
    let ptr = repr as *const NonZeroU64 as *const u8;
    let len = inline_len(*repr).get();
    // SAFETY: we are viewing the nonzero ASCII prefix of the inline repr's
    // contents as a slice of bytes. Input/output lifetimes are correctly
    // associated.
    let slice = unsafe { slice::from_raw_parts(ptr, len) };
    // SAFETY: the string contents are known to be only ASCII bytes, which are
    // always valid UTF-8.
    unsafe { str::from_utf8_unchecked(slice) }
}

// Decode varint. Varints consist of between one and eight base-128 digits, each
// of which is stored in a byte with most significant bit set. Adjacent to the
// varint in memory there is guaranteed to be at least 9 ASCII bytes, each of
// which has an unset most significant bit.
//
// SAFETY: ptr must be one of our own heap allocations, with the varint header
// already written.
unsafe fn decode_len(ptr: *const u8) -> NonZeroUsize {
    // SAFETY: There is at least one byte of varint followed by at least 9 bytes
    // of string content, which is at least 10 bytes total for the allocation,
    // so reading the first two is no problem.
    let [first, second] = unsafe { ptr::read(ptr as *const [u8; 2]) };
    if second < 0x80 {
        // SAFETY: the length of this heap allocated string has been encoded as
        // one base-128 digit, so the length is at least 9 and at most 127. It
        // cannot be zero.
        unsafe { NonZeroUsize::new_unchecked((first & 0x7f) as usize) }
    } else {
        return unsafe { decode_len_cold(ptr) };

        // Identifiers 128 bytes or longer. This is not exercised by any crate
        // version currently published to crates.io.
        #[cold]
        #[inline(never)]
        unsafe fn decode_len_cold(mut ptr: *const u8) -> NonZeroUsize {
            let mut len = 0;
            let mut shift = 0;
            loop {
                // SAFETY: varint continues while there are bytes having the
                // most significant bit set, i.e. until we start hitting the
                // ASCII string content with msb unset.
                let byte = unsafe { *ptr };
                if byte < 0x80 {
                    // SAFETY: the string length is known to be 128 bytes or
                    // longer.
                    return unsafe { NonZeroUsize::new_unchecked(len) };
                }
                // SAFETY: still in bounds of the same allocation.
                ptr = unsafe { ptr.add(1) };
                len += ((byte & 0x7f) as usize) << shift;
                shift += 7;
            }
        }
    }
}

// SAFETY: repr must be in the heap allocated representation, with varint header
// and string contents already written.
unsafe fn ptr_as_str(repr: &NonZeroU64) -> &str {
    let ptr = repr_to_ptr(*repr);
    let len = unsafe { decode_len(ptr) };
    let header = bytes_for_varint(len);
    let slice = unsafe { slice::from_raw_parts(ptr.add(header), len.get()) };
    // SAFETY: all identifier contents are ASCII bytes, which are always valid
    // UTF-8.
    unsafe { str::from_utf8_unchecked(slice) }
}

// Number of base-128 digits required for the varint representation of a length.
fn bytes_for_varint(len: NonZeroUsize) -> usize {
    let usize_bits = mem::size_of::<usize>() * 8;
    let len_bits = usize_bits - len.leading_zeros() as usize;
    (len_bits + 6) / 7
}
<|endoftext|>


<commit_before>use rustc_serialize::Decoder;
use rustc_serialize::Decodable;

use Request;
use RouteError;

use std::mem;
use std::num;
use std::str::ParseBoolError;
use url::form_urlencoded;

/// Error that can happen when decoding POST data.
#[derive(Clone, Debug)]
pub enum PostError {
    /// The `Content-Type` header of the request indicates that it doesn't contain POST data.
    WrongContentType,

    /// A field is missing from the received data.
    MissingField(String),

    /// Failed to parse a `bool` field.
    WrongDataTypeBool(ParseBoolError),

    /// Failed to parse an integer field.
    WrongDataTypeInt(num::ParseIntError),

    /// Failed to parse a floating-point field.
    WrongDataTypeFloat(num::ParseFloatError),

    /// Failed to parse a string field.
    NotUtf8(String),
}

impl From<PostError> for RouteError {
    #[inline]
    fn from(err: PostError) -> RouteError {
        RouteError::WrongInput
    }
}

impl From<ParseBoolError> for PostError {
    #[inline]
    fn from(err: ParseBoolError) -> PostError {
        PostError::WrongDataTypeBool(err)
    }
}

impl From<num::ParseIntError> for PostError {
    #[inline]
    fn from(err: num::ParseIntError) -> PostError {
        PostError::WrongDataTypeInt(err)
    }
}

impl From<num::ParseFloatError> for PostError {
    #[inline]
    fn from(err: num::ParseFloatError) -> PostError {
        PostError::WrongDataTypeFloat(err)
    }
}

/// Attempts to decode the `POST` data received by the request into a struct.
///
/// The struct must implement the `Decodable` trait from `rustc_serialize`.
///
/// An error is returned if a field is missing, if the content type is not POST data, or if a field
/// cannot be parsed.
///
/// # Example
///
/// ```no_run
/// # extern crate rustc_serialize;
/// # extern crate rouille;
/// # fn main() {
/// # let request: rouille::Request = unsafe { std::mem::uninitialized() };
/// #[derive(RustcDecodable)]
/// struct FormData {
///     field1: u32,
///     field2: String,
/// }
///
/// let data: FormData = rouille::input::get_post_input(&request).unwrap();
/// # }
/// ```
///
pub fn get_post_input<T>(request: &Request) -> Result<T, PostError> where T: Decodable {
    // TODO: slow
    if request.header("Content-Type") != Some("application/x-www-form-urlencoded".to_owned()) {
        return Err(PostError::WrongContentType);
    }

    let data = form_urlencoded::parse(&request.data());
    let mut decoder = PostDecoder::Start(data);
    T::decode(&mut decoder)
}

enum PostDecoder {
    Empty,

    Start(Vec<(String, String)>),

    ExpectsStructMember(Vec<(String, String)>),

    ExpectsData(Vec<(String, String)>, String),
}

impl Decoder for PostDecoder {
    type Error = PostError;

    fn read_usize(&mut self) -> Result<usize, PostError> { Ok(try!(try!(self.read_str()).parse())) }
    fn read_u64(&mut self) -> Result<u64, PostError> { Ok(try!(try!(self.read_str()).parse())) }
    fn read_u32(&mut self) -> Result<u32, PostError> { Ok(try!(try!(self.read_str()).parse())) }
    fn read_u16(&mut self) -> Result<u16, PostError> { Ok(try!(try!(self.read_str()).parse())) }
    fn read_u8(&mut self) -> Result<u8, PostError> { Ok(try!(try!(self.read_str()).parse())) }
    fn read_isize(&mut self) -> Result<isize, PostError> { Ok(try!(try!(self.read_str()).parse())) }
    fn read_i64(&mut self) -> Result<i64, PostError> { Ok(try!(try!(self.read_str()).parse())) }
    fn read_i32(&mut self) -> Result<i32, PostError> { Ok(try!(try!(self.read_str()).parse())) }
    fn read_i16(&mut self) -> Result<i16, PostError> { Ok(try!(try!(self.read_str()).parse())) }
    fn read_i8(&mut self) -> Result<i8, PostError> { Ok(try!(try!(self.read_str()).parse())) }
    fn read_bool(&mut self) -> Result<bool, PostError> { Ok(try!(try!(self.read_str()).parse())) }
    fn read_f64(&mut self) -> Result<f64, PostError> { Ok(try!(try!(self.read_str()).parse())) }
    fn read_f32(&mut self) -> Result<f32, PostError> { Ok(try!(try!(self.read_str()).parse())) }

    fn read_char(&mut self) -> Result<char, PostError> {
        unimplemented!();
    }

    fn read_str(&mut self) -> Result<String, PostError> {
        match self {
            &mut PostDecoder::ExpectsData(ref data, ref field_name) => {
                let val = data.iter().find(|&&(ref key, _)| key == field_name)
                              .map(|&(_, ref value)| value);

                if let Some(val) = val {
                    Ok(val.clone())
                } else {
                    Err(PostError::MissingField(field_name.clone()))
                }
            },

            _ => panic!()
        }
    }

    fn read_nil(&mut self) -> Result<(), PostError> {
        unimplemented!();
    }

    fn read_enum<T, F>(&mut self, name: &str, f: F) -> Result<T, PostError> where F: FnOnce(&mut Self) -> Result<T, PostError> {
        unimplemented!();
    }

    fn read_enum_variant<T, F>(&mut self, names: &[&str], f: F) -> Result<T, PostError> where F: FnMut(&mut Self, usize) -> Result<T, PostError> {
        unimplemented!();
    }

    fn read_enum_variant_arg<T, F>(&mut self, a_idx: usize, f: F) -> Result<T, PostError> where F: FnOnce(&mut Self) -> Result<T, PostError> {
        unimplemented!();
    }

    fn read_enum_struct_variant<T, F>(&mut self, names: &[&str], f: F) -> Result<T, PostError> where F: FnMut(&mut Self, usize) -> Result<T, PostError> {
        unimplemented!();
    }

    fn read_enum_struct_variant_field<T, F>(&mut self, f_name: &str, f_idx: usize, f: F) -> Result<T, PostError> where F: FnOnce(&mut Self) -> Result<T, PostError> {
        unimplemented!();
    }

    fn read_struct<T, F>(&mut self, s_name: &str, len: usize, mut f: F) -> Result<T, PostError> where F: FnOnce(&mut Self) -> Result<T, PostError> {
        let mut tmp = match mem::replace(self, PostDecoder::Empty) {
            PostDecoder::Start(data) => PostDecoder::ExpectsStructMember(data),
            _ => panic!()
        };

        f(&mut tmp)
    }

    fn read_struct_field<T, F>(&mut self, f_name: &str, f_idx: usize, f: F) -> Result<T, PostError> where F: FnOnce(&mut Self) -> Result<T, PostError> {
        let mut tmp = match mem::replace(self, PostDecoder::Empty) {
            PostDecoder::ExpectsStructMember(data) => PostDecoder::ExpectsData(data, f_name.to_owned()),
            _ => panic!()
        };

        let result = f(&mut tmp);

        match tmp {
            PostDecoder::ExpectsData(data, _) => mem::replace(self, PostDecoder::ExpectsStructMember(data)),
            _ => panic!()
        };

        result
    }

    fn read_tuple<T, F>(&mut self, len: usize, f: F) -> Result<T, PostError> where F: FnOnce(&mut Self) -> Result<T, PostError> {
        unimplemented!();
    }

    fn read_tuple_arg<T, F>(&mut self, a_idx: usize, f: F) -> Result<T, PostError> where F: FnOnce(&mut Self) -> Result<T, PostError> {
        unimplemented!();
    }

    fn read_tuple_struct<T, F>(&mut self, s_name: &str, len: usize, f: F) -> Result<T, PostError> where F: FnOnce(&mut Self) -> Result<T, PostError> {
        unimplemented!();
    }

    fn read_tuple_struct_arg<T, F>(&mut self, a_idx: usize, f: F) -> Result<T, PostError> where F: FnOnce(&mut Self) -> Result<T, PostError> {
        unimplemented!();
    }

    fn read_option<T, F>(&mut self, f: F) -> Result<T, PostError> where F: FnMut(&mut Self, bool) -> Result<T, PostError> {
        unimplemented!();
    }

    fn read_seq<T, F>(&mut self, f: F) -> Result<T, PostError> where F: FnOnce(&mut Self, usize) -> Result<T, PostError> {
        unimplemented!();
    }

    fn read_seq_elt<T, F>(&mut self, idx: usize, f: F) -> Result<T, PostError> where F: FnOnce(&mut Self) -> Result<T, PostError> {
        unimplemented!();
    }

    fn read_map<T, F>(&mut self, f: F) -> Result<T, PostError> where F: FnOnce(&mut Self, usize) -> Result<T, PostError> {
        unimplemented!();
    }

    fn read_map_elt_key<T, F>(&mut self, idx: usize, f: F) -> Result<T, PostError> where F: FnOnce(&mut Self) -> Result<T, PostError> {
        unimplemented!();
    }

    fn read_map_elt_val<T, F>(&mut self, idx: usize, f: F) -> Result<T, PostError> where F: FnOnce(&mut Self) -> Result<T, PostError> {
        unimplemented!();
    }

    fn error(&mut self, err: &str) -> PostError {
        unimplemented!();
    }
}
<commit_msg>Implement the POST decoder for Option<commit_after>use rustc_serialize::Decoder;
use rustc_serialize::Decodable;

use Request;
use RouteError;

use std::mem;
use std::num;
use std::str::ParseBoolError;
use url::form_urlencoded;

/// Error that can happen when decoding POST data.
#[derive(Clone, Debug)]
pub enum PostError {
    /// The `Content-Type` header of the request indicates that it doesn't contain POST data.
    WrongContentType,

    /// A field is missing from the received data.
    MissingField(String),

    /// Failed to parse a `bool` field.
    WrongDataTypeBool(ParseBoolError),

    /// Failed to parse an integer field.
    WrongDataTypeInt(num::ParseIntError),

    /// Failed to parse a floating-point field.
    WrongDataTypeFloat(num::ParseFloatError),

    /// Failed to parse a string field.
    NotUtf8(String),
}

impl From<PostError> for RouteError {
    #[inline]
    fn from(err: PostError) -> RouteError {
        RouteError::WrongInput
    }
}

impl From<ParseBoolError> for PostError {
    #[inline]
    fn from(err: ParseBoolError) -> PostError {
        PostError::WrongDataTypeBool(err)
    }
}

impl From<num::ParseIntError> for PostError {
    #[inline]
    fn from(err: num::ParseIntError) -> PostError {
        PostError::WrongDataTypeInt(err)
    }
}

impl From<num::ParseFloatError> for PostError {
    #[inline]
    fn from(err: num::ParseFloatError) -> PostError {
        PostError::WrongDataTypeFloat(err)
    }
}

/// Attempts to decode the `POST` data received by the request into a struct.
///
/// The struct must implement the `Decodable` trait from `rustc_serialize`.
///
/// An error is returned if a field is missing, if the content type is not POST data, or if a field
/// cannot be parsed.
///
/// # Example
///
/// ```no_run
/// # extern crate rustc_serialize;
/// # extern crate rouille;
/// # fn main() {
/// # let request: rouille::Request = unsafe { std::mem::uninitialized() };
/// #[derive(RustcDecodable)]
/// struct FormData {
///     field1: u32,
///     field2: String,
/// }
///
/// let data: FormData = rouille::input::get_post_input(&request).unwrap();
/// # }
/// ```
///
pub fn get_post_input<T>(request: &Request) -> Result<T, PostError> where T: Decodable {
    // TODO: slow
    if request.header("Content-Type") != Some("application/x-www-form-urlencoded".to_owned()) {
        return Err(PostError::WrongContentType);
    }

    let data = form_urlencoded::parse(&request.data());
    let mut decoder = PostDecoder::Start(data);
    T::decode(&mut decoder)
}

enum PostDecoder {
    Empty,

    Start(Vec<(String, String)>),

    ExpectsStructMember(Vec<(String, String)>),

    ExpectsData(Vec<(String, String)>, String),
}

impl Decoder for PostDecoder {
    type Error = PostError;

    fn read_usize(&mut self) -> Result<usize, PostError> { Ok(try!(try!(self.read_str()).parse())) }
    fn read_u64(&mut self) -> Result<u64, PostError> { Ok(try!(try!(self.read_str()).parse())) }
    fn read_u32(&mut self) -> Result<u32, PostError> { Ok(try!(try!(self.read_str()).parse())) }
    fn read_u16(&mut self) -> Result<u16, PostError> { Ok(try!(try!(self.read_str()).parse())) }
    fn read_u8(&mut self) -> Result<u8, PostError> { Ok(try!(try!(self.read_str()).parse())) }
    fn read_isize(&mut self) -> Result<isize, PostError> { Ok(try!(try!(self.read_str()).parse())) }
    fn read_i64(&mut self) -> Result<i64, PostError> { Ok(try!(try!(self.read_str()).parse())) }
    fn read_i32(&mut self) -> Result<i32, PostError> { Ok(try!(try!(self.read_str()).parse())) }
    fn read_i16(&mut self) -> Result<i16, PostError> { Ok(try!(try!(self.read_str()).parse())) }
    fn read_i8(&mut self) -> Result<i8, PostError> { Ok(try!(try!(self.read_str()).parse())) }
    fn read_bool(&mut self) -> Result<bool, PostError> { Ok(try!(try!(self.read_str()).parse())) }
    fn read_f64(&mut self) -> Result<f64, PostError> { Ok(try!(try!(self.read_str()).parse())) }
    fn read_f32(&mut self) -> Result<f32, PostError> { Ok(try!(try!(self.read_str()).parse())) }

    fn read_char(&mut self) -> Result<char, PostError> {
        unimplemented!();
    }

    fn read_str(&mut self) -> Result<String, PostError> {
        match self {
            &mut PostDecoder::ExpectsData(ref data, ref field_name) => {
                let val = data.iter().find(|&&(ref key, _)| key == field_name)
                              .map(|&(_, ref value)| value);

                if let Some(val) = val {
                    Ok(val.clone())
                } else {
                    Err(PostError::MissingField(field_name.clone()))
                }
            },

            _ => panic!()
        }
    }

    fn read_nil(&mut self) -> Result<(), PostError> {
        unimplemented!();
    }

    fn read_enum<T, F>(&mut self, name: &str, f: F) -> Result<T, PostError> where F: FnOnce(&mut Self) -> Result<T, PostError> {
        unimplemented!();
    }

    fn read_enum_variant<T, F>(&mut self, names: &[&str], f: F) -> Result<T, PostError> where F: FnMut(&mut Self, usize) -> Result<T, PostError> {
        unimplemented!();
    }

    fn read_enum_variant_arg<T, F>(&mut self, a_idx: usize, f: F) -> Result<T, PostError> where F: FnOnce(&mut Self) -> Result<T, PostError> {
        unimplemented!();
    }

    fn read_enum_struct_variant<T, F>(&mut self, names: &[&str], f: F) -> Result<T, PostError> where F: FnMut(&mut Self, usize) -> Result<T, PostError> {
        unimplemented!();
    }

    fn read_enum_struct_variant_field<T, F>(&mut self, f_name: &str, f_idx: usize, f: F) -> Result<T, PostError> where F: FnOnce(&mut Self) -> Result<T, PostError> {
        unimplemented!();
    }

    fn read_struct<T, F>(&mut self, s_name: &str, len: usize, mut f: F) -> Result<T, PostError> where F: FnOnce(&mut Self) -> Result<T, PostError> {
        let mut tmp = match mem::replace(self, PostDecoder::Empty) {
            PostDecoder::Start(data) => PostDecoder::ExpectsStructMember(data),
            _ => panic!()
        };

        f(&mut tmp)
    }

    fn read_struct_field<T, F>(&mut self, f_name: &str, f_idx: usize, f: F) -> Result<T, PostError> where F: FnOnce(&mut Self) -> Result<T, PostError> {
        let mut tmp = match mem::replace(self, PostDecoder::Empty) {
            PostDecoder::ExpectsStructMember(data) => PostDecoder::ExpectsData(data, f_name.to_owned()),
            _ => panic!()
        };

        let result = f(&mut tmp);

        match tmp {
            PostDecoder::ExpectsData(data, _) => mem::replace(self, PostDecoder::ExpectsStructMember(data)),
            _ => panic!()
        };

        result
    }

    fn read_tuple<T, F>(&mut self, len: usize, f: F) -> Result<T, PostError> where F: FnOnce(&mut Self) -> Result<T, PostError> {
        unimplemented!();
    }

    fn read_tuple_arg<T, F>(&mut self, a_idx: usize, f: F) -> Result<T, PostError> where F: FnOnce(&mut Self) -> Result<T, PostError> {
        unimplemented!();
    }

    fn read_tuple_struct<T, F>(&mut self, s_name: &str, len: usize, f: F) -> Result<T, PostError> where F: FnOnce(&mut Self) -> Result<T, PostError> {
        unimplemented!();
    }

    fn read_tuple_struct_arg<T, F>(&mut self, a_idx: usize, f: F) -> Result<T, PostError> where F: FnOnce(&mut Self) -> Result<T, PostError> {
        unimplemented!();
    }

    fn read_option<T, F>(&mut self, mut f: F) -> Result<T, PostError> where F: FnMut(&mut Self, bool) -> Result<T, PostError> {
        let found = match self {
            &mut PostDecoder::ExpectsData(ref data, ref field_name) => {
                data.iter().find(|&&(ref key, _)| key == field_name).is_some()
            },
            _ => panic!()
        };

        f(self, found)
    }

    fn read_seq<T, F>(&mut self, f: F) -> Result<T, PostError> where F: FnOnce(&mut Self, usize) -> Result<T, PostError> {
        unimplemented!();
    }

    fn read_seq_elt<T, F>(&mut self, idx: usize, f: F) -> Result<T, PostError> where F: FnOnce(&mut Self) -> Result<T, PostError> {
        unimplemented!();
    }

    fn read_map<T, F>(&mut self, f: F) -> Result<T, PostError> where F: FnOnce(&mut Self, usize) -> Result<T, PostError> {
        unimplemented!();
    }

    fn read_map_elt_key<T, F>(&mut self, idx: usize, f: F) -> Result<T, PostError> where F: FnOnce(&mut Self) -> Result<T, PostError> {
        unimplemented!();
    }

    fn read_map_elt_val<T, F>(&mut self, idx: usize, f: F) -> Result<T, PostError> where F: FnOnce(&mut Self) -> Result<T, PostError> {
        unimplemented!();
    }

    fn error(&mut self, err: &str) -> PostError {
        unimplemented!();
    }
}
<|endoftext|>


<commit_before>use syntax::ast::{self, MetaItem, MetaItemKind, TyKind};
use syntax::attr::AttrMetaMethods;
use syntax::codemap::Span;
use syntax::ext::base::{Annotatable, ExtCtxt};
use syntax::ext::build::AstBuilder;
use syntax::ptr::P;
use syntax::parse::token::{InternedString, str_to_ident};

use attr::Attr;
use model::Model;
use util::{ty_param_of_option, is_option_ty};

pub fn expand_changeset_for(
    cx: &mut ExtCtxt,
    span: Span,
    meta_item: &MetaItem,
    annotatable: &Annotatable,
    push: &mut FnMut(Annotatable),
) {
    if let Some(model) = Model::from_annotable(cx, span, annotatable) {
        let options = changeset_options(cx, meta_item).unwrap();
        push(Annotatable::Item(changeset_impl(cx, span, &options, &model).unwrap()));
        let items = save_changes_impl(cx, span, &options, &model);
        for item in items.into_iter().filter_map(|x| x) {
            push(Annotatable::Item(item));
        }
    } else {
        cx.span_err(meta_item.span,
            "`changeset_for` may only be apllied to enums and structs");
    }
}

struct ChangesetOptions {
    table_name: ast::Ident,
    treat_none_as_null: bool,
}

fn changeset_options(cx: &mut ExtCtxt, meta_item: &MetaItem) -> Result<ChangesetOptions, ()> {
    match meta_item.node {
        MetaItemKind::List(_, ref meta_items) => {
            let table_name = try!(table_name(cx, &meta_items[0]));
            let treat_none_as_null = try!(boolean_option(cx, &meta_items[1..], "treat_none_as_null"))
                .unwrap_or(false);
            Ok(ChangesetOptions {
                table_name: str_to_ident(&table_name),
                treat_none_as_null: treat_none_as_null,
            })
        }
        _ => usage_error(cx, meta_item),
    }
}

fn table_name(cx: &mut ExtCtxt, meta_item: &MetaItem) -> Result<InternedString, ()> {
    match meta_item.node {
        MetaItemKind::Word(ref word) => Ok(word.clone()),
        _ => usage_error(cx, meta_item),
    }
}

fn boolean_option(cx: &mut ExtCtxt, meta_items: &[P<MetaItem>], option_name: &str)
    -> Result<Option<bool>, ()>
{
    if let Some(item) = meta_items.iter().find(|item| item.name() == option_name) {
        match item.value_str() {
            Some(ref s) if *s == "true" => Ok(Some(true)),
            Some(ref s) if *s == "false" => Ok(Some(false)),
            _ => {
                cx.span_err(item.span,
                    &format!("Expected {} to be in the form `option=\"true\"` or \
                            option=\"false\"", option_name));
                Err(())
            }
        }
    } else {
        Ok(None)
    }
}

fn usage_error<T>(cx: &mut ExtCtxt, meta_item: &MetaItem) -> Result<T, ()> {
    cx.span_err(meta_item.span,
        "`changeset_for` must be used in the form `#[changeset_for(table1)]`");
    Err(())
}

fn changeset_impl(
    cx: &mut ExtCtxt,
    span: Span,
    options: &ChangesetOptions,
    model: &Model,
) -> Option<P<ast::Item>> {
    let ref struct_name = model.ty;
    let pk = model.primary_key_name();
    let table_name = options.table_name;
    let attrs_for_changeset = model.attrs.iter().filter(|a| a.column_name.name != pk.name)
        .collect::<Vec<_>>();
    let changeset_ty = cx.ty(span, TyKind::Tup(
        attrs_for_changeset.iter()
              .map(|a| changeset_ty(cx, span, &options, a))
              .collect()
    ));
    let changeset_body = cx.expr_tuple(span, attrs_for_changeset.iter()
        .map(|a| changeset_expr(cx, span, &options, a))
        .collect());
    quote_item!(cx,
        impl<'a: 'update, 'update> ::diesel::query_builder::AsChangeset for
            &'update $struct_name
        {
            type Target = $table_name::table;
            type Changeset = $changeset_ty;

            fn as_changeset(self) -> Self::Changeset {
                $changeset_body
            }
        }
    )
}

#[allow(unused_imports)]
fn save_changes_impl(
    cx: &mut ExtCtxt,
    span: Span,
    options: &ChangesetOptions,
    model: &Model,
) -> Vec<Option<P<ast::Item>>> {
    let ref struct_name = model.ty;
    let pk = model.primary_key_name();
    let sql_type = cx.path(span, vec![options.table_name, str_to_ident("SqlType")]);
    let table = cx.path(span, vec![options.table_name, str_to_ident("table")]);
    let mut result = Vec::new();
    if let Some(pk) = model.attr_for_column(pk) {
        let pk_field = pk.field_name.unwrap();
        if cfg!(feature = "postgres") {
            result.push(quote_item!(cx,
                impl<'a> SaveChangesDsl<
                    ::diesel::pg::PgConnection,
                    $sql_type,
                > for $struct_name {
                    fn save_changes<T>(
                        &self,
                        connection: &::diesel::pg::PgConnection,
                    ) -> ::diesel::QueryResult<T> where
                        T: Queryable<$sql_type, ::diesel::pg::Pg>,
                    {
                        use ::diesel::update;
                        update($table.filter($table.primary_key().eq(&self.$pk_field)))
                            .set(self)
                            .get_result(connection)
                    }
                }
            ));
        }
        if cfg!(feature = "sqlite") {
            result.push(quote_item!(cx,
                impl<'a> SaveChangesDsl<
                    ::diesel::sqlite::SqliteConnection,
                    $sql_type,
                > for $struct_name {
                    fn save_changes<T>(
                        &self,
                        connection: &::diesel::sqlite::SqliteConnection,
                    ) -> ::diesel::QueryResult<T> where
                        T: Queryable<$sql_type, ::diesel::sqlite::Sqlite>,
                    {
                        use ::diesel::update;
                        try!(update($table.filter($table.primary_key().eq(&self.$pk_field)))
                            .set(self)
                            .execute(connection));
                        $table.find(&self.$pk_field).first(connection)
                    }
                }
            ));
        }
    }
    result
}

fn changeset_ty(
    cx: &ExtCtxt,
    span: Span,
    options: &ChangesetOptions,
    attr: &Attr,
) -> P<ast::Ty> {
    let column = cx.path(span, vec![options.table_name, attr.column_name]);
    match (options.treat_none_as_null, ty_param_of_option(&attr.ty)) {
        (false, Some(ty)) => {
            let inner_ty = inner_changeset_ty(cx, column, &ty);
            quote_ty!(cx, Option<$inner_ty>)
        }
        _ => inner_changeset_ty(cx, column, &attr.ty),
    }
}

fn inner_changeset_ty(
    cx: &ExtCtxt,
    column: ast::Path,
    field_ty: &ast::Ty,
) -> P<ast::Ty> {
    quote_ty!(cx,
        ::diesel::expression::predicates::Eq<
            $column,
            ::diesel::expression::bound::Bound<
                <$column as ::diesel::expression::Expression>::SqlType,
                &'update $field_ty,
            >,
        >
    )
}

fn changeset_expr(
    cx: &ExtCtxt,
    span: Span,
    options: &ChangesetOptions,
    attr: &Attr,
) -> P<ast::Expr> {
    let column = cx.path(span, vec![options.table_name, attr.column_name]);
    let field_name = &attr.field_name.unwrap();
    if !options.treat_none_as_null && is_option_ty(&attr.ty) {
        quote_expr!(cx, self.$field_name.as_ref().map(|f| $column.eq(f)))
    } else {
        quote_expr!(cx, $column.eq(&self.$field_name))
    }
}
<commit_msg>Use `find` instead of `filter` in `SaveChangesDsl`<commit_after>use syntax::ast::{self, MetaItem, MetaItemKind, TyKind};
use syntax::attr::AttrMetaMethods;
use syntax::codemap::Span;
use syntax::ext::base::{Annotatable, ExtCtxt};
use syntax::ext::build::AstBuilder;
use syntax::ptr::P;
use syntax::parse::token::{InternedString, str_to_ident};

use attr::Attr;
use model::Model;
use util::{ty_param_of_option, is_option_ty};

pub fn expand_changeset_for(
    cx: &mut ExtCtxt,
    span: Span,
    meta_item: &MetaItem,
    annotatable: &Annotatable,
    push: &mut FnMut(Annotatable),
) {
    if let Some(model) = Model::from_annotable(cx, span, annotatable) {
        let options = changeset_options(cx, meta_item).unwrap();
        push(Annotatable::Item(changeset_impl(cx, span, &options, &model).unwrap()));
        let items = save_changes_impl(cx, span, &options, &model);
        for item in items.into_iter().filter_map(|x| x) {
            push(Annotatable::Item(item));
        }
    } else {
        cx.span_err(meta_item.span,
            "`changeset_for` may only be apllied to enums and structs");
    }
}

struct ChangesetOptions {
    table_name: ast::Ident,
    treat_none_as_null: bool,
}

fn changeset_options(cx: &mut ExtCtxt, meta_item: &MetaItem) -> Result<ChangesetOptions, ()> {
    match meta_item.node {
        MetaItemKind::List(_, ref meta_items) => {
            let table_name = try!(table_name(cx, &meta_items[0]));
            let treat_none_as_null = try!(boolean_option(cx, &meta_items[1..], "treat_none_as_null"))
                .unwrap_or(false);
            Ok(ChangesetOptions {
                table_name: str_to_ident(&table_name),
                treat_none_as_null: treat_none_as_null,
            })
        }
        _ => usage_error(cx, meta_item),
    }
}

fn table_name(cx: &mut ExtCtxt, meta_item: &MetaItem) -> Result<InternedString, ()> {
    match meta_item.node {
        MetaItemKind::Word(ref word) => Ok(word.clone()),
        _ => usage_error(cx, meta_item),
    }
}

fn boolean_option(cx: &mut ExtCtxt, meta_items: &[P<MetaItem>], option_name: &str)
    -> Result<Option<bool>, ()>
{
    if let Some(item) = meta_items.iter().find(|item| item.name() == option_name) {
        match item.value_str() {
            Some(ref s) if *s == "true" => Ok(Some(true)),
            Some(ref s) if *s == "false" => Ok(Some(false)),
            _ => {
                cx.span_err(item.span,
                    &format!("Expected {} to be in the form `option=\"true\"` or \
                            option=\"false\"", option_name));
                Err(())
            }
        }
    } else {
        Ok(None)
    }
}

fn usage_error<T>(cx: &mut ExtCtxt, meta_item: &MetaItem) -> Result<T, ()> {
    cx.span_err(meta_item.span,
        "`changeset_for` must be used in the form `#[changeset_for(table1)]`");
    Err(())
}

fn changeset_impl(
    cx: &mut ExtCtxt,
    span: Span,
    options: &ChangesetOptions,
    model: &Model,
) -> Option<P<ast::Item>> {
    let ref struct_name = model.ty;
    let pk = model.primary_key_name();
    let table_name = options.table_name;
    let attrs_for_changeset = model.attrs.iter().filter(|a| a.column_name.name != pk.name)
        .collect::<Vec<_>>();
    let changeset_ty = cx.ty(span, TyKind::Tup(
        attrs_for_changeset.iter()
              .map(|a| changeset_ty(cx, span, &options, a))
              .collect()
    ));
    let changeset_body = cx.expr_tuple(span, attrs_for_changeset.iter()
        .map(|a| changeset_expr(cx, span, &options, a))
        .collect());
    quote_item!(cx,
        impl<'a: 'update, 'update> ::diesel::query_builder::AsChangeset for
            &'update $struct_name
        {
            type Target = $table_name::table;
            type Changeset = $changeset_ty;

            fn as_changeset(self) -> Self::Changeset {
                $changeset_body
            }
        }
    )
}

#[allow(unused_imports)]
fn save_changes_impl(
    cx: &mut ExtCtxt,
    span: Span,
    options: &ChangesetOptions,
    model: &Model,
) -> Vec<Option<P<ast::Item>>> {
    let ref struct_name = model.ty;
    let pk = model.primary_key_name();
    let sql_type = cx.path(span, vec![options.table_name, str_to_ident("SqlType")]);
    let table = cx.path(span, vec![options.table_name, str_to_ident("table")]);
    let mut result = Vec::new();
    if let Some(pk) = model.attr_for_column(pk) {
        let pk_field = pk.field_name.unwrap();
        if cfg!(feature = "postgres") {
            result.push(quote_item!(cx,
                impl<'a> SaveChangesDsl<
                    ::diesel::pg::PgConnection,
                    $sql_type,
                > for $struct_name {
                    fn save_changes<T>(
                        &self,
                        connection: &::diesel::pg::PgConnection,
                    ) -> ::diesel::QueryResult<T> where
                        T: Queryable<$sql_type, ::diesel::pg::Pg>,
                    {
                        use ::diesel::update;
                        update($table.find(&self.$pk_field))
                            .set(self)
                            .get_result(connection)
                    }
                }
            ));
        }
        if cfg!(feature = "sqlite") {
            result.push(quote_item!(cx,
                impl<'a> SaveChangesDsl<
                    ::diesel::sqlite::SqliteConnection,
                    $sql_type,
                > for $struct_name {
                    fn save_changes<T>(
                        &self,
                        connection: &::diesel::sqlite::SqliteConnection,
                    ) -> ::diesel::QueryResult<T> where
                        T: Queryable<$sql_type, ::diesel::sqlite::Sqlite>,
                    {
                        use ::diesel::update;
                        try!(update($table.find(&self.$pk_field))
                            .set(self)
                            .execute(connection));
                        $table.find(&self.$pk_field).first(connection)
                    }
                }
            ));
        }
    }
    result
}

fn changeset_ty(
    cx: &ExtCtxt,
    span: Span,
    options: &ChangesetOptions,
    attr: &Attr,
) -> P<ast::Ty> {
    let column = cx.path(span, vec![options.table_name, attr.column_name]);
    match (options.treat_none_as_null, ty_param_of_option(&attr.ty)) {
        (false, Some(ty)) => {
            let inner_ty = inner_changeset_ty(cx, column, &ty);
            quote_ty!(cx, Option<$inner_ty>)
        }
        _ => inner_changeset_ty(cx, column, &attr.ty),
    }
}

fn inner_changeset_ty(
    cx: &ExtCtxt,
    column: ast::Path,
    field_ty: &ast::Ty,
) -> P<ast::Ty> {
    quote_ty!(cx,
        ::diesel::expression::predicates::Eq<
            $column,
            ::diesel::expression::bound::Bound<
                <$column as ::diesel::expression::Expression>::SqlType,
                &'update $field_ty,
            >,
        >
    )
}

fn changeset_expr(
    cx: &ExtCtxt,
    span: Span,
    options: &ChangesetOptions,
    attr: &Attr,
) -> P<ast::Expr> {
    let column = cx.path(span, vec![options.table_name, attr.column_name]);
    let field_name = &attr.field_name.unwrap();
    if !options.treat_none_as_null && is_option_ty(&attr.ty) {
        quote_expr!(cx, self.$field_name.as_ref().map(|f| $column.eq(f)))
    } else {
        quote_expr!(cx, $column.eq(&self.$field_name))
    }
}
<|endoftext|>


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

//! Tests for ioreg! syntax extension

#![feature(phase)]
#[phase(plugin)] extern crate ioreg;
#[phase(plugin,link)] extern crate shiny;
extern crate core;

#[path="../zinc/util/volatile_cell.rs"] mod volatile_cell;

#[cfg(test)]
mod test {
  use std::mem::{transmute, zeroed};
  use std::ptr::PtrExt;
  use volatile_cell::VolatileCell;

  fn get_value<'a, T>(v: &'a T, offset: uint) -> u32 {
    unsafe {
      let ptr: *const u32 = transmute(v);
      *(ptr.offset(offset as int))
    }
  }

  fn zeroed_safe<T: Copy>() -> T {
    unsafe {
      return zeroed();
    }
  }

  ioregs!(BASIC_TEST = {
    0x0 => reg32 reg1 {
      0      => field1,
      1..3   => field2,
      16..24 => field3,
      25     => field4: set_to_clear,
    }
    0x4 => reg32 reg2 {
      0      => field1,
    }
    0x8 => reg32 wo_reg {
      0..15  => field1: wo,
      16..31 => field2: wo,
    }
  });

  describe!(
    before_each {
      let test: BASIC_TEST = zeroed_safe();
    }

    it "can round_trip simple field values 1" {
      test.reg1.set_field1(true);
      assert_eq!(test.reg1.field1(), true);
      assert_eq!(get_value(&test, 0), 1);
      assert_eq!(get_value(&test, 1), 0);
    }

    it "can round trip simple field values 2" {
      test.reg1.set_field3(0xde);
      assert_eq!(test.reg1.field3(), 0xde);
      assert_eq!(get_value(&test, 0), 0xde<<16);
    }

    it "sets set_to_clear fields" {
      test.reg1.clear_field4();
      assert_eq!(get_value(&test, 0), 1<<25);
    }

    it "does not read from writeonly registers" {
      test.wo_reg.set_field1(0xdead);
      assert_eq!(get_value(&test, 2), 0xdead);
      test.wo_reg.set_field2(0xdead);
      assert_eq!(get_value(&test, 2), 0xdead<<16);
    }
  );

  ioregs!(GROUP_TEST = {
    0x0 => group regs[5] {
      0x0 => reg32 reg1 {
        0..31 => field1
      }
      0x4 => reg32 reg2 {
        0..31 => field2
      }
    }
  });

  describe!(
    before_each {
      let test: GROUP_TEST = zeroed_safe();
    }

    it "sets groups correctly" {
      test.regs[0].reg1.set_field1(0xdeadbeef);
      assert_eq!(test.regs[0].reg1.field1(), 0xdeadbeef);
      assert_eq!(get_value(&test, 0), 0xdeadbeef);
      for i in range(1, 10) {
        assert_eq!(get_value(&test, i), 0);
      }

      test.regs[2].reg2.set_field2(0xfeedbeef);
      assert_eq!(test.regs[2].reg2.field2(), 0xfeedbeef);
      assert_eq!(get_value(&test, 5), 0xfeedbeef);
    }
  );

  ioregs!(FIELD_ARRAY_TEST = {
    0x0 => reg32 reg1 {
      0..31 => field[16]
    }
  });

  describe!(
    before_each {
      let test: FIELD_ARRAY_TEST = zeroed_safe();
    }

    it "sets field arrays correctly" {
      test.reg1.set_field(0, 1);
      assert_eq!(test.reg1.field(0), 1);
      assert_eq!(get_value(&test, 0), 0x1);

      test.reg1.set_field(4, 3);
      assert_eq!(test.reg1.field(4), 3);
      assert_eq!(get_value(&test, 0), 0x1 | 0x3<<8);
    }
  );

  ioregs!(GAP_TEST = {
    0x0 => reg32 reg1 {
      0..31 => field,
    }
    0x10 => reg32 reg2 {
      0..31 => field,
    }
    0x14 => reg32 reg3 {
      0..31 => field,
    }
    0x20 => reg32 reg4 {
      0..31 => field,
    }
  });

  describe!(
    before_each {
      let test: GAP_TEST = zeroed_safe();
      let base = &test as *const GAP_TEST;
    }
    it "has zero base offset" {
      let addr = &test.reg1 as *const GAP_TEST_reg1;
      assert_eq!(addr as uint - base as uint, 0x0);
    }
    it "computes the correct first gap" {
      let addr = &test.reg2 as *const GAP_TEST_reg2;
      assert_eq!(addr as uint - base as uint, 0x10);
    }
    it "computes the correct second gap" {
      let addr = &test.reg4 as *const GAP_TEST_reg4;
      assert_eq!(addr as uint - base as uint, 0x20);
    }
  );
}
<commit_msg>ioreg::test: Fix imports<commit_after>// Zinc, the bare metal stack for rust.
// Copyright 2014 Ben Gamari <bgamari@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Tests for ioreg! syntax extension

#![feature(plugin)]

#[plugin] extern crate ioreg;
#[plugin] extern crate shiny;
extern crate core;

#[path="../zinc/util/volatile_cell.rs"] mod volatile_cell;

#[cfg(test)]
mod test {
  use std::mem::{transmute, zeroed};
  use std::ptr::PtrExt;
  use volatile_cell::VolatileCell;

  fn get_value<'a, T>(v: &'a T, offset: uint) -> u32 {
    unsafe {
      let ptr: *const u32 = transmute(v);
      *(ptr.offset(offset as int))
    }
  }

  fn zeroed_safe<T: Copy>() -> T {
    unsafe {
      return zeroed();
    }
  }

  ioregs!(BASIC_TEST = {
    0x0 => reg32 reg1 {
      0      => field1,
      1..3   => field2,
      16..24 => field3,
      25     => field4: set_to_clear,
    }
    0x4 => reg32 reg2 {
      0      => field1,
    }
    0x8 => reg32 wo_reg {
      0..15  => field1: wo,
      16..31 => field2: wo,
    }
  });

  describe!(
    before_each {
      let test: BASIC_TEST = zeroed_safe();
    }

    it "can round_trip simple field values 1" {
      test.reg1.set_field1(true);
      assert_eq!(test.reg1.field1(), true);
      assert_eq!(get_value(&test, 0), 1);
      assert_eq!(get_value(&test, 1), 0);
    }

    it "can round trip simple field values 2" {
      test.reg1.set_field3(0xde);
      assert_eq!(test.reg1.field3(), 0xde);
      assert_eq!(get_value(&test, 0), 0xde<<16);
    }

    it "sets set_to_clear fields" {
      test.reg1.clear_field4();
      assert_eq!(get_value(&test, 0), 1<<25);
    }

    it "does not read from writeonly registers" {
      test.wo_reg.set_field1(0xdead);
      assert_eq!(get_value(&test, 2), 0xdead);
      test.wo_reg.set_field2(0xdead);
      assert_eq!(get_value(&test, 2), 0xdead<<16);
    }
  );

  ioregs!(GROUP_TEST = {
    0x0 => group regs[5] {
      0x0 => reg32 reg1 {
        0..31 => field1
      }
      0x4 => reg32 reg2 {
        0..31 => field2
      }
    }
  });

  describe!(
    before_each {
      let test: GROUP_TEST = zeroed_safe();
    }

    it "sets groups correctly" {
      test.regs[0].reg1.set_field1(0xdeadbeef);
      assert_eq!(test.regs[0].reg1.field1(), 0xdeadbeef);
      assert_eq!(get_value(&test, 0), 0xdeadbeef);
      for i in range(1, 10) {
        assert_eq!(get_value(&test, i), 0);
      }

      test.regs[2].reg2.set_field2(0xfeedbeef);
      assert_eq!(test.regs[2].reg2.field2(), 0xfeedbeef);
      assert_eq!(get_value(&test, 5), 0xfeedbeef);
    }
  );

  ioregs!(FIELD_ARRAY_TEST = {
    0x0 => reg32 reg1 {
      0..31 => field[16]
    }
  });

  describe!(
    before_each {
      let test: FIELD_ARRAY_TEST = zeroed_safe();
    }

    it "sets field arrays correctly" {
      test.reg1.set_field(0, 1);
      assert_eq!(test.reg1.field(0), 1);
      assert_eq!(get_value(&test, 0), 0x1);

      test.reg1.set_field(4, 3);
      assert_eq!(test.reg1.field(4), 3);
      assert_eq!(get_value(&test, 0), 0x1 | 0x3<<8);
    }
  );

  ioregs!(GAP_TEST = {
    0x0 => reg32 reg1 {
      0..31 => field,
    }
    0x10 => reg32 reg2 {
      0..31 => field,
    }
    0x14 => reg32 reg3 {
      0..31 => field,
    }
    0x20 => reg32 reg4 {
      0..31 => field,
    }
  });

  describe!(
    before_each {
      let test: GAP_TEST = zeroed_safe();
      let base = &test as *const GAP_TEST;
    }
    it "has zero base offset" {
      let addr = &test.reg1 as *const GAP_TEST_reg1;
      assert_eq!(addr as uint - base as uint, 0x0);
    }
    it "computes the correct first gap" {
      let addr = &test.reg2 as *const GAP_TEST_reg2;
      assert_eq!(addr as uint - base as uint, 0x10);
    }
    it "computes the correct second gap" {
      let addr = &test.reg4 as *const GAP_TEST_reg4;
      assert_eq!(addr as uint - base as uint, 0x20);
    }
  );
}
<|endoftext|>


<commit_before>use std::ops::Range;

use gameboy::{Gpu, Irq, Memory, Timer};
use gameboy::cartridge::{Cartridge, CartridgeDetails};
use gameboy::frame::Frame;
use super::memory_map::{self, Address};

const MAIN_MEM_SIZE: usize = 0x2000;
const ZRAM_SIZE: usize = 0x80;
const MMAP_SIZE: usize = 0x80;

pub struct Interconnect {
    pub gpu: Gpu,
    pub ram: Memory,
    pub zram: Memory,
    pub mmap_io: Memory,
    pub timer: Timer,
    pub irq: Irq,
    pub cart: Option<Cartridge>,
    pub interrupt: u8,
}

impl Interconnect {
    pub fn new() -> Interconnect {
        Interconnect {
            gpu: Gpu::new(),
            ram: Memory::new(MAIN_MEM_SIZE),
            zram: Memory::new(ZRAM_SIZE),
            mmap_io: Memory::new(MMAP_SIZE),
            timer: Timer::new(),
            irq: Irq::new(),
            cart: None,
            interrupt: 0x00,
        }
    }

    pub fn with_cart(cart: Cartridge) -> Interconnect {
        Interconnect {
            gpu: Gpu::new(),
            ram: Memory::new(MAIN_MEM_SIZE),
            zram: Memory::new(ZRAM_SIZE),
            mmap_io: Memory::new(MMAP_SIZE),
            timer: Timer::new(),
            irq: Irq::new(),
            cart: Some(cart),
            interrupt: 0x00,
        }
    }

    pub fn step(&mut self, cycles: usize) -> Result<(), String> {
        self.gpu.step(&mut self.irq, cycles)?;
        self.timer.step(&mut self.irq, cycles)?;

        Ok(())
    }

    pub fn reset(&mut self) {
        self.gpu.reset();
        self.timer.reset();
        self.irq.reset();
    }

    pub fn cart_details(&self) -> CartridgeDetails {
        let cart = self.cart.as_ref().expect("Cartridge is empty");

        cart.details(&self)
    }

    pub fn request_frame(&self) -> &Frame {
        &self.gpu.frame
    }

    pub fn write_u8(&mut self, addr: u16, byte: u8) {
        // Special case - DMA transfer
        if addr == 0xFF46 {
            self.dma_transfer(byte);
            return;
        }
        let cart = self.cart.as_mut().expect("Cartridge is empty");

        match memory_map::map_address(addr) {
            Address::Ram(a) => self.ram.write_u8(a, byte),
            Address::RamShadow(a) => self.ram.write_u8(a, byte),
            Address::Gfx(a) => self.gpu.ram.write_u8(a, byte),
            Address::CartRam(a) => cart.ram.write_u8(a, byte),
            Address::CartRom(a) => cart.rom.write_u8(a, byte),
            Address::ZRam(a) => {
                // if a != 0x00 {
                self.zram.write_u8(a, byte);
                // }
            }
            Address::Oam(a) => self.gpu.sprite_data.write_u8(a, byte),
            Address::Unused(_) => (),
            Address::Io(a) => {
                match a {
                    0x00 => println!("err: write to joypad not supported"),
                    0x01...0x02 => println!("err: write to serial driver not supported"),
                    0x04...0x07 => self.timer.write_u8(a, byte),
                    0x0F => self.irq.request_flag = byte,
                    0x10...0x26 => println!("err: write to sound driver not supported"),
                    0x30...0x3F => println!("err: write to wave pattern RAM not supported"),
                    0x40...0x45 => self.gpu.write_u8(a, byte),
                    0x47...0x49 => self.gpu.write_u8(a, byte),
                    0x4A...0x4B => self.gpu.write_u8(a, byte),
                    0x7F => self.mmap_io.write_u8(a, byte),
                    _ => panic!("write memory mapped I/O in unsupported range: {:04X}", a),
                }
            }
            Address::InterruptEnableRegister(a) => self.irq.enable_flag = byte,
            _ => {
                panic!("Unable to write byte to: {:#X}, invalid memory region.",
                       addr)
            }
        }
    }

    pub fn read_u8(&self, addr: u16) -> u8 {
        let cart = self.cart.as_ref().expect("Cartridge is empty");

        match memory_map::map_address(addr) {
            Address::Ram(addr) => self.ram.read_u8(addr),
            Address::RamShadow(addr) => self.ram.read_u8(addr),
            Address::CartRom(addr) |
            Address::CartRomOtherBank(addr) => cart.rom.read_u8(addr),
            Address::Gfx(value) => self.gpu.ram.read_u8(value),
            Address::CartRam(a) => cart.ram.read_u8(a),
            Address::ZRam(a) => self.zram.read_u8(a),
            Address::Oam(a) => self.gpu.sprite_data.read_u8(a),
            Address::Unused(_) => 0xFF, // Always return high
            Address::Io(a) => {
                match a {
                    0x00 => {
                        println!("err: read from joypad not supported");
                        0xFF
                    }
                    0x01...0x02 => {
                        println!("err: read from serial driver not supported");
                        0
                    }
                    0x04...0x07 => self.timer.read_u8(a),
                    0x0F => self.irq.request_flag,
                    0x10...0x26 => {
                        println!("err: read from sound driver not supported");
                        0
                    }
                    0x30...0x3F => {
                        println!("err: write to wave pattern RAM not supported");
                        0
                    }
                    0x40...0x45 => self.gpu.read_u8(a),
                    0x47...0x49 => self.gpu.read_u8(a),
                    0x4A...0x4B => self.gpu.read_u8(a),
                    0x7F => self.mmap_io.read_u8(a),
                    _ => panic!("read memory mapped I/O in unsupported range"),
                }
            }
            Address::InterruptEnableRegister(a) => self.irq.enable_flag,
            _ => panic!("Unable to read address: {:#X}", addr),
        }
    }

    pub fn read_bytes(&self, r: Range<u16>) -> &[u8] {
        let cart = self.cart.as_ref().expect("Cartridge is empty");

        match memory_map::map_address(r.start) {
            Address::Ram(_) |
            Address::RamShadow(_) => self.ram.read_bytes(r),
            Address::CartRom(_) |
            Address::CartRomOtherBank(_) => cart.rom.read_bytes(r),
            Address::Gfx(_) => self.gpu.ram.read_bytes(r),
            Address::CartRam(_) => cart.ram.read_bytes(r),
            Address::ZRam(a) => self.zram.read_bytes(r),
            Address::Io(a) => self.mmap_io.read_bytes(r),
            _ => panic!("Unable to read address range: {:?}", r),
        }
    }

    pub fn write_u16(&mut self, addr: u16, val: u16) {
        let cart = self.cart.as_ref().expect("Cartridge is empty");

        match memory_map::map_address(addr) {
            Address::Ram(a) => self.ram.write_u16(a, val),
            Address::RamShadow(a) => self.ram.write_u16(a, val),
            Address::ZRam(a) => self.zram.write_u16(a, val),
            _ => panic!("Unable to write address: {:#X}", addr),
        }
    }

    pub fn read_u16(&self, addr: u16) -> u16 {
        let cart = self.cart.as_ref().expect("Cartridge is empty");

        match memory_map::map_address(addr) {
            Address::Ram(addr) => self.ram.read_u16(addr),
            Address::RamShadow(addr) => self.ram.read_u16(addr),
            Address::CartRom(addr) |
            Address::CartRomOtherBank(addr) => cart.rom.read_u16(addr),
            Address::Gfx(value) => self.gpu.ram.read_u16(value),
            Address::CartRam(a) => cart.ram.read_u16(a),
            Address::ZRam(a) => self.zram.read_u16(a),
            Address::Io(a) => self.mmap_io.read_u16(a),
            _ => panic!("Unable to read address: {:#X}", addr),
        }
    }

    fn dma_transfer(&mut self, byte: u8) {
        let addr = ((byte as u16) << 0x08); // "The written value specifies the transfer source address divided by 0x100"
        for x in 0..0xA0 {
            let val = self.read_u8(addr + x);
            self.write_u8(0xFE00 + x, val);
        }
    }
}
<commit_msg>Remove debug println calls slowing down the emulator<commit_after>use std::ops::Range;

use gameboy::{Gpu, Irq, Memory, Timer};
use gameboy::cartridge::{Cartridge, CartridgeDetails};
use gameboy::frame::Frame;
use super::memory_map::{self, Address};

const MAIN_MEM_SIZE: usize = 0x2000;
const ZRAM_SIZE: usize = 0x80;
const MMAP_SIZE: usize = 0x80;

pub struct Interconnect {
    pub gpu: Gpu,
    pub ram: Memory,
    pub zram: Memory,
    pub mmap_io: Memory,
    pub timer: Timer,
    pub irq: Irq,
    pub cart: Option<Cartridge>,
    pub interrupt: u8,
}

impl Interconnect {
    pub fn new() -> Interconnect {
        Interconnect {
            gpu: Gpu::new(),
            ram: Memory::new(MAIN_MEM_SIZE),
            zram: Memory::new(ZRAM_SIZE),
            mmap_io: Memory::new(MMAP_SIZE),
            timer: Timer::new(),
            irq: Irq::new(),
            cart: None,
            interrupt: 0x00,
        }
    }

    pub fn with_cart(cart: Cartridge) -> Interconnect {
        Interconnect {
            gpu: Gpu::new(),
            ram: Memory::new(MAIN_MEM_SIZE),
            zram: Memory::new(ZRAM_SIZE),
            mmap_io: Memory::new(MMAP_SIZE),
            timer: Timer::new(),
            irq: Irq::new(),
            cart: Some(cart),
            interrupt: 0x00,
        }
    }

    pub fn step(&mut self, cycles: usize) -> Result<(), String> {
        self.gpu.step(&mut self.irq, cycles)?;
        self.timer.step(&mut self.irq, cycles)?;

        Ok(())
    }

    pub fn reset(&mut self) {
        self.gpu.reset();
        self.timer.reset();
        self.irq.reset();
    }

    pub fn cart_details(&self) -> CartridgeDetails {
        let cart = self.cart.as_ref().expect("Cartridge is empty");

        cart.details(&self)
    }

    pub fn request_frame(&self) -> &Frame {
        &self.gpu.frame
    }

    pub fn write_u8(&mut self, addr: u16, byte: u8) {
        // Special case - DMA transfer
        if addr == 0xFF46 {
            self.dma_transfer(byte);
            return;
        }
        let cart = self.cart.as_mut().expect("Cartridge is empty");

        match memory_map::map_address(addr) {
            Address::Ram(a) => self.ram.write_u8(a, byte),
            Address::RamShadow(a) => self.ram.write_u8(a, byte),
            Address::Gfx(a) => self.gpu.ram.write_u8(a, byte),
            Address::CartRam(a) => cart.ram.write_u8(a, byte),
            Address::CartRom(a) => cart.rom.write_u8(a, byte),
            Address::ZRam(a) => {
                // if a != 0x00 {
                self.zram.write_u8(a, byte);
                // }
            }
            Address::Oam(a) => self.gpu.sprite_data.write_u8(a, byte),
            Address::Unused(_) => (),
            Address::Io(a) => {
                match a {
                    0x00 => (), //println!("err: write to joypad not supported"),
                    0x01...0x02 => (), // println!("err: write to serial driver not supported"),
                    0x04...0x07 => self.timer.write_u8(a, byte),
                    0x0F => self.irq.request_flag = byte,
                    0x10...0x26 => (), // println!("err: write to sound driver not supported"),
                    0x30...0x3F => (), // println!("err: write to wave pattern RAM not supported"),
                    0x40...0x45 => self.gpu.write_u8(a, byte),
                    0x47...0x49 => self.gpu.write_u8(a, byte),
                    0x4A...0x4B => self.gpu.write_u8(a, byte),
                    0x7F => self.mmap_io.write_u8(a, byte),
                    _ => panic!("write memory mapped I/O in unsupported range: {:04X}", a),
                }
            }
            Address::InterruptEnableRegister(a) => self.irq.enable_flag = byte,
            _ => {
                panic!("Unable to write byte to: {:#X}, invalid memory region.",
                       addr)
            }
        }
    }

    pub fn read_u8(&self, addr: u16) -> u8 {
        let cart = self.cart.as_ref().expect("Cartridge is empty");

        match memory_map::map_address(addr) {
            Address::Ram(addr) => self.ram.read_u8(addr),
            Address::RamShadow(addr) => self.ram.read_u8(addr),
            Address::CartRom(addr) |
            Address::CartRomOtherBank(addr) => cart.rom.read_u8(addr),
            Address::Gfx(value) => self.gpu.ram.read_u8(value),
            Address::CartRam(a) => cart.ram.read_u8(a),
            Address::ZRam(a) => self.zram.read_u8(a),
            Address::Oam(a) => self.gpu.sprite_data.read_u8(a),
            Address::Unused(_) => 0xFF, // Always return high
            Address::Io(a) => {
                match a {
                    0x00 => {
                        // println!("err: read from joypad not supported");
                        0xFF
                    }
                    0x01...0x02 => {
                        // println!("err: read from serial driver not supported");
                        0
                    }
                    0x04...0x07 => self.timer.read_u8(a),
                    0x0F => self.irq.request_flag,
                    0x10...0x26 => {
                        // println!("err: read from sound driver not supported");
                        0
                    }
                    0x30...0x3F => {
                        // println!("err: write to wave pattern RAM not supported");
                        0
                    }
                    0x40...0x45 => self.gpu.read_u8(a),
                    0x47...0x49 => self.gpu.read_u8(a),
                    0x4A...0x4B => self.gpu.read_u8(a),
                    0x7F => self.mmap_io.read_u8(a),
                    _ => panic!("read memory mapped I/O in unsupported range"),
                }
            }
            Address::InterruptEnableRegister(a) => self.irq.enable_flag,
            _ => panic!("Unable to read address: {:#X}", addr),
        }
    }

    pub fn read_bytes(&self, r: Range<u16>) -> &[u8] {
        let cart = self.cart.as_ref().expect("Cartridge is empty");

        match memory_map::map_address(r.start) {
            Address::Ram(_) |
            Address::RamShadow(_) => self.ram.read_bytes(r),
            Address::CartRom(_) |
            Address::CartRomOtherBank(_) => cart.rom.read_bytes(r),
            Address::Gfx(_) => self.gpu.ram.read_bytes(r),
            Address::CartRam(_) => cart.ram.read_bytes(r),
            Address::ZRam(a) => self.zram.read_bytes(r),
            Address::Io(a) => self.mmap_io.read_bytes(r),
            _ => panic!("Unable to read address range: {:?}", r),
        }
    }

    pub fn write_u16(&mut self, addr: u16, val: u16) {
        let cart = self.cart.as_ref().expect("Cartridge is empty");

        match memory_map::map_address(addr) {
            Address::Ram(a) => self.ram.write_u16(a, val),
            Address::RamShadow(a) => self.ram.write_u16(a, val),
            Address::ZRam(a) => self.zram.write_u16(a, val),
            _ => panic!("Unable to write address: {:#X}", addr),
        }
    }

    pub fn read_u16(&self, addr: u16) -> u16 {
        let cart = self.cart.as_ref().expect("Cartridge is empty");

        match memory_map::map_address(addr) {
            Address::Ram(addr) => self.ram.read_u16(addr),
            Address::RamShadow(addr) => self.ram.read_u16(addr),
            Address::CartRom(addr) |
            Address::CartRomOtherBank(addr) => cart.rom.read_u16(addr),
            Address::Gfx(value) => self.gpu.ram.read_u16(value),
            Address::CartRam(a) => cart.ram.read_u16(a),
            Address::ZRam(a) => self.zram.read_u16(a),
            Address::Io(a) => self.mmap_io.read_u16(a),
            _ => panic!("Unable to read address: {:#X}", addr),
        }
    }

    fn dma_transfer(&mut self, byte: u8) {
        let addr = (byte as u16) << 0x08; // "The written value specifies the transfer source address divided by 0x100"
        for x in 0..0xA0 {
            let val = self.read_u8(addr + x);
            self.write_u8(0xFE00 + x, val);
        }
    }
}
<|endoftext|>