<commit_before>// Copyright 2017 The Exonum Team
//
// 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.

//! A definition of `StorageKey` trait and implementations for common types.

use byteorder::{ByteOrder, BigEndian};
use crypto::{Hash, PublicKey, HASH_SIZE, PUBLIC_KEY_LENGTH};

/// A type that can be (de)serialized as a key in the blockchain storage.
///
/// Since keys are sorted in a serialized form, the big-endian encoding should be used
/// with unsigned integer types. Note however that the big-endian encoding on its own
/// will not sort signed integer types in the natural order; therefore, they are
/// mapped to a corresponding unsigned type by adding a constant to a source value.
///
/// # Examples
///
/// ```
/// # extern crate exonum;
/// # extern crate byteorder;
/// use std::mem;
/// use exonum::storage::StorageKey;
/// use byteorder::{BigEndian, ByteOrder};
///
/// struct Key {
///     a: i16,
///     b: u32,
/// }
///
/// impl StorageKey for Key {
///     fn size(&self) -> usize {
///         mem::size_of_val(&self.a) + mem::size_of_val(&self.b)
///     }
///
///     fn write(&self, buffer: &mut [u8]) {
///         self.a.write(&mut buffer[0..2]);
///         self.b.write(&mut buffer[2..6]);
///     }
///
///     fn read(buffer: &[u8]) -> Self {
///         let a = i16::read(&buffer[0..2]);
///         let b = u32::read(&buffer[2..6]);
///         Key { a, b }
///     }
/// }
/// # fn main() {
/// # // Check the natural ordering of keys
/// # let (mut x, mut y) = (vec![0u8; 6], vec![0u8; 6]);
/// # Key { a: -1, b: 2 }.write(&mut x);
/// # Key { a: 1, b: 513 }.write(&mut y);
/// # assert!(x < y);
/// # // Check the roundtrip
/// # let key = Key::read(&x);
/// # assert_eq!(key.a, -1);
/// # assert_eq!(key.b, 2);
/// # }
/// ```
pub trait StorageKey {
    /// Returns the size of the serialized key in bytes.
    fn size(&self) -> usize;

    /// Serializes the key into the specified buffer of bytes.
    ///
    /// The caller must guarantee that the size of the buffer is equal to the precalculated size
    /// of the serialized key.
    // TODO: should be unsafe (ECR-174)?
    fn write(&self, buffer: &mut [u8]);

    /// Deserializes the key from the specified buffer of bytes.
    // TODO: should be unsafe (ECR-174)?
    fn read(buffer: &[u8]) -> Self;
}

/// No-op implementation.
impl StorageKey for () {
    fn size(&self) -> usize {
        0
    }

    fn write(&self, _buffer: &mut [u8]) {
        // no-op
    }

    fn read(_buffer: &[u8]) -> Self {
        ()
    }
}

impl StorageKey for u8 {
    fn size(&self) -> usize {
        1
    }

    fn write(&self, buffer: &mut [u8]) {
        buffer[0] = *self
    }

    fn read(buffer: &[u8]) -> Self {
        buffer[0]
    }
}

/// Uses encoding with the values mapped to `u8`
/// by adding the corresponding constant (`128`) to the value.
impl StorageKey for i8 {
    fn size(&self) -> usize {
        1
    }

    fn write(&self, buffer: &mut [u8]) {
        buffer[0] = self.wrapping_add(i8::min_value()) as u8;
    }

    fn read(buffer: &[u8]) -> Self {
        buffer[0].wrapping_sub(i8::min_value() as u8) as i8
    }
}

macro_rules! storage_key_for_ints {
    ($utype:ident, $itype:ident, $size:expr, $read_method:ident, $write_method:ident) => {
        /// Uses big-endian encoding.
        impl StorageKey for $utype {
            fn size(&self) -> usize {
                $size
            }

            fn write(&self, buffer: &mut [u8]) {
                BigEndian::$write_method(buffer, *self);
            }

            fn read(buffer: &[u8]) -> Self {
                BigEndian::$read_method(buffer)
            }
        }

        /// Uses big-endian encoding with the values mapped to the unsigned format
        /// by adding the corresponding constant to the value.
        impl StorageKey for $itype {
            fn size(&self) -> usize {
                $size
            }

            fn write(&self, buffer: &mut [u8]) {
                BigEndian::$write_method(
                    buffer,
                    self.wrapping_add($itype::min_value()) as $utype,
                );
            }

            fn read(buffer: &[u8]) -> Self {
                BigEndian::$read_method(buffer)
                    .wrapping_sub($itype::min_value() as $utype) as $itype
            }
        }
    }
}

storage_key_for_ints!{u16, i16, 2, read_u16, write_u16}
storage_key_for_ints!{u32, i32, 4, read_u32, write_u32}
storage_key_for_ints!{u64, i64, 8, read_u64, write_u64}

impl StorageKey for Hash {
    fn size(&self) -> usize {
        HASH_SIZE
    }

    fn write(&self, buffer: &mut [u8]) {
        buffer.copy_from_slice(self.as_ref())
    }

    fn read(buffer: &[u8]) -> Self {
        Hash::from_slice(buffer).unwrap()
    }
}

impl StorageKey for PublicKey {
    fn size(&self) -> usize {
        PUBLIC_KEY_LENGTH
    }

    fn write(&self, buffer: &mut [u8]) {
        buffer.copy_from_slice(self.as_ref())
    }

    fn read(buffer: &[u8]) -> Self {
        PublicKey::from_slice(buffer).unwrap()
    }
}

impl StorageKey for Vec<u8> {
    fn size(&self) -> usize {
        self.len()
    }

    fn write(&self, buffer: &mut [u8]) {
        buffer.copy_from_slice(self)
    }

    fn read(buffer: &[u8]) -> Self {
        buffer.to_vec()
    }
}

/// Uses UTF-8 string serialization.
impl StorageKey for String {
    fn size(&self) -> usize {
        self.len()
    }

    fn write(&self, buffer: &mut [u8]) {
        buffer.copy_from_slice(self.as_bytes())
    }

    fn read(buffer: &[u8]) -> Self {
        unsafe { ::std::str::from_utf8_unchecked(buffer).to_string() }
    }
}

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

    // Number of samples for fuzz testing
    const FUZZ_SAMPLES: usize = 100_000;

    macro_rules! test_storage_key_for_int_type {
        (full $type:ident, $size:expr => $test_name:ident) => {
            #[test]
            fn $test_name() {
                use std::iter::once;

                const MIN: $type = ::std::$type::MIN;
                const MAX: $type = ::std::$type::MAX;

                // Roundtrip
                let mut buffer = [0u8; $size];
                for x in (MIN..MAX).chain(once(MAX)) {
                    x.write(&mut buffer);
                    assert_eq!($type::read(&buffer), x);
                }

                // Ordering
                let (mut x_buffer, mut y_buffer) = ([0u8; $size], [0u8; $size]);
                for x in MIN..MAX {
                    let y = x + 1;
                    x.write(&mut x_buffer);
                    y.write(&mut y_buffer);
                    assert!(x_buffer < y_buffer);
                }
            }
        };
        (fuzz $type:ident, $size:expr => $test_name:ident) => {
            #[test]
            fn $test_name() {
                use rand::{Rng, thread_rng};
                let mut rng = thread_rng();

                // Fuzzed roundtrip
                let mut buffer = [0u8; $size];
                let handpicked_vals = vec![$type::min_value(), $type::max_value()];
                for x in rng.gen_iter::<$type>().take(FUZZ_SAMPLES).chain(handpicked_vals) {
                    x.write(&mut buffer);
                    assert_eq!($type::read(&buffer), x);
                }

                // Fuzzed ordering
                let (mut x_buffer, mut y_buffer) = ([0u8; $size], [0u8; $size]);
                let mut vals: Vec<$type> = rng.gen_iter().take(FUZZ_SAMPLES).collect();
                vals.sort();
                for w in vals.windows(2) {
                    let (x, y) = (w[0], w[1]);
                    if x == y { continue; }

                    x.write(&mut x_buffer);
                    y.write(&mut y_buffer);
                    assert!(x_buffer < y_buffer);
                }
            }
        }
    }

    test_storage_key_for_int_type!{full  u8, 1 => test_storage_key_for_u8}
    test_storage_key_for_int_type!{full  i8, 1 => test_storage_key_for_i8}
    test_storage_key_for_int_type!{full u16, 2 => test_storage_key_for_u16}
    test_storage_key_for_int_type!{full i16, 2 => test_storage_key_for_i16}
    test_storage_key_for_int_type!{fuzz u32, 4 => test_storage_key_for_u32}
    test_storage_key_for_int_type!{fuzz i32, 4 => test_storage_key_for_i32}
    test_storage_key_for_int_type!{fuzz u64, 8 => test_storage_key_for_u64}
    test_storage_key_for_int_type!{fuzz i64, 8 => test_storage_key_for_i64}
}
<commit_msg>Add index-focused tests for signed ints<commit_after>// Copyright 2017 The Exonum Team
//
// 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.

//! A definition of `StorageKey` trait and implementations for common types.

use byteorder::{ByteOrder, BigEndian};
use crypto::{Hash, PublicKey, HASH_SIZE, PUBLIC_KEY_LENGTH};

/// A type that can be (de)serialized as a key in the blockchain storage.
///
/// Since keys are sorted in a serialized form, the big-endian encoding should be used
/// with unsigned integer types. Note however that the big-endian encoding on its own
/// will not sort signed integer types in the natural order; therefore, they are
/// mapped to a corresponding unsigned type by adding a constant to a source value.
///
/// # Examples
///
/// ```
/// # extern crate exonum;
/// # extern crate byteorder;
/// use std::mem;
/// use exonum::storage::StorageKey;
/// use byteorder::{BigEndian, ByteOrder};
///
/// struct Key {
///     a: i16,
///     b: u32,
/// }
///
/// impl StorageKey for Key {
///     fn size(&self) -> usize {
///         mem::size_of_val(&self.a) + mem::size_of_val(&self.b)
///     }
///
///     fn write(&self, buffer: &mut [u8]) {
///         self.a.write(&mut buffer[0..2]);
///         self.b.write(&mut buffer[2..6]);
///     }
///
///     fn read(buffer: &[u8]) -> Self {
///         let a = i16::read(&buffer[0..2]);
///         let b = u32::read(&buffer[2..6]);
///         Key { a, b }
///     }
/// }
/// # fn main() {
/// # // Check the natural ordering of keys
/// # let (mut x, mut y) = (vec![0u8; 6], vec![0u8; 6]);
/// # Key { a: -1, b: 2 }.write(&mut x);
/// # Key { a: 1, b: 513 }.write(&mut y);
/// # assert!(x < y);
/// # // Check the roundtrip
/// # let key = Key::read(&x);
/// # assert_eq!(key.a, -1);
/// # assert_eq!(key.b, 2);
/// # }
/// ```
pub trait StorageKey {
    /// Returns the size of the serialized key in bytes.
    fn size(&self) -> usize;

    /// Serializes the key into the specified buffer of bytes.
    ///
    /// The caller must guarantee that the size of the buffer is equal to the precalculated size
    /// of the serialized key.
    // TODO: should be unsafe (ECR-174)?
    fn write(&self, buffer: &mut [u8]);

    /// Deserializes the key from the specified buffer of bytes.
    // TODO: should be unsafe (ECR-174)?
    fn read(buffer: &[u8]) -> Self;
}

/// No-op implementation.
impl StorageKey for () {
    fn size(&self) -> usize {
        0
    }

    fn write(&self, _buffer: &mut [u8]) {
        // no-op
    }

    fn read(_buffer: &[u8]) -> Self {
        ()
    }
}

impl StorageKey for u8 {
    fn size(&self) -> usize {
        1
    }

    fn write(&self, buffer: &mut [u8]) {
        buffer[0] = *self
    }

    fn read(buffer: &[u8]) -> Self {
        buffer[0]
    }
}

/// Uses encoding with the values mapped to `u8`
/// by adding the corresponding constant (`128`) to the value.
impl StorageKey for i8 {
    fn size(&self) -> usize {
        1
    }

    fn write(&self, buffer: &mut [u8]) {
        buffer[0] = self.wrapping_add(i8::min_value()) as u8;
    }

    fn read(buffer: &[u8]) -> Self {
        buffer[0].wrapping_sub(i8::min_value() as u8) as i8
    }
}

macro_rules! storage_key_for_ints {
    ($utype:ident, $itype:ident, $size:expr, $read_method:ident, $write_method:ident) => {
        /// Uses big-endian encoding.
        impl StorageKey for $utype {
            fn size(&self) -> usize {
                $size
            }

            fn write(&self, buffer: &mut [u8]) {
                BigEndian::$write_method(buffer, *self);
            }

            fn read(buffer: &[u8]) -> Self {
                BigEndian::$read_method(buffer)
            }
        }

        /// Uses big-endian encoding with the values mapped to the unsigned format
        /// by adding the corresponding constant to the value.
        impl StorageKey for $itype {
            fn size(&self) -> usize {
                $size
            }

            fn write(&self, buffer: &mut [u8]) {
                BigEndian::$write_method(
                    buffer,
                    self.wrapping_add($itype::min_value()) as $utype,
                );
            }

            fn read(buffer: &[u8]) -> Self {
                BigEndian::$read_method(buffer)
                    .wrapping_sub($itype::min_value() as $utype) as $itype
            }
        }
    }
}

storage_key_for_ints!{u16, i16, 2, read_u16, write_u16}
storage_key_for_ints!{u32, i32, 4, read_u32, write_u32}
storage_key_for_ints!{u64, i64, 8, read_u64, write_u64}

impl StorageKey for Hash {
    fn size(&self) -> usize {
        HASH_SIZE
    }

    fn write(&self, buffer: &mut [u8]) {
        buffer.copy_from_slice(self.as_ref())
    }

    fn read(buffer: &[u8]) -> Self {
        Hash::from_slice(buffer).unwrap()
    }
}

impl StorageKey for PublicKey {
    fn size(&self) -> usize {
        PUBLIC_KEY_LENGTH
    }

    fn write(&self, buffer: &mut [u8]) {
        buffer.copy_from_slice(self.as_ref())
    }

    fn read(buffer: &[u8]) -> Self {
        PublicKey::from_slice(buffer).unwrap()
    }
}

impl StorageKey for Vec<u8> {
    fn size(&self) -> usize {
        self.len()
    }

    fn write(&self, buffer: &mut [u8]) {
        buffer.copy_from_slice(self)
    }

    fn read(buffer: &[u8]) -> Self {
        buffer.to_vec()
    }
}

/// Uses UTF-8 string serialization.
impl StorageKey for String {
    fn size(&self) -> usize {
        self.len()
    }

    fn write(&self, buffer: &mut [u8]) {
        buffer.copy_from_slice(self.as_bytes())
    }

    fn read(buffer: &[u8]) -> Self {
        unsafe { ::std::str::from_utf8_unchecked(buffer).to_string() }
    }
}

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

    // Number of samples for fuzz testing
    const FUZZ_SAMPLES: usize = 100_000;

    macro_rules! test_storage_key_for_int_type {
        (full $type:ident, $size:expr => $test_name:ident) => {
            #[test]
            fn $test_name() {
                use std::iter::once;

                const MIN: $type = ::std::$type::MIN;
                const MAX: $type = ::std::$type::MAX;

                // Roundtrip
                let mut buffer = [0u8; $size];
                for x in (MIN..MAX).chain(once(MAX)) {
                    x.write(&mut buffer);
                    assert_eq!($type::read(&buffer), x);
                }

                // Ordering
                let (mut x_buffer, mut y_buffer) = ([0u8; $size], [0u8; $size]);
                for x in MIN..MAX {
                    let y = x + 1;
                    x.write(&mut x_buffer);
                    y.write(&mut y_buffer);
                    assert!(x_buffer < y_buffer);
                }
            }
        };
        (fuzz $type:ident, $size:expr => $test_name:ident) => {
            #[test]
            fn $test_name() {
                use rand::{Rng, thread_rng};
                let mut rng = thread_rng();

                // Fuzzed roundtrip
                let mut buffer = [0u8; $size];
                let handpicked_vals = vec![$type::min_value(), $type::max_value()];
                for x in rng.gen_iter::<$type>().take(FUZZ_SAMPLES).chain(handpicked_vals) {
                    x.write(&mut buffer);
                    assert_eq!($type::read(&buffer), x);
                }

                // Fuzzed ordering
                let (mut x_buffer, mut y_buffer) = ([0u8; $size], [0u8; $size]);
                let mut vals: Vec<$type> = rng.gen_iter().take(FUZZ_SAMPLES).collect();
                vals.sort();
                for w in vals.windows(2) {
                    let (x, y) = (w[0], w[1]);
                    if x == y { continue; }

                    x.write(&mut x_buffer);
                    y.write(&mut y_buffer);
                    assert!(x_buffer < y_buffer);
                }
            }
        }
    }

    test_storage_key_for_int_type!{full  u8, 1 => test_storage_key_for_u8}
    test_storage_key_for_int_type!{full  i8, 1 => test_storage_key_for_i8}
    test_storage_key_for_int_type!{full u16, 2 => test_storage_key_for_u16}
    test_storage_key_for_int_type!{full i16, 2 => test_storage_key_for_i16}
    test_storage_key_for_int_type!{fuzz u32, 4 => test_storage_key_for_u32}
    test_storage_key_for_int_type!{fuzz i32, 4 => test_storage_key_for_i32}
    test_storage_key_for_int_type!{fuzz u64, 8 => test_storage_key_for_u64}
    test_storage_key_for_int_type!{fuzz i64, 8 => test_storage_key_for_i64}

    #[test]
    fn test_signed_int_key_in_index() {
        use storage::{Database, MapIndex, MemoryDB};

        let db: Box<Database> = Box::new(MemoryDB::new());
        let mut fork = db.fork();
        {
            let mut index: MapIndex<_, i32, u64> = MapIndex::new("test_index", &mut fork);
            index.put(&5, 100);
            index.put(&-3, 200);
        }
        db.merge(fork.into_patch()).unwrap();

        let snapshot = db.snapshot();
        let index: MapIndex<_, i32, u64> = MapIndex::new("test_index", snapshot);
        assert_eq!(index.get(&5), Some(100));
        assert_eq!(index.get(&-3), Some(200));

        assert_eq!(
            index.iter_from(&-4).collect::<Vec<_>>(),
            vec![(-3, 200), (5, 100)]
        );
        assert_eq!(index.iter_from(&-2).collect::<Vec<_>>(), vec![(5, 100)]);
        assert_eq!(index.iter_from(&1).collect::<Vec<_>>(), vec![(5, 100)]);
        assert_eq!(index.iter_from(&6).collect::<Vec<_>>(), vec![]);

        assert_eq!(index.values().collect::<Vec<_>>(), vec![200, 100]);
    }

    // Example how to migrate from Exonum <= 0.5 implementation of `StorageKey`
    // for signed integers.
    #[test]
    fn test_old_signed_int_key_in_index() {
        use storage::{Database, MapIndex, MemoryDB};

        // Simple wrapper around a signed integer type with the `StorageKey` implementation,
        // which was used in Exonum <= 0.5.
        #[derive(Debug, PartialEq)]
        struct QuirkyI32Key(i32);

        impl StorageKey for QuirkyI32Key {
            fn size(&self) -> usize {
                4
            }

            fn write(&self, buffer: &mut [u8]) {
                BigEndian::write_i32(buffer, self.0);
            }

            fn read(buffer: &[u8]) -> Self {
                QuirkyI32Key(BigEndian::read_i32(buffer))
            }
        }

        let db: Box<Database> = Box::new(MemoryDB::new());
        let mut fork = db.fork();
        {
            let mut index: MapIndex<_, QuirkyI32Key, u64> = MapIndex::new("test_index", &mut fork);
            index.put(&QuirkyI32Key(5), 100);
            index.put(&QuirkyI32Key(-3), 200);
        }
        db.merge(fork.into_patch()).unwrap();

        let snapshot = db.snapshot();
        let index: MapIndex<_, QuirkyI32Key, u64> = MapIndex::new("test_index", snapshot);
        assert_eq!(index.get(&QuirkyI32Key(5)), Some(100));
        assert_eq!(index.get(&QuirkyI32Key(-3)), Some(200));

        // Bunch of counterintuitive behavior here
        assert_eq!(
            index.iter_from(&QuirkyI32Key(-4)).collect::<Vec<_>>(),
            vec![(QuirkyI32Key(-3), 200)]
        );
        assert_eq!(
            index.iter_from(&QuirkyI32Key(-2)).collect::<Vec<_>>(),
            vec![]
        );
        assert_eq!(
            index.iter_from(&QuirkyI32Key(1)).collect::<Vec<_>>(),
            vec![(QuirkyI32Key(5), 100), (QuirkyI32Key(-3), 200)]
        );
        assert_eq!(
            index.iter_from(&QuirkyI32Key(6)).collect::<Vec<_>>(),
            vec![(QuirkyI32Key(-3), 200)]
        );

        // Notice the different order of values compared to the previous test
        assert_eq!(index.values().collect::<Vec<_>>(), vec![100, 200]);
    }
}
<|endoftext|>


<commit_before>//! [PUT /_matrix/federation/v1/send/{txnId}](https://matrix.org/docs/spec/server_server/r0.1.4#put-matrix-federation-v1-send-txnid)

use std::collections::BTreeMap;

use ruma_api::ruma_api;
use ruma_common::MilliSecondsSinceUnixEpoch;
use ruma_identifiers::{EventId, ServerName, TransactionId};
use ruma_serde::Raw;
use serde_json::value::RawValue as RawJsonValue;

use crate::transactions::edu::Edu;

ruma_api! {
    metadata: {
        description: "Send transaction messages to another server",
        name: "send_transaction_message",
        method: PUT,
        path: "/_matrix/federation/v1/send/:transaction_id",
        rate_limited: false,
        authentication: ServerSignatures,
    }

    request: {
        /// A transaction ID unique between sending and receiving homeservers.
        #[ruma_api(path)]
        pub transaction_id: &'a TransactionId,

        /// The server_name of the homeserver sending this transaction.
        pub origin: &'a ServerName,

        /// POSIX timestamp in milliseconds on the originating homeserver when this transaction
        /// started.
        pub origin_server_ts: MilliSecondsSinceUnixEpoch,

        /// List of persistent updates to rooms.
        ///
        /// Must not be more than 50 items.
        #[cfg_attr(feature = "unstable-pre-spec", serde(default, skip_serializing_if = "<[_]>::is_empty"))]
        pub pdus: &'a [Box<RawJsonValue>],

        /// List of ephemeral messages.
        ///
        /// Must not be more than 100 items.
        #[serde(default, skip_serializing_if = "<[_]>::is_empty")]
        pub edus: &'a [Raw<Edu>],
    }

    #[derive(Default)]
    response: {
        /// Map of event IDs and response for each PDU given in the request.
        #[serde(with = "crate::serde::pdu_process_response")]
        pub pdus: BTreeMap<Box<EventId>, Result<(), String>>,
    }
}

impl<'a> Request<'a> {
    /// Creates a new `Request` with the given transaction ID, origin, timestamp.
    ///
    /// The PDU and EDU lists will start off empty.
    pub fn new(
        transaction_id: &'a TransactionId,
        origin: &'a ServerName,
        origin_server_ts: MilliSecondsSinceUnixEpoch,
    ) -> Self {
        Self { transaction_id, origin, origin_server_ts, pdus: &[], edus: &[] }
    }
}

impl Response {
    /// Creates a new `Response` with the given PDUs.
    pub fn new(pdus: BTreeMap<Box<EventId>, Result<(), String>>) -> Self {
        Self { pdus }
    }
}
<commit_msg>federation-api: Support MSC3618<commit_after>//! [PUT /_matrix/federation/v1/send/{txnId}](https://matrix.org/docs/spec/server_server/r0.1.4#put-matrix-federation-v1-send-txnid)

use std::collections::BTreeMap;

use ruma_api::ruma_api;
use ruma_common::MilliSecondsSinceUnixEpoch;
use ruma_identifiers::{EventId, ServerName, TransactionId};
use ruma_serde::Raw;
use serde_json::value::RawValue as RawJsonValue;

use crate::transactions::edu::Edu;

ruma_api! {
    metadata: {
        description: "Send transaction messages to another server",
        name: "send_transaction_message",
        method: PUT,
        path: "/_matrix/federation/v1/send/:transaction_id",
        rate_limited: false,
        authentication: ServerSignatures,
    }

    request: {
        /// A transaction ID unique between sending and receiving homeservers.
        #[ruma_api(path)]
        pub transaction_id: &'a TransactionId,

        /// The server_name of the homeserver sending this transaction.
        pub origin: &'a ServerName,

        /// POSIX timestamp in milliseconds on the originating homeserver when this transaction
        /// started.
        pub origin_server_ts: MilliSecondsSinceUnixEpoch,

        /// List of persistent updates to rooms.
        ///
        /// Must not be more than 50 items.
        #[cfg_attr(feature = "unstable-pre-spec", serde(default, skip_serializing_if = "<[_]>::is_empty"))]
        pub pdus: &'a [Box<RawJsonValue>],

        /// List of ephemeral messages.
        ///
        /// Must not be more than 100 items.
        #[serde(default, skip_serializing_if = "<[_]>::is_empty")]
        pub edus: &'a [Raw<Edu>],
    }

    #[derive(Default)]
    response: {
        /// Map of event IDs and response for each PDU given in the request.
        // https://github.com/matrix-org/matrix-doc/pull/3618 makes returning `pdus` optional.
        #[cfg_attr(feature = "unstable-pre-spec", serde(default))]
        #[serde(with = "crate::serde::pdu_process_response")]
        pub pdus: BTreeMap<Box<EventId>, Result<(), String>>,
    }
}

impl<'a> Request<'a> {
    /// Creates a new `Request` with the given transaction ID, origin, timestamp.
    ///
    /// The PDU and EDU lists will start off empty.
    pub fn new(
        transaction_id: &'a TransactionId,
        origin: &'a ServerName,
        origin_server_ts: MilliSecondsSinceUnixEpoch,
    ) -> Self {
        Self { transaction_id, origin, origin_server_ts, pdus: &[], edus: &[] }
    }
}

impl Response {
    /// Creates a new `Response` with the given PDUs.
    pub fn new(pdus: BTreeMap<Box<EventId>, Result<(), String>>) -> Self {
        Self { pdus }
    }
}
<|endoftext|>


<commit_before>use clap::{ App, Arg, ArgMatches };
use std::fs::File;
use std::io::{ BufRead, BufReader };
use std::path::Path;

pub fn read_args() -> Result<(Vec<String>, String), String> {
    let matches = load_matches();

    // The only things that can cause an early return here are
    // an absent dictionary and the lack of a target prefix. Here
    // we handle the prefix:
    let prefix = match matches.value_of("prefix") {
        Some(prefix) => prefix,
        None => return Err("Prefix not provided".to_string()),
    };

    // And here we handle the dictionary:
    let file = match matches.value_of("dictionary").map(|p| File::open(&Path::new(p))) {
        Some(Ok(file)) => file,
        Some(Err(_)) => return Err("Unable to open file".to_string()),
        None => return Err("Dictionary not provided".to_string()),
    };

    let sort = matches.is_present("sort");
    let ddup = matches.is_present("dedup");

    Ok((load_file(BufReader::new(file), sort, ddup), prefix.to_string()))
}

fn load_file<R: BufRead>(r: R, sort: bool, ddup: bool) -> Vec<String> {
    let mut vec: Vec<String> = r.lines()
        .filter_map(|l| l.map(|l| l.trim().to_string()).ok())
        .collect();

    if sort { vec.sort(); }
    if ddup { vec.dedup(); }

    vec
}

fn load_matches<'a>() -> ArgMatches<'a> {
    App::new("fin")
        .version("0.0.5")
        .author("J/A <archer884@gmail.com>")
        .about("Provides word completions")
        .arg(Arg::new("prefix")
             .help("Search prefix, e.g. 'app' for 'apple'")
             .required(true)
             .index(1))
        .arg(Arg::new("dictionary")
             .help("Dictionary input file(s)")
             .required(true)
             .index(2))
        .arg(Arg::new("sort")
             .short("s")
             .long("sort")
             .help("Ensure dictionary is sorted")
             .takes_value(false))
        .arg(Arg::new("dedup")
             .short("d")
             .long("dedup")
             .help("Ensure dictionary is deduplicated")
             .takes_value(false))
        .get_matches()
}
<commit_msg>Include error description in error message.<commit_after>use clap::{ App, Arg, ArgMatches };
use std::error::Error;
use std::fs::File;
use std::io::{ BufRead, BufReader };
use std::path::Path;

pub fn read_args() -> Result<(Vec<String>, String), String> {
    let matches = load_matches();

    // The only things that can cause an early return here are
    // an absent dictionary and the lack of a target prefix. Here
    // we handle the prefix:
    let prefix = match matches.value_of("prefix") {
        Some(prefix) => prefix,
        None => return Err("Prefix not provided".to_string()),
    };

    // And here we handle the dictionary:
    let file = match matches.value_of("dictionary").map(|p| File::open(&Path::new(p))) {
        Some(Ok(file)) => file,
        Some(Err(e)) => return Err(format!("Unable to open file: {}", e.description())),
        None => return Err("Dictionary not provided".to_string()),
    };

    let sort = matches.is_present("sort");
    let ddup = matches.is_present("dedup");

    Ok((load_file(BufReader::new(file), sort, ddup), prefix.to_string()))
}

fn load_file<R: BufRead>(r: R, sort: bool, ddup: bool) -> Vec<String> {
    let mut vec: Vec<String> = r.lines()
        .filter_map(|l| l.map(|l| l.trim().to_string()).ok())
        .collect();

    if sort { vec.sort(); }
    if ddup { vec.dedup(); }

    vec
}

fn load_matches<'a>() -> ArgMatches<'a> {
    App::new("fin")
        .version("0.0.5")
        .author("J/A <archer884@gmail.com>")
        .about("Provides word completions")
        .arg(Arg::new("prefix")
             .help("Search prefix, e.g. 'app' for 'apple'")
             .required(true)
             .index(1))
        .arg(Arg::new("dictionary")
             .help("Dictionary input file(s)")
             .required(true)
             .index(2))
        .arg(Arg::new("sort")
             .short("s")
             .long("sort")
             .help("Ensure dictionary is sorted")
             .takes_value(false))
        .arg(Arg::new("dedup")
             .short("d")
             .long("dedup")
             .help("Ensure dictionary is deduplicated")
             .takes_value(false))
        .get_matches()
}
<|endoftext|>


<commit_before>use syntax::ast;
use syntax::parse::parser::Parser;
use syntax::parse::token;
use syntax::ptr::P;

use block::{Block, Describe, It, Bench};

pub fn parse(parser: &mut Parser) -> Describe {
    parse_describe("sup", parser)
}

fn parse_describe(name: &str, parser: &mut Parser) -> Describe {
    let brace = token::CloseDelim(token::Brace);

    let mut before = vec![];
    let mut after = vec![];
    let mut blocks = vec![];

    loop {
        if parser.token == brace || parser.token == token::Eof {
            break
        }

        let span = parser.span;
        let ident = parser.parse_ident().unwrap();

        match &*ident.name.as_str() {
            "describe" | "context" => {
                let (name, _) = parser.parse_str().unwrap();
                parser.expect(&token::OpenDelim(token::Brace)).unwrap();
                let block = Block::Describe(parse_describe(&name, parser));
                parser.expect(&token::CloseDelim(token::Brace)).unwrap();
                blocks.push(block);
            },

            "it" | "test" => {
                let (name, _) = parser.parse_str().unwrap();
                let block = parse_block(parser);

                blocks.push(Block::It(It {
                    name: name.to_string(),
                    block: block
                }))
            },

            "bench" => {
                let (name, _) = parser.parse_str().unwrap();
                parser.expect(&token::BinOp(token::Or)).unwrap();
                let ident = parser.parse_ident().unwrap();
                parser.expect(&token::BinOp(token::Or)).unwrap();
                let block = parse_block(parser);

                blocks.push(Block::Bench(Bench {
                    name: name.to_string(),
                    ident: ident,
                    block: block
                }))
            },

            "before" => {
                before.push(parse_block(parser));
            },

            "after" => {
                after.push(parse_block(parser));
            },

            otherwise => {
                let message = format!("Expected `describe`, `context`, \
`before`, `after`, `it`, `test`, or `bench`, found `{}`", otherwise);
                panic!("{}", parser.span_fatal(span, &message))
            }
        }
    }

    Describe {
        name: name.to_string(),
        before: before,
        after: after,
        blocks: blocks
    }
}

fn parse_block(parser: &mut Parser) -> P<ast::Block> {
    let span = parser.span;
    let block = parser.parse_block().unwrap();
    if block.expr.is_some() {
        panic!("{}", parser.span_fatal(
            span,
            "last expression in this block must be terminated by `;`"))
    }
    block
}
<commit_msg>Refactor `parser::parse_describe`.<commit_after>use syntax::ast;
use syntax::parse::parser::Parser;
use syntax::parse::token;
use syntax::ptr::P;

use block::{Block, Describe, It, Bench};

pub fn parse(parser: &mut Parser) -> Describe {
    parse_describe("sup", parser)
}

fn parse_describe(name: &str, parser: &mut Parser) -> Describe {
    let mut before = vec![];
    let mut after = vec![];
    let mut blocks = vec![];

    loop {
        if parser.token == token::CloseDelim(token::Brace) ||
            parser.token == token::Eof {
            break
        }

        let span = parser.span;
        let ident = parser.parse_ident().unwrap();

        match &*ident.name.as_str() {
            "describe" | "context" => {
                let (name, _) = parser.parse_str().unwrap();
                parser.expect(&token::OpenDelim(token::Brace)).unwrap();
                let block = Block::Describe(parse_describe(&name, parser));
                parser.expect(&token::CloseDelim(token::Brace)).unwrap();
                blocks.push(block);
            },

            "it" | "test" => {
                let (name, _) = parser.parse_str().unwrap();
                let block = parse_block(parser);

                blocks.push(Block::It(It {
                    name: name.to_string(),
                    block: block
                }))
            },

            "bench" => {
                let (name, _) = parser.parse_str().unwrap();
                parser.expect(&token::BinOp(token::Or)).unwrap();
                let ident = parser.parse_ident().unwrap();
                parser.expect(&token::BinOp(token::Or)).unwrap();
                let block = parse_block(parser);

                blocks.push(Block::Bench(Bench {
                    name: name.to_string(),
                    ident: ident,
                    block: block
                }))
            },

            "before" => {
                before.push(parse_block(parser));
            },

            "after" => {
                after.push(parse_block(parser));
            },

            otherwise => {
                let message = format!("Expected `describe`, `context`, \
`before`, `after`, `it`, `test`, or `bench`, found `{}`", otherwise);
                panic!("{}", parser.span_fatal(span, &message))
            }
        }
    }

    Describe {
        name: name.to_string(),
        before: before,
        after: after,
        blocks: blocks
    }
}

fn parse_block(parser: &mut Parser) -> P<ast::Block> {
    let span = parser.span;
    let block = parser.parse_block().unwrap();
    if block.expr.is_some() {
        panic!("{}", parser.span_fatal(
            span,
            "last expression in this block must be terminated by `;`"))
    }
    block
}
<|endoftext|>


<commit_before>use ast::{Token, TokenData, Expr};
use ast::{BlockExpr, ThrowExpr, ReturnExpr, CallExpr, ConstructExpr, IfExpr, WhileLoopExpr, SwitchExpr, TypeOfExpr, FunctionDeclExpr, LocalExpr, ArrayDeclExpr, ObjectDeclExpr, GetConstFieldExpr, GetFieldExpr, NumOpExpr, BitOpExpr, ConstExpr, AssignExpr};
use ast::{CBool, CNull, CUndefined, CString, CNum};
use ast::{TIdent, TNumber, TString, TSemicolon, TColon, TDot, TOpenParen, TCloseParen, TComma, TOpenBlock, TCloseBlock, TOpenArray, TCloseArray, TQuestion, TNumOp, TBitOp, TEqual};
use collections::treemap::TreeMap;
use std::fmt;
use std::vec::Vec;
#[deriving(Clone)]
#[deriving(Eq)]
/// An error encountered during parsing an expression
pub enum ParseError {
	/// When it expected a certain kind of token, but got another
	Expected(Vec<TokenData>, Token),
	/// When it expected a certain expression, but got another
	ExpectedExpr(~str, Expr)
}
impl fmt::Show for ParseError {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		return match *self {
			Expected(ref wanted, ref got) if wanted.len() == 0 => write!(f.buf, "Line {}, Column {}: Expected expression, got {}", got.line_number, got.column_number, got.data),
			Expected(ref wanted, ref got) => {
				try!(write!(f.buf, "Line {}, Column {}:", got.line_number, got.column_number));
				try!(write!(f.buf, "Expected "));
				let last = wanted.last().unwrap();
				for wanted_token in wanted.iter() {
					try!(write!(f.buf, "'{}'{}", wanted_token, if wanted_token == last {""} else {", "}));
				}
				write!(f.buf, " but got {}", got)
			},
			ExpectedExpr(ref wanted, ref got) => {
				write!(f.buf, "Expected {}, but got {}", wanted, got)
			}
		}
	}
}
/// A result which gives a pretty-printed error if it fails
pub trait VerboseResult<T> {
	/// Unwrap the value if it's Ok and if not pretty-print the error
	fn v_unwrap(&self) -> T;
}
impl<T : Clone, E : fmt::Show> VerboseResult<T> for Result<T, E> {
	fn v_unwrap(&self) -> T {
		match *self {
			Ok(ref val) => val.clone(),
			Err(ref err) => fail!("{}", err)
		}
	}
}
pub type ParseResult = Result<~Expr, ParseError>;
pub type ParseStructResult = Result<Option<~Expr>, ParseError>;
/// A Javascript parser
pub struct Parser {
	/// The tokens being input
	tokens: Vec<Token>,
	/// The current position within the tokens
	pos: uint
}
impl Parser {
	/// Creates a new parser, using [tokens] as input
	pub fn new(tokens: Vec<Token>) -> ~Parser {
		return ~Parser {tokens: tokens, pos: 0};
	}
	/// Parse all expressions in the token array
	pub fn parse_all(&mut self) -> ParseResult {
		let mut exprs = Vec::new();
		while self.pos < self.tokens.len() {
			let result = try!(self.parse());
			exprs.push(result);
		}
		return Ok(~BlockExpr(exprs));
	}
	fn parse_struct(&mut self, name:&str) -> ParseStructResult {
		match name {
			"true" => Ok(Some(~ConstExpr(CBool(true)))),
			"false" => Ok(Some(~ConstExpr(CBool(false)))),
			"null" => Ok(Some(~ConstExpr(CNull))),
			"undefined" => Ok(Some(~ConstExpr(CUndefined))),
			"throw" => {
				let thrown = try!(self.parse());
				Ok(Some(~ThrowExpr(thrown)))
			},
			"return" => Ok(Some(~ReturnExpr(Some(try!(self.parse()))))),
			"new" => {
				let call = try!(self.parse());
				match *call {
					CallExpr(ref func, ref args) => Ok(Some(~ConstructExpr(func.clone(), args.clone()))),
					_ => Err(ExpectedExpr(~"constructor", *call))
				}
			},
			"typeof" => Ok(Some(~TypeOfExpr(try!(self.parse())))),
			"if" => {
				try!(self.expect(TOpenParen));
				let cond = try!(self.parse());
				try!(self.expect(TCloseParen));
				let expr = try!(self.parse());
				let next = self.tokens.get(self.pos + 1).clone();
				Ok(Some(~IfExpr(cond, expr, if next.data == TIdent(~"else") {
					self.pos += 2;
					Some(try!(self.parse()))
				} else {
					None
				})))
			},
			"while" => {
				try!(self.expect(TOpenParen));
				let cond = try!(self.parse());
				try!(self.expect(TCloseParen));
				let expr = try!(self.parse());
				Ok(Some(~WhileLoopExpr(cond, expr)))
			},
			"switch" => {
				try!(self.expect(TOpenParen));
				let value = self.parse();
				try!(self.expect(TCloseParen));
				try!(self.expect(TOpenBlock));
				let mut cases = Vec::new();
				let mut default = None;
				while self.pos + 1 < self.tokens.len() {
					let tok = self.tokens.get(self.pos).data.clone();
					self.pos += 1;
					match tok {
						TIdent(ref id) if *id == ~"case" => {
							let cond = self.parse();
							let mut block = Vec::new();
							try!(self.expect(TColon));
							loop {
								match self.tokens.get(self.pos).data.clone() {
									TIdent(ref id) if *id == ~"case" || *id == ~"default" => break,
									TCloseBlock => break,
									_ => block.push(try!(self.parse()))
								}
							}
							cases.push((cond.unwrap(), block));
						},
						TIdent(ref id) if *id == ~"default" => {
							let mut block = Vec::new();
							try!(self.expect(TColon));
							loop {
								match self.tokens.get(self.pos).data.clone() {
									TIdent(ref id) if *id == ~"case" || *id == ~"default" => break,
									TCloseBlock => break,
									_ => block.push(try!(self.parse()))
								}
							}
							default = Some(~BlockExpr(block));
						},
						TCloseBlock => break,
						_ => fail!("Expected 'case', 'default' or '{}', not '{}'", '}', tok)
					}
				}
				try!(self.expect(TCloseBlock));
				Ok(Some(~SwitchExpr(value.unwrap(), cases, default)))
			},
			"function" => {
				let tk = self.tokens.get(self.pos).clone();
				let name : Option<~str> = match tk.data {
					TIdent(ref name) => {
						self.pos += 1;
						Some(name.clone())
					},
					TOpenParen => None,
					_ => return Err(Expected(vec!(TIdent(~"identifier")), tk.clone()))
				};
				try!(self.expect(TOpenParen));
				let mut args:Vec<~str> = Vec::new();
				let mut tk = self.tokens.get(self.pos).clone();
				while tk.data != TCloseParen {
					match tk.data {
						TIdent(ref id) => args.push(id.to_owned()),
						_ => return Err(Expected(vec!(TIdent(~"identifier")), tk.clone()))
					}
					self.pos += 1;
					if self.tokens.get(self.pos).data == TComma {
						self.pos += 1;
					}
					tk = self.tokens.get(self.pos).clone();
				}
				self.pos += 1;
				let block = try!(self.parse());
				Ok(Some(~FunctionDeclExpr(name, args, block)))
			},
			_ => Ok(None)
		}
	}
	/// Parse a single expression
	pub fn parse(&mut self) -> ParseResult {
		let token = self.tokens.get(self.pos).clone();
		self.pos += 1;
		let expr : ~Expr = match token.data {
			TSemicolon => try!(self.parse()),
			TIdent(ref s) => {
				let structure = try!(self.parse_struct(s.clone()));
				match structure {
					Some(v) => v,
					None => ~LocalExpr(s.to_owned())
				}
			},
			TString(ref s) => ~ConstExpr(CString(s.to_owned())),
			TOpenParen => {
				let nexte = try!(self.parse());
				try!(self.expect(TCloseParen));
				nexte
			},
			TOpenArray => {
				let mut array = Vec::new();
				let mut expect_comma_or_end = self.tokens.get(self.pos).data == TCloseArray;
				loop {
					let token = self.tokens.get(self.pos).clone();
					if token.data == TCloseArray && expect_comma_or_end {
						self.pos += 1;
						break;
					} else if token.data == TComma && expect_comma_or_end {
						expect_comma_or_end = false;
					} else if token.data == TComma && !expect_comma_or_end {
						array.push(~ConstExpr(CNull));
						expect_comma_or_end = false;
					} else if expect_comma_or_end {
						return Err(Expected(vec!(TComma, TCloseArray), token.clone()));
					} else {
						let parsed = try!(self.parse());
						self.pos -= 1;
						array.push(parsed);
						expect_comma_or_end = true;
					}
					self.pos += 1;
				}
				~ArrayDeclExpr(array)
			},
			TOpenBlock if self.tokens.get(self.pos).data == TCloseBlock => {
				self.pos += 1;
				~ObjectDeclExpr(~TreeMap::new())
			},
			TOpenBlock if self.tokens.get(self.pos + 1).data == TColon => {
				let mut map = ~TreeMap::new();
				while self.tokens.get(self.pos - 1).data == TComma || map.len() == 0 {
					let tk = self.tokens.get(self.pos).clone();
					let name = match tk.data {
						TIdent(ref id) => id,
						TString(ref str) => str,
						_ => return Err(Expected(vec!(TIdent(~"identifier"), TString(~"string")), tk))
					};
					self.pos += 1;
					try!(self.expect(TColon));
					let value = try!(self.parse());
					map.insert(name.to_owned(), value);
					self.pos += 1;
				}
				~ObjectDeclExpr(map)
			},
			TOpenBlock => {
				let mut exprs = Vec::new();
				loop {
					if self.tokens.get(self.pos).data == TCloseBlock {
						break;
					} else {
						exprs.push(try!(self.parse()));
					}
				}
				self.pos += 1;
				~BlockExpr(exprs)
			},
			TNumber(num) => ~ConstExpr(CNum(num)),
			_ => return Err(Expected(Vec::new(), token.clone()))
		};
		return if self.pos >= self.tokens.len() { Ok(expr) } else {self.parse_next(expr)};
	}
	fn parse_next(&mut self, expr:~Expr) -> ParseResult {
		let next = self.tokens.get(self.pos).clone();
		let mut carry_on = true;
		let mut result = expr.clone();
		match next.data {
			TDot => {
				self.pos += 1;
				let tk = self.tokens.get(self.pos).clone();
				match tk.data {
					TIdent(ref s) => result = ~GetConstFieldExpr(expr, s.to_owned()),
					_ => return Err(Expected(vec!(TIdent(~"identifier")), tk))
				}
				self.pos += 1;
			},
			TOpenParen => {
				let mut args = Vec::new();
				let mut expect_comma_or_end = self.tokens.get(self.pos + 1).data == TCloseParen;
				loop {
					self.pos += 1;
					let token = self.tokens.get(self.pos).clone();
					if token.data == TCloseParen && expect_comma_or_end {
						self.pos += 1;
						break;
					} else if token.data == TComma && expect_comma_or_end {
						expect_comma_or_end = false;
					} else if expect_comma_or_end {
						return Err(Expected(vec!(TComma, TCloseParen), token));
					} else {
						let parsed = try!(self.parse());
						self.pos -= 1;
						args.push(parsed);
						expect_comma_or_end = true;
					}
				}
				result = ~CallExpr(expr, args);
			},
			TQuestion => {
				self.pos += 1;
				let if_e = try!(self.parse());
				try!(self.expect(TColon));
				let else_e = try!(self.parse());
				result = ~IfExpr(expr, if_e, Some(else_e));
			},
			TOpenArray => {
				self.pos += 1;
				let index = try!(self.parse());
				try!(self.expect(TCloseArray));
				result = ~GetFieldExpr(expr, index);
			},
			TSemicolon => {
				self.pos += 1;
			},
			TNumOp(op) => {
				self.pos += 1;
				let next = try!(self.parse());
				result = ~NumOpExpr(op, expr, next);
			},
			TBitOp(op) => {
				self.pos += 1;
				let next = try!(self.parse());
				result = ~BitOpExpr(op, expr, next);
			},
			TEqual => {
				self.pos += 1;
				let next = try!(self.parse());
				result = ~AssignExpr(expr, next);
			},
			_ => carry_on = false
		};
		return if carry_on && self.pos < self.tokens.len() { self.parse_next(result) } else {Ok(result)};
	}
	/// Returns an error if the next symbol is not [tk]
	fn expect(&mut self, tk:TokenData) -> Result<(), ParseError> {
		self.pos += 1;
		let curr_tk = self.tokens.get(self.pos - 1).clone();
		return if curr_tk.data != tk {
			Err(Expected(vec!(tk), curr_tk))
		} else {
			Ok(())
		};
	}
}<commit_msg>Format unexpected error better<commit_after>use ast::{Token, TokenData, Expr};
use ast::{BlockExpr, ThrowExpr, ReturnExpr, CallExpr, ConstructExpr, IfExpr, WhileLoopExpr, SwitchExpr, TypeOfExpr, FunctionDeclExpr, LocalExpr, ArrayDeclExpr, ObjectDeclExpr, GetConstFieldExpr, GetFieldExpr, NumOpExpr, BitOpExpr, ConstExpr, AssignExpr};
use ast::{CBool, CNull, CUndefined, CString, CNum};
use ast::{TIdent, TNumber, TString, TSemicolon, TColon, TDot, TOpenParen, TCloseParen, TComma, TOpenBlock, TCloseBlock, TOpenArray, TCloseArray, TQuestion, TNumOp, TBitOp, TEqual};
use collections::treemap::TreeMap;
use std::fmt;
use std::vec::Vec;
#[deriving(Clone)]
#[deriving(Eq)]
/// An error encountered during parsing an expression
pub enum ParseError {
	/// When it expected a certain kind of token, but got another
	Expected(Vec<TokenData>, Token),
	/// When it expected a certain expression, but got another
	ExpectedExpr(~str, Expr)
}
impl fmt::Show for ParseError {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		return match *self {
			Expected(ref wanted, ref got) if wanted.len() == 0 => write!(f.buf, "Line {}, Column {}: Expected expression, got {}", got.line_number, got.column_number, got.data),
			Expected(ref wanted, ref got) => {
				try!(write!(f.buf, "Line {}, Column {}: ", got.line_number, got.column_number));
				try!(write!(f.buf, "Expected "));
				let last = wanted.last().unwrap();
				for wanted_token in wanted.iter() {
					try!(write!(f.buf, "'{}'{}", wanted_token, if wanted_token == last {""} else {", "}));
				}
				write!(f.buf, " but got {}", got.data)
			},
			ExpectedExpr(ref wanted, ref got) => {
				write!(f.buf, "Expected {}, but got {}", wanted, got)
			}
		}
	}
}
/// A result which gives a pretty-printed error if it fails
pub trait VerboseResult<T> {
	/// Unwrap the value if it's Ok and if not pretty-print the error
	fn v_unwrap(&self) -> T;
}
impl<T : Clone, E : fmt::Show> VerboseResult<T> for Result<T, E> {
	fn v_unwrap(&self) -> T {
		match *self {
			Ok(ref val) => val.clone(),
			Err(ref err) => fail!("{}", err)
		}
	}
}
pub type ParseResult = Result<~Expr, ParseError>;
pub type ParseStructResult = Result<Option<~Expr>, ParseError>;
/// A Javascript parser
pub struct Parser {
	/// The tokens being input
	tokens: Vec<Token>,
	/// The current position within the tokens
	pos: uint
}
impl Parser {
	/// Creates a new parser, using [tokens] as input
	pub fn new(tokens: Vec<Token>) -> ~Parser {
		return ~Parser {tokens: tokens, pos: 0};
	}
	/// Parse all expressions in the token array
	pub fn parse_all(&mut self) -> ParseResult {
		let mut exprs = Vec::new();
		while self.pos < self.tokens.len() {
			let result = try!(self.parse());
			exprs.push(result);
		}
		return Ok(~BlockExpr(exprs));
	}
	fn parse_struct(&mut self, name:&str) -> ParseStructResult {
		match name {
			"true" => Ok(Some(~ConstExpr(CBool(true)))),
			"false" => Ok(Some(~ConstExpr(CBool(false)))),
			"null" => Ok(Some(~ConstExpr(CNull))),
			"undefined" => Ok(Some(~ConstExpr(CUndefined))),
			"throw" => {
				let thrown = try!(self.parse());
				Ok(Some(~ThrowExpr(thrown)))
			},
			"return" => Ok(Some(~ReturnExpr(Some(try!(self.parse()))))),
			"new" => {
				let call = try!(self.parse());
				match *call {
					CallExpr(ref func, ref args) => Ok(Some(~ConstructExpr(func.clone(), args.clone()))),
					_ => Err(ExpectedExpr(~"constructor", *call))
				}
			},
			"typeof" => Ok(Some(~TypeOfExpr(try!(self.parse())))),
			"if" => {
				try!(self.expect(TOpenParen));
				let cond = try!(self.parse());
				try!(self.expect(TCloseParen));
				let expr = try!(self.parse());
				let next = self.tokens.get(self.pos + 1).clone();
				Ok(Some(~IfExpr(cond, expr, if next.data == TIdent(~"else") {
					self.pos += 2;
					Some(try!(self.parse()))
				} else {
					None
				})))
			},
			"while" => {
				try!(self.expect(TOpenParen));
				let cond = try!(self.parse());
				try!(self.expect(TCloseParen));
				let expr = try!(self.parse());
				Ok(Some(~WhileLoopExpr(cond, expr)))
			},
			"switch" => {
				try!(self.expect(TOpenParen));
				let value = self.parse();
				try!(self.expect(TCloseParen));
				try!(self.expect(TOpenBlock));
				let mut cases = Vec::new();
				let mut default = None;
				while self.pos + 1 < self.tokens.len() {
					let tok = self.tokens.get(self.pos).data.clone();
					self.pos += 1;
					match tok {
						TIdent(ref id) if *id == ~"case" => {
							let cond = self.parse();
							let mut block = Vec::new();
							try!(self.expect(TColon));
							loop {
								match self.tokens.get(self.pos).data.clone() {
									TIdent(ref id) if *id == ~"case" || *id == ~"default" => break,
									TCloseBlock => break,
									_ => block.push(try!(self.parse()))
								}
							}
							cases.push((cond.unwrap(), block));
						},
						TIdent(ref id) if *id == ~"default" => {
							let mut block = Vec::new();
							try!(self.expect(TColon));
							loop {
								match self.tokens.get(self.pos).data.clone() {
									TIdent(ref id) if *id == ~"case" || *id == ~"default" => break,
									TCloseBlock => break,
									_ => block.push(try!(self.parse()))
								}
							}
							default = Some(~BlockExpr(block));
						},
						TCloseBlock => break,
						_ => fail!("Expected 'case', 'default' or '{}', not '{}'", '}', tok)
					}
				}
				try!(self.expect(TCloseBlock));
				Ok(Some(~SwitchExpr(value.unwrap(), cases, default)))
			},
			"function" => {
				let tk = self.tokens.get(self.pos).clone();
				let name : Option<~str> = match tk.data {
					TIdent(ref name) => {
						self.pos += 1;
						Some(name.clone())
					},
					TOpenParen => None,
					_ => return Err(Expected(vec!(TIdent(~"identifier")), tk.clone()))
				};
				try!(self.expect(TOpenParen));
				let mut args:Vec<~str> = Vec::new();
				let mut tk = self.tokens.get(self.pos).clone();
				while tk.data != TCloseParen {
					match tk.data {
						TIdent(ref id) => args.push(id.to_owned()),
						_ => return Err(Expected(vec!(TIdent(~"identifier")), tk.clone()))
					}
					self.pos += 1;
					if self.tokens.get(self.pos).data == TComma {
						self.pos += 1;
					}
					tk = self.tokens.get(self.pos).clone();
				}
				self.pos += 1;
				let block = try!(self.parse());
				Ok(Some(~FunctionDeclExpr(name, args, block)))
			},
			_ => Ok(None)
		}
	}
	/// Parse a single expression
	pub fn parse(&mut self) -> ParseResult {
		let token = self.tokens.get(self.pos).clone();
		self.pos += 1;
		let expr : ~Expr = match token.data {
			TSemicolon => try!(self.parse()),
			TIdent(ref s) => {
				let structure = try!(self.parse_struct(s.clone()));
				match structure {
					Some(v) => v,
					None => ~LocalExpr(s.to_owned())
				}
			},
			TString(ref s) => ~ConstExpr(CString(s.to_owned())),
			TOpenParen => {
				let nexte = try!(self.parse());
				try!(self.expect(TCloseParen));
				nexte
			},
			TOpenArray => {
				let mut array = Vec::new();
				let mut expect_comma_or_end = self.tokens.get(self.pos).data == TCloseArray;
				loop {
					let token = self.tokens.get(self.pos).clone();
					if token.data == TCloseArray && expect_comma_or_end {
						self.pos += 1;
						break;
					} else if token.data == TComma && expect_comma_or_end {
						expect_comma_or_end = false;
					} else if token.data == TComma && !expect_comma_or_end {
						array.push(~ConstExpr(CNull));
						expect_comma_or_end = false;
					} else if expect_comma_or_end {
						return Err(Expected(vec!(TComma, TCloseArray), token.clone()));
					} else {
						let parsed = try!(self.parse());
						self.pos -= 1;
						array.push(parsed);
						expect_comma_or_end = true;
					}
					self.pos += 1;
				}
				~ArrayDeclExpr(array)
			},
			TOpenBlock if self.tokens.get(self.pos).data == TCloseBlock => {
				self.pos += 1;
				~ObjectDeclExpr(~TreeMap::new())
			},
			TOpenBlock if self.tokens.get(self.pos + 1).data == TColon => {
				let mut map = ~TreeMap::new();
				while self.tokens.get(self.pos - 1).data == TComma || map.len() == 0 {
					let tk = self.tokens.get(self.pos).clone();
					let name = match tk.data {
						TIdent(ref id) => id,
						TString(ref str) => str,
						_ => return Err(Expected(vec!(TIdent(~"identifier"), TString(~"string")), tk))
					};
					self.pos += 1;
					try!(self.expect(TColon));
					let value = try!(self.parse());
					map.insert(name.to_owned(), value);
					self.pos += 1;
				}
				~ObjectDeclExpr(map)
			},
			TOpenBlock => {
				let mut exprs = Vec::new();
				loop {
					if self.tokens.get(self.pos).data == TCloseBlock {
						break;
					} else {
						exprs.push(try!(self.parse()));
					}
				}
				self.pos += 1;
				~BlockExpr(exprs)
			},
			TNumber(num) => ~ConstExpr(CNum(num)),
			_ => return Err(Expected(Vec::new(), token.clone()))
		};
		return if self.pos >= self.tokens.len() { Ok(expr) } else {self.parse_next(expr)};
	}
	fn parse_next(&mut self, expr:~Expr) -> ParseResult {
		let next = self.tokens.get(self.pos).clone();
		let mut carry_on = true;
		let mut result = expr.clone();
		match next.data {
			TDot => {
				self.pos += 1;
				let tk = self.tokens.get(self.pos).clone();
				match tk.data {
					TIdent(ref s) => result = ~GetConstFieldExpr(expr, s.to_owned()),
					_ => return Err(Expected(vec!(TIdent(~"identifier")), tk))
				}
				self.pos += 1;
			},
			TOpenParen => {
				let mut args = Vec::new();
				let mut expect_comma_or_end = self.tokens.get(self.pos + 1).data == TCloseParen;
				loop {
					self.pos += 1;
					let token = self.tokens.get(self.pos).clone();
					if token.data == TCloseParen && expect_comma_or_end {
						self.pos += 1;
						break;
					} else if token.data == TComma && expect_comma_or_end {
						expect_comma_or_end = false;
					} else if expect_comma_or_end {
						return Err(Expected(vec!(TComma, TCloseParen), token));
					} else {
						let parsed = try!(self.parse());
						self.pos -= 1;
						args.push(parsed);
						expect_comma_or_end = true;
					}
				}
				result = ~CallExpr(expr, args);
			},
			TQuestion => {
				self.pos += 1;
				let if_e = try!(self.parse());
				try!(self.expect(TColon));
				let else_e = try!(self.parse());
				result = ~IfExpr(expr, if_e, Some(else_e));
			},
			TOpenArray => {
				self.pos += 1;
				let index = try!(self.parse());
				try!(self.expect(TCloseArray));
				result = ~GetFieldExpr(expr, index);
			},
			TSemicolon => {
				self.pos += 1;
			},
			TNumOp(op) => {
				self.pos += 1;
				let next = try!(self.parse());
				result = ~NumOpExpr(op, expr, next);
			},
			TBitOp(op) => {
				self.pos += 1;
				let next = try!(self.parse());
				result = ~BitOpExpr(op, expr, next);
			},
			TEqual => {
				self.pos += 1;
				let next = try!(self.parse());
				result = ~AssignExpr(expr, next);
			},
			_ => carry_on = false
		};
		return if carry_on && self.pos < self.tokens.len() { self.parse_next(result) } else {Ok(result)};
	}
	/// Returns an error if the next symbol is not [tk]
	fn expect(&mut self, tk:TokenData) -> Result<(), ParseError> {
		self.pos += 1;
		let curr_tk = self.tokens.get(self.pos - 1).clone();
		return if curr_tk.data != tk {
			Err(Expected(vec!(tk), curr_tk))
		} else {
			Ok(())
		};
	}
}<|endoftext|>


<commit_before>extern crate byteorder;
extern crate encoding;

use std::borrow::Cow;
use std::default::Default;
use std::error;
use std::fmt;
use std::io;

use self::byteorder::{BigEndian, ByteOrder, LittleEndian};
use self::encoding::label::encoding_from_whatwg_label;
use self::encoding::types::DecoderTrap::Strict;
use self::encoding::types::EncodingRef;

use super::plurals::{Ast, Resolver};
use super::{Catalog, Message};
use metadata::parse_metadata;

#[allow(non_upper_case_globals)]
static utf8_encoding: EncodingRef = &encoding::codec::utf_8::UTF8Encoding;

/// Represents an error encountered while parsing an MO file.
#[derive(Debug)]
pub enum Error {
    /// An incorrect magic number has been encountered
    BadMagic,
    /// An invalid byte sequence for the given encoding has been encountered
    DecodingError,
    /// An unexpected EOF occured
    Eof,
    /// An I/O error occured
    Io(io::Error),
    /// Incorrect syntax encountered while parsing the meta information
    MalformedMetadata,
    /// Meta information string was not the first string in the catalog
    MisplacedMetadata,
    /// An unknown encoding was specified in the metadata
    UnknownEncoding,
    /// Invalid Plural-Forms metadata
    PluralParsing,
}
use Error::*;

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            BadMagic => "bad magic number",
            DecodingError => "invalid byte sequence in a string",
            Eof => "unxpected end of file",
            Io(ref err) => err.description(),
            MalformedMetadata => "metadata syntax error",
            MisplacedMetadata => "misplaced metadata",
            UnknownEncoding => "unknown encoding specified",
            PluralParsing => "invalid plural expression",
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let self_err: &error::Error = self;
        write!(fmt, "{}", self_err.description())
    }
}

impl From<io::Error> for Error {
    fn from(inner: io::Error) -> Error {
        Io(inner)
    }
}

impl From<Cow<'static, str>> for Error {
    fn from(_: Cow<'static, str>) -> Error {
        DecodingError
    }
}

/// ParseOptions allows setting options for parsing MO catalogs.
///
/// # Examples
/// ```ignore
/// use std::fs::File;
///
/// extern crate encoding;
/// use encoding::all::ISO_8859_1;
///
/// let file = File::open("french.mo").unwrap();
/// let catalog = ParseOptions::new().force_encoding(ISO_8859_1).parse(file).unwrap();
/// ```
#[allow(missing_debug_implementations)]
#[derive(Default)]
pub struct ParseOptions {
    force_encoding: Option<EncodingRef>,
    force_plural: Option<fn(u64) -> usize>,
}

impl ParseOptions {
    /// Returns a new instance of ParseOptions with default options.
    pub fn new() -> Self {
        Default::default()
    }

    /// Tries to parse the catalog from the given reader using the specified options.
    pub fn parse<R: io::Read>(self, reader: R) -> Result<Catalog, Error> {
        parse_catalog(reader, self)
    }

    /// Forces a use of a specific encoding
    /// when parsing strings from a catalog.
    /// If this option is not enabled,
    /// the parser tries to use the encoding specified in the metadata
    /// or UTF-8 if metadata is non-existent.
    pub fn force_encoding(mut self, encoding: EncodingRef) -> Self {
        self.force_encoding = Some(encoding);
        self
    }

    /// Forces a use of the given plural formula
    /// for deciding the proper plural form for a message.
    /// If this option is not enabled,
    /// the parser uses the default formula
    /// (`n != 1`).
    pub fn force_plural(mut self, plural: fn(u64) -> usize) -> Self {
        self.force_plural = Some(plural);
        self
    }
}

/// According to the given magic number of a MO file,
/// returns the function which reads a `u32` in the relevant endianness.
fn get_read_u32_fn(magic: &[u8]) -> Option<fn(&[u8]) -> u32> {
    if magic == [0xde, 0x12, 0x04, 0x95] {
        Some(LittleEndian::read_u32)
    } else if magic == [0x95, 0x04, 0x12, 0xde] {
        Some(BigEndian::read_u32)
    } else {
        None
    }
}

pub fn parse_catalog<'a, R: io::Read>(
    mut file: R,
    opts: ParseOptions,
) -> Result<Catalog, Error> {
    let mut contents = vec![];
    let n = try!(file.read_to_end(&mut contents));
    if n < 28 {
        return Err(Eof);
    }

    let read_u32 = match get_read_u32_fn(&contents[0..4]) {
        Some(f) => f,
        None => return Err(BadMagic),
    };

    // ignore hashing tables (bytes at 20..28)
    let num_strings = read_u32(&contents[8..12]) as usize;
    let mut off_otable = read_u32(&contents[12..16]) as usize;
    let mut off_ttable = read_u32(&contents[16..20]) as usize;
    if n < off_otable || n < off_ttable {
        return Err(Eof);
    }

    let mut catalog = Catalog::new();
    if let Some(f) = opts.force_plural {
        catalog.resolver = Resolver::Function(f);
    }
    let mut encoding = opts.force_encoding.unwrap_or(utf8_encoding);

    for i in 0..num_strings {
        // Parse the original string
        if n < off_otable + 8 {
            return Err(Eof);
        }
        let len = read_u32(&contents[off_otable..off_otable + 4]) as usize;
        let off = read_u32(&contents[off_otable + 4..off_otable + 8]) as usize;
        // +1 compensates for the ending NUL byte which is not included in length
        if n < off + len + 1 {
            return Err(Eof);
        }
        let mut original = &contents[off..off + len + 1];
        // check for context
        let context = match original.iter().position(|x| *x == 4) {
            Some(idx) => {
                let ctx = &original[..idx];
                original = &original[idx + 1..];
                Some(try!(encoding.decode(ctx, Strict)))
            }
            None => None,
        };
        // extract msg_id singular, ignoring the plural
        let id = match original
            .iter()
            .position(|x| *x == 0)
            .map(|i| &original[..i])
        {
            Some(b) => try!(encoding.decode(b, Strict)),
            None => return Err(Eof),
        };
        if id == "" && i != 0 {
            return Err(MisplacedMetadata);
        }

        // Parse the translation strings
        if n < off_ttable + 8 {
            return Err(Eof);
        }
        let len = read_u32(&contents[off_ttable..off_ttable + 4]) as usize;
        let off = read_u32(&contents[off_ttable + 4..off_ttable + 8]) as usize;
        // +1 compensates for the ending NUL byte which is not included in length
        if n < off + len + 1 {
            return Err(Eof);
        }
        let translated = try!(
            (&contents[off..off + len])
                .split(|x| *x == 0)
                .map(|b| encoding.decode(b, Strict))
                .collect::<Result<Vec<_>, _>>()
        );
        if id == "" {
            let map = parse_metadata(&*translated[0])?;
            if let (Some(c), None) = (map.charset(), opts.force_encoding) {
                encoding = match encoding_from_whatwg_label(c) {
                    Some(enc_ref) => enc_ref,
                    None => return Err(UnknownEncoding),
                }
            }
            if opts.force_plural.is_none() {
                if let Some(p) = map.plural_forms().1 {
                    catalog.resolver = Ast::parse(p).map(Resolver::Expr)?;
                }
            }
        }

        catalog.insert(Message::new(id, context, translated));

        off_otable += 8;
        off_ttable += 8;
    }

    Ok(catalog)
}

/// The default plural resolver.
///
/// It will be used if not `Plural-Forms` header is found in the .mo file, and if
/// `ParseOptions::force_plural` was not called.
///
/// It is valid for English and similar languages: plural will be used for any quantity
/// different of 1.
pub fn default_resolver(n: u64) -> usize {
    if n == 1 {
        0
    } else {
        1
    }
}

#[test]
fn test_get_read_u32_fn() {
    use std::mem;

    assert!(get_read_u32_fn(&[]).is_none());
    assert!(get_read_u32_fn(&[0xde, 0x12, 0x04, 0x95, 0x00]).is_none());

    {
        let le_ptr: *const ();
        let ret_ptr;
        unsafe {
            le_ptr = mem::transmute(LittleEndian::read_u32 as usize);
            ret_ptr = mem::transmute(get_read_u32_fn(&[0xde, 0x12, 0x04, 0x95]).unwrap());
        }
        assert_eq!(le_ptr, ret_ptr);
    }

    {
        let be_ptr: *const ();
        let ret_ptr;
        unsafe {
            be_ptr = mem::transmute(BigEndian::read_u32 as usize);
            ret_ptr = mem::transmute(get_read_u32_fn(&[0x95, 0x04, 0x12, 0xde]).unwrap());
        }
        assert_eq!(be_ptr, ret_ptr);
    }
}

#[test]
fn test_parse_catalog() {
    macro_rules! assert_variant {
        ($value:expr, $variant:path) => {
            match $value {
                $variant => (),
                _ => panic!("Expected {:?}, got {:?}", $variant, $value),
            }
        };
    }

    let fluff = [0; 24]; // zeros to pad our magic test cases to satisfy the length requirements

    {
        let mut reader = vec![1u8, 2, 3];
        reader.extend(fluff.iter().cloned());
        let err = parse_catalog(&reader[..], ParseOptions::new()).unwrap_err();
        assert_variant!(err, Eof);
    }

    {
        let mut reader = vec![1u8, 2, 3, 4];
        reader.extend(fluff.iter().cloned());
        let err = parse_catalog(&reader[..], ParseOptions::new()).unwrap_err();
        assert_variant!(err, BadMagic);
    }

    {
        let mut reader = vec![0x95, 0x04, 0x12, 0xde];
        reader.extend(fluff.iter().cloned());
        assert!(parse_catalog(&reader[..], ParseOptions::new()).is_ok());
    }

    {
        let mut reader = vec![0xde, 0x12, 0x04, 0x95];
        reader.extend(fluff.iter().cloned());
        assert!(parse_catalog(&reader[..], ParseOptions::new()).is_ok());
    }

    {
        let reader: &[u8] = include_bytes!("../test_cases/1.mo");
        let catalog = parse_catalog(reader, ParseOptions::new()).unwrap();
        assert_eq!(catalog.strings.len(), 1);
        assert_eq!(
            catalog.strings["this is context\x04Text"],
            Message::new("Text", Some("this is context"), vec!["Tekstas", "Tekstai"])
        );
    }

    {
        let reader: &[u8] = include_bytes!("../test_cases/2.mo");
        let catalog = parse_catalog(reader, ParseOptions::new()).unwrap();
        assert_eq!(catalog.strings.len(), 2);
        assert_eq!(
            catalog.strings["Image"],
            Message::new("Image", None, vec!["Nuotrauka", "Nuotraukos"])
        );
    }

    {
        let reader: &[u8] = include_bytes!("../test_cases/invalid_utf8.mo");
        let err = parse_catalog(reader, ParseOptions::new()).unwrap_err();
        assert_variant!(err, DecodingError);
    }
}
<commit_msg>Rearrange Error variants in alphabetical order<commit_after>extern crate byteorder;
extern crate encoding;

use std::borrow::Cow;
use std::default::Default;
use std::error;
use std::fmt;
use std::io;

use self::byteorder::{BigEndian, ByteOrder, LittleEndian};
use self::encoding::label::encoding_from_whatwg_label;
use self::encoding::types::DecoderTrap::Strict;
use self::encoding::types::EncodingRef;

use super::plurals::{Ast, Resolver};
use super::{Catalog, Message};
use metadata::parse_metadata;

#[allow(non_upper_case_globals)]
static utf8_encoding: EncodingRef = &encoding::codec::utf_8::UTF8Encoding;

/// Represents an error encountered while parsing an MO file.
#[derive(Debug)]
pub enum Error {
    /// An incorrect magic number has been encountered
    BadMagic,
    /// An invalid byte sequence for the given encoding has been encountered
    DecodingError,
    /// An unexpected EOF occured
    Eof,
    /// An I/O error occured
    Io(io::Error),
    /// Incorrect syntax encountered while parsing the meta information
    MalformedMetadata,
    /// Meta information string was not the first string in the catalog
    MisplacedMetadata,
    /// Invalid Plural-Forms metadata
    PluralParsing,
    /// An unknown encoding was specified in the metadata
    UnknownEncoding,
}
use Error::*;

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            BadMagic => "bad magic number",
            DecodingError => "invalid byte sequence in a string",
            Eof => "unxpected end of file",
            Io(ref err) => err.description(),
            MalformedMetadata => "metadata syntax error",
            MisplacedMetadata => "misplaced metadata",
            UnknownEncoding => "unknown encoding specified",
            PluralParsing => "invalid plural expression",
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let self_err: &error::Error = self;
        write!(fmt, "{}", self_err.description())
    }
}

impl From<io::Error> for Error {
    fn from(inner: io::Error) -> Error {
        Io(inner)
    }
}

impl From<Cow<'static, str>> for Error {
    fn from(_: Cow<'static, str>) -> Error {
        DecodingError
    }
}

/// ParseOptions allows setting options for parsing MO catalogs.
///
/// # Examples
/// ```ignore
/// use std::fs::File;
///
/// extern crate encoding;
/// use encoding::all::ISO_8859_1;
///
/// let file = File::open("french.mo").unwrap();
/// let catalog = ParseOptions::new().force_encoding(ISO_8859_1).parse(file).unwrap();
/// ```
#[allow(missing_debug_implementations)]
#[derive(Default)]
pub struct ParseOptions {
    force_encoding: Option<EncodingRef>,
    force_plural: Option<fn(u64) -> usize>,
}

impl ParseOptions {
    /// Returns a new instance of ParseOptions with default options.
    pub fn new() -> Self {
        Default::default()
    }

    /// Tries to parse the catalog from the given reader using the specified options.
    pub fn parse<R: io::Read>(self, reader: R) -> Result<Catalog, Error> {
        parse_catalog(reader, self)
    }

    /// Forces a use of a specific encoding
    /// when parsing strings from a catalog.
    /// If this option is not enabled,
    /// the parser tries to use the encoding specified in the metadata
    /// or UTF-8 if metadata is non-existent.
    pub fn force_encoding(mut self, encoding: EncodingRef) -> Self {
        self.force_encoding = Some(encoding);
        self
    }

    /// Forces a use of the given plural formula
    /// for deciding the proper plural form for a message.
    /// If this option is not enabled,
    /// the parser uses the default formula
    /// (`n != 1`).
    pub fn force_plural(mut self, plural: fn(u64) -> usize) -> Self {
        self.force_plural = Some(plural);
        self
    }
}

/// According to the given magic number of a MO file,
/// returns the function which reads a `u32` in the relevant endianness.
fn get_read_u32_fn(magic: &[u8]) -> Option<fn(&[u8]) -> u32> {
    if magic == [0xde, 0x12, 0x04, 0x95] {
        Some(LittleEndian::read_u32)
    } else if magic == [0x95, 0x04, 0x12, 0xde] {
        Some(BigEndian::read_u32)
    } else {
        None
    }
}

pub fn parse_catalog<'a, R: io::Read>(
    mut file: R,
    opts: ParseOptions,
) -> Result<Catalog, Error> {
    let mut contents = vec![];
    let n = try!(file.read_to_end(&mut contents));
    if n < 28 {
        return Err(Eof);
    }

    let read_u32 = match get_read_u32_fn(&contents[0..4]) {
        Some(f) => f,
        None => return Err(BadMagic),
    };

    // ignore hashing tables (bytes at 20..28)
    let num_strings = read_u32(&contents[8..12]) as usize;
    let mut off_otable = read_u32(&contents[12..16]) as usize;
    let mut off_ttable = read_u32(&contents[16..20]) as usize;
    if n < off_otable || n < off_ttable {
        return Err(Eof);
    }

    let mut catalog = Catalog::new();
    if let Some(f) = opts.force_plural {
        catalog.resolver = Resolver::Function(f);
    }
    let mut encoding = opts.force_encoding.unwrap_or(utf8_encoding);

    for i in 0..num_strings {
        // Parse the original string
        if n < off_otable + 8 {
            return Err(Eof);
        }
        let len = read_u32(&contents[off_otable..off_otable + 4]) as usize;
        let off = read_u32(&contents[off_otable + 4..off_otable + 8]) as usize;
        // +1 compensates for the ending NUL byte which is not included in length
        if n < off + len + 1 {
            return Err(Eof);
        }
        let mut original = &contents[off..off + len + 1];
        // check for context
        let context = match original.iter().position(|x| *x == 4) {
            Some(idx) => {
                let ctx = &original[..idx];
                original = &original[idx + 1..];
                Some(try!(encoding.decode(ctx, Strict)))
            }
            None => None,
        };
        // extract msg_id singular, ignoring the plural
        let id = match original
            .iter()
            .position(|x| *x == 0)
            .map(|i| &original[..i])
        {
            Some(b) => try!(encoding.decode(b, Strict)),
            None => return Err(Eof),
        };
        if id == "" && i != 0 {
            return Err(MisplacedMetadata);
        }

        // Parse the translation strings
        if n < off_ttable + 8 {
            return Err(Eof);
        }
        let len = read_u32(&contents[off_ttable..off_ttable + 4]) as usize;
        let off = read_u32(&contents[off_ttable + 4..off_ttable + 8]) as usize;
        // +1 compensates for the ending NUL byte which is not included in length
        if n < off + len + 1 {
            return Err(Eof);
        }
        let translated = try!(
            (&contents[off..off + len])
                .split(|x| *x == 0)
                .map(|b| encoding.decode(b, Strict))
                .collect::<Result<Vec<_>, _>>()
        );
        if id == "" {
            let map = parse_metadata(&*translated[0])?;
            if let (Some(c), None) = (map.charset(), opts.force_encoding) {
                encoding = match encoding_from_whatwg_label(c) {
                    Some(enc_ref) => enc_ref,
                    None => return Err(UnknownEncoding),
                }
            }
            if opts.force_plural.is_none() {
                if let Some(p) = map.plural_forms().1 {
                    catalog.resolver = Ast::parse(p).map(Resolver::Expr)?;
                }
            }
        }

        catalog.insert(Message::new(id, context, translated));

        off_otable += 8;
        off_ttable += 8;
    }

    Ok(catalog)
}

/// The default plural resolver.
///
/// It will be used if not `Plural-Forms` header is found in the .mo file, and if
/// `ParseOptions::force_plural` was not called.
///
/// It is valid for English and similar languages: plural will be used for any quantity
/// different of 1.
pub fn default_resolver(n: u64) -> usize {
    if n == 1 {
        0
    } else {
        1
    }
}

#[test]
fn test_get_read_u32_fn() {
    use std::mem;

    assert!(get_read_u32_fn(&[]).is_none());
    assert!(get_read_u32_fn(&[0xde, 0x12, 0x04, 0x95, 0x00]).is_none());

    {
        let le_ptr: *const ();
        let ret_ptr;
        unsafe {
            le_ptr = mem::transmute(LittleEndian::read_u32 as usize);
            ret_ptr = mem::transmute(get_read_u32_fn(&[0xde, 0x12, 0x04, 0x95]).unwrap());
        }
        assert_eq!(le_ptr, ret_ptr);
    }

    {
        let be_ptr: *const ();
        let ret_ptr;
        unsafe {
            be_ptr = mem::transmute(BigEndian::read_u32 as usize);
            ret_ptr = mem::transmute(get_read_u32_fn(&[0x95, 0x04, 0x12, 0xde]).unwrap());
        }
        assert_eq!(be_ptr, ret_ptr);
    }
}

#[test]
fn test_parse_catalog() {
    macro_rules! assert_variant {
        ($value:expr, $variant:path) => {
            match $value {
                $variant => (),
                _ => panic!("Expected {:?}, got {:?}", $variant, $value),
            }
        };
    }

    let fluff = [0; 24]; // zeros to pad our magic test cases to satisfy the length requirements

    {
        let mut reader = vec![1u8, 2, 3];
        reader.extend(fluff.iter().cloned());
        let err = parse_catalog(&reader[..], ParseOptions::new()).unwrap_err();
        assert_variant!(err, Eof);
    }

    {
        let mut reader = vec![1u8, 2, 3, 4];
        reader.extend(fluff.iter().cloned());
        let err = parse_catalog(&reader[..], ParseOptions::new()).unwrap_err();
        assert_variant!(err, BadMagic);
    }

    {
        let mut reader = vec![0x95, 0x04, 0x12, 0xde];
        reader.extend(fluff.iter().cloned());
        assert!(parse_catalog(&reader[..], ParseOptions::new()).is_ok());
    }

    {
        let mut reader = vec![0xde, 0x12, 0x04, 0x95];
        reader.extend(fluff.iter().cloned());
        assert!(parse_catalog(&reader[..], ParseOptions::new()).is_ok());
    }

    {
        let reader: &[u8] = include_bytes!("../test_cases/1.mo");
        let catalog = parse_catalog(reader, ParseOptions::new()).unwrap();
        assert_eq!(catalog.strings.len(), 1);
        assert_eq!(
            catalog.strings["this is context\x04Text"],
            Message::new("Text", Some("this is context"), vec!["Tekstas", "Tekstai"])
        );
    }

    {
        let reader: &[u8] = include_bytes!("../test_cases/2.mo");
        let catalog = parse_catalog(reader, ParseOptions::new()).unwrap();
        assert_eq!(catalog.strings.len(), 2);
        assert_eq!(
            catalog.strings["Image"],
            Message::new("Image", None, vec!["Nuotrauka", "Nuotraukos"])
        );
    }

    {
        let reader: &[u8] = include_bytes!("../test_cases/invalid_utf8.mo");
        let err = parse_catalog(reader, ParseOptions::new()).unwrap_err();
        assert_variant!(err, DecodingError);
    }
}
<|endoftext|>


<commit_before>use draw::RGB;

#[derive(Debug, PartialEq, Eq)]
pub struct Point {
   pub x: i64,
   pub y: i64,
}

impl Point {
   #[inline]
   pub fn new(x: i64, y: i64) -> Self {
      Point {
         x: x,
         y: y,
      }
   }
}

#[derive(Debug)]
pub struct Segment {
   pub p1: usize,
   pub p2: usize,
}

impl Segment {
   #[inline]
   pub fn new(p1: usize, p2: usize) -> Self {
      Segment {
         p1: p1,
         p2: p2,
      }
   }
}

#[derive(Debug)]
pub struct Circle {
   pub center: usize,
   pub radius: i64,
}

impl Circle {
   #[inline]
   pub fn new(center: usize, radius: i64) -> Self {
      Circle {
         center: center,
         radius: radius,
      }
   }
}

#[derive(Debug)]
pub enum EdgeType {
   LTR,  // line top-right
   LTL,  // line top-left
   LBR,  // line bottom-right
   LBL,  // line bottom-left

   LHR,  // line horizontal-right
   LHL,  // line horizontal-left
   LVT,  // line vertical-top
   LVB,  // line vertical-bottom

   CTR, // clockwise arc top-right
   CTL, // clockwise arc top-left
   CBR, // clockwise arc bottom-right
   CBL, // clockwise arc bottom-left

   ATR, // anti-clockwise arc top-right
   ATL, // anti-clockwise arc top-left
   ABR, // anti-clockwise arc bottom-right
   ABL, // anti-clockwise arc bottom-left
}

impl EdgeType {
   #[inline]
   pub fn reversed(&self) -> bool {
      match *self {
         EdgeType::LBR | EdgeType::LBL | EdgeType::LHL | EdgeType::LVB |
         EdgeType::CBR | EdgeType::CBL | EdgeType::ATR | EdgeType::ATL => {
            true
         },
         _ => {
            false
         }
      }
   }
}

#[derive(Debug)]
pub struct Edge {
   pub edge_type: EdgeType,
   pub segment: usize,
   pub circle: usize,
}

impl Edge {
   #[inline]
   pub fn new(edge_type: EdgeType, segment: usize, circle: usize) -> Self {
      Edge {
         edge_type: edge_type,
         segment: segment,
         circle: circle,
      }
   }

   #[inline]
   pub fn reversed(&self) -> bool {
      self.edge_type.reversed()
   }
}

#[derive(Debug)]
pub struct Poly {
   pub start: usize,
   pub end: usize,
   pub color: usize,
}

impl Poly {
   #[inline]
   pub fn new(start: usize, end: usize, color: usize) -> Self {
      Poly {
         start: start,
         end: end,
         color: color,
      }
   }
}

pub struct Scene {
   pub points: Vec<Point>,
   pub segments: Vec<Segment>,
   pub circles: Vec<Circle>,
   pub edges: Vec<Edge>,
   pub polys: Vec<Poly>,
   pub colors: Vec<RGB>,
}

impl Scene {
   pub fn check_correctness(&self) {
      self.check_all_polys_connected();
   }

   fn check_all_polys_connected(&self) {
      for poly in &self.polys {
         self.check_poly_connected(poly);
      }
   }

   fn check_poly_connected(&self, poly: &Poly) {
      let mut prev = self.edge_head(&self.edges[poly.end - 1]);

      for edge_index in poly.start..poly.end {
         let ref edge = self.edges[edge_index];

         let current = self.edge_tail(edge);
         if current != prev {
            panic!("Unclosed poly : {:?}", poly);
         }

         prev = self.edge_head(edge);
      }
   }

   fn edge_head(&self, edge: &Edge) -> &Point {
      let ref segment = self.segments[edge.segment];
      if edge.reversed() {
         &self.points[segment.p1]
      } else {
         &self.points[segment.p2]
      }
   }

   fn edge_tail(&self, edge: &Edge) -> &Point {
      let ref segment = self.segments[edge.segment];
      if edge.reversed() {
         &self.points[segment.p2]
      } else {
         &self.points[segment.p1]
      }
   }
}
<commit_msg>Checking for correct segments' orientation<commit_after>use std::cmp::{PartialOrd, Ordering};

use draw::RGB;

#[derive(Debug, PartialEq, Eq)]
pub struct Point {
   pub x: i64,
   pub y: i64,
}

impl Point {
   #[inline]
   pub fn new(x: i64, y: i64) -> Self {
      Point {
         x: x,
         y: y,
      }
   }
}

impl PartialOrd for Point {
   fn partial_cmp(&self, other: &Point) -> Option<Ordering> {
      Some(self.cmp(other))
   }
}

impl Ord for Point {
   fn cmp(&self, other: &Point) -> Ordering {
      if self.y < other.y {
         Ordering::Less
      } else if self.y > other.y {
         Ordering::Greater
      } else if self.x < other.x {
         Ordering::Less
      } else if self.x > other.x {
         Ordering::Greater
      } else {
         Ordering::Equal
      }
   }
}

#[derive(Debug)]
pub struct Segment {
   pub p1: usize,
   pub p2: usize,
}

impl Segment {
   #[inline]
   pub fn new(p1: usize, p2: usize) -> Self {
      Segment {
         p1: p1,
         p2: p2,
      }
   }
}

#[derive(Debug)]
pub struct Circle {
   pub center: usize,
   pub radius: i64,
}

impl Circle {
   #[inline]
   pub fn new(center: usize, radius: i64) -> Self {
      Circle {
         center: center,
         radius: radius,
      }
   }
}

#[derive(Debug)]
pub enum EdgeType {
   LTR,  // line top-right
   LTL,  // line top-left
   LBR,  // line bottom-right
   LBL,  // line bottom-left

   LHR,  // line horizontal-right
   LHL,  // line horizontal-left
   LVT,  // line vertical-top
   LVB,  // line vertical-bottom

   CTR, // clockwise arc top-right
   CTL, // clockwise arc top-left
   CBR, // clockwise arc bottom-right
   CBL, // clockwise arc bottom-left

   ATR, // anti-clockwise arc top-right
   ATL, // anti-clockwise arc top-left
   ABR, // anti-clockwise arc bottom-right
   ABL, // anti-clockwise arc bottom-left
}

impl EdgeType {
   #[inline]
   pub fn reversed(&self) -> bool {
      match *self {
         EdgeType::LBR | EdgeType::LBL | EdgeType::LHL | EdgeType::LVB |
         EdgeType::CBR | EdgeType::CBL | EdgeType::ATR | EdgeType::ATL => {
            true
         },
         _ => {
            false
         }
      }
   }
}

#[derive(Debug)]
pub struct Edge {
   pub edge_type: EdgeType,
   pub segment: usize,
   pub circle: usize,
}

impl Edge {
   #[inline]
   pub fn new(edge_type: EdgeType, segment: usize, circle: usize) -> Self {
      Edge {
         edge_type: edge_type,
         segment: segment,
         circle: circle,
      }
   }

   #[inline]
   pub fn reversed(&self) -> bool {
      self.edge_type.reversed()
   }
}

#[derive(Debug)]
pub struct Poly {
   pub start: usize,
   pub end: usize,
   pub color: usize,
}

impl Poly {
   #[inline]
   pub fn new(start: usize, end: usize, color: usize) -> Self {
      Poly {
         start: start,
         end: end,
         color: color,
      }
   }
}

pub struct Scene {
   pub points: Vec<Point>,
   pub segments: Vec<Segment>,
   pub circles: Vec<Circle>,
   pub edges: Vec<Edge>,
   pub polys: Vec<Poly>,
   pub colors: Vec<RGB>,
}

impl Scene {
   pub fn check_correctness(&self) {
      for poly in &self.polys {
         self.check_poly_connected(poly);
         self.check_segments_orientation(poly);
      }
   }

   fn check_poly_connected(&self, poly: &Poly) {
      let mut prev = self.edge_head(&self.edges[poly.end - 1]);

      for edge_index in poly.start..poly.end {
         let ref edge = self.edges[edge_index];

         let current = self.edge_tail(edge);
         if current != prev {
            panic!("Unclosed poly : {:?}", poly);
         }

         prev = self.edge_head(edge);
      }
   }

   fn check_segments_orientation(&self, poly: &Poly) {
      for edge_index in poly.start..poly.end {
         let ref edge = self.edges[edge_index];
         let ref segment = self.segments[edge.segment];

         let ref less = self.points[segment.p1];
         let ref greater = self.points[segment.p2];

         if greater <= less {
            panic!("Wrong segment orientation : {:?}", edge);
         }
      }
   }

   fn edge_head(&self, edge: &Edge) -> &Point {
      let ref segment = self.segments[edge.segment];
      if edge.reversed() {
         &self.points[segment.p1]
      } else {
         &self.points[segment.p2]
      }
   }

   fn edge_tail(&self, edge: &Edge) -> &Point {
      let ref segment = self.segments[edge.segment];
      if edge.reversed() {
         &self.points[segment.p2]
      } else {
         &self.points[segment.p1]
      }
   }
}
<|endoftext|>


<commit_before>pub struct Recipe {
    pub fat: &'static str,
    pub flour: &'static str,
    pub liquid: &'static str,
    pub optional: &'static str,
    pub spice: &'static str,
    pub sugar: &'static str,
}

pub static FAT: [&'static str; 6] = [
    "coconut cream",
    "coconut oil",
    "margarine",
    "olive oil",
    "rapeseed oil",
    "sunflower oil",
];

pub static FLOUR: [&'static str; 4] = [
    "gluten-free flour",
    "spelt flour",
    "white flour",
    "wholegrain flour",
];

pub static SUGAR: [&'static str; 8] = [
    "agave syrup",
    "black treacle",
    "brown sugar",
    "caster sugar",
    "golden syrup",
    "stevia",
    "vanilla sugar",
    "white sugar",
];

pub static LIQUID: [&'static str; 13] = [
    "almond milk",
    "apple juice, non-filtered",
    "barley milk",
    "cashew milk",
    "cold, strong coffee",
    "cold, strong earl grey tea",
    "hemp milk",
    "macadamia milk",
    "oat milk",
    "pear juice, non-filtered",
    "rice milk",
    "soy milk",
    "soy-rice milk",
    "spelt milk",
    "water",
];

pub static SPICE: [&'static str; 26] = [
    "anise seed",
    "basil",
    "black pepper",
    "cardamon",
    "cayenne pepper",
    "chilli",
    "chopped parsley",
    "cinnamon",
    "cloves",
    "coriander powder",
    "cumin",
    "curry powder",
    "curry powder",
    "dill",
    // "double espresso",
    "fresh coriander",
    "fresh ginger",
    "fresh mint",
    "garam masala",
    "marjoram leaves",
    "nutmeg",
    "orange peel",
    "powdered ginger",
    "rosemary",
    "thyme leaf",
    "vanilla extract",
];

pub static FRUITS: [&'static str; 20] = [
    "apricots",
    "avocado",
    "blueberries",
    "chopped apples",
    "chopped bananas",
    "chopped mango",
    "chopped nectarine",
    "chopped pears",
    "cooked pumpkin pulp",
    "cooked sweet potato pulp",
    "grated apples",
    "pitted cherries",
    "plums",
    "pomegranade seeds",
    "raspberries",
    "shredded beetroot",
    "shredded carrots",
    "shredded zucchini",
    "smashed bananas",
    "strawberries",
];

pub static NUTS: [&'static str; 13] = [
    "almond flakes",
    "almond powder",
    "chopped almonds",
    "chopped cashews",
    "chopped macadamia",
    "chopped peanuts",
    "chopped walnuts",
    "dates",
    "dried fruit mix",
    "pecans",
    "poppy seeds",
    "raisins",
    "walnut powder",
];

pub static SPRINKLES: [&'static str; 5] = [
    "cacao",
    "chopped chocolate",
    "lemon zest",
    "oats",
    "shredded coconut",
];
<commit_msg>Length of array is important and fixed in Rust, oops<commit_after>pub struct Recipe {
    pub fat: &'static str,
    pub flour: &'static str,
    pub liquid: &'static str,
    pub optional: &'static str,
    pub spice: &'static str,
    pub sugar: &'static str,
}

pub static FAT: [&'static str; 6] = [
    "coconut cream",
    "coconut oil",
    "margarine",
    "olive oil",
    "rapeseed oil",
    "sunflower oil",
];

pub static FLOUR: [&'static str; 4] = [
    "gluten-free flour",
    "spelt flour",
    "white flour",
    "wholegrain flour",
];

pub static SUGAR: [&'static str; 8] = [
    "agave syrup",
    "black treacle",
    "brown sugar",
    "caster sugar",
    "golden syrup",
    "stevia",
    "vanilla sugar",
    "white sugar",
];

pub static LIQUID: [&'static str; 15] = [
    "almond milk",
    "apple juice, non-filtered",
    "barley milk",
    "cashew milk",
    "cold, strong coffee",
    "cold, strong earl grey tea",
    "hemp milk",
    "macadamia milk",
    "oat milk",
    "pear juice, non-filtered",
    "rice milk",
    "soy milk",
    "soy-rice milk",
    "spelt milk",
    "water",
];

pub static SPICE: [&'static str; 25] = [
    "anise seed",
    "basil",
    "black pepper",
    "cardamon",
    "cayenne pepper",
    "chilli",
    "chopped parsley",
    "cinnamon",
    "cloves",
    "coriander powder",
    "cumin",
    "curry powder",
    "curry powder",
    "dill",
    // "double espresso",
    "fresh coriander",
    "fresh ginger",
    "fresh mint",
    "garam masala",
    "marjoram leaves",
    "nutmeg",
    "orange peel",
    "powdered ginger",
    "rosemary",
    "thyme leaf",
    "vanilla extract",
];

pub static FRUITS: [&'static str; 20] = [
    "apricots",
    "avocado",
    "blueberries",
    "chopped apples",
    "chopped bananas",
    "chopped mango",
    "chopped nectarine",
    "chopped pears",
    "cooked pumpkin pulp",
    "cooked sweet potato pulp",
    "grated apples",
    "pitted cherries",
    "plums",
    "pomegranade seeds",
    "raspberries",
    "shredded beetroot",
    "shredded carrots",
    "shredded zucchini",
    "smashed bananas",
    "strawberries",
];

pub static NUTS: [&'static str; 13] = [
    "almond flakes",
    "almond powder",
    "chopped almonds",
    "chopped cashews",
    "chopped macadamia",
    "chopped peanuts",
    "chopped walnuts",
    "dates",
    "dried fruit mix",
    "pecans",
    "poppy seeds",
    "raisins",
    "walnut powder",
];

pub static SPRINKLES: [&'static str; 5] = [
    "cacao",
    "chopped chocolate",
    "lemon zest",
    "oats",
    "shredded coconut",
];
<|endoftext|>