<commit_before>// Copyright 2019 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.

//! Module of the rust-protobuf generated files.

// For protobuf generated files.
#![allow(bare_trait_objects)]

use failure::Error;
use protobuf::{well_known_types::Empty, RepeatedField};
use std::borrow::Cow;

use crate::{proof_map_index::ProofPath, BinaryKey, BinaryValue};
use exonum_crypto::proto::*;
use exonum_proto::ProtobufConvert;

pub use self::{list_proof::*, map_proof::*};

include!(concat!(env!("OUT_DIR"), "/protobuf_mod.rs"));

impl<K, V, S> ProtobufConvert for crate::MapProof<K, V, S>
where
    K: BinaryKey + ToOwned<Owned = K>,
    V: BinaryValue,
{
    type ProtoStruct = MapProof;

    fn to_pb(&self) -> Self::ProtoStruct {
        let mut map_proof = MapProof::new();

        let proof: Vec<MapProofEntry> = self
            .proof_unchecked()
            .iter()
            .map(|(p, h)| {
                let mut entry = MapProofEntry::new();
                entry.set_hash(h.to_pb());
                entry.set_proof_path(p.as_bytes().to_vec());
                entry
            })
            .collect();

        let entries: Vec<OptionalEntry> = self
            .all_entries_unchecked()
            .map(|(key, value)| {
                let mut entry = OptionalEntry::new();
                let mut buf = vec![0_u8; key.size()];
                key.write(&mut buf);
                entry.set_key(buf.to_vec());

                match value {
                    Some(value) => entry.set_value(value.to_bytes()),
                    None => entry.set_no_value(Empty::new()),
                }

                entry
            })
            .collect();

        map_proof.set_proof(RepeatedField::from_vec(proof));
        map_proof.set_entries(RepeatedField::from_vec(entries));

        map_proof
    }

    fn from_pb(pb: Self::ProtoStruct) -> Result<Self, Error> {
        let proof = pb
            .get_proof()
            .iter()
            .map(|entry| {
                Ok((
                    ProofPath::read(entry.get_proof_path()),
                    exonum_crypto::Hash::from_pb(entry.get_hash().clone())?,
                ))
            })
            .collect::<Result<Vec<_>, Error>>()?;

        let entries = pb
            .get_entries()
            .iter()
            .map(|entry| {
                let key = K::read(entry.get_key());

                let value = if entry.has_value() {
                    Some(V::from_bytes(Cow::Borrowed(entry.get_value()))?)
                } else {
                    ensure!(
                        entry.has_no_value(),
                        "malformed message, no_value is absent"
                    );
                    None
                };

                Ok((key, value))
            })
            .collect::<Result<Vec<_>, Error>>()?;

        let mut map_proof = crate::MapProof::new().add_proof_entries(proof);

        for entry in entries {
            map_proof = match entry.1 {
                Some(value) => map_proof.add_entry(entry.0, value),
                None => map_proof.add_missing(entry.0),
            };
        }

        Ok(map_proof)
    }
}

#[cfg(test)]
mod tests {
    use exonum_crypto::{proto::types, PublicKey};
    use exonum_proto::ProtobufConvert;
    use std::fmt;

    use crate::{
        access::AccessExt, proof_map_index::ToProofPath, proto, BinaryKey, BinaryValue, Database,
        ListProof, MapProof, ObjectHash, TemporaryDB,
    };
    use protobuf::RepeatedField;

    #[test]
    fn serialize_map_proof() {
        let db = TemporaryDB::default();
        let fork = db.fork();
        let mut table = fork.get_proof_map("index");

        let proof = table.get_proof(0);
        assert_proof_roundtrip(&proof);

        for i in 0..10 {
            table.put(&i, i);
        }

        let proof = table.get_proof(5);
        assert_proof_roundtrip(&proof);
        let proof = table.get_multiproof(5..15);
        assert_proof_roundtrip(&proof);
    }

    fn assert_proof_roundtrip<K, V, S>(proof: &MapProof<K, V, S>)
    where
        K: BinaryKey + ObjectHash + fmt::Debug,
        V: BinaryValue + ObjectHash + fmt::Debug,
        S: ToProofPath<K> + fmt::Debug,
        MapProof<K, V, S>: ProtobufConvert + PartialEq,
    {
        let pb = proof.to_pb();
        let deserialized: MapProof<K, V, S> = MapProof::from_pb(pb).unwrap();
        let checked_proof = deserialized
            .check()
            .expect("deserialized proof is not valid");

        assert_eq!(proof, &deserialized);
        assert_eq!(
            checked_proof.index_hash(),
            proof.check().unwrap().index_hash()
        );
    }

    #[test]
    fn map_proof_malformed_serialize() {
        let mut proof = proto::MapProof::new();
        let mut proof_entry = proto::MapProofEntry::new();
        let mut hash = types::Hash::new();

        hash.set_data(vec![0_u8; 31]);
        proof_entry.set_hash(hash);
        proof_entry.set_proof_path(vec![0_u8; 34]);
        proof.set_proof(RepeatedField::from_vec(vec![proof_entry]));

        let res = MapProof::<u8, u8>::from_pb(proof.clone());
        assert!(res.unwrap_err().to_string().contains("Wrong Hash size"));

        let mut entry = proto::OptionalEntry::new();
        entry.set_key(vec![0_u8; 32]);
        proof.clear_proof();
        proof.set_entries(RepeatedField::from_vec(vec![entry]));

        let res = MapProof::<PublicKey, u8>::from_pb(proof.clone());
        assert!(res.unwrap_err().to_string().contains("malformed message"));
    }

    #[test]
    #[should_panic]
    fn map_proof_malformed_key_serialize() {
        let mut proof = proto::MapProof::new();
        let mut proof_entry = proto::MapProofEntry::new();
        proof_entry.set_proof_path(vec![0_u8; 33]);
        proof.set_proof(RepeatedField::from_vec(vec![proof_entry]));

        // TODO: will panic at runtime, should change BinaryKey::read signature (ECR-174)
        let _res = MapProof::<u8, u8>::from_pb(proof);
    }

    #[test]
    fn serialize_list_proof() {
        let db = TemporaryDB::default();
        let fork = db.fork();
        let mut table = fork.get_proof_list("index");

        let proof = table.get_proof(0);
        assert_list_proof_roundtrip(&proof);

        for i in 0..256 {
            table.push(i);
        }

        let proof = table.get_proof(5);
        assert_list_proof_roundtrip(&proof);
        let proof = table.get_range_proof(250..260);
        assert_list_proof_roundtrip(&proof);
    }

    fn assert_list_proof_roundtrip<V>(proof: &ListProof<V>)
    where
        V: BinaryValue + ObjectHash + std::fmt::Debug,
        ListProof<V>: ProtobufConvert + PartialEq,
    {
        let pb = proof.to_pb();
        let deserialized: ListProof<V> = ListProof::from_pb(pb).unwrap();
        let checked_proof = deserialized
            .check()
            .expect("deserialized proof is not valid");

        assert_eq!(proof, &deserialized);
        assert_eq!(
            checked_proof.index_hash(),
            proof.check().unwrap().index_hash()
        );
    }
}
<commit_msg>Additional list proof deserialization tests. (#1575)<commit_after>// Copyright 2019 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.

//! Module of the rust-protobuf generated files.

// For protobuf generated files.
#![allow(bare_trait_objects)]

use failure::Error;
use protobuf::{well_known_types::Empty, RepeatedField};
use std::borrow::Cow;

use crate::{proof_map_index::ProofPath, BinaryKey, BinaryValue};
use exonum_crypto::proto::*;
use exonum_proto::ProtobufConvert;

pub use self::{list_proof::*, map_proof::*};

include!(concat!(env!("OUT_DIR"), "/protobuf_mod.rs"));

impl<K, V, S> ProtobufConvert for crate::MapProof<K, V, S>
where
    K: BinaryKey + ToOwned<Owned = K>,
    V: BinaryValue,
{
    type ProtoStruct = MapProof;

    fn to_pb(&self) -> Self::ProtoStruct {
        let mut map_proof = MapProof::new();

        let proof: Vec<MapProofEntry> = self
            .proof_unchecked()
            .iter()
            .map(|(p, h)| {
                let mut entry = MapProofEntry::new();
                entry.set_hash(h.to_pb());
                entry.set_proof_path(p.as_bytes().to_vec());
                entry
            })
            .collect();

        let entries: Vec<OptionalEntry> = self
            .all_entries_unchecked()
            .map(|(key, value)| {
                let mut entry = OptionalEntry::new();
                let mut buf = vec![0_u8; key.size()];
                key.write(&mut buf);
                entry.set_key(buf.to_vec());

                match value {
                    Some(value) => entry.set_value(value.to_bytes()),
                    None => entry.set_no_value(Empty::new()),
                }

                entry
            })
            .collect();

        map_proof.set_proof(RepeatedField::from_vec(proof));
        map_proof.set_entries(RepeatedField::from_vec(entries));

        map_proof
    }

    fn from_pb(pb: Self::ProtoStruct) -> Result<Self, Error> {
        let proof = pb
            .get_proof()
            .iter()
            .map(|entry| {
                Ok((
                    ProofPath::read(entry.get_proof_path()),
                    exonum_crypto::Hash::from_pb(entry.get_hash().clone())?,
                ))
            })
            .collect::<Result<Vec<_>, Error>>()?;

        let entries = pb
            .get_entries()
            .iter()
            .map(|entry| {
                let key = K::read(entry.get_key());

                let value = if entry.has_value() {
                    Some(V::from_bytes(Cow::Borrowed(entry.get_value()))?)
                } else {
                    ensure!(
                        entry.has_no_value(),
                        "malformed message, no_value is absent"
                    );
                    None
                };

                Ok((key, value))
            })
            .collect::<Result<Vec<_>, Error>>()?;

        let mut map_proof = crate::MapProof::new().add_proof_entries(proof);

        for entry in entries {
            map_proof = match entry.1 {
                Some(value) => map_proof.add_entry(entry.0, value),
                None => map_proof.add_missing(entry.0),
            };
        }

        Ok(map_proof)
    }
}

#[cfg(test)]
mod tests {
    use exonum_crypto::{proto::types, PublicKey};
    use exonum_proto::ProtobufConvert;
    use std::fmt;

    use crate::{
        access::AccessExt, proof_map_index::ToProofPath, proto, BinaryKey, BinaryValue, Database,
        ListProof, MapProof, ObjectHash, TemporaryDB,
    };
    use protobuf::RepeatedField;

    #[test]
    fn serialize_map_proof() {
        let db = TemporaryDB::default();
        let fork = db.fork();
        let mut table = fork.get_proof_map("index");

        let proof = table.get_proof(0);
        assert_proof_roundtrip(&proof);

        for i in 0..10 {
            table.put(&i, i);
        }

        let proof = table.get_proof(5);
        assert_proof_roundtrip(&proof);
        let proof = table.get_multiproof(5..15);
        assert_proof_roundtrip(&proof);
    }

    fn assert_proof_roundtrip<K, V, S>(proof: &MapProof<K, V, S>)
    where
        K: BinaryKey + ObjectHash + fmt::Debug,
        V: BinaryValue + ObjectHash + fmt::Debug,
        S: ToProofPath<K> + fmt::Debug,
        MapProof<K, V, S>: ProtobufConvert + PartialEq,
    {
        let pb = proof.to_pb();
        let deserialized: MapProof<K, V, S> = MapProof::from_pb(pb).unwrap();
        let checked_proof = deserialized
            .check()
            .expect("deserialized proof is not valid");

        assert_eq!(proof, &deserialized);
        assert_eq!(
            checked_proof.index_hash(),
            proof.check().unwrap().index_hash()
        );
    }

    #[test]
    fn map_proof_malformed_serialize() {
        let mut proof = proto::MapProof::new();
        let mut proof_entry = proto::MapProofEntry::new();
        let mut hash = types::Hash::new();

        hash.set_data(vec![0_u8; 31]);
        proof_entry.set_hash(hash);
        proof_entry.set_proof_path(vec![0_u8; 34]);
        proof.set_proof(RepeatedField::from_vec(vec![proof_entry]));

        let res = MapProof::<u8, u8>::from_pb(proof.clone());
        assert!(res.unwrap_err().to_string().contains("Wrong Hash size"));

        let mut entry = proto::OptionalEntry::new();
        entry.set_key(vec![0_u8; 32]);
        proof.clear_proof();
        proof.set_entries(RepeatedField::from_vec(vec![entry]));

        let res = MapProof::<PublicKey, u8>::from_pb(proof);
        assert!(res.unwrap_err().to_string().contains("malformed message"));
    }

    #[test]
    #[should_panic]
    fn map_proof_malformed_key_serialize() {
        let mut proof = proto::MapProof::new();
        let mut proof_entry = proto::MapProofEntry::new();
        proof_entry.set_proof_path(vec![0_u8; 33]);
        proof.set_proof(RepeatedField::from_vec(vec![proof_entry]));

        // TODO: will panic at runtime, should change BinaryKey::read signature (ECR-174)
        let _res = MapProof::<u8, u8>::from_pb(proof);
    }

    #[test]
    fn serialize_list_proof() {
        let db = TemporaryDB::default();
        let fork = db.fork();
        let mut table = fork.get_proof_list("index");

        let proof = table.get_proof(0);
        assert_list_proof_roundtrip(&proof);

        for i in 0..256 {
            table.push(i);
        }

        let proof = table.get_proof(5);
        assert_list_proof_roundtrip(&proof);
        let proof = table.get_range_proof(250..260);
        assert_list_proof_roundtrip(&proof);
    }

    fn assert_list_proof_roundtrip<V>(proof: &ListProof<V>)
    where
        V: BinaryValue + ObjectHash + std::fmt::Debug,
        ListProof<V>: ProtobufConvert + PartialEq,
    {
        let pb = proof.to_pb();
        let deserialized: ListProof<V> = ListProof::from_pb(pb).unwrap();
        let checked_proof = deserialized
            .check()
            .expect("deserialized proof is not valid");

        assert_eq!(proof, &deserialized);
        assert_eq!(
            checked_proof.index_hash(),
            proof.check().unwrap().index_hash()
        );
    }

    #[test]
    fn invalid_list_proof_key() {
        let mut proof = proto::ListProof::new();
        let mut key = proto::ProofListKey::new();
        key.set_index(2_u64.pow(56));

        let mut hashed_entry = proto::HashedEntry::new();
        hashed_entry.set_key(key.clone());

        proof.set_proof(RepeatedField::from_vec(vec![hashed_entry]));

        let de_proof = ListProof::<u8>::from_pb(proof.clone());
        assert!(de_proof
            .unwrap_err()
            .to_string()
            .contains("index is out of range"));

        key.set_index(1);
        key.set_height(59);
        let mut hashed_entry = proto::HashedEntry::new();
        hashed_entry.set_key(key);

        proof.set_proof(RepeatedField::from_vec(vec![hashed_entry]));

        let de_proof = ListProof::<u8>::from_pb(proof);
        assert!(de_proof
            .unwrap_err()
            .to_string()
            .contains("height is out of range"));
    }

    #[test]
    fn invalid_list_proof_hashed_entry() {
        let mut proof = proto::ListProof::new();
        let mut hashed_entry = proto::HashedEntry::new();

        let mut hash = types::Hash::new();
        hash.set_data(vec![0_u8; 31]);
        hashed_entry.set_hash(hash);
        proof.set_proof(RepeatedField::from_vec(vec![hashed_entry]));

        let de_proof = ListProof::<u8>::from_pb(proof);
        assert!(de_proof
            .unwrap_err()
            .to_string()
            .contains("Wrong Hash size"));
    }
}
<|endoftext|>


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

use dom::bindings::codegen::Bindings::TextDecoderBinding;
use dom::bindings::codegen::Bindings::TextDecoderBinding::TextDecoderMethods;
use dom::bindings::conversions::array_buffer_view_data;
use dom::bindings::error::{Error, Fallible};
use dom::bindings::js::Root;
use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::bindings::str::{DOMString, USVString};
use dom::globalscope::GlobalScope;
use encoding::label::encoding_from_whatwg_label;
use encoding::types::{DecoderTrap, EncodingRef};
use js::jsapi::{JSContext, JSObject};
use std::borrow::ToOwned;

#[dom_struct]
pub struct TextDecoder {
    reflector_: Reflector,
    #[ignore_heap_size_of = "Defined in rust-encoding"]
    encoding: EncodingRef,
    fatal: bool,
}

impl TextDecoder {
    fn new_inherited(encoding: EncodingRef, fatal: bool) -> TextDecoder {
        TextDecoder {
            reflector_: Reflector::new(),
            encoding: encoding,
            fatal: fatal,
        }
    }

    fn make_range_error() -> Fallible<Root<TextDecoder>> {
        Err(Error::Range("The given encoding is not supported.".to_owned()))
    }

    pub fn new(global: &GlobalScope, encoding: EncodingRef, fatal: bool) -> Root<TextDecoder> {
        reflect_dom_object(box TextDecoder::new_inherited(encoding, fatal),
                           global,
                           TextDecoderBinding::Wrap)
    }

    /// https://encoding.spec.whatwg.org/#dom-textdecoder
    pub fn Constructor(global: &GlobalScope,
                       label: DOMString,
                       options: &TextDecoderBinding::TextDecoderOptions)
                            -> Fallible<Root<TextDecoder>> {
        let encoding = match encoding_from_whatwg_label(&label) {
            None => return TextDecoder::make_range_error(),
            Some(enc) => enc
        };
        // The rust-encoding crate has WHATWG compatibility, so we are
        // guaranteed to have a whatwg_name because we successfully got
        // the encoding from encoding_from_whatwg_label.
        // Use match + panic! instead of unwrap for better error message
        match encoding.whatwg_name() {
            None => panic!("Label {} fits valid encoding without valid name", label),
            Some("replacement") => return TextDecoder::make_range_error(),
            _ => ()
        };
        Ok(TextDecoder::new(global, encoding, options.fatal))
    }
}

impl TextDecoderMethods for TextDecoder {
    // https://encoding.spec.whatwg.org/#dom-textdecoder-encoding
    fn Encoding(&self) -> DOMString {
        DOMString::from(self.encoding.whatwg_name().unwrap())
    }

    // https://encoding.spec.whatwg.org/#dom-textdecoder-fatal
    fn Fatal(&self) -> bool {
        self.fatal
    }

    #[allow(unsafe_code)]
    // https://encoding.spec.whatwg.org/#dom-textdecoder-decode
    unsafe fn Decode(&self, _cx: *mut JSContext, input: Option<*mut JSObject>)
              -> Fallible<USVString> {
        let input = match input {
            Some(input) => input,
            None => return Ok(USVString("".to_owned())),
        };

        let data = match array_buffer_view_data::<u8>(input) {
            Some(data) => data,
            None => {
                return Err(Error::Type("Argument to TextDecoder.decode is not an ArrayBufferView".to_owned()));
            }
        };

        let trap = if self.fatal {
            DecoderTrap::Strict
        } else {
            DecoderTrap::Replace
        };

        match self.encoding.decode(data, trap) {
            Ok(s) => Ok(USVString(s)),
            Err(_) => Err(Error::Type("Decoding failed".to_owned())),
        }
    }
}
<commit_msg>Use typed array API in TextDecoder::Decode<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::Bindings::TextDecoderBinding;
use dom::bindings::codegen::Bindings::TextDecoderBinding::TextDecoderMethods;
use dom::bindings::error::{Error, Fallible};
use dom::bindings::js::Root;
use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::bindings::str::{DOMString, USVString};
use dom::globalscope::GlobalScope;
use encoding::label::encoding_from_whatwg_label;
use encoding::types::{DecoderTrap, EncodingRef};
use js::jsapi::{JSContext, JSObject};
use std::borrow::ToOwned;

#[dom_struct]
pub struct TextDecoder {
    reflector_: Reflector,
    #[ignore_heap_size_of = "Defined in rust-encoding"]
    encoding: EncodingRef,
    fatal: bool,
}

impl TextDecoder {
    fn new_inherited(encoding: EncodingRef, fatal: bool) -> TextDecoder {
        TextDecoder {
            reflector_: Reflector::new(),
            encoding: encoding,
            fatal: fatal,
        }
    }

    fn make_range_error() -> Fallible<Root<TextDecoder>> {
        Err(Error::Range("The given encoding is not supported.".to_owned()))
    }

    pub fn new(global: &GlobalScope, encoding: EncodingRef, fatal: bool) -> Root<TextDecoder> {
        reflect_dom_object(box TextDecoder::new_inherited(encoding, fatal),
                           global,
                           TextDecoderBinding::Wrap)
    }

    /// https://encoding.spec.whatwg.org/#dom-textdecoder
    pub fn Constructor(global: &GlobalScope,
                       label: DOMString,
                       options: &TextDecoderBinding::TextDecoderOptions)
                            -> Fallible<Root<TextDecoder>> {
        let encoding = match encoding_from_whatwg_label(&label) {
            None => return TextDecoder::make_range_error(),
            Some(enc) => enc
        };
        // The rust-encoding crate has WHATWG compatibility, so we are
        // guaranteed to have a whatwg_name because we successfully got
        // the encoding from encoding_from_whatwg_label.
        // Use match + panic! instead of unwrap for better error message
        match encoding.whatwg_name() {
            None => panic!("Label {} fits valid encoding without valid name", label),
            Some("replacement") => return TextDecoder::make_range_error(),
            _ => ()
        };
        Ok(TextDecoder::new(global, encoding, options.fatal))
    }
}

impl TextDecoderMethods for TextDecoder {
    // https://encoding.spec.whatwg.org/#dom-textdecoder-encoding
    fn Encoding(&self) -> DOMString {
        DOMString::from(self.encoding.whatwg_name().unwrap())
    }

    // https://encoding.spec.whatwg.org/#dom-textdecoder-fatal
    fn Fatal(&self) -> bool {
        self.fatal
    }

    #[allow(unsafe_code)]
    // https://encoding.spec.whatwg.org/#dom-textdecoder-decode
    unsafe fn Decode(&self, _cx: *mut JSContext, input: Option<*mut JSObject>)
              -> Fallible<USVString> {
        let input = match input {
            Some(input) => input,
            None => return Ok(USVString("".to_owned())),
        };

        typedarray!(in(_cx) let data_res: ArrayBufferView = input);
        let mut data = match data_res {
            Ok(data) => data,
            Err(_)   => {
                return Err(Error::Type("Argument to TextDecoder.decode is not an ArrayBufferView".to_owned()));
            }
        };

        let trap = if self.fatal {
            DecoderTrap::Strict
        } else {
            DecoderTrap::Replace
        };

        match self.encoding.decode(data.as_slice(), trap) {
            Ok(s) => Ok(USVString(s)),
            Err(_) => Err(Error::Type("Decoding failed".to_owned())),
        }
    }
}
<|endoftext|>


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

use dom::bindings::codegen::Bindings::TextEncoderBinding;
use dom::bindings::codegen::Bindings::TextEncoderBinding::TextEncoderMethods;
use dom::bindings::error::{Error, Fallible};
use dom::bindings::global::GlobalRef;
use dom::bindings::js::Root;
use dom::bindings::str::USVString;
use dom::bindings::utils::{Reflector, reflect_dom_object};
use encoding::label::encoding_from_whatwg_label;
use encoding::types::EncodingRef;
use encoding::{EncoderTrap, Encoding};
use js::jsapi::{JSContext, JSObject};
use js::jsapi::{JS_GetUint8ArrayData, JS_NewUint8Array};
use libc::uint8_t;
use std::borrow::ToOwned;
use std::ptr;
use util::str::DOMString;

#[dom_struct]
pub struct TextEncoder {
    reflector_: Reflector,
    encoding: DOMString,
    #[ignore_heap_size_of = "Defined in rust-encoding"]
    encoder: EncodingRef,
}

impl TextEncoder {
    fn new_inherited(encoding: DOMString, encoder: EncodingRef) -> TextEncoder {
        TextEncoder {
            reflector_: Reflector::new(),
            encoding: encoding,
            encoder: encoder,
        }
    }

    pub fn new(global: GlobalRef, encoding: DOMString, encoder: EncodingRef) -> Root<TextEncoder> {
        reflect_dom_object(box TextEncoder::new_inherited(encoding, encoder),
                           global,
                           TextEncoderBinding::Wrap)
    }

    // https://encoding.spec.whatwg.org/#dom-textencoder
    pub fn Constructor(global: GlobalRef,
                       label: DOMString) -> Fallible<Root<TextEncoder>> {
        let encoding = match encoding_from_whatwg_label(&label) {
            Some(enc) => enc,
            None => {
                debug!("Encoding Label Not Supported");
                return Err(Error::Range("The given encoding is not supported.".to_owned()))
            }
        };

        match encoding.name() {
            "utf-8" | "utf-16be" | "utf-16le" => {
                Ok(TextEncoder::new(global, encoding.name().to_owned(), encoding))
            }
            _ => {
                debug!("Encoding Not UTF");
                Err(Error::Range("The encoding must be utf-8, utf-16le, or utf-16be.".to_owned()))
            }
        }
    }
}

impl TextEncoderMethods for TextEncoder {
    // https://encoding.spec.whatwg.org/#dom-textencoder-encoding
    fn Encoding(&self) -> DOMString {
        self.encoding.clone()
    }

    #[allow(unsafe_code)]
    // https://encoding.spec.whatwg.org/#dom-textencoder-encode
    fn Encode(&self, cx: *mut JSContext, input: USVString) -> *mut JSObject {
        unsafe {
            let encoded = self.encoder.encode(&input.0, EncoderTrap::Strict).unwrap();
            let length = encoded.len() as u32;
            let js_object: *mut JSObject = JS_NewUint8Array(cx, length);

            let js_object_data: *mut uint8_t = JS_GetUint8ArrayData(js_object, ptr::null());
            ptr::copy_nonoverlapping(encoded.as_ptr(), js_object_data, length as usize);
            js_object
        }
    }
}
<commit_msg>Remove the pointless TextEncoder::encoding field.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::Bindings::TextEncoderBinding;
use dom::bindings::codegen::Bindings::TextEncoderBinding::TextEncoderMethods;
use dom::bindings::error::{Error, Fallible};
use dom::bindings::global::GlobalRef;
use dom::bindings::js::Root;
use dom::bindings::str::USVString;
use dom::bindings::utils::{Reflector, reflect_dom_object};
use encoding::label::encoding_from_whatwg_label;
use encoding::types::EncodingRef;
use encoding::{EncoderTrap, Encoding};
use js::jsapi::{JSContext, JSObject};
use js::jsapi::{JS_GetUint8ArrayData, JS_NewUint8Array};
use libc::uint8_t;
use std::borrow::ToOwned;
use std::ptr;
use util::str::DOMString;

#[dom_struct]
pub struct TextEncoder {
    reflector_: Reflector,
    #[ignore_heap_size_of = "Defined in rust-encoding"]
    encoder: EncodingRef,
}

impl TextEncoder {
    fn new_inherited(encoder: EncodingRef) -> TextEncoder {
        TextEncoder {
            reflector_: Reflector::new(),
            encoder: encoder,
        }
    }

    pub fn new(global: GlobalRef, encoder: EncodingRef) -> Root<TextEncoder> {
        reflect_dom_object(box TextEncoder::new_inherited(encoder),
                           global,
                           TextEncoderBinding::Wrap)
    }

    // https://encoding.spec.whatwg.org/#dom-textencoder
    pub fn Constructor(global: GlobalRef,
                       label: DOMString) -> Fallible<Root<TextEncoder>> {
        let encoding = match encoding_from_whatwg_label(&label) {
            Some(enc) => enc,
            None => {
                debug!("Encoding Label Not Supported");
                return Err(Error::Range("The given encoding is not supported.".to_owned()))
            }
        };

        match encoding.name() {
            "utf-8" | "utf-16be" | "utf-16le" => {
                Ok(TextEncoder::new(global, encoding))
            }
            _ => {
                debug!("Encoding Not UTF");
                Err(Error::Range("The encoding must be utf-8, utf-16le, or utf-16be.".to_owned()))
            }
        }
    }
}

impl TextEncoderMethods for TextEncoder {
    // https://encoding.spec.whatwg.org/#dom-textencoder-encoding
    fn Encoding(&self) -> DOMString {
        self.encoder.name().to_owned()
    }

    #[allow(unsafe_code)]
    // https://encoding.spec.whatwg.org/#dom-textencoder-encode
    fn Encode(&self, cx: *mut JSContext, input: USVString) -> *mut JSObject {
        unsafe {
            let encoded = self.encoder.encode(&input.0, EncoderTrap::Strict).unwrap();
            let length = encoded.len() as u32;
            let js_object: *mut JSObject = JS_NewUint8Array(cx, length);

            let js_object_data: *mut uint8_t = JS_GetUint8ArrayData(js_object, ptr::null());
            ptr::copy_nonoverlapping(encoded.as_ptr(), js_object_data, length as usize);
            js_object
        }
    }
}
<|endoftext|>


<commit_before>use lazy_static::lazy_static;
use std::fs;
use std::path::{Path, PathBuf};
use tree_sitter::Language;
use tree_sitter_highlight::HighlightConfiguration;
use tree_sitter_loader::Loader;

include!("./dirs.rs");

lazy_static! {
    static ref TEST_LOADER: Loader = Loader::with_parser_lib_path(SCRATCH_DIR.clone());
}

pub fn test_loader<'a>() -> &'a Loader {
    &*TEST_LOADER
}

pub fn fixtures_dir<'a>() -> &'static Path {
    &FIXTURES_DIR
}

pub fn get_language(name: &str) -> Language {
    TEST_LOADER
        .load_language_at_path(&GRAMMARS_DIR.join(name).join("src"), &HEADER_DIR)
        .unwrap()
}

pub fn get_language_queries_path(language_name: &str) -> PathBuf {
    GRAMMARS_DIR.join(language_name).join("queries")
}

pub fn get_highlight_config(
    language_name: &str,
    injection_query_filename: Option<&str>,
    highlight_names: &[String],
) -> HighlightConfiguration {
    let language = get_language(language_name);
    let queries_path = get_language_queries_path(language_name);
    let highlights_query = fs::read_to_string(queries_path.join("highlights.scm")).unwrap();
    let injections_query = if let Some(injection_query_filename) = injection_query_filename {
        fs::read_to_string(queries_path.join(injection_query_filename)).unwrap()
    } else {
        String::new()
    };
    let locals_query = fs::read_to_string(queries_path.join("locals.scm")).unwrap_or(String::new());
    let mut result = HighlightConfiguration::new(
        language,
        &highlights_query,
        &injections_query,
        &locals_query,
    )
    .unwrap();
    result.configure(&highlight_names);
    result
}

pub fn get_test_language(name: &str, parser_code: &str, path: Option<&Path>) -> Language {
    let parser_c_path = SCRATCH_DIR.join(&format!("{}-parser.c", name));
    if !fs::read_to_string(&parser_c_path)
        .map(|content| content == parser_code)
        .unwrap_or(false)
    {
        fs::write(&parser_c_path, parser_code).unwrap();
    }
    let scanner_path = path.and_then(|p| {
        let result = p.join("scanner.c");
        if result.exists() {
            Some(result)
        } else {
            None
        }
    });
    TEST_LOADER
        .load_language_from_sources(name, &HEADER_DIR, &parser_c_path, &scanner_path)
        .unwrap()
}

pub fn get_test_grammar(name: &str) -> (String, Option<PathBuf>) {
    let dir = fixtures_dir().join("test_grammars").join(name);
    let grammar = fs::read_to_string(&dir.join("grammar.json")).unwrap();
    (grammar, Some(dir))
}
<commit_msg>add tags config fixture test helper<commit_after>use lazy_static::lazy_static;
use std::fs;
use std::path::{Path, PathBuf};
use tree_sitter::Language;
use tree_sitter_highlight::HighlightConfiguration;
use tree_sitter_loader::Loader;
use tree_sitter_tags::TagsConfiguration;

include!("./dirs.rs");

lazy_static! {
    static ref TEST_LOADER: Loader = Loader::with_parser_lib_path(SCRATCH_DIR.clone());
}

pub fn test_loader<'a>() -> &'a Loader {
    &*TEST_LOADER
}

pub fn fixtures_dir<'a>() -> &'static Path {
    &FIXTURES_DIR
}

pub fn get_language(name: &str) -> Language {
    TEST_LOADER
        .load_language_at_path(&GRAMMARS_DIR.join(name).join("src"), &HEADER_DIR)
        .unwrap()
}

pub fn get_language_queries_path(language_name: &str) -> PathBuf {
    GRAMMARS_DIR.join(language_name).join("queries")
}

pub fn get_highlight_config(
    language_name: &str,
    injection_query_filename: Option<&str>,
    highlight_names: &[String],
) -> HighlightConfiguration {
    let language = get_language(language_name);
    let queries_path = get_language_queries_path(language_name);
    let highlights_query = fs::read_to_string(queries_path.join("highlights.scm")).unwrap();
    let injections_query = if let Some(injection_query_filename) = injection_query_filename {
        fs::read_to_string(queries_path.join(injection_query_filename)).unwrap()
    } else {
        String::new()
    };
    let locals_query = fs::read_to_string(queries_path.join("locals.scm")).unwrap_or(String::new());
    let mut result = HighlightConfiguration::new(
        language,
        &highlights_query,
        &injections_query,
        &locals_query,
    )
    .unwrap();
    result.configure(&highlight_names);
    result
}

pub fn get_tags_config(language_name: &str) -> TagsConfiguration {
    let language = get_language(language_name);
    let queries_path = get_language_queries_path(language_name);
    let tags_query = fs::read_to_string(queries_path.join("tags.scm")).unwrap();
    let locals_query = fs::read_to_string(queries_path.join("locals.scm")).unwrap_or(String::new());
    TagsConfiguration::new(language, &tags_query, &locals_query).unwrap()
}

pub fn get_test_language(name: &str, parser_code: &str, path: Option<&Path>) -> Language {
    let parser_c_path = SCRATCH_DIR.join(&format!("{}-parser.c", name));
    if !fs::read_to_string(&parser_c_path)
        .map(|content| content == parser_code)
        .unwrap_or(false)
    {
        fs::write(&parser_c_path, parser_code).unwrap();
    }
    let scanner_path = path.and_then(|p| {
        let result = p.join("scanner.c");
        if result.exists() {
            Some(result)
        } else {
            None
        }
    });
    TEST_LOADER
        .load_language_from_sources(name, &HEADER_DIR, &parser_c_path, &scanner_path)
        .unwrap()
}

pub fn get_test_grammar(name: &str) -> (String, Option<PathBuf>) {
    let dir = fixtures_dir().join("test_grammars").join(name);
    let grammar = fs::read_to_string(&dir.join("grammar.json")).unwrap();
    (grammar, Some(dir))
}
<|endoftext|>


<commit_before>macro_rules! run_find_test {
    ( $db:expr, $coll:expr, $filter:expr, $opt:expr, $outcome:expr ) => {{
        let mut cursor = $coll.find($filter, $opt).unwrap();

        let array = match $outcome.result {
            Bson::Array(ref arr) => arr.clone(),
            _ => panic!("Invalid `result` of find test")
        };

        for bson in array {
            assert!(eq::bson_eq(&bson, &Bson::Document(cursor.next().unwrap().unwrap())));
        }

        assert!(!cursor.has_next().ok().expect("Failed to execute 'has_next()' on cursor."));
        check_coll!($db, $coll, $outcome.collection);
    }};
}

macro_rules! run_insert_many_test {
    ( $db:expr, $coll: expr, $docs:expr, $outcome:expr ) => {{
        let inserted = $coll.insert_many($docs, true, None).unwrap().inserted_ids.unwrap();
        let ids_bson = match $outcome.result {
            Bson::Document(ref doc) => doc.get("insertedIds").unwrap(),
            _ => panic!("`insert_many` test result should be a document")
        };

        let ids = match ids_bson {
            &Bson::Array(ref arr) => arr.into_iter(),
            _ => panic!("`insertedIds` test result should be an array")
        };

        let mut actual_ids = inserted.values();

        for expected_id in ids {
            assert!(eq::bson_eq(&expected_id, actual_ids.next().unwrap()));
        }

        check_coll!($db, $coll, $outcome.collection);
    }};
}

macro_rules! run_insert_one_test {
    ( $db:expr, $coll: expr, $doc:expr, $outcome:expr ) => {{
        let inserted = $coll.insert_one($doc, None).unwrap().inserted_id.unwrap();
        let id = match $outcome.result {
            Bson::Document(ref doc) => doc.get("insertedId").unwrap(),
            _ => panic!("`insert_one` test result should be a document")
        };

        assert!(eq::bson_eq(&id, &inserted));
        check_coll!($db, $coll, $outcome.collection);
    }};
}

macro_rules! run_delete_test {
    ( $db:expr, $coll: expr, $filter:expr, $outcome:expr, $many:expr ) => {{
        let count = if $many {
                        $coll.delete_many($filter, None)
                    } else {
                        $coll.delete_one($filter, None)
                    };

        let expected = count.unwrap().deleted_count;

        let actual = match $outcome.result {
            Bson::Document(ref doc) => doc.get("deletedCount").unwrap(),
            _ => panic!("`delete` test result should be a document")
        };

        assert!(actual.int_eq(expected as i64));
        check_coll!($db, $coll, $outcome.collection);
    }};
}

macro_rules! run_update_test {
    ( $db:expr, $coll: expr, $filter:expr, $update:expr, $upsert:expr,
      $many:expr, $outcome:expr ) => {{
          let result = if $many {
                           $coll.update_many($filter, $update, $upsert, None)
                       } else {
                           $coll.update_one($filter, $update, $upsert, None)
                       };

          let actual = result.unwrap();

          let (matched, modified, upserted) = match $outcome.result {
              Bson::Document(ref doc) => (
                  doc.get("matchedCount").unwrap(),
                  doc.get("modifiedCount").unwrap(),
                  doc.get("upsertedId"),
              ),
              _ => panic!("`delete` test result should be a document")
          };

          assert!(matched.int_eq(actual.matched_count as i64));
          assert!(modified.int_eq(actual.modified_count as i64));

          let id = match actual.upserted_id {
	          Some(Bson::Document(ref doc)) => doc.get("_id"),
              _ => None
          };

          match (upserted, id) {
              (None, None) => (),
              (Some(ref bson1), Some(ref bson2)) =>
                  assert!(eq::bson_eq(&bson1, &bson2)),
              _ => panic!("Wrong `upsertedId` returned")
          };

          check_coll!($db, $coll, $outcome.collection);
    }};
}

#[macro_export]
macro_rules! run_suite {
    ( $file:expr, $coll:expr ) => {{
        let json = Json::from_file($file).unwrap();
        let suite = json.get_suite().unwrap();
        let client =  MongoClient::new("localhost", 27017).unwrap();
        let db = client.db("test");
        let coll = db.collection($coll);

        for test in suite.tests {
            coll.drop().unwrap();
            coll.insert_many(suite.data.clone(), true, None).unwrap();

            match test.operation {
                Arguments::Delete { filter, many } =>
                    run_delete_test!(db, coll, filter, test.outcome, many),
                Arguments::Find { filter, options } =>
                    run_find_test!(db, coll, filter, Some(options), test.outcome),
                Arguments::InsertMany { documents } =>
                    run_insert_many_test!(db, coll, documents, test.outcome),
                Arguments::InsertOne { document } =>
                    run_insert_one_test!(db, coll, document, test.outcome),
                Arguments::Update { filter, update, upsert, many } =>
                    run_update_test!(db, coll, filter, update, upsert, many, test.outcome),
            };
        }
    }};
}

#[macro_export]
macro_rules! check_coll {
    ( $db:expr, $coll:expr, $coll_opt:expr ) => {{
        let outcome_coll = match $coll_opt {
            Some(ref coll) => coll.clone(),
            None => continue
        };

        let coll = match outcome_coll.name {
            Some(ref str) => $db.collection(&str),
            None => $db.collection(&$coll.name())
        };

        let mut cursor = coll.find(None, None).unwrap();

        for doc in outcome_coll.data.iter() {
            assert!(eq::bson_eq(&Bson::Document(doc.clone()),
                                &Bson::Document(cursor.next().unwrap().unwrap())));
        }

        assert!(!cursor.has_next().ok().expect("Failed to execute 'has_next()' on cursor."));
    }};
}
<commit_msg>fixed mistaken error message<commit_after>macro_rules! run_find_test {
    ( $db:expr, $coll:expr, $filter:expr, $opt:expr, $outcome:expr ) => {{
        let mut cursor = $coll.find($filter, $opt).unwrap();

        let array = match $outcome.result {
            Bson::Array(ref arr) => arr.clone(),
            _ => panic!("Invalid `result` of find test")
        };

        for bson in array {
            assert!(eq::bson_eq(&bson, &Bson::Document(cursor.next().unwrap().unwrap())));
        }

        assert!(!cursor.has_next().ok().expect("Failed to execute 'has_next()' on cursor."));
        check_coll!($db, $coll, $outcome.collection);
    }};
}

macro_rules! run_insert_many_test {
    ( $db:expr, $coll: expr, $docs:expr, $outcome:expr ) => {{
        let inserted = $coll.insert_many($docs, true, None).unwrap().inserted_ids.unwrap();
        let ids_bson = match $outcome.result {
            Bson::Document(ref doc) => doc.get("insertedIds").unwrap(),
            _ => panic!("`insert_many` test result should be a document")
        };

        let ids = match ids_bson {
            &Bson::Array(ref arr) => arr.into_iter(),
            _ => panic!("`insertedIds` test result should be an array")
        };

        let mut actual_ids = inserted.values();

        for expected_id in ids {
            assert!(eq::bson_eq(&expected_id, actual_ids.next().unwrap()));
        }

        check_coll!($db, $coll, $outcome.collection);
    }};
}

macro_rules! run_insert_one_test {
    ( $db:expr, $coll: expr, $doc:expr, $outcome:expr ) => {{
        let inserted = $coll.insert_one($doc, None).unwrap().inserted_id.unwrap();
        let id = match $outcome.result {
            Bson::Document(ref doc) => doc.get("insertedId").unwrap(),
            _ => panic!("`insert_one` test result should be a document")
        };

        assert!(eq::bson_eq(&id, &inserted));
        check_coll!($db, $coll, $outcome.collection);
    }};
}

macro_rules! run_delete_test {
    ( $db:expr, $coll: expr, $filter:expr, $outcome:expr, $many:expr ) => {{
        let count = if $many {
                        $coll.delete_many($filter, None)
                    } else {
                        $coll.delete_one($filter, None)
                    };

        let expected = count.unwrap().deleted_count;

        let actual = match $outcome.result {
            Bson::Document(ref doc) => doc.get("deletedCount").unwrap(),
            _ => panic!("`delete` test result should be a document")
        };

        assert!(actual.int_eq(expected as i64));
        check_coll!($db, $coll, $outcome.collection);
    }};
}

macro_rules! run_update_test {
    ( $db:expr, $coll: expr, $filter:expr, $update:expr, $upsert:expr,
      $many:expr, $outcome:expr ) => {{
          let result = if $many {
                           $coll.update_many($filter, $update, $upsert, None)
                       } else {
                           $coll.update_one($filter, $update, $upsert, None)
                       };

          let actual = result.unwrap();

          let (matched, modified, upserted) = match $outcome.result {
              Bson::Document(ref doc) => (
                  doc.get("matchedCount").unwrap(),
                  doc.get("modifiedCount").unwrap(),
                  doc.get("upsertedId"),
              ),
              _ => panic!("`update` test result should be a document")
          };

          assert!(matched.int_eq(actual.matched_count as i64));
          assert!(modified.int_eq(actual.modified_count as i64));

          let id = match actual.upserted_id {
	          Some(Bson::Document(ref doc)) => doc.get("_id"),
              _ => None
          };

          match (upserted, id) {
              (None, None) => (),
              (Some(ref bson1), Some(ref bson2)) =>
                  assert!(eq::bson_eq(&bson1, &bson2)),
              _ => panic!("Wrong `upsertedId` returned")
          };

          check_coll!($db, $coll, $outcome.collection);
    }};
}

#[macro_export]
macro_rules! run_suite {
    ( $file:expr, $coll:expr ) => {{
        let json = Json::from_file($file).unwrap();
        let suite = json.get_suite().unwrap();
        let client =  MongoClient::new("localhost", 27017).unwrap();
        let db = client.db("test");
        let coll = db.collection($coll);

        for test in suite.tests {
            coll.drop().unwrap();
            coll.insert_many(suite.data.clone(), true, None).unwrap();

            match test.operation {
                Arguments::Delete { filter, many } =>
                    run_delete_test!(db, coll, filter, test.outcome, many),
                Arguments::Find { filter, options } =>
                    run_find_test!(db, coll, filter, Some(options), test.outcome),
                Arguments::InsertMany { documents } =>
                    run_insert_many_test!(db, coll, documents, test.outcome),
                Arguments::InsertOne { document } =>
                    run_insert_one_test!(db, coll, document, test.outcome),
                Arguments::Update { filter, update, upsert, many } =>
                    run_update_test!(db, coll, filter, update, upsert, many, test.outcome),
            };
        }
    }};
}

#[macro_export]
macro_rules! check_coll {
    ( $db:expr, $coll:expr, $coll_opt:expr ) => {{
        let outcome_coll = match $coll_opt {
            Some(ref coll) => coll.clone(),
            None => continue
        };

        let coll = match outcome_coll.name {
            Some(ref str) => $db.collection(&str),
            None => $db.collection(&$coll.name())
        };

        let mut cursor = coll.find(None, None).unwrap();

        for doc in outcome_coll.data.iter() {
            assert!(eq::bson_eq(&Bson::Document(doc.clone()),
                                &Bson::Document(cursor.next().unwrap().unwrap())));
        }

        assert!(!cursor.has_next().ok().expect("Failed to execute 'has_next()' on cursor."));
    }};
}
<|endoftext|>


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

use cssparser::Parser;
use media_queries::CSSErrorReporterTest;
use servo_url::ServoUrl;
use style::parser::ParserContext;
use style::stylesheets::Origin;
use style_traits::ToCss;
use style::properties::longhands;
use style::properties::longhands::{perspective_origin, transform_origin};

#[test]
fn test_clip() {
    use style::properties::longhands::clip;

    assert_roundtrip_with_context!(clip::parse, "auto");
    assert_roundtrip_with_context!(clip::parse, "rect(1px, 2px, 3px, 4px)");
    assert_roundtrip_with_context!(clip::parse, "rect(1px, auto, auto, 4px)");
    assert_roundtrip_with_context!(clip::parse, "rect(auto, auto, auto, auto)");

    // Non-standard syntax
    assert_roundtrip_with_context!(clip::parse,
                                   "rect(1px 2px 3px 4px)",
                                   "rect(1px, 2px, 3px, 4px)");
    assert_roundtrip_with_context!(clip::parse,
                                   "rect(auto 2px 3px auto)",
                                   "rect(auto, 2px, 3px, auto)");
    assert_roundtrip_with_context!(clip::parse,
                                   "rect(1px auto auto 4px)",
                                   "rect(1px, auto, auto, 4px)");
    assert_roundtrip_with_context!(clip::parse,
                                   "rect(auto auto auto auto)",
                                   "rect(auto, auto, auto, auto)");
}

#[test]
fn test_longhands_parse_origin() {
    let url = ServoUrl::parse("http://localhost").unwrap();
    let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest));

    let mut parser = Parser::new("1px some-rubbish");
    let parsed = longhands::parse_origin(&context, &mut parser);
    assert!(parsed.is_ok());
    assert_eq!(parser.is_exhausted(), false);

    let mut parser = Parser::new("1px 2px");
    let parsed = longhands::parse_origin(&context, &mut parser);
    assert!(parsed.is_ok());
    assert_eq!(parser.is_exhausted(), true);

    let mut parser = Parser::new("1px");
    let parsed = longhands::parse_origin(&context, &mut parser);
    assert!(parsed.is_ok());
    assert_eq!(parser.is_exhausted(), true);
}

#[test]
fn test_effects_parser_exhaustion() {
    assert_parser_exhausted!(perspective_origin, "1px 1px", true);
    assert_parser_exhausted!(transform_origin, "1px 1px", true);

    assert_parser_exhausted!(perspective_origin, "1px some-rubbish", false);
    assert_parser_exhausted!(transform_origin, "1px some-rubbish", false);
}
<commit_msg>rebase and fix tidiness lint<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use cssparser::Parser;
use media_queries::CSSErrorReporterTest;
use servo_url::ServoUrl;
use style::parser::ParserContext;
use style::properties::longhands::{self, perspective_origin, transform_origin};
use style::stylesheets::Origin;
use style_traits::ToCss;

#[test]
fn test_clip() {
    use style::properties::longhands::clip;

    assert_roundtrip_with_context!(clip::parse, "auto");
    assert_roundtrip_with_context!(clip::parse, "rect(1px, 2px, 3px, 4px)");
    assert_roundtrip_with_context!(clip::parse, "rect(1px, auto, auto, 4px)");
    assert_roundtrip_with_context!(clip::parse, "rect(auto, auto, auto, auto)");

    // Non-standard syntax
    assert_roundtrip_with_context!(clip::parse,
                                   "rect(1px 2px 3px 4px)",
                                   "rect(1px, 2px, 3px, 4px)");
    assert_roundtrip_with_context!(clip::parse,
                                   "rect(auto 2px 3px auto)",
                                   "rect(auto, 2px, 3px, auto)");
    assert_roundtrip_with_context!(clip::parse,
                                   "rect(1px auto auto 4px)",
                                   "rect(1px, auto, auto, 4px)");
    assert_roundtrip_with_context!(clip::parse,
                                   "rect(auto auto auto auto)",
                                   "rect(auto, auto, auto, auto)");
}

#[test]
fn test_longhands_parse_origin() {
    let url = ServoUrl::parse("http://localhost").unwrap();
    let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest));

    let mut parser = Parser::new("1px some-rubbish");
    let parsed = longhands::parse_origin(&context, &mut parser);
    assert!(parsed.is_ok());
    assert_eq!(parser.is_exhausted(), false);

    let mut parser = Parser::new("1px 2px");
    let parsed = longhands::parse_origin(&context, &mut parser);
    assert!(parsed.is_ok());
    assert_eq!(parser.is_exhausted(), true);

    let mut parser = Parser::new("1px");
    let parsed = longhands::parse_origin(&context, &mut parser);
    assert!(parsed.is_ok());
    assert_eq!(parser.is_exhausted(), true);
}

#[test]
fn test_effects_parser_exhaustion() {
    assert_parser_exhausted!(perspective_origin, "1px 1px", true);
    assert_parser_exhausted!(transform_origin, "1px 1px", true);

    assert_parser_exhausted!(perspective_origin, "1px some-rubbish", false);
    assert_parser_exhausted!(transform_origin, "1px some-rubbish", false);
}
<|endoftext|>


<commit_before>//since this is going to get included in examples that might not use everything, clear out warnings
//that are unnecessary
#![allow(dead_code)]

use std;
use std::io::{Write, Read};
use egg_mode;

//This is not an example that can be built with cargo! This is some helper code for the other
//examples so they can load access keys from the same place.

pub struct Config {
    pub con_token: egg_mode::Token<'static>,
    pub access_token: egg_mode::Token<'static>,
    pub user_id: i64,
    pub screen_name: String,
}

impl Config {
    pub fn load() -> Self {
        //IMPORTANT: make an app for yourself at apps.twitter.com and get your
        //key/secret into these files; these examples won't work without them
        let consumer_key = include_str!("consumer_key").trim();
        let consumer_secret = include_str!("consumer_secret").trim();

        let token = egg_mode::Token::new(consumer_key, consumer_secret);

        let mut config = String::new();
        let user_id: i64;
        let username: String;
        let access_token: egg_mode::Token;

        //look at all this unwrapping! who told you it was my birthday?
        if let Ok(mut f) = std::fs::File::open("twitter_settings") {
            f.read_to_string(&mut config).unwrap();

            let mut iter = config.split('\n');

            username = iter.next().unwrap().to_string();
            user_id = i64::from_str_radix(&iter.next().unwrap(), 10).unwrap();
            access_token = egg_mode::Token::new(iter.next().unwrap().to_string(),
                                                     iter.next().unwrap().to_string());

            if let Err(err) = egg_mode::verify_tokens(&token, &access_token) {
                println!("We've hit an error using your old tokens: {:?}", err);
                println!("We'll have to reauthenticate before continuing.");
                std::fs::remove_file("twitter_settings").unwrap();
            }
            else {
                println!("Welcome back, {}!", username);
            }
        }
        else {
            let request_token = egg_mode::request_token(&token, "oob").unwrap();

            println!("Go to the following URL, sign in, and give me the PIN that comes back:");
            println!("{}", egg_mode::authorize_url(&request_token));

            let mut pin = String::new();
            std::io::stdin().read_line(&mut pin).unwrap();
            println!("");

            let tok_result = egg_mode::access_token(&token, &request_token, pin).unwrap();

            access_token = tok_result.0;
            user_id = tok_result.1;
            username = tok_result.2;

            config.push_str(&username);
            config.push('\n');
            config.push_str(&format!("{}", user_id));
            config.push('\n');
            config.push_str(&access_token.key);
            config.push('\n');
            config.push_str(&access_token.secret);

            let mut f = std::fs::File::create("twitter_settings").unwrap();
            f.write_all(config.as_bytes()).unwrap();

            println!("Welcome, {}, let's get this show on the road!", username);
        }

        //TODO: Is there a better way to query whether a file exists?
        if std::fs::metadata("twitter_settings").is_ok() {
            Config {
                con_token: token,
                access_token: access_token,
                user_id: user_id,
                screen_name: username,
            }
        }
        else {
            Self::load()
        }
    }
}

pub fn print_tweet(tweet: &egg_mode::tweet::Tweet) {
    println!("{} (@{}) posted at {}", tweet.user.name, tweet.user.screen_name, tweet.created_at);

    if let Some(ref screen_name) = tweet.in_reply_to_screen_name {
        println!("--> in reply to @{}", screen_name);
    }

    println!("{}", tweet.text);

    if let Some(ref status) = tweet.quoted_status {
        println!("--Quoting the following status:");
        print_tweet(status);
    }

    if !tweet.entities.hashtags.is_empty() {
        println!("Hashtags contained in the tweet:");
        for tag in &tweet.entities.hashtags {
            println!("{}", tag.text);
        }
    }

    if !tweet.entities.symbols.is_empty() {
        println!("Symbols contained in the tweet:");
        for tag in &tweet.entities.symbols {
            println!("{}", tag.text);
        }
    }

    if !tweet.entities.urls.is_empty() {
        println!("URLs contained in the tweet:");
        for url in &tweet.entities.urls {
            println!("{}", url.expanded_url);
        }
    }

    if !tweet.entities.user_mentions.is_empty() {
        println!("Users mentioned in the tweet:");
        for user in &tweet.entities.user_mentions {
            println!("{}", user.screen_name);
        }
    }

    if let Some(ref media) = tweet.extended_entities {
        println!("Media attached to the tweet:");
        for info in &media.media {
            println!("A {:?}", info.media_type);
        }
    }
}
<commit_msg>update examples/common's print_tweet to handle retweets better<commit_after>//since this is going to get included in examples that might not use everything, clear out warnings
//that are unnecessary
#![allow(dead_code)]

use std;
use std::io::{Write, Read};
use egg_mode;

//This is not an example that can be built with cargo! This is some helper code for the other
//examples so they can load access keys from the same place.

pub struct Config {
    pub con_token: egg_mode::Token<'static>,
    pub access_token: egg_mode::Token<'static>,
    pub user_id: i64,
    pub screen_name: String,
}

impl Config {
    pub fn load() -> Self {
        //IMPORTANT: make an app for yourself at apps.twitter.com and get your
        //key/secret into these files; these examples won't work without them
        let consumer_key = include_str!("consumer_key").trim();
        let consumer_secret = include_str!("consumer_secret").trim();

        let token = egg_mode::Token::new(consumer_key, consumer_secret);

        let mut config = String::new();
        let user_id: i64;
        let username: String;
        let access_token: egg_mode::Token;

        //look at all this unwrapping! who told you it was my birthday?
        if let Ok(mut f) = std::fs::File::open("twitter_settings") {
            f.read_to_string(&mut config).unwrap();

            let mut iter = config.split('\n');

            username = iter.next().unwrap().to_string();
            user_id = i64::from_str_radix(&iter.next().unwrap(), 10).unwrap();
            access_token = egg_mode::Token::new(iter.next().unwrap().to_string(),
                                                     iter.next().unwrap().to_string());

            if let Err(err) = egg_mode::verify_tokens(&token, &access_token) {
                println!("We've hit an error using your old tokens: {:?}", err);
                println!("We'll have to reauthenticate before continuing.");
                std::fs::remove_file("twitter_settings").unwrap();
            }
            else {
                println!("Welcome back, {}!", username);
            }
        }
        else {
            let request_token = egg_mode::request_token(&token, "oob").unwrap();

            println!("Go to the following URL, sign in, and give me the PIN that comes back:");
            println!("{}", egg_mode::authorize_url(&request_token));

            let mut pin = String::new();
            std::io::stdin().read_line(&mut pin).unwrap();
            println!("");

            let tok_result = egg_mode::access_token(&token, &request_token, pin).unwrap();

            access_token = tok_result.0;
            user_id = tok_result.1;
            username = tok_result.2;

            config.push_str(&username);
            config.push('\n');
            config.push_str(&format!("{}", user_id));
            config.push('\n');
            config.push_str(&access_token.key);
            config.push('\n');
            config.push_str(&access_token.secret);

            let mut f = std::fs::File::create("twitter_settings").unwrap();
            f.write_all(config.as_bytes()).unwrap();

            println!("Welcome, {}, let's get this show on the road!", username);
        }

        //TODO: Is there a better way to query whether a file exists?
        if std::fs::metadata("twitter_settings").is_ok() {
            Config {
                con_token: token,
                access_token: access_token,
                user_id: user_id,
                screen_name: username,
            }
        }
        else {
            Self::load()
        }
    }
}

pub fn print_tweet(tweet: &egg_mode::tweet::Tweet) {
    println!("{} (@{}) posted at {}", tweet.user.name, tweet.user.screen_name, tweet.created_at);

    if let Some(ref screen_name) = tweet.in_reply_to_screen_name {
        println!("--> in reply to @{}", screen_name);
    }

    if let Some(ref status) = tweet.retweeted_status {
        println!("Retweeted from {}:", status.user.name);
        print_tweet(status);
        return;
    }
    else {
        println!("{}", tweet.text);
    }

    if let Some(ref status) = tweet.quoted_status {
        println!("--Quoting the following status:");
        print_tweet(status);
    }

    if !tweet.entities.hashtags.is_empty() {
        println!("Hashtags contained in the tweet:");
        for tag in &tweet.entities.hashtags {
            println!("{}", tag.text);
        }
    }

    if !tweet.entities.symbols.is_empty() {
        println!("Symbols contained in the tweet:");
        for tag in &tweet.entities.symbols {
            println!("{}", tag.text);
        }
    }

    if !tweet.entities.urls.is_empty() {
        println!("URLs contained in the tweet:");
        for url in &tweet.entities.urls {
            println!("{}", url.expanded_url);
        }
    }

    if !tweet.entities.user_mentions.is_empty() {
        println!("Users mentioned in the tweet:");
        for user in &tweet.entities.user_mentions {
            println!("{}", user.screen_name);
        }
    }

    if let Some(ref media) = tweet.extended_entities {
        println!("Media attached to the tweet:");
        for info in &media.media {
            println!("A {:?}", info.media_type);
        }
    }
}
<|endoftext|>


<commit_before>#![feature(plugin, custom_attribute)]
#![plugin(gfx_macros)]

extern crate cgmath;
extern crate glutin;
extern crate gfx;
extern crate gfx_device_gl;
extern crate gfx_phase;

use cgmath::{Matrix, Matrix4, Point3, Vector3, vec3};
use cgmath::{FixedArray, Transform, AffineMatrix3};
use gfx::traits::*;
use gfx_phase::AbstractPhase;

#[vertex_format]
#[derive(Copy)]
struct Vertex {
    #[as_float]
    #[name = "a_Pos"]
    pos: [i8; 3],
}

impl Vertex {
    fn new(x: i8, y: i8, z: i8) -> Vertex {
        Vertex {
            pos: [x, y, z],
        }
    }
}

// The shader_param attribute makes sure the following struct can be used to
// pass parameters to a shader.
#[shader_param]
struct Params<R: gfx::Resources> {
    transform: [[f32; 4]; 4],
    color: [f32; 4],
    _dummy: std::marker::PhantomData<R>,
}

static VERTEX_SRC: &'static [u8] = b"
    #version 120
    attribute vec3 a_Pos;
    uniform mat4 transform;
    void main() {
        gl_Position = transform * vec4(a_Pos, 1.0);
    }
";

static FRAGMENT_SRC: &'static [u8] = b"
    #version 120
    uniform vec4 color;
    void main() {
        gl_FragColor = color;
    }
";

// Defining the technique, material, and entity

struct Technique<R: gfx::Resources> {
    program: gfx::ProgramHandle<R>,
    state_opaque: gfx::DrawState,
    state_transparent: gfx::DrawState,
}

impl<R: gfx::Resources> Technique<R> {
    pub fn new<F: Factory<R>>(factory: &mut F) -> Technique<R> {
        let program = factory.link_program(VERTEX_SRC, FRAGMENT_SRC).unwrap();
        //let opaque = gfx::DrawState::new().depth(gfx::state::Comparison::LessEqual, true);
        let opaque = gfx::DrawState::new();
        let transparent = opaque.clone().blend(gfx::BlendPreset::Alpha);
        Technique {
            program: program,
            state_opaque: opaque,
            state_transparent: transparent,
        }
    }
}

struct Material {
    alpha: f32,
}

impl gfx_phase::Material for Material {}

#[derive(Copy)]
struct SpaceData(cgmath::Matrix4<f32>);

impl gfx_phase::ToDepth for SpaceData {
    type Depth = f32;
    fn to_depth(&self) -> f32 {0.0}
}

impl<R: gfx::Resources> gfx_phase::Technique<R, Material, SpaceData>
for Technique<R> {
    type Params = Params<R>;

    fn does_apply(&self, _mesh: &gfx::Mesh<R>, _mat: &Material) -> bool { true }

    fn compile<'a>(&'a self, _mesh: &gfx::Mesh<R>, mat: &Material, space: SpaceData)
                   -> gfx_phase::TechResult<'a, R, Params<R>> {
        (   &self.program,
            Params {
                transform: space.0.into_fixed(),
                color: [0.4, 0.5, 0.6, mat.alpha],
                _dummy: std::marker::PhantomData,
            },
            None,
            if mat.alpha < 1.0 {&self.state_transparent} else {&self.state_opaque},
        )
    }

    fn fix_params(&self, mat: &Material, space: &SpaceData, params: &mut Params<R>) {
        params.transform = *space.0.as_fixed();
        params.color[3] = mat.alpha;
    }
}

struct Entity<R: gfx::Resources> {
    mesh: gfx::Mesh<R>,
    slice: gfx::Slice<R>,
    material: Material,
}

impl<R: gfx::Resources> gfx_phase::Entity<R, Material> for Entity<R> {
    fn get_material(&self) -> &Material { &self.material }
    fn get_mesh(&self) -> (&gfx::Mesh<R>, &gfx::Slice<R>) { (&self.mesh, &self.slice) }
}

//----------------------------------------

fn main() {
    let window = glutin::Window::new().unwrap();
    window.set_title("glutin initialization example");
    unsafe { window.make_current() };
    let (w, h) = window.get_inner_size().unwrap();
    let frame = gfx::Frame::new(w as u16, h as u16);

    let mut device = gfx_device_gl::GlDevice::new(|s| window.get_proc_address(s));
    let mut renderer = device.create_renderer();
    let mut context = gfx::batch::Context::new();

    let vertex_data = [
        Vertex::new(-1, -1, -1),
        Vertex::new(0, 1, -1),
        Vertex::new(1, 0, -1),
        Vertex::new(0, 0, 2),
    ];

    let mesh = device.create_mesh(&vertex_data);

    let index_data: &[u8] = &[
        0, 1, 2,
        0, 3, 1,
        1, 3, 2,
        2, 3, 0,
    ];

    let slice = device
        .create_buffer_static(index_data)
        .to_slice(gfx::PrimitiveType::TriangleList);

    let entities: Vec<_> = (0..10).map(|i| Entity {
        mesh: mesh.clone(),
        slice: slice.clone(),
        material: Material { alpha: i as f32 / 10.0 },
    }).collect();

    let mut phase = gfx_phase::Phase::new(
        "Main",
        Technique::new(&mut device),
        gfx_phase::Sort::DrawState
    );

    let aspect = w as f32 / h as f32;
    let proj = cgmath::perspective(cgmath::deg(90.0f32), aspect, 1.0, 10.0);
    let view: AffineMatrix3<f32> = Transform::look_at(
        &Point3::new(1.5f32, -5.0, 3.0),
        &Point3::new(0f32, 0.0, 0.0),
        &Vector3::unit_z(),
    );
    let proj_view = proj.mul_m(&view.mat);

    let clear_data = gfx::ClearData {
        color: [0.3, 0.3, 0.3, 1.0],
        depth: 1.0,
        stencil: 0,
    };

    'main: loop {
        // quit when Esc is pressed.
        for event in window.poll_events() {
            match event {
                glutin::Event::KeyboardInput(_, _, Some(glutin::VirtualKeyCode::Escape)) => break 'main,
                glutin::Event::Closed => break 'main,
                _ => {},
            }
        }

        renderer.reset();
        renderer.clear(clear_data, gfx::COLOR | gfx::DEPTH, &frame);

        // somehow, rust doesn't see the namespace... why?
        let p: &mut gfx_phase::AbstractPhase<gfx_device_gl::GlDevice, _, _> = &mut phase;

        for ent in entities.iter() {
            let model = Matrix4::from_translation(&vec3(ent.material.alpha*16.0 - 8.0, 0.0, 0.0));
            let space_data = SpaceData(proj_view.mul_m(&model));
            p.enqueue(ent, space_data, &mut context).unwrap();
        }
        p.flush(&frame, &mut context, &mut renderer).unwrap();

        device.submit(renderer.as_buffer());
        window.swap_buffers();
        device.after_frame();
    }
}
<commit_msg>Changed tetrahedra pattern to be a circle<commit_after>#![feature(plugin, custom_attribute)]
#![plugin(gfx_macros)]

extern crate cgmath;
extern crate glutin;
extern crate gfx;
extern crate gfx_device_gl;
extern crate gfx_phase;

use cgmath::{Matrix, Matrix4, Point3, Vector3, vec3};
use cgmath::{FixedArray, Transform, AffineMatrix3};
use gfx::traits::*;
use gfx_phase::AbstractPhase;

#[vertex_format]
#[derive(Copy)]
struct Vertex {
    #[as_float]
    #[name = "a_Pos"]
    pos: [i8; 3],
}

impl Vertex {
    fn new(x: i8, y: i8, z: i8) -> Vertex {
        Vertex {
            pos: [x, y, z],
        }
    }
}

// The shader_param attribute makes sure the following struct can be used to
// pass parameters to a shader.
#[shader_param]
struct Params<R: gfx::Resources> {
    transform: [[f32; 4]; 4],
    color: [f32; 4],
    _dummy: std::marker::PhantomData<R>,
}

static VERTEX_SRC: &'static [u8] = b"
    #version 120
    attribute vec3 a_Pos;
    uniform mat4 transform;
    void main() {
        gl_Position = transform * vec4(a_Pos, 1.0);
    }
";

static FRAGMENT_SRC: &'static [u8] = b"
    #version 120
    uniform vec4 color;
    void main() {
        gl_FragColor = color;
    }
";

// Defining the technique, material, and entity

struct Technique<R: gfx::Resources> {
    program: gfx::ProgramHandle<R>,
    state_opaque: gfx::DrawState,
    state_transparent: gfx::DrawState,
}

impl<R: gfx::Resources> Technique<R> {
    pub fn new<F: Factory<R>>(factory: &mut F) -> Technique<R> {
        let program = factory.link_program(VERTEX_SRC, FRAGMENT_SRC).unwrap();
        //let opaque = gfx::DrawState::new().depth(gfx::state::Comparison::LessEqual, true);
        let opaque = gfx::DrawState::new();
        let transparent = opaque.clone().blend(gfx::BlendPreset::Alpha);
        Technique {
            program: program,
            state_opaque: opaque,
            state_transparent: transparent,
        }
    }
}

struct Material {
    alpha: f32,
}

impl gfx_phase::Material for Material {}

#[derive(Copy)]
struct SpaceData(cgmath::Matrix4<f32>);

impl gfx_phase::ToDepth for SpaceData {
    type Depth = f32;
    fn to_depth(&self) -> f32 {0.0}
}

impl<R: gfx::Resources> gfx_phase::Technique<R, Material, SpaceData>
for Technique<R> {
    type Params = Params<R>;

    fn does_apply(&self, _mesh: &gfx::Mesh<R>, _mat: &Material) -> bool { true }

    fn compile<'a>(&'a self, _mesh: &gfx::Mesh<R>, mat: &Material, space: SpaceData)
                   -> gfx_phase::TechResult<'a, R, Params<R>> {
        (   &self.program,
            Params {
                transform: space.0.into_fixed(),
                color: [0.4, 0.5, 0.6, mat.alpha],
                _dummy: std::marker::PhantomData,
            },
            None,
            if mat.alpha < 1.0 {&self.state_transparent} else {&self.state_opaque},
        )
    }

    fn fix_params(&self, mat: &Material, space: &SpaceData, params: &mut Params<R>) {
        params.transform = *space.0.as_fixed();
        params.color[3] = mat.alpha;
    }
}

struct Entity<R: gfx::Resources> {
    mesh: gfx::Mesh<R>,
    slice: gfx::Slice<R>,
    material: Material,
}

impl<R: gfx::Resources> gfx_phase::Entity<R, Material> for Entity<R> {
    fn get_material(&self) -> &Material { &self.material }
    fn get_mesh(&self) -> (&gfx::Mesh<R>, &gfx::Slice<R>) { (&self.mesh, &self.slice) }
}

//----------------------------------------

fn main() {
    let window = glutin::Window::new().unwrap();
    window.set_title("glutin initialization example");
    unsafe { window.make_current() };
    let (w, h) = window.get_inner_size().unwrap();
    let frame = gfx::Frame::new(w as u16, h as u16);

    let mut device = gfx_device_gl::GlDevice::new(|s| window.get_proc_address(s));
    let mut renderer = device.create_renderer();
    let mut context = gfx::batch::Context::new();

    let vertex_data = [
        Vertex::new(-1, -1, -1),
        Vertex::new(0, 2, -1),
        Vertex::new(2, 0, -1),
        Vertex::new(0, 0, 2),
    ];

    let mesh = device.create_mesh(&vertex_data);

    let index_data: &[u8] = &[
        0, 1, 2,
        0, 3, 1,
        1, 3, 2,
        2, 3, 0,
    ];

    let slice = device
        .create_buffer_static(index_data)
        .to_slice(gfx::PrimitiveType::TriangleList);

    let entities: Vec<_> = (0..10).map(|i| Entity {
        mesh: mesh.clone(),
        slice: slice.clone(),
        material: Material { alpha: i as f32 / 10.0 },
    }).collect();

    let mut phase = gfx_phase::Phase::new(
        "Main",
        Technique::new(&mut device),
        gfx_phase::Sort::DrawState
    );

    let aspect = w as f32 / h as f32;
    let proj = cgmath::perspective(cgmath::deg(90.0f32), aspect, 1.0, 10.0);
    let view: AffineMatrix3<f32> = Transform::look_at(
        &Point3::new(1.5f32, -5.0, 3.0),
        &Point3::new(0f32, 0.0, 0.0),
        &Vector3::unit_z(),
    );
    let proj_view = proj.mul_m(&view.mat);

    let clear_data = gfx::ClearData {
        color: [0.3, 0.3, 0.3, 1.0],
        depth: 1.0,
        stencil: 0,
    };

    'main: loop {
        // quit when Esc is pressed.
        for event in window.poll_events() {
            match event {
                glutin::Event::KeyboardInput(_, _, Some(glutin::VirtualKeyCode::Escape)) => break 'main,
                glutin::Event::Closed => break 'main,
                _ => {},
            }
        }

        renderer.reset();
        renderer.clear(clear_data, gfx::COLOR | gfx::DEPTH, &frame);

        // somehow, rust doesn't see the namespace... why?
        let p: &mut gfx_phase::AbstractPhase<gfx_device_gl::GlDevice, _, _> = &mut phase;

        for ent in entities.iter() {
            use std::num::Float;
            let angle = ent.material.alpha * std::f32::consts::PI * 2.0;
            let model = Matrix4::from_translation(&vec3(
                3.0 * angle.cos(), 0.0, 3.0 * angle.sin()
            ));
            let space_data = SpaceData(proj_view.mul_m(&model));
            p.enqueue(ent, space_data, &mut context).unwrap();
        }
        p.flush(&frame, &mut context, &mut renderer).unwrap();

        device.submit(renderer.as_buffer());
        window.swap_buffers();
        device.after_frame();
    }
}
<|endoftext|>


<commit_before>use crate::protobuf_ident::ProtobufIdent;
use crate::ProtobufRelativePath;
use std::fmt;
use std::ops::Deref;

#[derive(Clone, Eq, PartialEq, Debug, Hash)]
pub struct ProtobufAbsolutePath {
    pub path: String,
}

impl Default for ProtobufAbsolutePath {
    fn default() -> ProtobufAbsolutePath {
        ProtobufAbsolutePath::root()
    }
}

impl Deref for ProtobufAbsolutePath {
    type Target = str;

    fn deref(&self) -> &str {
        &self.path
    }
}

impl ProtobufAbsolutePath {
    pub fn root() -> ProtobufAbsolutePath {
        ProtobufAbsolutePath::new(String::new())
    }

    /// If given name is an fully quialified protobuf name.
    pub fn is_abs(path: &str) -> bool {
        path.is_empty() || path.starts_with(".")
    }

    pub fn new<S: Into<String>>(path: S) -> ProtobufAbsolutePath {
        let path = path.into();
        assert!(
            ProtobufAbsolutePath::is_abs(&path),
            "path is not absolute: `{}`",
            path
        );
        assert!(!path.ends_with("."), path);
        ProtobufAbsolutePath { path }
    }

    pub fn concat(mut a: ProtobufAbsolutePath, b: ProtobufRelativePath) -> ProtobufAbsolutePath {
        a.push_relative(&b.into());
        a
    }

    pub fn is_root(&self) -> bool {
        self.path.is_empty()
    }

    pub fn from_path_without_dot(path: &str) -> ProtobufAbsolutePath {
        assert!(!path.is_empty());
        assert!(!path.starts_with("."));
        assert!(!path.ends_with("."));
        ProtobufAbsolutePath::new(format!(".{}", path))
    }

    pub fn from_path_maybe_dot(path: &str) -> ProtobufAbsolutePath {
        if path.starts_with(".") {
            ProtobufAbsolutePath::new(path.to_owned())
        } else {
            ProtobufAbsolutePath::from_path_without_dot(path)
        }
    }

    pub fn push_simple(&mut self, simple: ProtobufIdent) {
        self.path.push('.');
        self.path.push_str(simple.get());
    }

    pub fn push_relative(&mut self, relative: &ProtobufRelativePath) {
        if !relative.is_empty() {
            self.path.push('.');
            self.path.push_str(&format!("{}", relative));
        }
    }

    pub fn remove_prefix(&self, prefix: &ProtobufAbsolutePath) -> Option<ProtobufRelativePath> {
        if self.path.starts_with(&prefix.path) {
            let rem = &self.path[prefix.path.len()..];
            if rem.is_empty() {
                return Some(ProtobufRelativePath::empty());
            }
            if rem.starts_with('.') {
                return Some(ProtobufRelativePath::new(rem[1..].to_owned()));
            }
        }
        None
    }

    pub fn parent(&self) -> Option<ProtobufAbsolutePath> {
        match self.path.rfind('.') {
            Some(pos) => Some(ProtobufAbsolutePath::new(self.path[..pos].to_owned())),
            None => {
                if self.path.is_empty() {
                    None
                } else {
                    Some(ProtobufAbsolutePath::root())
                }
            }
        }
    }

    /// Pop the last name component
    pub fn pop(&mut self) -> Option<ProtobufIdent> {
        match self.path.rfind('.') {
            Some(dot) => {
                let ident = ProtobufIdent::new(&self.path[dot + 1..]);
                self.path.truncate(dot);
                Some(ident)
            }
            None => None,
        }
    }

    pub fn self_and_parents(&self) -> Vec<ProtobufAbsolutePath> {
        let mut tmp = self.clone();

        let mut r = Vec::new();

        r.push(self.clone());

        while let Some(parent) = tmp.parent() {
            r.push(parent.clone());
            tmp = parent;
        }

        r
    }

    pub fn to_root_rel(&self) -> ProtobufRelativePath {
        if self == &Self::root() {
            ProtobufRelativePath::empty()
        } else {
            ProtobufRelativePath::new(&self.path[1..])
        }
    }

    pub fn starts_with(&self, that: &ProtobufAbsolutePath) -> bool {
        self.remove_prefix(that).is_some()
    }
}

impl From<&'_ str> for ProtobufAbsolutePath {
    fn from(s: &str) -> Self {
        ProtobufAbsolutePath::new(s.to_owned())
    }
}

impl From<String> for ProtobufAbsolutePath {
    fn from(s: String) -> Self {
        ProtobufAbsolutePath::new(s)
    }
}

impl fmt::Display for ProtobufAbsolutePath {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.path, f)
    }
}

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

    #[test]
    fn absolute_path_push_simple() {
        let mut foo = ProtobufAbsolutePath::new(".foo".to_owned());
        foo.push_simple(ProtobufIdent::from("bar"));
        assert_eq!(ProtobufAbsolutePath::new(".foo.bar".to_owned()), foo);

        let mut foo = ProtobufAbsolutePath::root();
        foo.push_simple(ProtobufIdent::from("bar"));
        assert_eq!(ProtobufAbsolutePath::new(".bar".to_owned()), foo);
    }

    #[test]
    fn absolute_path_remove_prefix() {
        assert_eq!(
            Some(ProtobufRelativePath::empty()),
            ProtobufAbsolutePath::new(".foo".to_owned())
                .remove_prefix(&ProtobufAbsolutePath::new(".foo".to_owned()))
        );
        assert_eq!(
            Some(ProtobufRelativePath::new("bar".to_owned())),
            ProtobufAbsolutePath::new(".foo.bar".to_owned())
                .remove_prefix(&ProtobufAbsolutePath::new(".foo".to_owned()))
        );
        assert_eq!(
            Some(ProtobufRelativePath::new("baz.qux".to_owned())),
            ProtobufAbsolutePath::new(".foo.bar.baz.qux".to_owned())
                .remove_prefix(&ProtobufAbsolutePath::new(".foo.bar".to_owned()))
        );
        assert_eq!(
            None,
            ProtobufAbsolutePath::new(".foo.barbaz".to_owned())
                .remove_prefix(&ProtobufAbsolutePath::new(".foo.bar".to_owned()))
        );
    }

    #[test]
    fn self_and_parents() {
        assert_eq!(
            vec![
                ProtobufAbsolutePath::new(".ab.cde.fghi".to_owned()),
                ProtobufAbsolutePath::new(".ab.cde".to_owned()),
                ProtobufAbsolutePath::new(".ab".to_owned()),
                ProtobufAbsolutePath::root(),
            ],
            ProtobufAbsolutePath::new(".ab.cde.fghi".to_owned()).self_and_parents()
        );
    }
}
<commit_msg>Compat with Rust 2021<commit_after>use crate::protobuf_ident::ProtobufIdent;
use crate::ProtobufRelativePath;
use std::fmt;
use std::ops::Deref;

#[derive(Clone, Eq, PartialEq, Debug, Hash)]
pub struct ProtobufAbsolutePath {
    pub path: String,
}

impl Default for ProtobufAbsolutePath {
    fn default() -> ProtobufAbsolutePath {
        ProtobufAbsolutePath::root()
    }
}

impl Deref for ProtobufAbsolutePath {
    type Target = str;

    fn deref(&self) -> &str {
        &self.path
    }
}

impl ProtobufAbsolutePath {
    pub fn root() -> ProtobufAbsolutePath {
        ProtobufAbsolutePath::new(String::new())
    }

    /// If given name is an fully quialified protobuf name.
    pub fn is_abs(path: &str) -> bool {
        path.is_empty() || path.starts_with(".")
    }

    pub fn new<S: Into<String>>(path: S) -> ProtobufAbsolutePath {
        let path = path.into();
        assert!(
            ProtobufAbsolutePath::is_abs(&path),
            "path is not absolute: `{}`",
            path
        );
        assert!(!path.ends_with("."), "{}", path);
        ProtobufAbsolutePath { path }
    }

    pub fn concat(mut a: ProtobufAbsolutePath, b: ProtobufRelativePath) -> ProtobufAbsolutePath {
        a.push_relative(&b.into());
        a
    }

    pub fn is_root(&self) -> bool {
        self.path.is_empty()
    }

    pub fn from_path_without_dot(path: &str) -> ProtobufAbsolutePath {
        assert!(!path.is_empty());
        assert!(!path.starts_with("."));
        assert!(!path.ends_with("."));
        ProtobufAbsolutePath::new(format!(".{}", path))
    }

    pub fn from_path_maybe_dot(path: &str) -> ProtobufAbsolutePath {
        if path.starts_with(".") {
            ProtobufAbsolutePath::new(path.to_owned())
        } else {
            ProtobufAbsolutePath::from_path_without_dot(path)
        }
    }

    pub fn push_simple(&mut self, simple: ProtobufIdent) {
        self.path.push('.');
        self.path.push_str(simple.get());
    }

    pub fn push_relative(&mut self, relative: &ProtobufRelativePath) {
        if !relative.is_empty() {
            self.path.push('.');
            self.path.push_str(&format!("{}", relative));
        }
    }

    pub fn remove_prefix(&self, prefix: &ProtobufAbsolutePath) -> Option<ProtobufRelativePath> {
        if self.path.starts_with(&prefix.path) {
            let rem = &self.path[prefix.path.len()..];
            if rem.is_empty() {
                return Some(ProtobufRelativePath::empty());
            }
            if rem.starts_with('.') {
                return Some(ProtobufRelativePath::new(rem[1..].to_owned()));
            }
        }
        None
    }

    pub fn parent(&self) -> Option<ProtobufAbsolutePath> {
        match self.path.rfind('.') {
            Some(pos) => Some(ProtobufAbsolutePath::new(self.path[..pos].to_owned())),
            None => {
                if self.path.is_empty() {
                    None
                } else {
                    Some(ProtobufAbsolutePath::root())
                }
            }
        }
    }

    /// Pop the last name component
    pub fn pop(&mut self) -> Option<ProtobufIdent> {
        match self.path.rfind('.') {
            Some(dot) => {
                let ident = ProtobufIdent::new(&self.path[dot + 1..]);
                self.path.truncate(dot);
                Some(ident)
            }
            None => None,
        }
    }

    pub fn self_and_parents(&self) -> Vec<ProtobufAbsolutePath> {
        let mut tmp = self.clone();

        let mut r = Vec::new();

        r.push(self.clone());

        while let Some(parent) = tmp.parent() {
            r.push(parent.clone());
            tmp = parent;
        }

        r
    }

    pub fn to_root_rel(&self) -> ProtobufRelativePath {
        if self == &Self::root() {
            ProtobufRelativePath::empty()
        } else {
            ProtobufRelativePath::new(&self.path[1..])
        }
    }

    pub fn starts_with(&self, that: &ProtobufAbsolutePath) -> bool {
        self.remove_prefix(that).is_some()
    }
}

impl From<&'_ str> for ProtobufAbsolutePath {
    fn from(s: &str) -> Self {
        ProtobufAbsolutePath::new(s.to_owned())
    }
}

impl From<String> for ProtobufAbsolutePath {
    fn from(s: String) -> Self {
        ProtobufAbsolutePath::new(s)
    }
}

impl fmt::Display for ProtobufAbsolutePath {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.path, f)
    }
}

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

    #[test]
    fn absolute_path_push_simple() {
        let mut foo = ProtobufAbsolutePath::new(".foo".to_owned());
        foo.push_simple(ProtobufIdent::from("bar"));
        assert_eq!(ProtobufAbsolutePath::new(".foo.bar".to_owned()), foo);

        let mut foo = ProtobufAbsolutePath::root();
        foo.push_simple(ProtobufIdent::from("bar"));
        assert_eq!(ProtobufAbsolutePath::new(".bar".to_owned()), foo);
    }

    #[test]
    fn absolute_path_remove_prefix() {
        assert_eq!(
            Some(ProtobufRelativePath::empty()),
            ProtobufAbsolutePath::new(".foo".to_owned())
                .remove_prefix(&ProtobufAbsolutePath::new(".foo".to_owned()))
        );
        assert_eq!(
            Some(ProtobufRelativePath::new("bar".to_owned())),
            ProtobufAbsolutePath::new(".foo.bar".to_owned())
                .remove_prefix(&ProtobufAbsolutePath::new(".foo".to_owned()))
        );
        assert_eq!(
            Some(ProtobufRelativePath::new("baz.qux".to_owned())),
            ProtobufAbsolutePath::new(".foo.bar.baz.qux".to_owned())
                .remove_prefix(&ProtobufAbsolutePath::new(".foo.bar".to_owned()))
        );
        assert_eq!(
            None,
            ProtobufAbsolutePath::new(".foo.barbaz".to_owned())
                .remove_prefix(&ProtobufAbsolutePath::new(".foo.bar".to_owned()))
        );
    }

    #[test]
    fn self_and_parents() {
        assert_eq!(
            vec![
                ProtobufAbsolutePath::new(".ab.cde.fghi".to_owned()),
                ProtobufAbsolutePath::new(".ab.cde".to_owned()),
                ProtobufAbsolutePath::new(".ab".to_owned()),
                ProtobufAbsolutePath::root(),
            ],
            ProtobufAbsolutePath::new(".ab.cde.fghi".to_owned()).self_and_parents()
        );
    }
}
<|endoftext|>