<commit_before>use protobuf::descriptor;
use protobuf::reflect;
use protobuf::CodedInputStream;
use protobuf::CodedOutputStream;
use protobuf::Message;
use protobuf::ProtobufEnum;
use protobuf_test_common::hex::decode_hex;
use protobuf_test_common::*;

use super::test_basic_pb::*;

#[test]
fn test1() {
    let mut test1 = Test1::new();
    test1.set_a(150);
    test_serialize_deserialize_with_dynamic("08 96 01", &test1);
}

#[test]
fn test2() {
    let mut test2 = Test2::new();
    test2.set_b("testing".to_string());
    test_serialize_deserialize_with_dynamic("12 07 74 65 73 74 69 6e 67", &test2);
}

#[test]
fn test3() {
    let mut test1 = Test1::new();
    test1.set_a(150);
    let mut test3 = Test3::new();
    test3.set_c(test1);
    test_serialize_deserialize_with_dynamic("1a 03 08 96 01", &test3);
}

#[test]
fn test4() {
    let mut test4 = Test4::new();
    test4.set_d([3i32, 270, 86942].to_vec());
    test_serialize_deserialize_with_dynamic("22 06 03 8E 02 9E A7 05", &test4);
}

#[test]
fn test_recursion_limit() {
    let mut test = TestRecursion::new();
    for _ in 0..10 {
        let mut t = TestRecursion::new();
        t.mut_children().push(test);
        test = t;
    }

    let bytes = test.write_to_bytes().unwrap();
    let cases = vec![(None, false), (Some(9), true), (Some(10), false)];

    for (limit, has_err) in cases {
        let mut is = CodedInputStream::from_bytes(&bytes);
        if let Some(limit) = limit {
            is.set_recursion_limit(limit);
        }
        let mut t = TestRecursion::new();
        let res = t.merge_from(&mut is);
        assert_eq!(res.is_err(), has_err, "limit: {:?}", limit);
        if !has_err {
            assert_eq!(t, test, "limit: {:?}", limit);
        }
    }
}

#[test]
fn test_end_by_negative_int() {
    // added following https://github.com/stepancheg/rust-protobuf/pull/209
    let mut test = Test1::new();
    test.set_a(-1);
    test_serialize_deserialize("08 ff ff ff ff ff ff ff ff ff 01", &test);
}

#[test]
fn test_empty() {
    test_serialize_deserialize("", &TestEmpty::new());
}

#[test]
fn test_read_junk() {
    assert!(Test1::parse_from_bytes(&decode_hex("00")).is_err());
}

#[test]
fn test_unknown_fields_length_delimited() {
    let mut message = TestUnknownFields::new();
    message.set_a(150);
    message
        .mut_unknown_fields()
        .add_length_delimited(4, [0x10u8, 0x20, 0x30].to_vec());
    test_serialize_deserialize("08 96 01 22 03 10 20 30", &message);
}

#[test]
fn test_unknown_fields_fixed32() {
    let mut message = TestUnknownFields::new();
    message.set_a(150);
    message.mut_unknown_fields().add_fixed32(4, 0x01020304);
    message.mut_unknown_fields().add_fixed32(4, 0xA1A2A3A4);
    test_serialize_deserialize("08 96 01 25 04 03 02 01 25 A4 A3 A2 A1", &message);
}

#[test]
fn test_types_singular() {
    let mut message = TestTypesSingular::new();
    message.set_double_field(19f64);
    message.set_float_field(20f32);
    message.set_int32_field(21);
    message.set_int64_field(-22);
    message.set_uint32_field(23);
    message.set_uint64_field(24);
    message.set_sint32_field(-25);
    message.set_sint64_field(26);
    message.set_fixed32_field(27);
    message.set_fixed64_field(28);
    message.set_sfixed32_field(-29);
    message.set_sfixed64_field(30);
    message.set_bool_field(true);
    message.set_string_field("thirty two".to_string());
    message.set_bytes_field([33u8, 34].to_vec());
    message.set_enum_field(TestEnumDescriptor::BLUE);
    test_serialize_deserialize_no_hex_with_dynamic(&message);
}

#[test]
fn test_types_repeated() {
    let mut message = TestTypesRepeated::new();
    message.set_double_field([19f64, 20f64].to_vec());
    message.set_float_field([20f32].to_vec());
    message.set_int32_field([21i32, -22, 23].to_vec());
    message.set_int64_field([22i64].to_vec());
    message.set_uint32_field([23u32, 24].to_vec());
    message.set_uint64_field([24u64].to_vec());
    message.set_sint32_field([25i32].to_vec());
    message.set_sint64_field([26i64, -27].to_vec());
    message.set_fixed32_field([27u32].to_vec());
    message.set_fixed64_field([28u64].to_vec());
    message.set_sfixed32_field([29i32, -30].to_vec());
    message.set_sfixed64_field([30i64].to_vec());
    message.set_bool_field([true, true].to_vec());
    message.set_string_field(vec!["thirty two".to_string(), "thirty three".to_string()]);
    message.set_bytes_field(vec![[33u8, 34].to_vec(), [35u8].to_vec()]);
    message.set_enum_field(
        [
            TestEnumDescriptor::BLUE.into(),
            TestEnumDescriptor::GREEN.into(),
        ]
        .to_vec(),
    );
    test_serialize_deserialize_no_hex(&message);
}

#[test]
fn test_types_repeated_packed() {
    let mut message = TestTypesRepeatedPacked::new();
    message.set_double_field([19f64, 20f64].to_vec());
    message.set_float_field([20f32].to_vec());
    message.set_int32_field([21i32, -22, 23].to_vec());
    message.set_int64_field([22i64].to_vec());
    message.set_uint32_field([23u32, 24].to_vec());
    message.set_uint64_field([24u64].to_vec());
    message.set_sint32_field([-25i32, 26].to_vec());
    message.set_sint64_field([26i64, -27, 28].to_vec());
    message.set_fixed32_field([27u32].to_vec());
    message.set_fixed64_field([28u64].to_vec());
    message.set_sfixed32_field([29i32, -30].to_vec());
    message.set_sfixed64_field([30i64].to_vec());
    message.set_bool_field([true, true].to_vec());
    message.set_string_field(vec!["thirty two".to_string(), "thirty three".to_string()]);
    message.set_bytes_field(vec![[33u8, 34].to_vec(), [35u8].to_vec()]);
    message.set_enum_field(
        [
            TestEnumDescriptor::BLUE.into(),
            TestEnumDescriptor::GREEN.into(),
        ]
        .to_vec(),
    );
    test_serialize_deserialize_no_hex(&message);
}

#[test]
fn test_file_descriptor_proto() {
    let p: &'static descriptor::FileDescriptorProto = file_descriptor_proto();
    assert!(p.has_name());
    assert_eq!("test_basic_pb.proto", p.get_name());
}

#[test]
fn test_default_instance() {
    let d = TestDefaultInstance::new();
    assert_eq!("", d.get_field().get_s());
}

#[test]
fn test_message_descriptor() {
    assert_eq!("TestDescriptor", TestDescriptor::descriptor_static().name());

    let d = reflect::MessageDescriptor::for_type::<TestDescriptor>();
    assert_eq!("TestDescriptor", d.name());
    assert_eq!("basic.TestDescriptor", d.full_name());

    let mut t = TestDescriptor::new();
    t.set_stuff(55);

    let field = d.get_field_by_name("stuff").unwrap();
    assert_eq!(
        55,
        field.get_singular_field_or_default(&t).to_i32().unwrap()
    );
}

#[test]
fn test_enum_descriptor() {
    let d = TestEnumDescriptor::RED.enum_descriptor();
    assert_eq!("TestEnumDescriptor", d.get_name());
    assert_eq!(
        "TestEnumDescriptor",
        reflect::EnumDescriptor::for_type::<TestEnumDescriptor>().get_name()
    );
    assert_eq!("GREEN", d.get_value_by_name("GREEN").unwrap().get_name());
}

#[test]
fn test_invalid_tag() {
    // 01 is invalid tag, because field number for that tag would be 0
    let bytes = decode_hex("01 02 03");
    let r = TestInvalidTag::parse_from_bytes(&bytes);
    assert!(r.is_err());
}

#[test]
fn test_truncated_no_varint() {
    // 08 is valid tag that should be followed by varint
    let bytes = decode_hex("08");
    let r = TestTruncated::parse_from_bytes(&bytes);
    assert!(r.is_err());
}

#[test]
fn test_truncated_middle_of_varint() {
    // 08 is field 1, wire type varint
    // 96 is non-final byte of varint
    let bytes = decode_hex("08 96");
    let r = TestTruncated::parse_from_bytes(&bytes);
    assert!(r.is_err());
}

#[test]
fn test_truncated_middle_of_length_delimited() {
    // 0a is field 1, wire type length delimited
    // 03 is length 3
    let bytes = decode_hex("0a 03 10");
    let r = TestTruncated::parse_from_bytes(&bytes);
    assert!(r.is_err());
}

#[test]
fn test_truncated_repeated_packed() {
    // 12 is field 2, wire type length delimited
    // 04 is length 4
    let bytes = decode_hex("12 04 10 20");
    let r = TestTruncated::parse_from_bytes(&bytes);
    assert!(r.is_err());
}

#[test]
fn test_bug_sint() {
    {
        let mut x = TestBugSint::new();
        x.set_s32(-1);
        test_serialize_deserialize("08 01", &x);
    }
    {
        let mut x = TestBugSint::new();
        x.set_s64(-2);
        test_serialize_deserialize("10 03", &x);
    }
}

/// Smoke test which validates that read from the network doesn't block
#[test]
fn test_parse_length_delimited_from_network_smoke() {
    use std::io::Write;
    use std::net;
    use std::thread;

    let listener = net::TcpListener::bind(("127.0.0.1", 0)).expect("bind");
    let addr = listener.local_addr().expect("local_addr");
    thread::spawn(move || {
        let mut test1 = Test1::new();
        test1.set_a(10);
        let bytes = test1.write_length_delimited_to_bytes().expect("bytes");

        let mut stream = listener.accept().expect("accept").0;
        stream.write(&bytes).expect("write");
    });

    let mut tcp_stream = net::TcpStream::connect(addr).expect("connect");
    let mut is = CodedInputStream::new(&mut tcp_stream);
    let test1: Test1 = is.read_message().expect("read_message");
    assert_eq!(10, test1.get_a());
    is.check_eof().expect("check_eof");
}

/// Test if providing a smaller buffer, protobuf can detect and report error.
#[test]
fn test_serialize_too_large_message() {
    let mut test1 = Test1::new();
    test1.set_a(150);
    let len = test1.compute_size();
    let mut bytes = vec![0; len as usize - 1];
    let mut s = CodedOutputStream::bytes(&mut bytes);
    test1.write_to_with_cached_sizes(&mut s).unwrap_err();
}
<commit_msg>Enable more tests for dynamic message<commit_after>use protobuf::descriptor;
use protobuf::reflect;
use protobuf::CodedInputStream;
use protobuf::CodedOutputStream;
use protobuf::Message;
use protobuf::ProtobufEnum;
use protobuf_test_common::hex::decode_hex;
use protobuf_test_common::*;

use super::test_basic_pb::*;

#[test]
fn test1() {
    let mut test1 = Test1::new();
    test1.set_a(150);
    test_serialize_deserialize_with_dynamic("08 96 01", &test1);
}

#[test]
fn test2() {
    let mut test2 = Test2::new();
    test2.set_b("testing".to_string());
    test_serialize_deserialize_with_dynamic("12 07 74 65 73 74 69 6e 67", &test2);
}

#[test]
fn test3() {
    let mut test1 = Test1::new();
    test1.set_a(150);
    let mut test3 = Test3::new();
    test3.set_c(test1);
    test_serialize_deserialize_with_dynamic("1a 03 08 96 01", &test3);
}

#[test]
fn test4() {
    let mut test4 = Test4::new();
    test4.set_d([3i32, 270, 86942].to_vec());
    test_serialize_deserialize_with_dynamic("22 06 03 8E 02 9E A7 05", &test4);
}

#[test]
fn test_recursion_limit() {
    let mut test = TestRecursion::new();
    for _ in 0..10 {
        let mut t = TestRecursion::new();
        t.mut_children().push(test);
        test = t;
    }

    let bytes = test.write_to_bytes().unwrap();
    let cases = vec![(None, false), (Some(9), true), (Some(10), false)];

    for (limit, has_err) in cases {
        let mut is = CodedInputStream::from_bytes(&bytes);
        if let Some(limit) = limit {
            is.set_recursion_limit(limit);
        }
        let mut t = TestRecursion::new();
        let res = t.merge_from(&mut is);
        assert_eq!(res.is_err(), has_err, "limit: {:?}", limit);
        if !has_err {
            assert_eq!(t, test, "limit: {:?}", limit);
        }
    }
}

#[test]
fn test_end_by_negative_int() {
    // added following https://github.com/stepancheg/rust-protobuf/pull/209
    let mut test = Test1::new();
    test.set_a(-1);
    test_serialize_deserialize_with_dynamic("08 ff ff ff ff ff ff ff ff ff 01", &test);
}

#[test]
fn test_empty() {
    test_serialize_deserialize_with_dynamic("", &TestEmpty::new());
}

#[test]
fn test_read_junk() {
    assert!(Test1::parse_from_bytes(&decode_hex("00")).is_err());
}

#[test]
fn test_unknown_fields_length_delimited() {
    let mut message = TestUnknownFields::new();
    message.set_a(150);
    message
        .mut_unknown_fields()
        .add_length_delimited(4, [0x10u8, 0x20, 0x30].to_vec());
    // TODO: unknown fields are lost
    test_serialize_deserialize("08 96 01 22 03 10 20 30", &message);
}

#[test]
fn test_unknown_fields_fixed32() {
    let mut message = TestUnknownFields::new();
    message.set_a(150);
    message.mut_unknown_fields().add_fixed32(4, 0x01020304);
    message.mut_unknown_fields().add_fixed32(4, 0xA1A2A3A4);
    // TODO: unknown fields are lost
    test_serialize_deserialize("08 96 01 25 04 03 02 01 25 A4 A3 A2 A1", &message);
}

#[test]
fn test_types_singular() {
    let mut message = TestTypesSingular::new();
    message.set_double_field(19f64);
    message.set_float_field(20f32);
    message.set_int32_field(21);
    message.set_int64_field(-22);
    message.set_uint32_field(23);
    message.set_uint64_field(24);
    message.set_sint32_field(-25);
    message.set_sint64_field(26);
    message.set_fixed32_field(27);
    message.set_fixed64_field(28);
    message.set_sfixed32_field(-29);
    message.set_sfixed64_field(30);
    message.set_bool_field(true);
    message.set_string_field("thirty two".to_string());
    message.set_bytes_field([33u8, 34].to_vec());
    message.set_enum_field(TestEnumDescriptor::BLUE);
    test_serialize_deserialize_no_hex_with_dynamic(&message);
}

#[test]
fn test_types_repeated() {
    let mut message = TestTypesRepeated::new();
    message.set_double_field([19f64, 20f64].to_vec());
    message.set_float_field([20f32].to_vec());
    message.set_int32_field([21i32, -22, 23].to_vec());
    message.set_int64_field([22i64].to_vec());
    message.set_uint32_field([23u32, 24].to_vec());
    message.set_uint64_field([24u64].to_vec());
    message.set_sint32_field([25i32].to_vec());
    message.set_sint64_field([26i64, -27].to_vec());
    message.set_fixed32_field([27u32].to_vec());
    message.set_fixed64_field([28u64].to_vec());
    message.set_sfixed32_field([29i32, -30].to_vec());
    message.set_sfixed64_field([30i64].to_vec());
    message.set_bool_field([true, true].to_vec());
    message.set_string_field(vec!["thirty two".to_string(), "thirty three".to_string()]);
    message.set_bytes_field(vec![[33u8, 34].to_vec(), [35u8].to_vec()]);
    message.set_enum_field(
        [
            TestEnumDescriptor::BLUE.into(),
            TestEnumDescriptor::GREEN.into(),
        ]
        .to_vec(),
    );
    test_serialize_deserialize_no_hex_with_dynamic(&message);
}

#[test]
fn test_types_repeated_packed() {
    let mut message = TestTypesRepeatedPacked::new();
    message.set_double_field([19f64, 20f64].to_vec());
    message.set_float_field([20f32].to_vec());
    message.set_int32_field([21i32, -22, 23].to_vec());
    message.set_int64_field([22i64].to_vec());
    message.set_uint32_field([23u32, 24].to_vec());
    message.set_uint64_field([24u64].to_vec());
    message.set_sint32_field([-25i32, 26].to_vec());
    message.set_sint64_field([26i64, -27, 28].to_vec());
    message.set_fixed32_field([27u32].to_vec());
    message.set_fixed64_field([28u64].to_vec());
    message.set_sfixed32_field([29i32, -30].to_vec());
    message.set_sfixed64_field([30i64].to_vec());
    message.set_bool_field([true, true].to_vec());
    message.set_string_field(vec!["thirty two".to_string(), "thirty three".to_string()]);
    message.set_bytes_field(vec![[33u8, 34].to_vec(), [35u8].to_vec()]);
    message.set_enum_field(
        [
            TestEnumDescriptor::BLUE.into(),
            TestEnumDescriptor::GREEN.into(),
        ]
        .to_vec(),
    );
    test_serialize_deserialize_no_hex_with_dynamic(&message);
}

#[test]
fn test_file_descriptor_proto() {
    let p: &'static descriptor::FileDescriptorProto = file_descriptor_proto();
    assert!(p.has_name());
    assert_eq!("test_basic_pb.proto", p.get_name());
}

#[test]
fn test_default_instance() {
    let d = TestDefaultInstance::new();
    assert_eq!("", d.get_field().get_s());
}

#[test]
fn test_message_descriptor() {
    assert_eq!("TestDescriptor", TestDescriptor::descriptor_static().name());

    let d = reflect::MessageDescriptor::for_type::<TestDescriptor>();
    assert_eq!("TestDescriptor", d.name());
    assert_eq!("basic.TestDescriptor", d.full_name());

    let mut t = TestDescriptor::new();
    t.set_stuff(55);

    let field = d.get_field_by_name("stuff").unwrap();
    assert_eq!(
        55,
        field.get_singular_field_or_default(&t).to_i32().unwrap()
    );
}

#[test]
fn test_enum_descriptor() {
    let d = TestEnumDescriptor::RED.enum_descriptor();
    assert_eq!("TestEnumDescriptor", d.get_name());
    assert_eq!(
        "TestEnumDescriptor",
        reflect::EnumDescriptor::for_type::<TestEnumDescriptor>().get_name()
    );
    assert_eq!("GREEN", d.get_value_by_name("GREEN").unwrap().get_name());
}

#[test]
fn test_invalid_tag() {
    // 01 is invalid tag, because field number for that tag would be 0
    let bytes = decode_hex("01 02 03");
    let r = TestInvalidTag::parse_from_bytes(&bytes);
    assert!(r.is_err());
}

#[test]
fn test_truncated_no_varint() {
    // 08 is valid tag that should be followed by varint
    let bytes = decode_hex("08");
    let r = TestTruncated::parse_from_bytes(&bytes);
    assert!(r.is_err());
}

#[test]
fn test_truncated_middle_of_varint() {
    // 08 is field 1, wire type varint
    // 96 is non-final byte of varint
    let bytes = decode_hex("08 96");
    let r = TestTruncated::parse_from_bytes(&bytes);
    assert!(r.is_err());
}

#[test]
fn test_truncated_middle_of_length_delimited() {
    // 0a is field 1, wire type length delimited
    // 03 is length 3
    let bytes = decode_hex("0a 03 10");
    let r = TestTruncated::parse_from_bytes(&bytes);
    assert!(r.is_err());
}

#[test]
fn test_truncated_repeated_packed() {
    // 12 is field 2, wire type length delimited
    // 04 is length 4
    let bytes = decode_hex("12 04 10 20");
    let r = TestTruncated::parse_from_bytes(&bytes);
    assert!(r.is_err());
}

#[test]
fn test_bug_sint() {
    {
        let mut x = TestBugSint::new();
        x.set_s32(-1);
        test_serialize_deserialize("08 01", &x);
    }
    {
        let mut x = TestBugSint::new();
        x.set_s64(-2);
        test_serialize_deserialize("10 03", &x);
    }
}

/// Smoke test which validates that read from the network doesn't block
#[test]
fn test_parse_length_delimited_from_network_smoke() {
    use std::io::Write;
    use std::net;
    use std::thread;

    let listener = net::TcpListener::bind(("127.0.0.1", 0)).expect("bind");
    let addr = listener.local_addr().expect("local_addr");
    thread::spawn(move || {
        let mut test1 = Test1::new();
        test1.set_a(10);
        let bytes = test1.write_length_delimited_to_bytes().expect("bytes");

        let mut stream = listener.accept().expect("accept").0;
        stream.write(&bytes).expect("write");
    });

    let mut tcp_stream = net::TcpStream::connect(addr).expect("connect");
    let mut is = CodedInputStream::new(&mut tcp_stream);
    let test1: Test1 = is.read_message().expect("read_message");
    assert_eq!(10, test1.get_a());
    is.check_eof().expect("check_eof");
}

/// Test if providing a smaller buffer, protobuf can detect and report error.
#[test]
fn test_serialize_too_large_message() {
    let mut test1 = Test1::new();
    test1.set_a(150);
    let len = test1.compute_size();
    let mut bytes = vec![0; len as usize - 1];
    let mut s = CodedOutputStream::bytes(&mut bytes);
    test1.write_to_with_cached_sizes(&mut s).unwrap_err();
}
<|endoftext|>


<commit_before>// Copyright 2014 The CGMath Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// 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.

use std::{fmt,num};

use std::num::one;

use approx::ApproxEq;
use matrix::{Matrix, Matrix4, ToMatrix4};
use num::{BaseNum, BaseFloat};
use point::{Point, Point3};
use ray::Ray;
use rotation::{Rotation, Rotation3};
use quaternion::Quaternion;
use vector::{Vector, Vector3};

/// A trait representing an [affine
/// transformation](https://en.wikipedia.org/wiki/Affine_transformation) that
/// can be applied to points or vectors. An affine transformation is one which
pub trait Transform<S: BaseNum, V: Vector<S>, P: Point<S,V>> {
    /// Create an identity transformation. That is, a transformation which
    /// does nothing.
    fn identity() -> Self;

    /// Create a transformation that rotates a vector to look at `center` from
    /// `eye`, using `up` for orientation.
    fn look_at(eye: &P, center: &P, up: &V) -> Self;

    /// Transform a vector using this transform.
    fn transform_vector(&self, vec: &V) -> V;

    /// Transform a point using this transform.
    fn transform_point(&self, point: &P) -> P;

    /// Transform a ray using this transform.
    #[inline]
    fn transform_ray(&self, ray: &Ray<P,V>) -> Ray<P,V> {
        Ray::new( self.transform_point(&ray.origin), self.transform_vector(&ray.direction) )
    }

    /// Transform a vector as a point using this transform.
    #[inline]
    fn transform_as_point(&self, vec: &V) -> V {
        self.transform_point( &Point::from_vec(vec) ).to_vec()
    }

    /// Combine this transform with another, yielding a new transformation
    /// which has the effects of both.
    fn concat(&self, other: &Self) -> Self;

    /// Create a transform that "un-does" this one.
    fn invert(&self) -> Option<Self>;

    /// Combine this transform with another, in-place.
    #[inline]
    fn concat_self(&mut self, other: &Self) {
        *self = self.concat(other);
    }

    /// Invert this transform in-place, failing if the transformation is not
    /// invertible.
    #[inline]
    fn invert_self(&mut self) {
        *self = self.invert().unwrap()
    }
}

/// A generic transformation consisting of a rotation,
/// displacement vector and scale amount.
pub struct Decomposed<S,V,R> {
    pub scale: S,
    pub rot: R,
    pub disp: V,
}

impl<S: BaseFloat, V: Vector<S>, P: Point<S, V>, R: Rotation<S, V, P>> Transform<S, V, P> for Decomposed<S,V,R> {
    #[inline]
    fn identity() -> Decomposed<S,V,R> {
        Decomposed {
            scale: num::one(),
            rot: Rotation::identity(),
            disp: num::zero(),
        }
    }

    #[inline]
    fn look_at(eye: &P, center: &P, up: &V) -> Decomposed<S,V,R> {
        let origin :P = Point::origin();
        let rot :R = Rotation::look_at( &center.sub_p(eye), up );
        let disp :V = rot.rotate_vector( &origin.sub_p(eye) );
        Decomposed {
            scale: num::one(),
            rot: rot,
            disp: disp,
        }
    }

    #[inline]
    fn transform_vector(&self, vec: &V) -> V {
        self.rot.rotate_vector( &vec.mul_s( self.scale.clone() ))
    }

    #[inline]
    fn transform_point(&self, point: &P) -> P {
        self.rot.rotate_point( &point.mul_s( self.scale.clone() )).add_v( &self.disp )
    }

    fn concat(&self, other: &Decomposed<S,V,R>) -> Decomposed<S,V,R> {
        Decomposed {
            scale: self.scale * other.scale,
            rot: self.rot.concat( &other.rot ),
            disp: self.transform_as_point( &other.disp ),
        }
    }

    fn invert(&self) -> Option<Decomposed<S,V,R>> {
        if self.scale.approx_eq( &num::zero() ) {
            None
        }else {
            let _1 : S = num::one();
            let s = _1 / self.scale;
            let r = self.rot.invert();
            let d = r.rotate_vector( &self.disp ).mul_s( -s );
            Some( Decomposed {
                scale: s,
                rot: r,
                disp: d,
            })
        }
    }
}

pub trait Transform3<S>: Transform<S, Vector3<S>, Point3<S>>+ ToMatrix4<S> {}

impl<S: BaseFloat, R: Rotation3<S>> ToMatrix4<S> for Decomposed<S, Vector3<S>, R> {
    fn to_matrix4(&self) -> Matrix4<S> {
        let mut m = self.rot.to_matrix3().mul_s( self.scale.clone() ).to_matrix4();
        m.w = self.disp.extend( num::one() );
        m
    }
}

impl<S: BaseFloat, R: Rotation3<S>> Transform3<S> for Decomposed<S,Vector3<S>,R> {}

impl<S: BaseFloat, R: fmt::Show + Rotation3<S>> fmt::Show for Decomposed<S,Vector3<S>,R> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "(scale({}), rot({}), disp{})",
            self.scale, self.rot, self.disp)
    }
}

/// A homogeneous transformation matrix.
pub struct AffineMatrix3<S> {
    pub mat: Matrix4<S>,
}

impl<S : BaseFloat> Transform<S, Vector3<S>, Point3<S>> for AffineMatrix3<S> {
    #[inline]
    fn identity() -> AffineMatrix3<S> {
       AffineMatrix3 { mat: Matrix4::identity() }
    }

    #[inline]
    fn look_at(eye: &Point3<S>, center: &Point3<S>, up: &Vector3<S>) -> AffineMatrix3<S> {
        AffineMatrix3 { mat: Matrix4::look_at(eye, center, up) }
    }

    #[inline]
    fn transform_vector(&self, vec: &Vector3<S>) -> Vector3<S> {
        self.mat.mul_v( &vec.extend(num::zero()) ).truncate()
    }

    #[inline]
    fn transform_point(&self, point: &Point3<S>) -> Point3<S> {
        Point3::from_homogeneous( &self.mat.mul_v( &point.to_homogeneous() ))
    }

    #[inline]
    fn concat(&self, other: &AffineMatrix3<S>) -> AffineMatrix3<S> {
        AffineMatrix3 { mat: self.mat.mul_m( &other.mat ) }
    }

    #[inline]
    fn invert(&self) -> Option<AffineMatrix3<S>> {
        self.mat.invert().map(|m| AffineMatrix3{ mat: m })
    }
}

impl<S: BaseNum> ToMatrix4<S> for AffineMatrix3<S> {
    #[inline] fn to_matrix4(&self) -> Matrix4<S> { self.mat.clone() }
}

impl<S: BaseFloat> Transform3<S> for AffineMatrix3<S> {}

/// A transformation in three dimensions consisting of a rotation,
/// displacement vector and scale amount.
pub struct Transform3D<S>(Decomposed<S,Vector3<S>,Quaternion<S>>);

impl<S: BaseFloat> Transform3D<S> {
    #[inline]
    pub fn new(scale: S, rot: Quaternion<S>, disp: Vector3<S>) -> Transform3D<S> {
       Transform3D( Decomposed { scale: scale, rot: rot, disp: disp })
    }

    #[inline]
    pub fn translate(x: S, y: S, z: S) -> Transform3D<S> {
       Transform3D( Decomposed { scale: one(), rot: Quaternion::zero(), disp: Vector3::new(x, y, z) })
    }

    #[inline]
    pub fn get<'a>(&'a self) -> &'a Decomposed<S,Vector3<S>,Quaternion<S>> {
        let &Transform3D(ref d) = self;
        d
    }
}

impl<S: BaseFloat> ToMatrix4<S> for Transform3D<S> {
    fn to_matrix4(&self) -> Matrix4<S> { self.get().to_matrix4() }
}
<commit_msg>Remove Transform3D type<commit_after>// Copyright 2014 The CGMath Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// 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.

use std::{fmt,num};

use std::num::one;

use approx::ApproxEq;
use matrix::{Matrix, Matrix4, ToMatrix4};
use num::{BaseNum, BaseFloat};
use point::{Point, Point3};
use ray::Ray;
use rotation::{Rotation, Rotation3};
use quaternion::Quaternion;
use vector::{Vector, Vector3};

/// A trait representing an [affine
/// transformation](https://en.wikipedia.org/wiki/Affine_transformation) that
/// can be applied to points or vectors. An affine transformation is one which
pub trait Transform<S: BaseNum, V: Vector<S>, P: Point<S,V>> {
    /// Create an identity transformation. That is, a transformation which
    /// does nothing.
    fn identity() -> Self;

    /// Create a transformation that rotates a vector to look at `center` from
    /// `eye`, using `up` for orientation.
    fn look_at(eye: &P, center: &P, up: &V) -> Self;

    /// Transform a vector using this transform.
    fn transform_vector(&self, vec: &V) -> V;

    /// Transform a point using this transform.
    fn transform_point(&self, point: &P) -> P;

    /// Transform a ray using this transform.
    #[inline]
    fn transform_ray(&self, ray: &Ray<P,V>) -> Ray<P,V> {
        Ray::new( self.transform_point(&ray.origin), self.transform_vector(&ray.direction) )
    }

    /// Transform a vector as a point using this transform.
    #[inline]
    fn transform_as_point(&self, vec: &V) -> V {
        self.transform_point( &Point::from_vec(vec) ).to_vec()
    }

    /// Combine this transform with another, yielding a new transformation
    /// which has the effects of both.
    fn concat(&self, other: &Self) -> Self;

    /// Create a transform that "un-does" this one.
    fn invert(&self) -> Option<Self>;

    /// Combine this transform with another, in-place.
    #[inline]
    fn concat_self(&mut self, other: &Self) {
        *self = self.concat(other);
    }

    /// Invert this transform in-place, failing if the transformation is not
    /// invertible.
    #[inline]
    fn invert_self(&mut self) {
        *self = self.invert().unwrap()
    }
}

/// A generic transformation consisting of a rotation,
/// displacement vector and scale amount.
pub struct Decomposed<S,V,R> {
    pub scale: S,
    pub rot: R,
    pub disp: V,
}

impl<S: BaseFloat, V: Vector<S>, P: Point<S, V>, R: Rotation<S, V, P>> Transform<S, V, P> for Decomposed<S,V,R> {
    #[inline]
    fn identity() -> Decomposed<S,V,R> {
        Decomposed {
            scale: num::one(),
            rot: Rotation::identity(),
            disp: num::zero(),
        }
    }

    #[inline]
    fn look_at(eye: &P, center: &P, up: &V) -> Decomposed<S,V,R> {
        let origin :P = Point::origin();
        let rot :R = Rotation::look_at( &center.sub_p(eye), up );
        let disp :V = rot.rotate_vector( &origin.sub_p(eye) );
        Decomposed {
            scale: num::one(),
            rot: rot,
            disp: disp,
        }
    }

    #[inline]
    fn transform_vector(&self, vec: &V) -> V {
        self.rot.rotate_vector( &vec.mul_s( self.scale.clone() ))
    }

    #[inline]
    fn transform_point(&self, point: &P) -> P {
        self.rot.rotate_point( &point.mul_s( self.scale.clone() )).add_v( &self.disp )
    }

    fn concat(&self, other: &Decomposed<S,V,R>) -> Decomposed<S,V,R> {
        Decomposed {
            scale: self.scale * other.scale,
            rot: self.rot.concat( &other.rot ),
            disp: self.transform_as_point( &other.disp ),
        }
    }

    fn invert(&self) -> Option<Decomposed<S,V,R>> {
        if self.scale.approx_eq( &num::zero() ) {
            None
        }else {
            let _1 : S = num::one();
            let s = _1 / self.scale;
            let r = self.rot.invert();
            let d = r.rotate_vector( &self.disp ).mul_s( -s );
            Some( Decomposed {
                scale: s,
                rot: r,
                disp: d,
            })
        }
    }
}

pub trait Transform3<S>: Transform<S, Vector3<S>, Point3<S>>+ ToMatrix4<S> {}

impl<S: BaseFloat, R: Rotation3<S>> ToMatrix4<S> for Decomposed<S, Vector3<S>, R> {
    fn to_matrix4(&self) -> Matrix4<S> {
        let mut m = self.rot.to_matrix3().mul_s( self.scale.clone() ).to_matrix4();
        m.w = self.disp.extend( num::one() );
        m
    }
}

impl<S: BaseFloat, R: Rotation3<S>> Transform3<S> for Decomposed<S,Vector3<S>,R> {}

impl<S: BaseFloat, R: fmt::Show + Rotation3<S>> fmt::Show for Decomposed<S,Vector3<S>,R> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "(scale({}), rot({}), disp{})",
            self.scale, self.rot, self.disp)
    }
}

/// A homogeneous transformation matrix.
pub struct AffineMatrix3<S> {
    pub mat: Matrix4<S>,
}

impl<S : BaseFloat> Transform<S, Vector3<S>, Point3<S>> for AffineMatrix3<S> {
    #[inline]
    fn identity() -> AffineMatrix3<S> {
       AffineMatrix3 { mat: Matrix4::identity() }
    }

    #[inline]
    fn look_at(eye: &Point3<S>, center: &Point3<S>, up: &Vector3<S>) -> AffineMatrix3<S> {
        AffineMatrix3 { mat: Matrix4::look_at(eye, center, up) }
    }

    #[inline]
    fn transform_vector(&self, vec: &Vector3<S>) -> Vector3<S> {
        self.mat.mul_v( &vec.extend(num::zero()) ).truncate()
    }

    #[inline]
    fn transform_point(&self, point: &Point3<S>) -> Point3<S> {
        Point3::from_homogeneous( &self.mat.mul_v( &point.to_homogeneous() ))
    }

    #[inline]
    fn concat(&self, other: &AffineMatrix3<S>) -> AffineMatrix3<S> {
        AffineMatrix3 { mat: self.mat.mul_m( &other.mat ) }
    }

    #[inline]
    fn invert(&self) -> Option<AffineMatrix3<S>> {
        self.mat.invert().map(|m| AffineMatrix3{ mat: m })
    }
}

impl<S: BaseNum> ToMatrix4<S> for AffineMatrix3<S> {
    #[inline] fn to_matrix4(&self) -> Matrix4<S> { self.mat.clone() }
}

impl<S: BaseFloat> Transform3<S> for AffineMatrix3<S> {}
<|endoftext|>


<commit_before>use types::Value;

use super::array::Array;
use super::boolean::Boolean;
use super::class::Class;
use super::fixnum::Fixnum;
use super::hash::Hash;
use super::string::RString;
use super::symbol::Symbol;

use super::traits::Object;

/// Representation of any Ruby object while its type is unknown
///
/// As Ruby is a dynamically typed language, at some points Ruru does not know the exact Ruby type
/// of the object. It happens in the following cases:
///
/// - Retrieving an object from array
///
/// - Retrieving an object from hash
///
/// - Receiving arguments to callback
///
/// - Initializing new instance of a class which is not present in Ruru
///
/// - and some other places you can find in Ruru documentation
///
/// In these cases you should cast `AnyObject` to the type to which the object belongs
/// using functions below.
///
/// # Examples
///
/// ## Retrieving an object from `Array`
///
/// ```
/// use ruru::{Array, Fixnum, VM};
/// # VM::init();
///
/// let array = Array::new().push(Fixnum::new(1));
/// let value = array.at(0).to::<Fixnum>(); // `Array::at()` returns `AnyObject`
///
/// assert_eq!(value.to_i64(), 1);
/// ```
///
/// ## Retrieving an object from `Hash`
///
/// ```no_run
/// use ruru::{Fixnum, Hash, Symbol, VM};
/// # VM::init();
///
/// let mut hash = Hash::new();
///
/// hash.store(Symbol::new("key"), Fixnum::new(1));
///
/// // `Hash::at()` returns `AnyObject`
/// let value = hash.at(Symbol::new("key")).to::<Fixnum>();
///
/// assert_eq!(value, Fixnum::new(1));
/// ```
///
/// ## Receiving arguments from Ruby to Ruru callback
///
/// ```no_run
/// use ruru::types::Argc;
/// use ruru::{AnyObject, Boolean, Class, RString, VM};
///
/// #[no_mangle]
/// pub extern fn string_eq(argc: Argc, argv: *const AnyObject, itself: RString) -> Boolean {
///     // `VM::parse_arguments()` returns `Vec<AnyObject>`
///     let argv = VM::parse_arguments(argc, argv);
///     let other_string = argv[0].to::<RString>();
///
///     Boolean::new(itself.to_string() == other_string.to_string())
/// }
///
/// fn main() {
///     Class::from_existing("String").define_method("==", string_eq);
/// }
/// ```
#[derive(Clone)]
pub struct AnyObject {
    value: Value,
}

impl AnyObject {
    /// Casts `AnyObject` to the specified Ruby type
    ///
    /// # Examples
    ///
    /// ```
    /// use ruru::{AnyObject, Fixnum, VM};
    /// use ruru::traits::Object;
    /// # VM::init();
    ///
    /// let fixnum_as_any_object = Fixnum::new(1).to_any_object();
    ///
    /// let fixnum = fixnum_as_any_object.to::<Fixnum>();
    ///
    /// assert_eq!(fixnum.to_i64(), 1);
    /// ```
    pub fn to<T: Object>(&self) -> T {
        T::from(self.value)
    }
}

impl From<Value> for AnyObject {
    fn from(value: Value) -> Self {
        AnyObject { value: value }
    }
}

impl Object for AnyObject {
    fn value(&self) -> Value {
        self.value
    }
}
<commit_msg>Remove unused imports from AnyObject module<commit_after>use types::Value;

use super::traits::Object;

/// Representation of any Ruby object while its type is unknown
///
/// As Ruby is a dynamically typed language, at some points Ruru does not know the exact Ruby type
/// of the object. It happens in the following cases:
///
/// - Retrieving an object from array
///
/// - Retrieving an object from hash
///
/// - Receiving arguments to callback
///
/// - Initializing new instance of a class which is not present in Ruru
///
/// - and some other places you can find in Ruru documentation
///
/// In these cases you should cast `AnyObject` to the type to which the object belongs
/// using functions below.
///
/// # Examples
///
/// ## Retrieving an object from `Array`
///
/// ```
/// use ruru::{Array, Fixnum, VM};
/// # VM::init();
///
/// let array = Array::new().push(Fixnum::new(1));
/// let value = array.at(0).to::<Fixnum>(); // `Array::at()` returns `AnyObject`
///
/// assert_eq!(value.to_i64(), 1);
/// ```
///
/// ## Retrieving an object from `Hash`
///
/// ```no_run
/// use ruru::{Fixnum, Hash, Symbol, VM};
/// # VM::init();
///
/// let mut hash = Hash::new();
///
/// hash.store(Symbol::new("key"), Fixnum::new(1));
///
/// // `Hash::at()` returns `AnyObject`
/// let value = hash.at(Symbol::new("key")).to::<Fixnum>();
///
/// assert_eq!(value, Fixnum::new(1));
/// ```
///
/// ## Receiving arguments from Ruby to Ruru callback
///
/// ```no_run
/// use ruru::types::Argc;
/// use ruru::{AnyObject, Boolean, Class, RString, VM};
///
/// #[no_mangle]
/// pub extern fn string_eq(argc: Argc, argv: *const AnyObject, itself: RString) -> Boolean {
///     // `VM::parse_arguments()` returns `Vec<AnyObject>`
///     let argv = VM::parse_arguments(argc, argv);
///     let other_string = argv[0].to::<RString>();
///
///     Boolean::new(itself.to_string() == other_string.to_string())
/// }
///
/// fn main() {
///     Class::from_existing("String").define_method("==", string_eq);
/// }
/// ```
#[derive(Clone)]
pub struct AnyObject {
    value: Value,
}

impl AnyObject {
    /// Casts `AnyObject` to the specified Ruby type
    ///
    /// # Examples
    ///
    /// ```
    /// use ruru::{AnyObject, Fixnum, VM};
    /// use ruru::traits::Object;
    /// # VM::init();
    ///
    /// let fixnum_as_any_object = Fixnum::new(1).to_any_object();
    ///
    /// let fixnum = fixnum_as_any_object.to::<Fixnum>();
    ///
    /// assert_eq!(fixnum.to_i64(), 1);
    /// ```
    pub fn to<T: Object>(&self) -> T {
        T::from(self.value)
    }
}

impl From<Value> for AnyObject {
    fn from(value: Value) -> Self {
        AnyObject { value: value }
    }
}

impl Object for AnyObject {
    fn value(&self) -> Value {
        self.value
    }
}
<|endoftext|>


<commit_before>//! This module contains paths to types and functions Clippy needs to know
//! about.
//!
//! Whenever possible, please consider diagnostic items over hardcoded paths.
//! See <https://github.com/rust-lang/rust-clippy/issues/5393> for more information.

pub const ANY_TRAIT: [&str; 3] = ["std", "any", "Any"];
pub const ARC_PTR_EQ: [&str; 4] = ["alloc", "sync", "Arc", "ptr_eq"];
pub const ASMUT_TRAIT: [&str; 3] = ["core", "convert", "AsMut"];
pub const ASREF_TRAIT: [&str; 3] = ["core", "convert", "AsRef"];
pub const BEGIN_PANIC: [&str; 3] = ["std", "panicking", "begin_panic"];
pub const BEGIN_PANIC_FMT: [&str; 3] = ["std", "panicking", "begin_panic_fmt"];
pub const BINARY_HEAP: [&str; 4] = ["alloc", "collections", "binary_heap", "BinaryHeap"];
pub const BORROW_TRAIT: [&str; 3] = ["core", "borrow", "Borrow"];
pub const BOX: [&str; 3] = ["alloc", "boxed", "Box"];
pub const BTREEMAP: [&str; 5] = ["alloc", "collections", "btree", "map", "BTreeMap"];
pub const BTREEMAP_ENTRY: [&str; 5] = ["alloc", "collections", "btree", "map", "Entry"];
pub const BTREESET: [&str; 5] = ["alloc", "collections", "btree", "set", "BTreeSet"];
pub const CLONE_TRAIT: [&str; 3] = ["core", "clone", "Clone"];
pub const CLONE_TRAIT_METHOD: [&str; 4] = ["core", "clone", "Clone", "clone"];
pub const CMP_MAX: [&str; 3] = ["core", "cmp", "max"];
pub const CMP_MIN: [&str; 3] = ["core", "cmp", "min"];
pub const COW: [&str; 3] = ["alloc", "borrow", "Cow"];
pub const CSTRING: [&str; 4] = ["std", "ffi", "c_str", "CString"];
pub const CSTRING_AS_C_STR: [&str; 5] = ["std", "ffi", "c_str", "CString", "as_c_str"];
pub const DEFAULT_TRAIT: [&str; 3] = ["core", "default", "Default"];
pub const DEFAULT_TRAIT_METHOD: [&str; 4] = ["core", "default", "Default", "default"];
pub const DEREF_MUT_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "DerefMut", "deref_mut"];
pub const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"];
pub const DISPLAY_FMT_METHOD: [&str; 4] = ["core", "fmt", "Display", "fmt"];
pub const DISPLAY_TRAIT: [&str; 3] = ["core", "fmt", "Display"];
pub const DOUBLE_ENDED_ITERATOR: [&str; 4] = ["core", "iter", "traits", "DoubleEndedIterator"];
pub const DROP: [&str; 3] = ["core", "mem", "drop"];
pub const DROP_TRAIT: [&str; 4] = ["core", "ops", "drop", "Drop"];
pub const DURATION: [&str; 3] = ["core", "time", "Duration"];
pub const EARLY_CONTEXT: [&str; 4] = ["rustc", "lint", "context", "EarlyContext"];
pub const EXIT: [&str; 3] = ["std", "process", "exit"];
pub const F32_EPSILON: [&str; 2] = ["f32", "EPSILON"];
pub const F64_EPSILON: [&str; 2] = ["f64", "EPSILON"];
pub const FILE: [&str; 3] = ["std", "fs", "File"];
pub const FILE_TYPE: [&str; 3] = ["std", "fs", "FileType"];
pub const FMT_ARGUMENTS_NEW_V1: [&str; 4] = ["core", "fmt", "Arguments", "new_v1"];
pub const FMT_ARGUMENTS_NEW_V1_FORMATTED: [&str; 4] = ["core", "fmt", "Arguments", "new_v1_formatted"];
pub const FMT_ARGUMENTV1_NEW: [&str; 4] = ["core", "fmt", "ArgumentV1", "new"];
pub const FROM_FROM: [&str; 4] = ["core", "convert", "From", "from"];
pub const FROM_TRAIT: [&str; 3] = ["core", "convert", "From"];
pub const FUTURE_FROM_GENERATOR: [&str; 3] = ["core", "future", "from_generator"];
pub const HASH: [&str; 2] = ["hash", "Hash"];
pub const HASHMAP: [&str; 5] = ["std", "collections", "hash", "map", "HashMap"];
pub const HASHMAP_ENTRY: [&str; 5] = ["std", "collections", "hash", "map", "Entry"];
pub const HASHSET: [&str; 5] = ["std", "collections", "hash", "set", "HashSet"];
pub const INDEX: [&str; 3] = ["core", "ops", "Index"];
pub const INDEX_MUT: [&str; 3] = ["core", "ops", "IndexMut"];
pub const INTO: [&str; 3] = ["core", "convert", "Into"];
pub const INTO_ITERATOR: [&str; 5] = ["core", "iter", "traits", "collect", "IntoIterator"];
pub const IO_READ: [&str; 3] = ["std", "io", "Read"];
pub const IO_WRITE: [&str; 3] = ["std", "io", "Write"];
pub const ITERATOR: [&str; 5] = ["core", "iter", "traits", "iterator", "Iterator"];
pub const LATE_CONTEXT: [&str; 4] = ["rustc", "lint", "context", "LateContext"];
pub const LINKED_LIST: [&str; 4] = ["alloc", "collections", "linked_list", "LinkedList"];
pub const LINT: [&str; 3] = ["rustc_session", "lint", "Lint"];
pub const MEM_DISCRIMINANT: [&str; 3] = ["core", "mem", "discriminant"];
pub const MEM_FORGET: [&str; 3] = ["core", "mem", "forget"];
pub const MEM_MANUALLY_DROP: [&str; 4] = ["core", "mem", "manually_drop", "ManuallyDrop"];
pub const MEM_MAYBEUNINIT: [&str; 4] = ["core", "mem", "maybe_uninit", "MaybeUninit"];
pub const MEM_MAYBEUNINIT_UNINIT: [&str; 5] = ["core", "mem", "maybe_uninit", "MaybeUninit", "uninit"];
pub const MEM_REPLACE: [&str; 3] = ["core", "mem", "replace"];
pub const MUTEX_GUARD: [&str; 4] = ["std", "sync", "mutex", "MutexGuard"];
pub const OPEN_OPTIONS: [&str; 3] = ["std", "fs", "OpenOptions"];
pub const OPS_MODULE: [&str; 2] = ["core", "ops"];
pub const OPTION: [&str; 3] = ["core", "option", "Option"];
pub const OPTION_NONE: [&str; 4] = ["core", "option", "Option", "None"];
pub const OPTION_SOME: [&str; 4] = ["core", "option", "Option", "Some"];
pub const ORD: [&str; 3] = ["core", "cmp", "Ord"];
pub const OS_STRING: [&str; 4] = ["std", "ffi", "os_str", "OsString"];
pub const OS_STRING_AS_OS_STR: [&str; 5] = ["std", "ffi", "os_str", "OsString", "as_os_str"];
pub const OS_STR_TO_OS_STRING: [&str; 5] = ["std", "ffi", "os_str", "OsStr", "to_os_string"];
pub const PARKING_LOT_MUTEX_GUARD: [&str; 2] = ["parking_lot", "MutexGuard"];
pub const PARKING_LOT_RWLOCK_READ_GUARD: [&str; 2] = ["parking_lot", "RwLockReadGuard"];
pub const PARKING_LOT_RWLOCK_WRITE_GUARD: [&str; 2] = ["parking_lot", "RwLockWriteGuard"];
pub const PATH: [&str; 3] = ["std", "path", "Path"];
pub const PATH_BUF: [&str; 3] = ["std", "path", "PathBuf"];
pub const PATH_BUF_AS_PATH: [&str; 4] = ["std", "path", "PathBuf", "as_path"];
pub const PATH_TO_PATH_BUF: [&str; 4] = ["std", "path", "Path", "to_path_buf"];
pub const POLL: [&str; 4] = ["core", "task", "poll", "Poll"];
pub const PTR_EQ: [&str; 3] = ["core", "ptr", "eq"];
pub const PTR_NULL: [&str; 2] = ["ptr", "null"];
pub const PTR_NULL_MUT: [&str; 2] = ["ptr", "null_mut"];
pub const PUSH_STR: [&str; 4] = ["alloc", "string", "String", "push_str"];
pub const RANGE_ARGUMENT_TRAIT: [&str; 3] = ["core", "ops", "RangeBounds"];
pub const RC: [&str; 3] = ["alloc", "rc", "Rc"];
pub const RC_PTR_EQ: [&str; 4] = ["alloc", "rc", "Rc", "ptr_eq"];
pub const RECEIVER: [&str; 4] = ["std", "sync", "mpsc", "Receiver"];
pub const REGEX_BUILDER_NEW: [&str; 5] = ["regex", "re_builder", "unicode", "RegexBuilder", "new"];
pub const REGEX_BYTES_BUILDER_NEW: [&str; 5] = ["regex", "re_builder", "bytes", "RegexBuilder", "new"];
pub const REGEX_BYTES_NEW: [&str; 4] = ["regex", "re_bytes", "Regex", "new"];
pub const REGEX_BYTES_SET_NEW: [&str; 5] = ["regex", "re_set", "bytes", "RegexSet", "new"];
pub const REGEX_NEW: [&str; 4] = ["regex", "re_unicode", "Regex", "new"];
pub const REGEX_SET_NEW: [&str; 5] = ["regex", "re_set", "unicode", "RegexSet", "new"];
pub const REPEAT: [&str; 3] = ["core", "iter", "repeat"];
pub const RESULT: [&str; 3] = ["core", "result", "Result"];
pub const RESULT_ERR: [&str; 4] = ["core", "result", "Result", "Err"];
pub const RESULT_OK: [&str; 4] = ["core", "result", "Result", "Ok"];
pub const RWLOCK_READ_GUARD: [&str; 4] = ["std", "sync", "rwlock", "RwLockReadGuard"];
pub const RWLOCK_WRITE_GUARD: [&str; 4] = ["std", "sync", "rwlock", "RwLockWriteGuard"];
pub const SERDE_DESERIALIZE: [&str; 2] = ["_serde", "Deserialize"];
pub const SERDE_DE_VISITOR: [&str; 3] = ["serde", "de", "Visitor"];
pub const SLICE_INTO_VEC: [&str; 4] = ["alloc", "slice", "<impl [T]>", "into_vec"];
pub const SLICE_ITER: [&str; 3] = ["core", "slice", "Iter"];
pub const STDERR: [&str; 4] = ["std", "io", "stdio", "stderr"];
pub const STDOUT: [&str; 4] = ["std", "io", "stdio", "stdout"];
pub const STD_CONVERT_IDENTITY: [&str; 3] = ["std", "convert", "identity"];
pub const STD_FS_CREATE_DIR: [&str; 3] = ["std", "fs", "create_dir"];
pub const STD_MEM_TRANSMUTE: [&str; 3] = ["std", "mem", "transmute"];
pub const STD_PTR_NULL: [&str; 3] = ["std", "ptr", "null"];
pub const STRING_AS_MUT_STR: [&str; 4] = ["alloc", "string", "String", "as_mut_str"];
pub const STRING_AS_STR: [&str; 4] = ["alloc", "string", "String", "as_str"];
pub const SYNTAX_CONTEXT: [&str; 3] = ["rustc_span", "hygiene", "SyntaxContext"];
pub const TO_OWNED: [&str; 3] = ["alloc", "borrow", "ToOwned"];
pub const TO_OWNED_METHOD: [&str; 4] = ["alloc", "borrow", "ToOwned", "to_owned"];
pub const TO_STRING: [&str; 3] = ["alloc", "string", "ToString"];
pub const TO_STRING_METHOD: [&str; 4] = ["alloc", "string", "ToString", "to_string"];
pub const TRANSMUTE: [&str; 4] = ["core", "intrinsics", "", "transmute"];
pub const TRY_FROM: [&str; 4] = ["core", "convert", "TryFrom", "try_from"];
pub const TRY_INTO_TRAIT: [&str; 3] = ["core", "convert", "TryInto"];
pub const VEC: [&str; 3] = ["alloc", "vec", "Vec"];
pub const VEC_AS_MUT_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_mut_slice"];
pub const VEC_AS_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_slice"];
pub const VEC_DEQUE: [&str; 4] = ["alloc", "collections", "vec_deque", "VecDeque"];
pub const VEC_FROM_ELEM: [&str; 3] = ["alloc", "vec", "from_elem"];
pub const VEC_NEW: [&str; 4] = ["alloc", "vec", "Vec", "new"];
pub const VEC_RESIZE: [&str; 4] = ["alloc", "vec", "Vec", "resize"];
pub const WEAK_ARC: [&str; 3] = ["alloc", "sync", "Weak"];
pub const WEAK_RC: [&str; 3] = ["alloc", "rc", "Weak"];
<commit_msg>Fix clippy hard-code slice::Iter path<commit_after>//! This module contains paths to types and functions Clippy needs to know
//! about.
//!
//! Whenever possible, please consider diagnostic items over hardcoded paths.
//! See <https://github.com/rust-lang/rust-clippy/issues/5393> for more information.

pub const ANY_TRAIT: [&str; 3] = ["std", "any", "Any"];
pub const ARC_PTR_EQ: [&str; 4] = ["alloc", "sync", "Arc", "ptr_eq"];
pub const ASMUT_TRAIT: [&str; 3] = ["core", "convert", "AsMut"];
pub const ASREF_TRAIT: [&str; 3] = ["core", "convert", "AsRef"];
pub const BEGIN_PANIC: [&str; 3] = ["std", "panicking", "begin_panic"];
pub const BEGIN_PANIC_FMT: [&str; 3] = ["std", "panicking", "begin_panic_fmt"];
pub const BINARY_HEAP: [&str; 4] = ["alloc", "collections", "binary_heap", "BinaryHeap"];
pub const BORROW_TRAIT: [&str; 3] = ["core", "borrow", "Borrow"];
pub const BOX: [&str; 3] = ["alloc", "boxed", "Box"];
pub const BTREEMAP: [&str; 5] = ["alloc", "collections", "btree", "map", "BTreeMap"];
pub const BTREEMAP_ENTRY: [&str; 5] = ["alloc", "collections", "btree", "map", "Entry"];
pub const BTREESET: [&str; 5] = ["alloc", "collections", "btree", "set", "BTreeSet"];
pub const CLONE_TRAIT: [&str; 3] = ["core", "clone", "Clone"];
pub const CLONE_TRAIT_METHOD: [&str; 4] = ["core", "clone", "Clone", "clone"];
pub const CMP_MAX: [&str; 3] = ["core", "cmp", "max"];
pub const CMP_MIN: [&str; 3] = ["core", "cmp", "min"];
pub const COW: [&str; 3] = ["alloc", "borrow", "Cow"];
pub const CSTRING: [&str; 4] = ["std", "ffi", "c_str", "CString"];
pub const CSTRING_AS_C_STR: [&str; 5] = ["std", "ffi", "c_str", "CString", "as_c_str"];
pub const DEFAULT_TRAIT: [&str; 3] = ["core", "default", "Default"];
pub const DEFAULT_TRAIT_METHOD: [&str; 4] = ["core", "default", "Default", "default"];
pub const DEREF_MUT_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "DerefMut", "deref_mut"];
pub const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"];
pub const DISPLAY_FMT_METHOD: [&str; 4] = ["core", "fmt", "Display", "fmt"];
pub const DISPLAY_TRAIT: [&str; 3] = ["core", "fmt", "Display"];
pub const DOUBLE_ENDED_ITERATOR: [&str; 4] = ["core", "iter", "traits", "DoubleEndedIterator"];
pub const DROP: [&str; 3] = ["core", "mem", "drop"];
pub const DROP_TRAIT: [&str; 4] = ["core", "ops", "drop", "Drop"];
pub const DURATION: [&str; 3] = ["core", "time", "Duration"];
pub const EARLY_CONTEXT: [&str; 4] = ["rustc", "lint", "context", "EarlyContext"];
pub const EXIT: [&str; 3] = ["std", "process", "exit"];
pub const F32_EPSILON: [&str; 2] = ["f32", "EPSILON"];
pub const F64_EPSILON: [&str; 2] = ["f64", "EPSILON"];
pub const FILE: [&str; 3] = ["std", "fs", "File"];
pub const FILE_TYPE: [&str; 3] = ["std", "fs", "FileType"];
pub const FMT_ARGUMENTS_NEW_V1: [&str; 4] = ["core", "fmt", "Arguments", "new_v1"];
pub const FMT_ARGUMENTS_NEW_V1_FORMATTED: [&str; 4] = ["core", "fmt", "Arguments", "new_v1_formatted"];
pub const FMT_ARGUMENTV1_NEW: [&str; 4] = ["core", "fmt", "ArgumentV1", "new"];
pub const FROM_FROM: [&str; 4] = ["core", "convert", "From", "from"];
pub const FROM_TRAIT: [&str; 3] = ["core", "convert", "From"];
pub const FUTURE_FROM_GENERATOR: [&str; 3] = ["core", "future", "from_generator"];
pub const HASH: [&str; 2] = ["hash", "Hash"];
pub const HASHMAP: [&str; 5] = ["std", "collections", "hash", "map", "HashMap"];
pub const HASHMAP_ENTRY: [&str; 5] = ["std", "collections", "hash", "map", "Entry"];
pub const HASHSET: [&str; 5] = ["std", "collections", "hash", "set", "HashSet"];
pub const INDEX: [&str; 3] = ["core", "ops", "Index"];
pub const INDEX_MUT: [&str; 3] = ["core", "ops", "IndexMut"];
pub const INTO: [&str; 3] = ["core", "convert", "Into"];
pub const INTO_ITERATOR: [&str; 5] = ["core", "iter", "traits", "collect", "IntoIterator"];
pub const IO_READ: [&str; 3] = ["std", "io", "Read"];
pub const IO_WRITE: [&str; 3] = ["std", "io", "Write"];
pub const ITERATOR: [&str; 5] = ["core", "iter", "traits", "iterator", "Iterator"];
pub const LATE_CONTEXT: [&str; 4] = ["rustc", "lint", "context", "LateContext"];
pub const LINKED_LIST: [&str; 4] = ["alloc", "collections", "linked_list", "LinkedList"];
pub const LINT: [&str; 3] = ["rustc_session", "lint", "Lint"];
pub const MEM_DISCRIMINANT: [&str; 3] = ["core", "mem", "discriminant"];
pub const MEM_FORGET: [&str; 3] = ["core", "mem", "forget"];
pub const MEM_MANUALLY_DROP: [&str; 4] = ["core", "mem", "manually_drop", "ManuallyDrop"];
pub const MEM_MAYBEUNINIT: [&str; 4] = ["core", "mem", "maybe_uninit", "MaybeUninit"];
pub const MEM_MAYBEUNINIT_UNINIT: [&str; 5] = ["core", "mem", "maybe_uninit", "MaybeUninit", "uninit"];
pub const MEM_REPLACE: [&str; 3] = ["core", "mem", "replace"];
pub const MUTEX_GUARD: [&str; 4] = ["std", "sync", "mutex", "MutexGuard"];
pub const OPEN_OPTIONS: [&str; 3] = ["std", "fs", "OpenOptions"];
pub const OPS_MODULE: [&str; 2] = ["core", "ops"];
pub const OPTION: [&str; 3] = ["core", "option", "Option"];
pub const OPTION_NONE: [&str; 4] = ["core", "option", "Option", "None"];
pub const OPTION_SOME: [&str; 4] = ["core", "option", "Option", "Some"];
pub const ORD: [&str; 3] = ["core", "cmp", "Ord"];
pub const OS_STRING: [&str; 4] = ["std", "ffi", "os_str", "OsString"];
pub const OS_STRING_AS_OS_STR: [&str; 5] = ["std", "ffi", "os_str", "OsString", "as_os_str"];
pub const OS_STR_TO_OS_STRING: [&str; 5] = ["std", "ffi", "os_str", "OsStr", "to_os_string"];
pub const PARKING_LOT_MUTEX_GUARD: [&str; 2] = ["parking_lot", "MutexGuard"];
pub const PARKING_LOT_RWLOCK_READ_GUARD: [&str; 2] = ["parking_lot", "RwLockReadGuard"];
pub const PARKING_LOT_RWLOCK_WRITE_GUARD: [&str; 2] = ["parking_lot", "RwLockWriteGuard"];
pub const PATH: [&str; 3] = ["std", "path", "Path"];
pub const PATH_BUF: [&str; 3] = ["std", "path", "PathBuf"];
pub const PATH_BUF_AS_PATH: [&str; 4] = ["std", "path", "PathBuf", "as_path"];
pub const PATH_TO_PATH_BUF: [&str; 4] = ["std", "path", "Path", "to_path_buf"];
pub const POLL: [&str; 4] = ["core", "task", "poll", "Poll"];
pub const PTR_EQ: [&str; 3] = ["core", "ptr", "eq"];
pub const PTR_NULL: [&str; 2] = ["ptr", "null"];
pub const PTR_NULL_MUT: [&str; 2] = ["ptr", "null_mut"];
pub const PUSH_STR: [&str; 4] = ["alloc", "string", "String", "push_str"];
pub const RANGE_ARGUMENT_TRAIT: [&str; 3] = ["core", "ops", "RangeBounds"];
pub const RC: [&str; 3] = ["alloc", "rc", "Rc"];
pub const RC_PTR_EQ: [&str; 4] = ["alloc", "rc", "Rc", "ptr_eq"];
pub const RECEIVER: [&str; 4] = ["std", "sync", "mpsc", "Receiver"];
pub const REGEX_BUILDER_NEW: [&str; 5] = ["regex", "re_builder", "unicode", "RegexBuilder", "new"];
pub const REGEX_BYTES_BUILDER_NEW: [&str; 5] = ["regex", "re_builder", "bytes", "RegexBuilder", "new"];
pub const REGEX_BYTES_NEW: [&str; 4] = ["regex", "re_bytes", "Regex", "new"];
pub const REGEX_BYTES_SET_NEW: [&str; 5] = ["regex", "re_set", "bytes", "RegexSet", "new"];
pub const REGEX_NEW: [&str; 4] = ["regex", "re_unicode", "Regex", "new"];
pub const REGEX_SET_NEW: [&str; 5] = ["regex", "re_set", "unicode", "RegexSet", "new"];
pub const REPEAT: [&str; 3] = ["core", "iter", "repeat"];
pub const RESULT: [&str; 3] = ["core", "result", "Result"];
pub const RESULT_ERR: [&str; 4] = ["core", "result", "Result", "Err"];
pub const RESULT_OK: [&str; 4] = ["core", "result", "Result", "Ok"];
pub const RWLOCK_READ_GUARD: [&str; 4] = ["std", "sync", "rwlock", "RwLockReadGuard"];
pub const RWLOCK_WRITE_GUARD: [&str; 4] = ["std", "sync", "rwlock", "RwLockWriteGuard"];
pub const SERDE_DESERIALIZE: [&str; 2] = ["_serde", "Deserialize"];
pub const SERDE_DE_VISITOR: [&str; 3] = ["serde", "de", "Visitor"];
pub const SLICE_INTO_VEC: [&str; 4] = ["alloc", "slice", "<impl [T]>", "into_vec"];
pub const SLICE_ITER: [&str; 4] = ["core", "slice", "iter", "Iter"];
pub const STDERR: [&str; 4] = ["std", "io", "stdio", "stderr"];
pub const STDOUT: [&str; 4] = ["std", "io", "stdio", "stdout"];
pub const STD_CONVERT_IDENTITY: [&str; 3] = ["std", "convert", "identity"];
pub const STD_FS_CREATE_DIR: [&str; 3] = ["std", "fs", "create_dir"];
pub const STD_MEM_TRANSMUTE: [&str; 3] = ["std", "mem", "transmute"];
pub const STD_PTR_NULL: [&str; 3] = ["std", "ptr", "null"];
pub const STRING_AS_MUT_STR: [&str; 4] = ["alloc", "string", "String", "as_mut_str"];
pub const STRING_AS_STR: [&str; 4] = ["alloc", "string", "String", "as_str"];
pub const SYNTAX_CONTEXT: [&str; 3] = ["rustc_span", "hygiene", "SyntaxContext"];
pub const TO_OWNED: [&str; 3] = ["alloc", "borrow", "ToOwned"];
pub const TO_OWNED_METHOD: [&str; 4] = ["alloc", "borrow", "ToOwned", "to_owned"];
pub const TO_STRING: [&str; 3] = ["alloc", "string", "ToString"];
pub const TO_STRING_METHOD: [&str; 4] = ["alloc", "string", "ToString", "to_string"];
pub const TRANSMUTE: [&str; 4] = ["core", "intrinsics", "", "transmute"];
pub const TRY_FROM: [&str; 4] = ["core", "convert", "TryFrom", "try_from"];
pub const TRY_INTO_TRAIT: [&str; 3] = ["core", "convert", "TryInto"];
pub const VEC: [&str; 3] = ["alloc", "vec", "Vec"];
pub const VEC_AS_MUT_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_mut_slice"];
pub const VEC_AS_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_slice"];
pub const VEC_DEQUE: [&str; 4] = ["alloc", "collections", "vec_deque", "VecDeque"];
pub const VEC_FROM_ELEM: [&str; 3] = ["alloc", "vec", "from_elem"];
pub const VEC_NEW: [&str; 4] = ["alloc", "vec", "Vec", "new"];
pub const VEC_RESIZE: [&str; 4] = ["alloc", "vec", "Vec", "resize"];
pub const WEAK_ARC: [&str; 3] = ["alloc", "sync", "Weak"];
pub const WEAK_RC: [&str; 3] = ["alloc", "rc", "Weak"];
<|endoftext|>


<commit_before>use scroll::{self, Pread};

use error;

use pe::utils;
use pe::section_table;
use pe::data_directories;

#[repr(C)]
#[derive(Debug, PartialEq, Copy, Clone, Default)]
#[derive(Pread, Pwrite)]
pub struct ExportDirectoryTable {
    pub export_flags: u32,
    pub time_date_stamp: u32,
    pub major_version: u16,
    pub minor_version: u16,
    pub name_rva: u32,
    pub ordinal_base: u32,
    pub address_table_entries: u32,
    pub number_of_name_pointers: u32,
    pub export_address_table_rva: u32,
    pub name_pointer_rva: u32,
    pub ordinal_table_rva: u32,
}

pub const SIZEOF_EXPORT_DIRECTORY_TABLE: usize = 40;

impl ExportDirectoryTable {
    pub fn parse(bytes: &[u8], offset: usize) -> error::Result<Self> {
        let res = bytes.pread_with(offset, scroll::LE)?;
        Ok(res)
    }
}

#[derive(Debug)]
pub enum ExportAddressTableEntry {
  ExportRVA(u32),
  ForwarderRVA(u32),
}

pub const SIZEOF_EXPORT_ADDRESS_TABLE_ENTRY: usize = 4;

pub type ExportAddressTable = Vec<ExportAddressTableEntry>;

/// Array of rvas into the export name table
///
/// Export name is defined iff pointer table has pointer to the name
pub type ExportNamePointerTable = Vec<u32>;

/// Array of indexes into the export address table.
///
/// Should obey the formula `idx = ordinal - ordinalbase`
pub type ExportOrdinalTable = Vec<u16>;

#[derive(Debug, Default)]
/// Export data contains the `dll` name which other libraries can import symbols by (two-level namespace), as well as other important indexing data allowing symbol lookups
pub struct ExportData<'a> {
    pub name: &'a str,
    pub export_directory_table: ExportDirectoryTable,
    pub export_name_pointer_table: ExportNamePointerTable,
    pub export_ordinal_table: ExportOrdinalTable,
    pub export_address_table: ExportAddressTable,
}

impl<'a> ExportData<'a> {
    pub fn parse(bytes: &'a [u8], dd: &data_directories::DataDirectory, sections: &[section_table::SectionTable]) -> error::Result<ExportData<'a>> {
        let export_rva = dd.virtual_address as usize;
        let size = dd.size as usize;
        debug!("export_rva {:#x} size {:#}", export_rva, size);
        let export_offset = utils::find_offset_or(export_rva, sections, &format!("Cannot map export_rva ({:#x}) into offset", export_rva))?;
        let export_directory_table = ExportDirectoryTable::parse(bytes, export_offset)?;
        let number_of_name_pointers = export_directory_table.number_of_name_pointers as usize;
        let address_table_entries = export_directory_table.address_table_entries as usize;
        //let ordinal_base = export_directory_table.ordinal_base as usize;

        let mut name_pointer_table_offset = &mut utils::find_offset_or(export_directory_table.name_pointer_rva as usize, sections, &format!("Cannot map export_directory_table.name_pointer_rva ({:#x}) into offset", export_directory_table.name_pointer_rva))?;
        let mut export_name_pointer_table: ExportNamePointerTable = Vec::with_capacity(number_of_name_pointers);
        for _ in 0..number_of_name_pointers {
            export_name_pointer_table.push(bytes.gread_with(name_pointer_table_offset, scroll::LE)?);
        }

        let mut export_ordinal_table_offset = &mut utils::find_offset_or(export_directory_table.ordinal_table_rva as usize, sections, &format!("Cannot map export_directory_table.ordinal_table_rva ({:#x}) into offset", export_directory_table.ordinal_table_rva))?;
        let mut export_ordinal_table: ExportOrdinalTable = Vec::with_capacity(number_of_name_pointers);
        for _ in 0..number_of_name_pointers {
            export_ordinal_table.push(bytes.gread_with(export_ordinal_table_offset, scroll::LE)?);
        }

        let export_address_table_offset = utils::find_offset_or(export_directory_table.export_address_table_rva as usize, sections, &format!("Cannot map export_directory_table.export_address_table_rva ({:#x}) into offset", export_directory_table.export_address_table_rva))?;
        let export_end = export_rva + size;
        let mut offset = &mut export_address_table_offset.clone();
        let mut export_address_table: ExportAddressTable = Vec::with_capacity(address_table_entries);
        for _ in 0..address_table_entries {
            let rva: u32 = bytes.gread_with(offset, scroll::LE)?;
            if utils::is_in_range(rva as usize, export_rva, export_end) {
                export_address_table.push(ExportAddressTableEntry::ForwarderRVA(rva));
            } else {
                export_address_table.push(ExportAddressTableEntry::ExportRVA(rva));
            }
        }

        let name_offset = utils::find_offset_or(export_directory_table.name_rva as usize, sections, &format!("Cannot map export_directory_table.name_rva ({:#x}) into offset", export_directory_table.name_rva))?;
        debug!("ExportData.parse pointers: {:#x} ordinals: {:#x} addresses: {:#x}", name_pointer_table_offset, export_ordinal_table_offset, export_address_table_offset);
        let name: &'a str = bytes.pread(name_offset)?;
        Ok(ExportData {
            name: name,
            export_directory_table: export_directory_table,
            export_name_pointer_table: export_name_pointer_table,
            export_ordinal_table: export_ordinal_table,
            export_address_table: export_address_table,
        })
    }
}

#[derive(Debug)]
/// PE binaries have two kinds of reexports, either specifying the dll's name, or the ordinal value of the dll
pub enum Reexport<'a> {
  DLLName { export: &'a str, lib: &'a str },
  DLLOrdinal { export: &'a str, ordinal: usize }
}

impl<'a> scroll::ctx::TryFromCtx<'a, scroll::Endian> for Reexport<'a> {
    type Error = ::error::Error;
    type Size = usize;
    #[inline]
    fn try_from_ctx(bytes: &'a [u8], _ctx: scroll::Endian) -> Result<(Self, Self::Size), Self::Error> {
        use scroll::{Pread};
        let reexport = bytes.pread::<&str>(0)?;
        let reexport_len = reexport.len();
        //println!("reexport: {}", &reexport);
        for o in 0..reexport_len {
            let c: u8 = bytes.pread(o)?;
            //println!("reexport offset: {:#x} char: {:#x}", *o, c);
            match c {
                // '.'
                0x2e => {
                    let i = o - 1;
                    let dll: &'a str = bytes.pread_with(0, ::scroll::ctx::StrCtx::Length(i))?;
                    //println!("dll: {:?}", &dll);
                    let len = reexport_len - i - 1;
                    let rest: &'a [u8] = bytes.pread_with(o, len)?;
                    //println!("rest: {:?}", &rest);
                    let len = rest.len() - 1;
                    match rest[0] {
                        // '#'
                        0x23 => {
                            // UNTESTED
                            let ordinal = rest.pread_with::<&str>(1, ::scroll::ctx::StrCtx::Length(len))?;
                            let ordinal = ordinal.parse::<u32>().map_err(|_e| error::Error::Malformed(format!("Cannot parse reexport ordinal from {} bytes", bytes.len())))?;
                            // FIXME: return size
                            return Ok((Reexport::DLLOrdinal { export: dll, ordinal: ordinal as usize }, 0))
                        },
                        _ => {
                            let export = rest.pread_with::<&str>(1, ::scroll::ctx::StrCtx::Length(len))?;
                            // FIXME: return size
                            return Ok((Reexport::DLLName { export: export, lib: dll }, 0))
                        }
                    }
                },
                _ => {}
            }
        }
        Err(error::Error::Malformed(format!("Reexport {:#} is malformed", reexport)))
    }
}

impl<'a> Reexport<'a> {
    pub fn parse(bytes: &'a [u8], offset: usize) -> ::error::Result<Reexport<'a>> {
        bytes.pread(offset)
    }
}

#[derive(Debug, Default)]
/// An exported symbol in this binary, contains synthetic data (name offset, etc., are computed)
pub struct Export<'a> {
    pub name: &'a str,
    pub offset: usize,
    pub rva: usize,
    pub size: usize,
    pub reexport: Option<Reexport<'a>>,
}

#[derive(Debug, Copy, Clone)]
struct ExportCtx<'a> {
    pub ptr: u32,
    pub idx: usize,
    pub sections: &'a [section_table::SectionTable],
    pub addresses: &'a ExportAddressTable,
    pub ordinals: &'a ExportOrdinalTable,
}

impl<'a, 'b> scroll::ctx::TryFromCtx<'a, ExportCtx<'b>> for Export<'a> {
    type Error = error::Error;
    type Size = usize;
    #[inline]
    fn try_from_ctx(bytes: &'a [u8], ExportCtx { ptr, idx, sections, addresses, ordinals }: ExportCtx<'b>) -> Result<(Self, Self::Size), Self::Error> {
        use self::ExportAddressTableEntry::*;
        let i = idx;
        let name_offset = utils::find_offset_or(ptr as usize, sections, &format!("Cannot map export name pointer rva ({:#x}) into offset", ptr))?;
        let name = bytes.pread::<&str>(name_offset)?;
        let ordinal = ordinals[i];
        let address_index = ordinal as usize;
        debug!("name: {} name_offset: {:#x} ordinal: {} address_index: {}", name, name_offset, ordinal, address_index);
        if address_index >= addresses.len() {
            debug!("Export.pread bad address index ({}) for {}: idx: {} ordinal: {} addresses.len(): {}", name, address_index, i, ordinal, addresses.len());
            Ok((Export::default(), 0))
        } else {
            match addresses[address_index] {
                ExportRVA(rva) => {
                    let rva = rva as usize;
                    let offset = utils::find_offset_or(rva, sections, &format!("Cannot map export rva ({:#x}) into offset for {}", rva, name))?;
                    debug!("{}: {:#x}", name, offset);
                    Ok((Export { name: name, offset: offset, rva: rva, reexport: None, size: 0 }, 0))
                },
                ForwarderRVA(rva) => {
                    let rva = rva as usize;
                    let offset = utils::find_offset_or(rva, sections, &format!("Cannot map forwarder rva ({:#x}) into offset for {}", rva, name))?;
                    debug!("{}: stroffset {:#x}", name, offset);
                    let reexport = Reexport::parse(bytes, offset)?;
                    debug!("{}: reexport {:?}", name, reexport);
                    Ok((Export { name: name, offset: rva, rva: rva, reexport: Some(reexport), size: 0 }, 0))
                },
            }
        }
    }
}

impl<'a> Export<'a> {
    pub fn parse(bytes: &'a [u8], export_data: &ExportData, sections: &[section_table::SectionTable]) -> error::Result<Vec<Export<'a>>> {
        let pointers = &export_data.export_name_pointer_table;
        let addresses = &export_data.export_address_table;
        let ordinals = &export_data.export_ordinal_table;
        //let ordinal_base = export_data.export_directory_table.ordinal_base as usize;
        let mut exports = Vec::with_capacity(pointers.len());
        for (idx, ptr) in pointers.iter().enumerate() {
            let export = bytes.pread_with(0, ExportCtx { ptr: *ptr, idx: idx, sections: sections, addresses: addresses, ordinals: ordinals })?;
            exports.push(export);
        }
        // TODO: sort + compute size
        Ok (exports)
    }
}

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

    #[test]
    fn size_export_directory_table() {
        assert_eq!(::std::mem::size_of::<ExportDirectoryTable>(), SIZEOF_EXPORT_DIRECTORY_TABLE);
    }
}
<commit_msg>pe.export: add debug logs<commit_after>use scroll::{self, Pread};

use error;

use pe::utils;
use pe::section_table;
use pe::data_directories;

#[repr(C)]
#[derive(Debug, PartialEq, Copy, Clone, Default)]
#[derive(Pread, Pwrite)]
pub struct ExportDirectoryTable {
    pub export_flags: u32,
    pub time_date_stamp: u32,
    pub major_version: u16,
    pub minor_version: u16,
    pub name_rva: u32,
    pub ordinal_base: u32,
    pub address_table_entries: u32,
    pub number_of_name_pointers: u32,
    pub export_address_table_rva: u32,
    pub name_pointer_rva: u32,
    pub ordinal_table_rva: u32,
}

pub const SIZEOF_EXPORT_DIRECTORY_TABLE: usize = 40;

impl ExportDirectoryTable {
    pub fn parse(bytes: &[u8], offset: usize) -> error::Result<Self> {
        let res = bytes.pread_with(offset, scroll::LE)?;
        Ok(res)
    }
}

#[derive(Debug)]
pub enum ExportAddressTableEntry {
  ExportRVA(u32),
  ForwarderRVA(u32),
}

pub const SIZEOF_EXPORT_ADDRESS_TABLE_ENTRY: usize = 4;

pub type ExportAddressTable = Vec<ExportAddressTableEntry>;

/// Array of rvas into the export name table
///
/// Export name is defined iff pointer table has pointer to the name
pub type ExportNamePointerTable = Vec<u32>;

/// Array of indexes into the export address table.
///
/// Should obey the formula `idx = ordinal - ordinalbase`
pub type ExportOrdinalTable = Vec<u16>;

#[derive(Debug, Default)]
/// Export data contains the `dll` name which other libraries can import symbols by (two-level namespace), as well as other important indexing data allowing symbol lookups
pub struct ExportData<'a> {
    pub name: &'a str,
    pub export_directory_table: ExportDirectoryTable,
    pub export_name_pointer_table: ExportNamePointerTable,
    pub export_ordinal_table: ExportOrdinalTable,
    pub export_address_table: ExportAddressTable,
}

impl<'a> ExportData<'a> {
    pub fn parse(bytes: &'a [u8], dd: &data_directories::DataDirectory, sections: &[section_table::SectionTable]) -> error::Result<ExportData<'a>> {
        let export_rva = dd.virtual_address as usize;
        let size = dd.size as usize;
        debug!("export_rva {:#x} size {:#}", export_rva, size);
        let export_offset = utils::find_offset_or(export_rva, sections, &format!("Cannot map export_rva ({:#x}) into offset", export_rva))?;
        let export_directory_table = ExportDirectoryTable::parse(bytes, export_offset)?;
        let number_of_name_pointers = export_directory_table.number_of_name_pointers as usize;
        let address_table_entries = export_directory_table.address_table_entries as usize;
        //let ordinal_base = export_directory_table.ordinal_base as usize;

        let mut name_pointer_table_offset = &mut utils::find_offset_or(export_directory_table.name_pointer_rva as usize, sections, &format!("Cannot map export_directory_table.name_pointer_rva ({:#x}) into offset", export_directory_table.name_pointer_rva))?;
        let mut export_name_pointer_table: ExportNamePointerTable = Vec::with_capacity(number_of_name_pointers);
        for _ in 0..number_of_name_pointers {
            export_name_pointer_table.push(bytes.gread_with(name_pointer_table_offset, scroll::LE)?);
        }

        let mut export_ordinal_table_offset = &mut utils::find_offset_or(export_directory_table.ordinal_table_rva as usize, sections, &format!("Cannot map export_directory_table.ordinal_table_rva ({:#x}) into offset", export_directory_table.ordinal_table_rva))?;
        let mut export_ordinal_table: ExportOrdinalTable = Vec::with_capacity(number_of_name_pointers);
        for _ in 0..number_of_name_pointers {
            export_ordinal_table.push(bytes.gread_with(export_ordinal_table_offset, scroll::LE)?);
        }

        let export_address_table_offset = utils::find_offset_or(export_directory_table.export_address_table_rva as usize, sections, &format!("Cannot map export_directory_table.export_address_table_rva ({:#x}) into offset", export_directory_table.export_address_table_rva))?;
        let export_end = export_rva + size;
        let mut offset = &mut export_address_table_offset.clone();
        let mut export_address_table: ExportAddressTable = Vec::with_capacity(address_table_entries);
        for _ in 0..address_table_entries {
            let rva: u32 = bytes.gread_with(offset, scroll::LE)?;
            if utils::is_in_range(rva as usize, export_rva, export_end) {
                export_address_table.push(ExportAddressTableEntry::ForwarderRVA(rva));
            } else {
                export_address_table.push(ExportAddressTableEntry::ExportRVA(rva));
            }
        }

        let name_offset = utils::find_offset_or(export_directory_table.name_rva as usize, sections, &format!("Cannot map export_directory_table.name_rva ({:#x}) into offset", export_directory_table.name_rva))?;
        debug!("ExportData.parse pointers: {:#x} ordinals: {:#x} addresses: {:#x}", name_pointer_table_offset, export_ordinal_table_offset, export_address_table_offset);
        let name: &'a str = bytes.pread(name_offset)?;
        Ok(ExportData {
            name: name,
            export_directory_table: export_directory_table,
            export_name_pointer_table: export_name_pointer_table,
            export_ordinal_table: export_ordinal_table,
            export_address_table: export_address_table,
        })
    }
}

#[derive(Debug)]
/// PE binaries have two kinds of reexports, either specifying the dll's name, or the ordinal value of the dll
pub enum Reexport<'a> {
  DLLName { export: &'a str, lib: &'a str },
  DLLOrdinal { export: &'a str, ordinal: usize }
}

impl<'a> scroll::ctx::TryFromCtx<'a, scroll::Endian> for Reexport<'a> {
    type Error = ::error::Error;
    type Size = usize;
    #[inline]
    fn try_from_ctx(bytes: &'a [u8], _ctx: scroll::Endian) -> Result<(Self, Self::Size), Self::Error> {
        use scroll::{Pread};
        let reexport = bytes.pread::<&str>(0)?;
        let reexport_len = reexport.len();
        debug!("reexport: {}", &reexport);
        for o in 0..reexport_len {
            let c: u8 = bytes.pread(o)?;
            debug!("reexport offset: {:#x} char: {:#x}", o, c);
            match c {
                // '.'
                0x2e => {
                    let i = o - 1;
                    let dll: &'a str = bytes.pread_with(0, ::scroll::ctx::StrCtx::Length(i))?;
                    debug!("dll: {:?}", &dll);
                    let len = reexport_len - i - 1;
                    let rest: &'a [u8] = bytes.pread_with(o, len)?;
                    debug!("rest: {:?}", &rest);
                    let len = rest.len() - 1;
                    match rest[0] {
                        // '#'
                        0x23 => {
                            // UNTESTED
                            let ordinal = rest.pread_with::<&str>(1, ::scroll::ctx::StrCtx::Length(len))?;
                            let ordinal = ordinal.parse::<u32>().map_err(|_e| error::Error::Malformed(format!("Cannot parse reexport ordinal from {} bytes", bytes.len())))?;
                            // FIXME: return size
                            return Ok((Reexport::DLLOrdinal { export: dll, ordinal: ordinal as usize }, 0))
                        },
                        _ => {
                            let export = rest.pread_with::<&str>(1, ::scroll::ctx::StrCtx::Length(len))?;
                            // FIXME: return size
                            return Ok((Reexport::DLLName { export: export, lib: dll }, 0))
                        }
                    }
                },
                _ => {}
            }
        }
        Err(error::Error::Malformed(format!("Reexport {:#} is malformed", reexport)))
    }
}

impl<'a> Reexport<'a> {
    pub fn parse(bytes: &'a [u8], offset: usize) -> ::error::Result<Reexport<'a>> {
        bytes.pread(offset)
    }
}

#[derive(Debug, Default)]
/// An exported symbol in this binary, contains synthetic data (name offset, etc., are computed)
pub struct Export<'a> {
    pub name: &'a str,
    pub offset: usize,
    pub rva: usize,
    pub size: usize,
    pub reexport: Option<Reexport<'a>>,
}

#[derive(Debug, Copy, Clone)]
struct ExportCtx<'a> {
    pub ptr: u32,
    pub idx: usize,
    pub sections: &'a [section_table::SectionTable],
    pub addresses: &'a ExportAddressTable,
    pub ordinals: &'a ExportOrdinalTable,
}

impl<'a, 'b> scroll::ctx::TryFromCtx<'a, ExportCtx<'b>> for Export<'a> {
    type Error = error::Error;
    type Size = usize;
    #[inline]
    fn try_from_ctx(bytes: &'a [u8], ExportCtx { ptr, idx, sections, addresses, ordinals }: ExportCtx<'b>) -> Result<(Self, Self::Size), Self::Error> {
        use self::ExportAddressTableEntry::*;
        let i = idx;
        let name_offset = utils::find_offset_or(ptr as usize, sections, &format!("Cannot map export name pointer rva ({:#x}) into offset", ptr))?;
        let name = bytes.pread::<&str>(name_offset)?;
        let ordinal = ordinals[i];
        let address_index = ordinal as usize;
        debug!("name: {} name_offset: {:#x} ordinal: {} address_index: {}", name, name_offset, ordinal, address_index);
        if address_index >= addresses.len() {
            debug!("Export.pread bad address index ({}) for {}: idx: {} ordinal: {} addresses.len(): {}", name, address_index, i, ordinal, addresses.len());
            Ok((Export::default(), 0))
        } else {
            match addresses[address_index] {
                ExportRVA(rva) => {
                    let rva = rva as usize;
                    let offset = utils::find_offset_or(rva, sections, &format!("Cannot map export rva ({:#x}) into offset for {}", rva, name))?;
                    debug!("{}: {:#x}", name, offset);
                    Ok((Export { name: name, offset: offset, rva: rva, reexport: None, size: 0 }, 0))
                },
                ForwarderRVA(rva) => {
                    let rva = rva as usize;
                    let offset = utils::find_offset_or(rva, sections, &format!("Cannot map forwarder rva ({:#x}) into offset for {}", rva, name))?;
                    debug!("{}: stroffset {:#x}", name, offset);
                    let reexport = Reexport::parse(bytes, offset)?;
                    debug!("{}: reexport {:?}", name, reexport);
                    Ok((Export { name: name, offset: rva, rva: rva, reexport: Some(reexport), size: 0 }, 0))
                },
            }
        }
    }
}

impl<'a> Export<'a> {
    pub fn parse(bytes: &'a [u8], export_data: &ExportData, sections: &[section_table::SectionTable]) -> error::Result<Vec<Export<'a>>> {
        let pointers = &export_data.export_name_pointer_table;
        let addresses = &export_data.export_address_table;
        let ordinals = &export_data.export_ordinal_table;
        //let ordinal_base = export_data.export_directory_table.ordinal_base as usize;
        let mut exports = Vec::with_capacity(pointers.len());
        for (idx, ptr) in pointers.iter().enumerate() {
            let export = bytes.pread_with(0, ExportCtx { ptr: *ptr, idx: idx, sections: sections, addresses: addresses, ordinals: ordinals })?;
            exports.push(export);
        }
        // TODO: sort + compute size
        Ok (exports)
    }
}

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

    #[test]
    fn size_export_directory_table() {
        assert_eq!(::std::mem::size_of::<ExportDirectoryTable>(), SIZEOF_EXPORT_DIRECTORY_TABLE);
    }
}
<|endoftext|>


<commit_before>use cocoa::base::{id, nil};
use cocoa::foundation::NSString;
use error::NSError;
use objc_bringup::NSArray;
use std::borrow::Cow;
use std::convert::{AsRef, From};
use std::ffi::CStr;
use std::io::Error as _IoError;
use sys::MTLLibrary;
use {FromRaw, FromRawError, Function};

pub struct Library(id);

impl Library {
    pub fn new_function_with_name(&mut self, function_name: &AsRef<str>) -> Option<Function> {
        unsafe {
            let func_name_nsstr = NSString::alloc(nil).init_str(function_name.as_ref());
            let function = self.0.newFunctionWithName(func_name_nsstr);
            FromRaw::from_raw(function).ok()
        }
    }

    pub fn function_names(&self) -> Vec<Cow<str>> {
        let names_array = unsafe { self.0.functionNames() };
        let names_len = unsafe { names_array.count() };
        let mut names_vec = vec![];
        for i in 0..names_len {
            let name = unsafe {
                CStr::from_ptr(names_array.objectAtIndex(i).UTF8String()).to_string_lossy()
            };
            names_vec.push(name);
        }
        names_vec
    }

    pub fn set_label(&mut self, label: &AsRef<str>) {
        unsafe { self.0.setLabel(NSString::alloc(nil).init_str(label.as_ref())) }
    }

    pub fn label(&self) -> Cow<str> {
        unsafe { CStr::from_ptr(self.0.label().UTF8String()).to_string_lossy() }
    }
}

impl_from_into_raw!(Library, of protocol "MTLLibrary");

pub struct LibraryError {
    pub ns_error: Option<NSError>,
    pub error_type: LibraryErrorType
}

pub enum LibraryErrorType {
    SourceError,
    FromRaw(FromRawError),
    IoError(_IoError)
}

impl From<FromRawError> for LibraryError {
    fn from(error: FromRawError) -> Self {
        LibraryError {
            ns_error: None,
            error_type: LibraryErrorType::FromRaw(error)
        }
    }
}
<commit_msg>Refactor LibraryErrorType enum names<commit_after>use cocoa::base::{id, nil};
use cocoa::foundation::NSString;
use error::NSError;
use objc_bringup::NSArray;
use std::borrow::Cow;
use std::convert::{AsRef, From};
use std::ffi::CStr;
use std::io::Error as IoError;
use sys::MTLLibrary;
use {FromRaw, FromRawError, Function};

pub struct Library(id);

impl Library {
    pub fn new_function_with_name(&mut self, function_name: &AsRef<str>) -> Option<Function> {
        unsafe {
            let func_name_nsstr = NSString::alloc(nil).init_str(function_name.as_ref());
            let function = self.0.newFunctionWithName(func_name_nsstr);
            FromRaw::from_raw(function).ok()
        }
    }

    pub fn function_names(&self) -> Vec<Cow<str>> {
        let names_array = unsafe { self.0.functionNames() };
        let names_len = unsafe { names_array.count() };
        let mut names_vec = vec![];
        for i in 0..names_len {
            let name = unsafe {
                CStr::from_ptr(names_array.objectAtIndex(i).UTF8String()).to_string_lossy()
            };
            names_vec.push(name);
        }
        names_vec
    }

    pub fn set_label(&mut self, label: &AsRef<str>) {
        unsafe { self.0.setLabel(NSString::alloc(nil).init_str(label.as_ref())) }
    }

    pub fn label(&self) -> Cow<str> {
        unsafe { CStr::from_ptr(self.0.label().UTF8String()).to_string_lossy() }
    }
}

impl_from_into_raw!(Library, of protocol "MTLLibrary");

pub struct LibraryError {
    pub ns_error: Option<NSError>,
    pub error_type: LibraryErrorType
}

pub enum LibraryErrorType {
    SourceError,
    FromRaw(FromRawError),
    Io(IoError)
}

impl From<FromRawError> for LibraryError {
    fn from(error: FromRawError) -> Self {
        LibraryError {
            ns_error: None,
            error_type: LibraryErrorType::FromRaw(error)
        }
    }
}
<|endoftext|>