<commit_before>// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::mem::size_of;
use std::slice::{from_raw_parts, from_raw_parts_mut};

/// Types for which it is safe to initialize from raw data.
///
/// A type `T` is `DataInit` if and only if it can be initialized by reading its contents from a
/// byte array.  This is generally true for all plain-old-data structs.  It is notably not true for
/// any type that includes a reference.
///
/// Implementing this trait guarantees that it is safe to instantiate the struct with random data.
pub unsafe trait DataInit: Copy + Send + Sync {
    /// Converts a slice of raw data into a reference of `Self`.
    ///
    /// The value of `data` is not copied. Instead a reference is made from the given slice. The
    /// value of `Self` will depend on the representation of the type in memory, and may change in
    /// an unstable fashion.
    ///
    /// This will return `None` if the length of data does not match the size of `Self`, or if the
    /// data is not aligned for the type of `Self`.
    fn from_slice(data: &[u8]) -> Option<&Self> {
        // Early out to avoid an unneeded `align_to` call.
        if data.len() != size_of::<Self>() {
            return None;
        }

        // Safe because the DataInit trait asserts any data is valid for this type, and we ensured
        // the size of the pointer's buffer is the correct size. The `align_to` method ensures that
        // we don't have any unaligned references. This aliases a pointer, but because the pointer
        // is from a const slice reference, there are no mutable aliases. Finally, the reference
        // returned can not outlive data because they have equal implicit lifetime constraints.
        match unsafe { data.align_to::<Self>() } {
            ([], [mid], []) => Some(mid),
            _ => None,
        }
    }

    /// Converts a mutable slice of raw data into a mutable reference of `Self`.
    ///
    /// Because `Self` is made from a reference to the mutable slice`, mutations to the returned
    /// reference are immediately reflected in `data`. The value of the returned `Self` will depend
    /// on the representation of the type in memory, and may change in an unstable fashion.
    ///
    /// This will return `None` if the length of data does not match the size of `Self`, or if the
    /// data is not aligned for the type of `Self`.
    fn from_mut_slice(data: &mut [u8]) -> Option<&mut Self> {
        // Early out to avoid an unneeded `align_to_mut` call.
        if data.len() != size_of::<Self>() {
            return None;
        }

        // Safe because the DataInit trait asserts any data is valid for this type, and we ensured
        // the size of the pointer's buffer is the correct size. The `align_to` method ensures that
        // we don't have any unaligned references. This aliases a pointer, but because the pointer
        // is from a mut slice reference, we borrow the passed in mutable reference. Finally, the
        // reference returned can not outlive data because they have equal implicit lifetime
        // constraints.
        match unsafe { data.align_to_mut::<Self>() } {
            ([], [mid], []) => Some(mid),
            _ => None,
        }
    }

    /// Converts a reference to `self` into a slice of bytes.
    ///
    /// The value of `self` is not copied. Instead, the slice is made from a reference to `self`.
    /// The value of bytes in the returned slice will depend on the representation of the type in
    /// memory, and may change in an unstable fashion.
    fn as_slice(&self) -> &[u8] {
        // Safe because the entire size of self is accessible as bytes because the trait guarantees
        // it. The lifetime of the returned slice is the same as the passed reference, so that no
        // dangling pointers will result from this pointer alias.
        unsafe { from_raw_parts(self as *const Self as *const u8, size_of::<Self>()) }
    }

    /// Converts a mutable reference to `self` into a mutable slice of bytes.
    ///
    /// Because the slice is made from a reference to `self`, mutations to the returned slice are
    /// immediately reflected in `self`. The value of bytes in the returned slice will depend on
    /// the representation of the type in memory, and may change in an unstable fashion.
    fn as_mut_slice(&mut self) -> &mut [u8] {
        // Safe because the entire size of self is accessible as bytes because the trait guarantees
        // it. The trait also guarantees that any combination of bytes is valid for this type, so
        // modifying them in the form of a byte slice is valid. The lifetime of the returned slice
        // is the same as the passed reference, so that no dangling pointers will result from this
        // pointer alias. Although this does alias a mutable pointer, we do so by exclusively
        // borrowing the given mutable reference.
        unsafe { from_raw_parts_mut(self as *mut Self as *mut u8, size_of::<Self>()) }
    }
}

// All intrinsic types and arays of intrinsic types are DataInit.  They are just numbers.
macro_rules! array_data_init {
    ($T:ty, $($N:expr)+) => {
        $(
            unsafe impl DataInit for [$T; $N] {}
        )+
    }
}
macro_rules! data_init_type {
    ($($T:ident),*) => {
        $(
            unsafe impl DataInit for $T {}
            array_data_init! {
                $T,
                0  1  2  3  4  5  6  7  8  9
                10 11 12 13 14 15 16 17 18 19
                20 21 22 23 24 25 26 27 28 29
                30 31 32
            }
        )*
        #[cfg(test)]
        mod data_init_tests {
            use std::mem::{size_of, align_of};
            use crate::DataInit;

            #[test]
            fn from_slice_alignment() {
                let mut v = [0u8; 32];
                $(
                    let (pre, _, _) = unsafe { v.align_to::<$T>() };
                    let pre_len = pre.len();

                    let aligned_v = &mut v[pre_len..pre_len + size_of::<$T>()];

                    let from_aligned = $T::from_slice(aligned_v);
                    assert_eq!(from_aligned, Some(&0));

                    let from_aligned_mut = $T::from_mut_slice(aligned_v);
                    assert_eq!(from_aligned_mut, Some(&mut 0));

                    for i in 1..size_of::<$T>() {
                        let begin = pre_len + i;
                        let end = begin + size_of::<$T>();
                        let unaligned_v = &mut v[begin..end];

                        let from_unaligned = $T::from_slice(unaligned_v);
                        if align_of::<$T>() != 1 {
                            assert_eq!(from_unaligned, None);
                        }

                        let from_unaligned_mut = $T::from_mut_slice(unaligned_v);
                        if align_of::<$T>() != 1 {
                            assert_eq!(from_unaligned_mut, None);
                        }
                    }
                )*

            }
        }
    };
}
data_init_type!(u8, u16, u32, u64, usize, i8, i16, i32, i64, isize);

pub mod endian;
pub use crate::endian::*;

pub mod volatile_memory;
pub use crate::volatile_memory::*;
<commit_msg>data_model: allow reading structs from io::Read<commit_after>// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::io;
use std::mem::{align_of, size_of};
use std::slice::{from_raw_parts, from_raw_parts_mut};

/// Types for which it is safe to initialize from raw data.
///
/// A type `T` is `DataInit` if and only if it can be initialized by reading its contents from a
/// byte array.  This is generally true for all plain-old-data structs.  It is notably not true for
/// any type that includes a reference.
///
/// Implementing this trait guarantees that it is safe to instantiate the struct with random data.
pub unsafe trait DataInit: Copy + Send + Sync {
    /// Converts a slice of raw data into a reference of `Self`.
    ///
    /// The value of `data` is not copied. Instead a reference is made from the given slice. The
    /// value of `Self` will depend on the representation of the type in memory, and may change in
    /// an unstable fashion.
    ///
    /// This will return `None` if the length of data does not match the size of `Self`, or if the
    /// data is not aligned for the type of `Self`.
    fn from_slice(data: &[u8]) -> Option<&Self> {
        // Early out to avoid an unneeded `align_to` call.
        if data.len() != size_of::<Self>() {
            return None;
        }

        // Safe because the DataInit trait asserts any data is valid for this type, and we ensured
        // the size of the pointer's buffer is the correct size. The `align_to` method ensures that
        // we don't have any unaligned references. This aliases a pointer, but because the pointer
        // is from a const slice reference, there are no mutable aliases. Finally, the reference
        // returned can not outlive data because they have equal implicit lifetime constraints.
        match unsafe { data.align_to::<Self>() } {
            ([], [mid], []) => Some(mid),
            _ => None,
        }
    }

    /// Converts a mutable slice of raw data into a mutable reference of `Self`.
    ///
    /// Because `Self` is made from a reference to the mutable slice`, mutations to the returned
    /// reference are immediately reflected in `data`. The value of the returned `Self` will depend
    /// on the representation of the type in memory, and may change in an unstable fashion.
    ///
    /// This will return `None` if the length of data does not match the size of `Self`, or if the
    /// data is not aligned for the type of `Self`.
    fn from_mut_slice(data: &mut [u8]) -> Option<&mut Self> {
        // Early out to avoid an unneeded `align_to_mut` call.
        if data.len() != size_of::<Self>() {
            return None;
        }

        // Safe because the DataInit trait asserts any data is valid for this type, and we ensured
        // the size of the pointer's buffer is the correct size. The `align_to` method ensures that
        // we don't have any unaligned references. This aliases a pointer, but because the pointer
        // is from a mut slice reference, we borrow the passed in mutable reference. Finally, the
        // reference returned can not outlive data because they have equal implicit lifetime
        // constraints.
        match unsafe { data.align_to_mut::<Self>() } {
            ([], [mid], []) => Some(mid),
            _ => None,
        }
    }

    /// Creates an instance of `Self` by copying raw data from an io::Read stream.
    fn from_reader<R: io::Read>(mut read: R) -> io::Result<Self> {
        // Allocate a Vec<u8> with enough extra space for the worst-case alignment offset.
        let mut data = vec![0u8; size_of::<Self>() + align_of::<Self>()];

        // Get a u8 slice within data with sufficient alignment for Self.
        let align_offset = data.as_ptr().align_offset(align_of::<Self>());
        let mut aligned_data = &mut data[align_offset..align_offset + size_of::<Self>()];

        read.read_exact(&mut aligned_data)?;
        match Self::from_slice(&aligned_data) {
            Some(obj) => Ok(*obj),
            None => Err(io::Error::new(
                io::ErrorKind::InvalidData,
                "from_slice failed",
            )),
        }
    }

    /// Converts a reference to `self` into a slice of bytes.
    ///
    /// The value of `self` is not copied. Instead, the slice is made from a reference to `self`.
    /// The value of bytes in the returned slice will depend on the representation of the type in
    /// memory, and may change in an unstable fashion.
    fn as_slice(&self) -> &[u8] {
        // Safe because the entire size of self is accessible as bytes because the trait guarantees
        // it. The lifetime of the returned slice is the same as the passed reference, so that no
        // dangling pointers will result from this pointer alias.
        unsafe { from_raw_parts(self as *const Self as *const u8, size_of::<Self>()) }
    }

    /// Converts a mutable reference to `self` into a mutable slice of bytes.
    ///
    /// Because the slice is made from a reference to `self`, mutations to the returned slice are
    /// immediately reflected in `self`. The value of bytes in the returned slice will depend on
    /// the representation of the type in memory, and may change in an unstable fashion.
    fn as_mut_slice(&mut self) -> &mut [u8] {
        // Safe because the entire size of self is accessible as bytes because the trait guarantees
        // it. The trait also guarantees that any combination of bytes is valid for this type, so
        // modifying them in the form of a byte slice is valid. The lifetime of the returned slice
        // is the same as the passed reference, so that no dangling pointers will result from this
        // pointer alias. Although this does alias a mutable pointer, we do so by exclusively
        // borrowing the given mutable reference.
        unsafe { from_raw_parts_mut(self as *mut Self as *mut u8, size_of::<Self>()) }
    }
}

// All intrinsic types and arays of intrinsic types are DataInit.  They are just numbers.
macro_rules! array_data_init {
    ($T:ty, $($N:expr)+) => {
        $(
            unsafe impl DataInit for [$T; $N] {}
        )+
    }
}
macro_rules! data_init_type {
    ($($T:ident),*) => {
        $(
            unsafe impl DataInit for $T {}
            array_data_init! {
                $T,
                0  1  2  3  4  5  6  7  8  9
                10 11 12 13 14 15 16 17 18 19
                20 21 22 23 24 25 26 27 28 29
                30 31 32
            }
        )*
        #[cfg(test)]
        mod data_init_tests {
            use std::mem::{size_of, align_of};
            use crate::DataInit;

            #[test]
            fn from_slice_alignment() {
                let mut v = [0u8; 32];
                $(
                    let (pre, _, _) = unsafe { v.align_to::<$T>() };
                    let pre_len = pre.len();

                    let aligned_v = &mut v[pre_len..pre_len + size_of::<$T>()];

                    let from_aligned = $T::from_slice(aligned_v);
                    assert_eq!(from_aligned, Some(&0));

                    let from_aligned_mut = $T::from_mut_slice(aligned_v);
                    assert_eq!(from_aligned_mut, Some(&mut 0));

                    for i in 1..size_of::<$T>() {
                        let begin = pre_len + i;
                        let end = begin + size_of::<$T>();
                        let unaligned_v = &mut v[begin..end];

                        let from_unaligned = $T::from_slice(unaligned_v);
                        if align_of::<$T>() != 1 {
                            assert_eq!(from_unaligned, None);
                        }

                        let from_unaligned_mut = $T::from_mut_slice(unaligned_v);
                        if align_of::<$T>() != 1 {
                            assert_eq!(from_unaligned_mut, None);
                        }
                    }
                )*

            }
        }
    };
}
data_init_type!(u8, u16, u32, u64, usize, i8, i16, i32, i64, isize);

pub mod endian;
pub use crate::endian::*;

pub mod volatile_memory;
pub use crate::volatile_memory::*;
<|endoftext|>


<commit_before>use crate::common::util::*;

static INPUT: &str = "lists.txt";

struct TestedSequence<'b> {
    name: &'b str,
    sequence: &'b str,
}

static EXAMPLE_SEQUENCES: &[TestedSequence] = &[
    TestedSequence {
        name: "singular",
        sequence: "2",
    },
    TestedSequence {
        name: "prefix",
        sequence: "-2",
    },
    TestedSequence {
        name: "suffix",
        sequence: "2-",
    },
    TestedSequence {
        name: "range",
        sequence: "2-4",
    },
    TestedSequence {
        name: "aggregate",
        sequence: "9-,6-7,-2,4",
    },
    TestedSequence {
        name: "subsumed",
        sequence: "2-,3",
    },
];

static COMPLEX_SEQUENCE: &TestedSequence = &TestedSequence {
    name: "",
    sequence: "9-,6-7,-2,4",
};

#[test]
fn test_byte_sequence() {
    for &param in &["-b", "--bytes"] {
        for example_seq in EXAMPLE_SEQUENCES {
            new_ucmd!()
                .args(&[param, example_seq.sequence, INPUT])
                .succeeds()
                .stdout_only_fixture(format!("sequences/byte_{}.expected", example_seq.name));
        }
    }
}

#[test]
fn test_char_sequence() {
    for &param in &["-c", "--characters"] {
        for example_seq in EXAMPLE_SEQUENCES {
            //as of coreutils 8.25 a char range is effectively the same as a byte range; there is no distinct treatment of utf8 chars.
            new_ucmd!()
                .args(&[param, example_seq.sequence, INPUT])
                .succeeds()
                .stdout_only_fixture(format!("sequences/byte_{}.expected", example_seq.name));
        }
    }
}

#[test]
fn test_field_sequence() {
    for &param in &["-f", "--fields"] {
        for example_seq in EXAMPLE_SEQUENCES {
            new_ucmd!()
                .args(&[param, example_seq.sequence, INPUT])
                .succeeds()
                .stdout_only_fixture(format!("sequences/field_{}.expected", example_seq.name));
        }
    }
}

#[test]
fn test_specify_delimiter() {
    for &param in &["-d", "--delimiter"] {
        new_ucmd!()
            .args(&[param, ":", "-f", COMPLEX_SEQUENCE.sequence, INPUT])
            .succeeds()
            .stdout_only_fixture("delimiter_specified.expected");
    }
}

#[test]
fn test_output_delimiter() {
    // we use -d here to ensure output delimiter
    // is applied to the current, and not just the default, input delimiter
    new_ucmd!()
        .args(&[
            "-d:",
            "--output-delimiter=@",
            "-f",
            COMPLEX_SEQUENCE.sequence,
            INPUT,
        ])
        .succeeds()
        .stdout_only_fixture("output_delimiter.expected");
}

#[test]
fn test_complement() {
    new_ucmd!()
        .args(&["-d_", "--complement", "-f", "2"])
        .pipe_in("9_1\n8_2\n7_3")
        .succeeds()
        .stdout_only("9\n8\n7\n");
}

#[test]
fn test_zero_terminated() {
    new_ucmd!()
        .args(&["-d_", "-z", "-f", "1"])
        .pipe_in("9_1\n8_2\n\07_3")
        .succeeds()
        .stdout_only("9\07\0");
}

#[test]
fn test_only_delimited() {
    for param in &["-s", "--only-delimited"] {
        new_ucmd!()
            .args(&["-d_", param, "-f", "1"])
            .pipe_in("91\n82\n7_3")
            .succeeds()
            .stdout_only("7\n");
    }
}

#[test]
fn test_zero_terminated_only_delimited() {
    new_ucmd!()
        .args(&["-d_", "-z", "-s", "-f", "1"])
        .pipe_in("91\n\082\n7_3")
        .succeeds()
        .stdout_only("82\n7\0");
}

#[test]
fn test_directory_and_no_such_file() {
    let (at, mut ucmd) = at_and_ucmd!();

    at.mkdir("some");

    ucmd.arg("-b1")
        .arg("some")
        .run()
        .stderr_is("cut: some: Is a directory\n");

    new_ucmd!()
        .arg("-b1")
        .arg("some")
        .run()
        .stderr_is("cut: some: No such file or directory\n");
}

#[test]
fn test_equal_as_delimiter() {
    new_ucmd!()
        .args(&["-f", "2", "-d="])
        .pipe_in("--libdir=./out/lib")
        .succeeds()
        .stdout_only("./out/lib\n");
}
<commit_msg>tests ~ fix spelling errors<commit_after>use crate::common::util::*;

static INPUT: &str = "lists.txt";

struct TestedSequence<'b> {
    name: &'b str,
    sequence: &'b str,
}

static EXAMPLE_SEQUENCES: &[TestedSequence] = &[
    TestedSequence {
        name: "singular",
        sequence: "2",
    },
    TestedSequence {
        name: "prefix",
        sequence: "-2",
    },
    TestedSequence {
        name: "suffix",
        sequence: "2-",
    },
    TestedSequence {
        name: "range",
        sequence: "2-4",
    },
    TestedSequence {
        name: "aggregate",
        sequence: "9-,6-7,-2,4",
    },
    TestedSequence {
        name: "subsumed",
        sequence: "2-,3",
    },
];

static COMPLEX_SEQUENCE: &TestedSequence = &TestedSequence {
    name: "",
    sequence: "9-,6-7,-2,4",
};

#[test]
fn test_byte_sequence() {
    for &param in &["-b", "--bytes"] {
        for example_seq in EXAMPLE_SEQUENCES {
            new_ucmd!()
                .args(&[param, example_seq.sequence, INPUT])
                .succeeds()
                .stdout_only_fixture(format!("sequences/byte_{}.expected", example_seq.name));
        }
    }
}

#[test]
fn test_char_sequence() {
    for &param in &["-c", "--characters"] {
        for example_seq in EXAMPLE_SEQUENCES {
            //as of coreutils 8.25 a char range is effectively the same as a byte range; there is no distinct treatment of utf8 chars.
            new_ucmd!()
                .args(&[param, example_seq.sequence, INPUT])
                .succeeds()
                .stdout_only_fixture(format!("sequences/byte_{}.expected", example_seq.name));
        }
    }
}

#[test]
fn test_field_sequence() {
    for &param in &["-f", "--fields"] {
        for example_seq in EXAMPLE_SEQUENCES {
            new_ucmd!()
                .args(&[param, example_seq.sequence, INPUT])
                .succeeds()
                .stdout_only_fixture(format!("sequences/field_{}.expected", example_seq.name));
        }
    }
}

#[test]
fn test_specify_delimiter() {
    for &param in &["-d", "--delimiter"] {
        new_ucmd!()
            .args(&[param, ":", "-f", COMPLEX_SEQUENCE.sequence, INPUT])
            .succeeds()
            .stdout_only_fixture("delimiter_specified.expected");
    }
}

#[test]
fn test_output_delimiter() {
    // we use -d here to ensure output delimiter
    // is applied to the current, and not just the default, input delimiter
    new_ucmd!()
        .args(&[
            "-d:",
            "--output-delimiter=@",
            "-f",
            COMPLEX_SEQUENCE.sequence,
            INPUT,
        ])
        .succeeds()
        .stdout_only_fixture("output_delimiter.expected");
}

#[test]
fn test_complement() {
    new_ucmd!()
        .args(&["-d_", "--complement", "-f", "2"])
        .pipe_in("9_1\n8_2\n7_3")
        .succeeds()
        .stdout_only("9\n8\n7\n");
}

#[test]
fn test_zero_terminated() {
    new_ucmd!()
        .args(&["-d_", "-z", "-f", "1"])
        .pipe_in("9_1\n8_2\n\07_3")
        .succeeds()
        .stdout_only("9\07\0");
}

#[test]
fn test_only_delimited() {
    for param in &["-s", "--only-delimited"] {
        new_ucmd!()
            .args(&["-d_", param, "-f", "1"])
            .pipe_in("91\n82\n7_3")
            .succeeds()
            .stdout_only("7\n");
    }
}

#[test]
fn test_zero_terminated_only_delimited() {
    new_ucmd!()
        .args(&["-d_", "-z", "-s", "-f", "1"])
        .pipe_in("91\n\082\n7_3")
        .succeeds()
        .stdout_only("82\n7\0");
}

#[test]
fn test_directory_and_no_such_file() {
    let (at, mut ucmd) = at_and_ucmd!();

    at.mkdir("some");

    ucmd.arg("-b1")
        .arg("some")
        .run()
        .stderr_is("cut: some: Is a directory\n");

    new_ucmd!()
        .arg("-b1")
        .arg("some")
        .run()
        .stderr_is("cut: some: No such file or directory\n");
}

#[test]
fn test_equal_as_delimiter() {
    new_ucmd!()
        .args(&["-f", "2", "-d="])
        .pipe_in("--dir=./out/lib")
        .succeeds()
        .stdout_only("./out/lib\n");
}
<|endoftext|>


<commit_before>extern crate ralg as r;

#[cfg(test)]
mod tests {
    use r::linspace::point::*;

    #[test]
    fn point_init_test() {
        let p3 = Point3D::<f64>::init();

        assert_eq!(p3.x(), 0.0);
        assert_eq!(p3.y(), 0.0);
        assert_eq!(p3.z(), 0.0);
    }

    #[test]
    fn point_init_with_values_test() {
        let p3 = Point3D::<f64>::init_with_values(1.0, 2.5, -3.0);

        assert_eq!(p3.x(), 1.0);
        assert_eq!(p3.y(), 2.5);
        assert_eq!(p3.z(), -3.0);
    }
    #[test]
    fn point_set_x_test(){
        let mut a = Point3D::<u64>::init_with_values(256, 450, 178);
        a.set_x(200);

        assert_eq!(a.x(), 200);
        assert_eq!(a.y(), a.y());
        assert_eq!(a.z(), a.z());
    }
    #[test]
    fn point_set_y_test(){
        let mut a = Point3D::<i64>::init_with_values(-25, 40, -17);
        a.set_y(20);

        assert_eq!(a.x(), a.x());
        assert_eq!(a.y(), 20);
        assert_eq!(a.z(), a.z());
    }
    #[test]
    fn point_set_z_test(){
        let mut a = Point3D::<f32>::init_with_values(25.6, 4.5, 17.8);
        a.set_z(2.5);

        assert_eq!(a.x(), a.x());
        assert_eq!(a.y(), a.y());
        assert_eq!(a.z(), 2.5);
    }
    #[test]
    fn point_set_test(){
        let mut a = Point3D::<f32>::init_with_values(25.6, 4.5, 17.8);
        a.set(2.5, 0.1, 1.2);

        assert_eq!(a.x(), 2.5);
        assert_eq!(a.y(), 0.1);
        assert_eq!(a.z(), 1.2);
    }
    #[test]
    fn point_eucl_distance_test() {
        let p1 = Point3D::<i32>::init_with_values(-1, 2, 3);
        let p2 = Point3D::<i32>::init_with_values(0, 5, 8);

        let d = Point3D::<i32>::eucl_distance(&p1, &p2);
        println!("{}", p1);
        println!("{}", p2);
        println!("{}", d);
    }
}
<commit_msg>error in the test point.rs<commit_after>extern crate ralg as r;

#[cfg(test)]
mod tests {
    use r::linspace::point::*;

    #[test]
    fn point_init_test() {
        let p3 = Point3D::<f64>::init();

        assert_eq!(p3.x(), 0.0);
        assert_eq!(p3.y(), 0.0);
        assert_eq!(p3.z(), 0.0);
    }

    #[test]
    fn point_init_with_values_test() {
        let p3 = Point3D::<f64>::init_with_values(1.0, 2.5, -3.0);

        assert_eq!(p3.x(), 1.0);
        assert_eq!(p3.y(), 2.5);
        assert_eq!(p3.z(), -3.0);
    }
    #[test]
    fn point_set_x_test(){
        let mut a = Point3D::<u64>::init_with_values(256, 450, 178);
        a.set_x(200);

        assert_eq!(a.x(), 200);
        assert_eq!(a.y(), a.y());
        assert_eq!(a.z(), a.z());
    }
    #[test]
    fn point_set_y_test(){
        let mut a = Point3D::<i64>::init_with_values(-25, 40, -17);
        a.set_y(20);

        assert_eq!(a.x(), a.x());
        assert_eq!(a.y(), 20);
        assert_eq!(a.z(), a.z());
    }
    #[test]
    fn point_set_z_test(){
        let mut a = Point3D::<f32>::init_with_values(25.6, 4.5, 17.8);
        a.set_z(2.5);

        assert_eq!(a.x(), a.x());
        assert_eq!(a.y(), a.y());
        assert_eq!(a.z(), 2.5);
    }
    #[test]
    fn point_set_test(){
        let mut a = Point3D::<f32>::init_with_values(25.6, 4.5, 17.8);
        a.set(2.5, 0.1, 1.2);

        assert_eq!(a.x(), 2.5);
        assert_eq!(a.y(), 0.1);
        assert_eq!(a.z(), 1.2);
    }
    #[test]
    fn point_eucl_distance_test() {
        let p1 = Point3D::<i32>::init_with_values(-1, 2, 3);
        let p2 = Point3D::<i32>::init_with_values(0, 5, 8);

        let d = Point3D::<i32>::eucl_distance(&p1, &p2);

        assert_eq!(d, 5.916079783099616); // using online euclidean distance calculator
    }
}
<|endoftext|>


<commit_before>//! Expose a C compatible interface.

use std::ffi::{CStr, CString};
use std::os::raw;

#[repr(C)]
pub struct Api {
    inner: crate::Api,
    last_error: Option<CString>,
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct DetectedDac {
    pub kind: DetectedDacKind,
}

#[repr(C)]
#[derive(Clone, Copy)]
pub union DetectedDacKind {
    pub ether_dream: DacEtherDream,
}

#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct DacEtherDream {
    pub broadcast: ether_dream::protocol::DacBroadcast,
    pub source_addr: *const raw::c_char,
}

#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct StreamConfig {
    pub detected_dac: *const DetectedDac,
    pub point_hz: raw::c_uint,
    pub latency_points: raw::c_uint,
}

#[repr(C)]
pub struct FrameStream {
    stream: FrameStreamInner,
}

#[repr(C)]
pub struct RawStream {
    stream: RawStreamInner,
}

#[repr(C)]
#[derive(Clone, Copy)]
pub enum Result {
    Success = 0,
    FailedToDetectDac,
    FailedToBuildStream,
}

#[repr(C)]
#[derive(Clone, Debug)]
pub struct FrameStreamConfig {
    pub stream_conf: StreamConfig,
    pub frame_hz: u32,
    pub interpolation_conf: crate::stream::frame::opt::InterpolationConfig,
}

#[repr(C)]
pub struct Frame<'a> {
    frame: &'a mut crate::stream::frame::Frame,
}

#[repr(C)]
pub struct Buffer<'a> {
    buffer: &'a mut crate::stream::raw::Buffer,
}

struct FrameStreamModel(*mut raw::c_void, FrameRenderCallback, RawRenderCallback);
struct RawStreamModel(*mut raw::c_void, RawRenderCallback);

unsafe impl Send for FrameStreamModel {}
unsafe impl Send for RawStreamModel {}

type FrameStreamInner = crate::FrameStream<FrameStreamModel>;
type RawStreamInner = crate::RawStream<RawStreamModel>;

/// Cast to `extern fn(*mut raw::c_void, *mut Frame)` internally.
//pub type FrameRenderCallback = *const raw::c_void;
pub type FrameRenderCallback = extern "C" fn(*mut raw::c_void, *mut Frame);
/// Cast to `extern fn(*mut raw::c_void, *mut Buffer)` internally.
//pub type RawRenderCallback = *const raw::c_void;
pub type RawRenderCallback = extern "C" fn(*mut raw::c_void, *mut Buffer);

/// Given some uninitialized pointer to an `Api` struct, fill it with a new Api instance.
#[no_mangle]
pub unsafe extern "C" fn api_new(api_ptr: *mut *mut Api) {
    let inner = crate::Api::new();
    let last_error = None;
    let api = Api { inner, last_error };
    let boxed_api = Box::new(api);
    let new_api_ptr = Box::into_raw(boxed_api);
    *api_ptr = new_api_ptr;
}

/// Block the current thread until a new DAC is detected and return it.
#[no_mangle]
pub unsafe extern "C" fn detect_dac(api: *const Api, detected_dac: *mut DetectedDac) -> Result {
    let api: &Api = &*api;
    let mut iter = match api.inner.detect_dacs() {
        Err(err) => unimplemented!(),
        Ok(iter) => iter,
    };
    match iter.next() {
        None => return Result::FailedToDetectDac,
        Some(res) => match res {
            Ok(crate::DetectedDac::EtherDream {
                broadcast,
                source_addr,
            }) => {
                let string = format!("{}", source_addr);
                let bytes = string.into_bytes();
                let source_addr = bytes.as_ptr() as *const raw::c_char;
                std::mem::forget(bytes);
                let ether_dream = DacEtherDream {
                    broadcast,
                    source_addr,
                };
                let kind = DetectedDacKind { ether_dream };
                *detected_dac = DetectedDac { kind };
                return Result::Success;
            }
            Err(err) => unimplemented!(),
        },
    }
}

fn default_stream_config() -> StreamConfig {
    let detected_dac = std::ptr::null();
    let point_hz = crate::stream::DEFAULT_POINT_HZ;
    let latency_points = crate::stream::raw::default_latency_points(point_hz);
    StreamConfig {
        detected_dac,
        point_hz,
        latency_points,
    }
}

/// Initialise the given frame stream configuration with default values.
#[no_mangle]
pub unsafe extern "C" fn frame_stream_config_default(conf: *mut FrameStreamConfig) {
    let stream_conf = default_stream_config();
    let frame_hz = crate::stream::DEFAULT_FRAME_HZ;
    let interpolation_conf = crate::stream::frame::opt::InterpolationConfig::start().build();
    *conf = FrameStreamConfig {
        stream_conf,
        frame_hz,
        interpolation_conf,
    };
}

/// Initialise the given raw stream configuration with default values.
#[no_mangle]
pub unsafe extern "C" fn stream_config_default(conf: *mut StreamConfig) {
    *conf = default_stream_config();
}

/// Spawn a new frame rendering stream.
#[no_mangle]
pub unsafe extern "C" fn new_frame_stream(
    api: *const Api,
    stream: *mut *mut FrameStream,
    config: *const FrameStreamConfig,
    callback_data: *mut raw::c_void,
    frame_render_callback: FrameRenderCallback,
    process_raw_callback: RawRenderCallback,
) -> Result {
    let api: &Api = &*api;
    let model = FrameStreamModel(callback_data, frame_render_callback, process_raw_callback);

    fn render_fn(model: &mut FrameStreamModel, frame: &mut crate::stream::frame::Frame) {
        let FrameStreamModel(callback_data_ptr, frame_render_callback, _) = *model;
        let mut frame = Frame { frame };
        frame_render_callback(callback_data_ptr, &mut frame);
    }

    let mut builder = api
        .inner
        .new_frame_stream(model, render_fn)
        .point_hz((*config).stream_conf.point_hz as _)
        .latency_points((*config).stream_conf.latency_points as _)
        .frame_hz((*config).frame_hz as _);

    fn process_raw_fn(model: &mut FrameStreamModel, buffer: &mut crate::stream::raw::Buffer) {
        let FrameStreamModel(callback_data_ptr, _, process_raw_callback) = *model;
        let mut buffer = Buffer { buffer };
        process_raw_callback(callback_data_ptr, &mut buffer);
    }

    builder = builder.process_raw(process_raw_fn);

    if (*config).stream_conf.detected_dac != std::ptr::null() {
        let ffi_dac = (*(*config).stream_conf.detected_dac).clone();
        let broadcast = ffi_dac.kind.ether_dream.broadcast.clone();
        let source_addr_ptr = ffi_dac.kind.ether_dream.source_addr;
        let source_addr = CStr::from_ptr(source_addr_ptr)
            .to_string_lossy()
            .parse()
            .expect("failed to parse `source_addr`");
        let detected_dac = crate::DetectedDac::EtherDream {
            broadcast,
            source_addr,
        };
        builder = builder.detected_dac(detected_dac);
    }

    let frame_stream = match builder.build() {
        Err(err) => {
            unimplemented!();
            return Result::FailedToBuildStream;
        }
        Ok(stream) => Box::new(FrameStream { stream }),
    };
    *stream = Box::into_raw(frame_stream);
    Result::Success
}

/// Spawn a new frame rendering stream.
#[no_mangle]
pub unsafe extern "C" fn new_raw_stream(
    api: *const Api,
    stream: *mut *mut RawStream,
    config: *const StreamConfig,
    callback_data: *mut raw::c_void,
    process_raw_callback: RawRenderCallback,
) -> Result {
    let api: &Api = &*api;
    let model = RawStreamModel(callback_data, process_raw_callback);

    fn render_fn(model: &mut RawStreamModel, buffer: &mut crate::stream::raw::Buffer) {
        let RawStreamModel(callback_data_ptr, raw_render_callback) = *model;
        let mut buffer = Buffer { buffer };
        raw_render_callback(callback_data_ptr, &mut buffer);
    }

    let mut builder = api
        .inner
        .new_raw_stream(model, render_fn)
        .point_hz((*config).point_hz as _)
        .latency_points((*config).latency_points as _);

    if (*config).detected_dac != std::ptr::null() {
        let ffi_dac = (*(*config).detected_dac).clone();
        let broadcast = ffi_dac.kind.ether_dream.broadcast.clone();
        let source_addr_ptr = ffi_dac.kind.ether_dream.source_addr;
        let source_addr = CStr::from_ptr(source_addr_ptr)
            .to_string_lossy()
            .parse()
            .expect("failed to parse `source_addr`");
        let detected_dac = crate::DetectedDac::EtherDream {
            broadcast,
            source_addr,
        };
        builder = builder.detected_dac(detected_dac);
    }

    let raw_stream = match builder.build() {
        Err(err) => {
            unimplemented!();
            return Result::FailedToBuildStream;
        }
        Ok(stream) => Box::new(RawStream { stream }),
    };
    *stream = Box::into_raw(raw_stream);

    Result::Success
}

/// Add a sequence of consecutive points separated by blank space.
///
/// If some points already exist in the frame, this method will create a blank segment between the
/// previous point and the first point before appending this sequence.
#[no_mangle]
pub unsafe extern "C" fn frame_add_points(
    frame: *mut Frame,
    points: *const crate::Point,
    len: usize,
) {
    let frame = &mut *frame;
    let points = std::slice::from_raw_parts(points, len);
    frame.frame.add_points(points.iter().cloned());
}

/// Add a sequence of consecutive lines.
///
/// If some points already exist in the frame, this method will create a blank segment between the
/// previous point and the first point before appending this sequence.
#[no_mangle]
pub unsafe extern "C" fn frame_add_lines(
    frame: *mut Frame,
    points: *const crate::Point,
    len: usize,
) {
    let frame = &mut *frame;
    let points = std::slice::from_raw_parts(points, len);
    frame.frame.add_lines(points.iter().cloned());
}

pub unsafe extern "C" fn frame_hz(frame: *const Frame) -> u32 {
    (*frame).frame.frame_hz()
}

pub unsafe extern "C" fn frame_point_hz(frame: *const Frame) -> u32 {
    (*frame).frame.point_hz()
}

pub unsafe extern "C" fn frame_latency_points(frame: *const Frame) -> u32 {
    (*frame).frame.latency_points()
}

pub unsafe extern "C" fn points_per_frame(frame: *const Frame) -> u32 {
    (*frame).frame.latency_points()
}

/// Must be called in order to correctly clean up the frame stream.
#[no_mangle]
pub unsafe extern "C" fn frame_stream_drop(stream_ptr: *mut FrameStream) {
    if stream_ptr != std::ptr::null_mut() {
        Box::from_raw(stream_ptr);
    }
}

/// Must be called in order to correctly clean up the raw stream.
#[no_mangle]
pub unsafe extern "C" fn raw_stream_drop(stream_ptr: *mut RawStream) {
    if stream_ptr != std::ptr::null_mut() {
        Box::from_raw(stream_ptr);
    }
}

/// Must be called in order to correctly clean up the API resources.
#[no_mangle]
pub unsafe extern "C" fn api_drop(api_ptr: *mut Api) {
    if api_ptr != std::ptr::null_mut() {
        Box::from_raw(api_ptr);
    }
}
<commit_msg>Address warnings in nannou_laser<commit_after>//! Expose a C compatible interface.

use std::ffi::{CStr, CString};
use std::os::raw;

#[repr(C)]
pub struct Api {
    inner: crate::Api,
    last_error: Option<CString>,
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct DetectedDac {
    pub kind: DetectedDacKind,
}

#[repr(C)]
#[derive(Clone, Copy)]
pub union DetectedDacKind {
    pub ether_dream: DacEtherDream,
}

#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct DacEtherDream {
    pub broadcast: ether_dream::protocol::DacBroadcast,
    pub source_addr: *const raw::c_char,
}

#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct StreamConfig {
    pub detected_dac: *const DetectedDac,
    pub point_hz: raw::c_uint,
    pub latency_points: raw::c_uint,
}

#[repr(C)]
pub struct FrameStream {
    stream: FrameStreamInner,
}

#[repr(C)]
pub struct RawStream {
    stream: RawStreamInner,
}

#[repr(C)]
#[derive(Clone, Copy)]
pub enum Result {
    Success = 0,
    FailedToDetectDac,
    FailedToBuildStream,
}

#[repr(C)]
#[derive(Clone, Debug)]
pub struct FrameStreamConfig {
    pub stream_conf: StreamConfig,
    pub frame_hz: u32,
    pub interpolation_conf: crate::stream::frame::opt::InterpolationConfig,
}

#[repr(C)]
pub struct Frame<'a> {
    frame: &'a mut crate::stream::frame::Frame,
}

#[repr(C)]
pub struct Buffer<'a> {
    buffer: &'a mut crate::stream::raw::Buffer,
}

struct FrameStreamModel(*mut raw::c_void, FrameRenderCallback, RawRenderCallback);
struct RawStreamModel(*mut raw::c_void, RawRenderCallback);

unsafe impl Send for FrameStreamModel {}
unsafe impl Send for RawStreamModel {}

type FrameStreamInner = crate::FrameStream<FrameStreamModel>;
type RawStreamInner = crate::RawStream<RawStreamModel>;

/// Cast to `extern fn(*mut raw::c_void, *mut Frame)` internally.
//pub type FrameRenderCallback = *const raw::c_void;
pub type FrameRenderCallback = extern "C" fn(*mut raw::c_void, *mut Frame);
/// Cast to `extern fn(*mut raw::c_void, *mut Buffer)` internally.
//pub type RawRenderCallback = *const raw::c_void;
pub type RawRenderCallback = extern "C" fn(*mut raw::c_void, *mut Buffer);

/// Given some uninitialized pointer to an `Api` struct, fill it with a new Api instance.
#[no_mangle]
pub unsafe extern "C" fn api_new(api_ptr: *mut *mut Api) {
    let inner = crate::Api::new();
    let last_error = None;
    let api = Api { inner, last_error };
    let boxed_api = Box::new(api);
    let new_api_ptr = Box::into_raw(boxed_api);
    *api_ptr = new_api_ptr;
}

/// Block the current thread until a new DAC is detected and return it.
#[no_mangle]
pub unsafe extern "C" fn detect_dac(api: *const Api, detected_dac: *mut DetectedDac) -> Result {
    let api: &Api = &*api;
    let mut iter = match api.inner.detect_dacs() {
        Err(_err) => {
            // TODO: Store error
            return Result::FailedToDetectDac;
        }
        Ok(iter) => iter,
    };
    match iter.next() {
        None => return Result::FailedToDetectDac,
        Some(res) => match res {
            Ok(crate::DetectedDac::EtherDream {
                broadcast,
                source_addr,
            }) => {
                let string = format!("{}", source_addr);
                let bytes = string.into_bytes();
                let source_addr = bytes.as_ptr() as *const raw::c_char;
                std::mem::forget(bytes);
                let ether_dream = DacEtherDream {
                    broadcast,
                    source_addr,
                };
                let kind = DetectedDacKind { ether_dream };
                *detected_dac = DetectedDac { kind };
                return Result::Success;
            }
            Err(_err) => {
                // TODO: Store error
                return Result::FailedToDetectDac;
            }
        },
    }
}

fn default_stream_config() -> StreamConfig {
    let detected_dac = std::ptr::null();
    let point_hz = crate::stream::DEFAULT_POINT_HZ;
    let latency_points = crate::stream::raw::default_latency_points(point_hz);
    StreamConfig {
        detected_dac,
        point_hz,
        latency_points,
    }
}

/// Initialise the given frame stream configuration with default values.
#[no_mangle]
pub unsafe extern "C" fn frame_stream_config_default(conf: *mut FrameStreamConfig) {
    let stream_conf = default_stream_config();
    let frame_hz = crate::stream::DEFAULT_FRAME_HZ;
    let interpolation_conf = crate::stream::frame::opt::InterpolationConfig::start().build();
    *conf = FrameStreamConfig {
        stream_conf,
        frame_hz,
        interpolation_conf,
    };
}

/// Initialise the given raw stream configuration with default values.
#[no_mangle]
pub unsafe extern "C" fn stream_config_default(conf: *mut StreamConfig) {
    *conf = default_stream_config();
}

/// Spawn a new frame rendering stream.
#[no_mangle]
pub unsafe extern "C" fn new_frame_stream(
    api: *const Api,
    stream: *mut *mut FrameStream,
    config: *const FrameStreamConfig,
    callback_data: *mut raw::c_void,
    frame_render_callback: FrameRenderCallback,
    process_raw_callback: RawRenderCallback,
) -> Result {
    let api: &Api = &*api;
    let model = FrameStreamModel(callback_data, frame_render_callback, process_raw_callback);

    fn render_fn(model: &mut FrameStreamModel, frame: &mut crate::stream::frame::Frame) {
        let FrameStreamModel(callback_data_ptr, frame_render_callback, _) = *model;
        let mut frame = Frame { frame };
        frame_render_callback(callback_data_ptr, &mut frame);
    }

    let mut builder = api
        .inner
        .new_frame_stream(model, render_fn)
        .point_hz((*config).stream_conf.point_hz as _)
        .latency_points((*config).stream_conf.latency_points as _)
        .frame_hz((*config).frame_hz as _);

    fn process_raw_fn(model: &mut FrameStreamModel, buffer: &mut crate::stream::raw::Buffer) {
        let FrameStreamModel(callback_data_ptr, _, process_raw_callback) = *model;
        let mut buffer = Buffer { buffer };
        process_raw_callback(callback_data_ptr, &mut buffer);
    }

    builder = builder.process_raw(process_raw_fn);

    if (*config).stream_conf.detected_dac != std::ptr::null() {
        let ffi_dac = (*(*config).stream_conf.detected_dac).clone();
        let broadcast = ffi_dac.kind.ether_dream.broadcast.clone();
        let source_addr_ptr = ffi_dac.kind.ether_dream.source_addr;
        let source_addr = CStr::from_ptr(source_addr_ptr)
            .to_string_lossy()
            .parse()
            .expect("failed to parse `source_addr`");
        let detected_dac = crate::DetectedDac::EtherDream {
            broadcast,
            source_addr,
        };
        builder = builder.detected_dac(detected_dac);
    }

    let frame_stream = match builder.build() {
        Err(_err) => {
            // TODO: Store error
            return Result::FailedToBuildStream;
        }
        Ok(stream) => Box::new(FrameStream { stream }),
    };
    *stream = Box::into_raw(frame_stream);
    Result::Success
}

/// Spawn a new frame rendering stream.
#[no_mangle]
pub unsafe extern "C" fn new_raw_stream(
    api: *const Api,
    stream: *mut *mut RawStream,
    config: *const StreamConfig,
    callback_data: *mut raw::c_void,
    process_raw_callback: RawRenderCallback,
) -> Result {
    let api: &Api = &*api;
    let model = RawStreamModel(callback_data, process_raw_callback);

    fn render_fn(model: &mut RawStreamModel, buffer: &mut crate::stream::raw::Buffer) {
        let RawStreamModel(callback_data_ptr, raw_render_callback) = *model;
        let mut buffer = Buffer { buffer };
        raw_render_callback(callback_data_ptr, &mut buffer);
    }

    let mut builder = api
        .inner
        .new_raw_stream(model, render_fn)
        .point_hz((*config).point_hz as _)
        .latency_points((*config).latency_points as _);

    if (*config).detected_dac != std::ptr::null() {
        let ffi_dac = (*(*config).detected_dac).clone();
        let broadcast = ffi_dac.kind.ether_dream.broadcast.clone();
        let source_addr_ptr = ffi_dac.kind.ether_dream.source_addr;
        let source_addr = CStr::from_ptr(source_addr_ptr)
            .to_string_lossy()
            .parse()
            .expect("failed to parse `source_addr`");
        let detected_dac = crate::DetectedDac::EtherDream {
            broadcast,
            source_addr,
        };
        builder = builder.detected_dac(detected_dac);
    }

    let raw_stream = match builder.build() {
        Err(_err) => {
            // TODO: Store error
            return Result::FailedToBuildStream;
        }
        Ok(stream) => Box::new(RawStream { stream }),
    };
    *stream = Box::into_raw(raw_stream);

    Result::Success
}

/// Add a sequence of consecutive points separated by blank space.
///
/// If some points already exist in the frame, this method will create a blank segment between the
/// previous point and the first point before appending this sequence.
#[no_mangle]
pub unsafe extern "C" fn frame_add_points(
    frame: *mut Frame,
    points: *const crate::Point,
    len: usize,
) {
    let frame = &mut *frame;
    let points = std::slice::from_raw_parts(points, len);
    frame.frame.add_points(points.iter().cloned());
}

/// Add a sequence of consecutive lines.
///
/// If some points already exist in the frame, this method will create a blank segment between the
/// previous point and the first point before appending this sequence.
#[no_mangle]
pub unsafe extern "C" fn frame_add_lines(
    frame: *mut Frame,
    points: *const crate::Point,
    len: usize,
) {
    let frame = &mut *frame;
    let points = std::slice::from_raw_parts(points, len);
    frame.frame.add_lines(points.iter().cloned());
}

pub unsafe extern "C" fn frame_hz(frame: *const Frame) -> u32 {
    (*frame).frame.frame_hz()
}

pub unsafe extern "C" fn frame_point_hz(frame: *const Frame) -> u32 {
    (*frame).frame.point_hz()
}

pub unsafe extern "C" fn frame_latency_points(frame: *const Frame) -> u32 {
    (*frame).frame.latency_points()
}

pub unsafe extern "C" fn points_per_frame(frame: *const Frame) -> u32 {
    (*frame).frame.latency_points()
}

/// Must be called in order to correctly clean up the frame stream.
#[no_mangle]
pub unsafe extern "C" fn frame_stream_drop(stream_ptr: *mut FrameStream) {
    if stream_ptr != std::ptr::null_mut() {
        Box::from_raw(stream_ptr);
    }
}

/// Must be called in order to correctly clean up the raw stream.
#[no_mangle]
pub unsafe extern "C" fn raw_stream_drop(stream_ptr: *mut RawStream) {
    if stream_ptr != std::ptr::null_mut() {
        Box::from_raw(stream_ptr);
    }
}

/// Must be called in order to correctly clean up the API resources.
#[no_mangle]
pub unsafe extern "C" fn api_drop(api_ptr: *mut Api) {
    if api_ptr != std::ptr::null_mut() {
        Box::from_raw(api_ptr);
    }
}
<|endoftext|>


<commit_before>//! Licensed under the Apache License, Version 2.0
//! http://www.apache.org/licenses/LICENSE-2.0 or the MIT license
//! http://opensource.org/licenses/MIT, at your
//! option. This file may not be copied, modified, or distributed
//! except according to those terms.

#![feature(unboxed_closures)]
#![feature(phase)]

#[phase(plugin, link)] extern crate itertools;

extern crate test;

use std::fmt::Show;
use std::iter::order;
use itertools::Itertools;
use itertools::Interleave;
use std::cell::RefCell;

use itertools as it;

fn assert_iters_equal<
    A: PartialEq + Show,
    I: Iterator<A>,
    J: Iterator<A>>(mut it: I, mut jt: J)
{
    loop {
        let elti = it.next();
        let eltj = jt.next();
        assert_eq!(elti, eltj);
        if elti.is_none() { break; }
    }
}

#[test]
fn product2() {
    let s = "αβ";

    let mut prod = iproduct!(s.chars(), range(0, 2i));
    assert!(prod.next() == Some(('α', 0)));
    assert!(prod.next() == Some(('α', 1)));
    assert!(prod.next() == Some(('β', 0)));
    assert!(prod.next() == Some(('β', 1)));
    assert!(prod.next() == None);
}

#[test]
fn product3() {
    let prod = iproduct!(range(0, 3i), range(0, 2i), range(0, 2i));
    assert_eq!(prod.size_hint(), (12, Some(12)));
    let v = prod.collect_vec();
    for i in range(0,3i) {
        for j in range(0, 2i) {
            for k in range(0, 2i) {
                assert!((i, j, k) == v[(i * 2 * 2 + j * 2 + k) as uint]);
            }
        }
    }
    for (_, _, _, _) in iproduct!(range(0, 3i), range(0, 2i), range(0, 2i), range(0, 3i)) {
        /* test compiles */
    }
}

#[test]
fn izip3() {
    let mut zip = izip!(range(0, 3u), range(0, 2i), range(0, 2i8));
    for i in range(0, 2i) {
        assert!((i as uint, i, i as i8) == zip.next().unwrap());
    }
    assert!(zip.next().is_none());

    let xs: [int, ..0] = [];
    let mut zip = izip!(range(0, 3u), range(0, 2i), range(0, 2i8), xs.iter());
    assert!(zip.next().is_none());

    for (_, _, _, _) in izip!(range(0, 3i), range(0, 2i), range(0, 2i), range(0, 3i)) {
        /* test compiles */
    }
}

#[test]
fn fn_map() {
    let xs = [0, 1, 2i];
    fn mapper(x: &int) -> String { x.to_string() }
    let it = xs.iter().fn_map(mapper);
    let jt = it.clone();
    assert!(it.zip(jt).all(|(x,y)| x == y));
}

#[test]
fn map_unboxed() {
    let xs = [0, 1, 2i];
    fn mapper(x: &int) -> String { x.to_string() }
    let it = xs.iter().map_unboxed(mapper);
    let jt = it.clone();
    assert!(it.zip(jt).all(|(x,y)| x == y));

    let mut sum = 0i;
    xs.iter().map_unboxed(|x| sum += *x).drain();
    assert_eq!(sum, 3);
}

#[test]
fn write_to() {
    let xs = [7i, 9, 8];
    let mut ys = [0i, ..5];
    let cnt = it::write(ys.iter_mut(), xs.iter().map(|x| *x));
    assert!(cnt == xs.len());
    assert!(ys == [7i, 9, 8, 0, 0]);

    let cnt = it::write(ys.iter_mut(), range(0,10i));
    assert!(cnt == ys.len());
    assert!(ys == [0, 1, 2, 3, 4]);
}

#[test]
fn interleave() {
    let xs: [u8, ..0]  = [];
    let ys = [7u8, 9, 8, 10];
    let zs = [2u8, 77];
    let it = Interleave::new(xs.iter(), ys.iter());
    assert!(order::eq(it, ys.iter()));

    let rs = [7u8, 2, 9, 77, 8, 10];
    let it = Interleave::new(ys.iter(), zs.iter());
    assert!(order::eq(it, rs.iter()));
}

#[test]
fn times() {
    assert!(it::times(0).count() == 0);
    assert!(it::times(5).count() == 5);
}

#[test]
fn drain() {
    let xs = [1i,2,3];
    let mut sum = 0;
    xs.iter().map(|elt| sum += *elt).drain();
    assert!(sum == 6);
}

#[test]
fn apply() {
    let xs = [1i, 2, 3];
    let mut sum = 0;
    xs.iter().apply(|elt| sum += *elt);
    assert!(sum == 6);
}

#[test]
fn dropn() {
    let xs = [1i, 2, 3];
    let mut it = xs.iter();
    assert!(it.dropn(2) == 2);
    assert!(it.next().is_some());
    assert!(it.next().is_none());
    let mut it = xs.iter();
    assert!(it.dropn(5) == 3);
    assert!(it.next().is_none());
}

#[test]
fn intersperse() {
    let xs = ["a", "", "b", "c"];
    let v: Vec<&str> = xs.iter().map(|x| x.clone()).intersperse(", ").collect();
    let text = v.concat();
    assert_eq!(text, "a, , b, c".to_string());

    let ys = [0, 1, 2, 3i];
    let mut it = ys.slice_to(0).iter().map(|x| *x).intersperse(1i);
    assert!(it.next() == None);
}

#[test]
fn linspace() {
    let mut iter = it::linspace::<f32>(0., 2., 3);
    assert_eq!(iter.next(), Some(0.0));
    assert_eq!(iter.next(), Some(1.0));
    assert_eq!(iter.next(), Some(2.0));
    assert_eq!(iter.next(), None);

    let mut iter = it::linspace::<f32>(0., -2., 4);
    assert_eq!(iter.next(), Some(0.));
    assert_eq!(iter.next(), Some(-0.666666666667));
    assert_eq!(iter.next(), Some(-1.333333333333));
    assert_eq!(iter.next(), Some(-2.));
    assert_eq!(iter.next(), None);

    let mut iter = it::linspace::<f32>(0., 1., 1);
    assert_eq!(iter.next(), Some(0.));
    assert_eq!(iter.next(), None);

    let mut iter = it::linspace::<f32>(0., 1., 0);
    assert_eq!(iter.next(), None);
}

#[test]
fn dedup() {
    let xs = [0i, 1, 1, 1, 2, 1, 3, 3];
    let ys = [0i, 1, 2, 1, 3];
    assert_iters_equal(ys.iter(), xs.iter().dedup());
    let xs = [0i, 0, 0, 0, 0];
    let ys = [0i];
    assert_iters_equal(ys.iter(), xs.iter().dedup());
}

#[test]
fn batching() {
    let xs = [0i, 1, 2, 1, 3];
    let ys = [(0i, 1i), (2, 1)];

    // An iterator that gathers elements up in pairs
    let pit = xs.iter().cloned().batching(|mut it| {
               match it.next() {
                   None => None,
                   Some(x) => match it.next() {
                       None => None,
                       Some(y) => Some((x, y)),
                   }
               }
           });
    assert_iters_equal(pit, ys.iter().cloned());
}

#[test]
fn group_by() {
    let xs = [0i, 1, 1, 1, 2, 1, 3, 3];
    let ans = vec![(0, vec![0]), (1, vec![1, 1, 1]),
                   (2, vec![2]), (1, vec![1]), (3, vec![3, 3])];

    let gb = xs.iter().cloned().group_by(|elt| *elt);
    assert_iters_equal(gb, ans.into_iter());
}

#[test]
fn put_back() {
    let xs = [0i, 1, 1, 1, 2, 1, 3, 3];
    let mut pb = it::PutBack::new(xs.iter().cloned());
    pb.next();
    pb.put_back(1);
    pb.put_back(0);
    assert_iters_equal(pb, xs.iter().cloned());
}

#[test]
fn tee() {
    let xs  = [0, 1, 2, 3i];
    let (mut t1, mut t2) = xs.iter().cloned().tee();
    assert_eq!(t1.next(), Some(0));
    assert_eq!(t2.next(), Some(0));
    assert_eq!(t1.next(), Some(1));
    assert_eq!(t1.next(), Some(2));
    assert_eq!(t1.next(), Some(3));
    assert_eq!(t1.next(), None);
    assert_eq!(t2.next(), Some(1));
    assert_eq!(t2.next(), Some(2));
    assert_eq!(t1.next(), None);
    assert_eq!(t2.next(), Some(3));
    assert_eq!(t2.next(), None);
    assert_eq!(t1.next(), None);
    assert_eq!(t2.next(), None);

    let (t1, t2) = xs.iter().cloned().tee();
    assert_iters_equal(t1, xs.iter().cloned());
    assert_iters_equal(t2, xs.iter().cloned());

    let (t1, t2) = xs.iter().cloned().tee();
    assert_iters_equal(t1.zip(t2), xs.iter().cloned().zip(xs.iter().cloned()));
}

#[test]
#[should_fail]
fn tee_fail() {
    // Tie a tee knot
    let xs = &[1i];
    let it = xs.iter().map(|x| *x);

    let (t1, _) = it.tee();
    let rc = RefCell::new(t1);

    let jt = xs.iter().map(|_| rc.borrow_mut().next().unwrap());

    let (t1, mut t2) = jt.tee();
    *rc.borrow_mut() = t1;
    assert_eq!(t2.next(), None);
}

#[test]
fn rciter() {
    let xs = [0i, 1, 1, 1, 2, 1, 3, 5, 6];

    let mut r1 = xs.iter().cloned().into_rc();
    let mut r2 = r1.clone();
    assert_eq!(r1.next(), Some(0));
    assert_eq!(r2.next(), Some(1));
    let mut z = r1.zip(r2);
    assert_eq!(z.next(), Some((1, 1)));
    assert_eq!(z.next(), Some((2, 1)));
    assert_eq!(z.next(), Some((3, 5)));
    assert_eq!(z.next(), None);
}
<commit_msg>Remove tee test that doesn't compile<commit_after>//! Licensed under the Apache License, Version 2.0
//! http://www.apache.org/licenses/LICENSE-2.0 or the MIT license
//! http://opensource.org/licenses/MIT, at your
//! option. This file may not be copied, modified, or distributed
//! except according to those terms.

#![feature(unboxed_closures)]
#![feature(phase)]

#[phase(plugin, link)] extern crate itertools;

extern crate test;

use std::fmt::Show;
use std::iter::order;
use itertools::Itertools;
use itertools::Interleave;

use itertools as it;

fn assert_iters_equal<
    A: PartialEq + Show,
    I: Iterator<A>,
    J: Iterator<A>>(mut it: I, mut jt: J)
{
    loop {
        let elti = it.next();
        let eltj = jt.next();
        assert_eq!(elti, eltj);
        if elti.is_none() { break; }
    }
}

#[test]
fn product2() {
    let s = "αβ";

    let mut prod = iproduct!(s.chars(), range(0, 2i));
    assert!(prod.next() == Some(('α', 0)));
    assert!(prod.next() == Some(('α', 1)));
    assert!(prod.next() == Some(('β', 0)));
    assert!(prod.next() == Some(('β', 1)));
    assert!(prod.next() == None);
}

#[test]
fn product3() {
    let prod = iproduct!(range(0, 3i), range(0, 2i), range(0, 2i));
    assert_eq!(prod.size_hint(), (12, Some(12)));
    let v = prod.collect_vec();
    for i in range(0,3i) {
        for j in range(0, 2i) {
            for k in range(0, 2i) {
                assert!((i, j, k) == v[(i * 2 * 2 + j * 2 + k) as uint]);
            }
        }
    }
    for (_, _, _, _) in iproduct!(range(0, 3i), range(0, 2i), range(0, 2i), range(0, 3i)) {
        /* test compiles */
    }
}

#[test]
fn izip3() {
    let mut zip = izip!(range(0, 3u), range(0, 2i), range(0, 2i8));
    for i in range(0, 2i) {
        assert!((i as uint, i, i as i8) == zip.next().unwrap());
    }
    assert!(zip.next().is_none());

    let xs: [int, ..0] = [];
    let mut zip = izip!(range(0, 3u), range(0, 2i), range(0, 2i8), xs.iter());
    assert!(zip.next().is_none());

    for (_, _, _, _) in izip!(range(0, 3i), range(0, 2i), range(0, 2i), range(0, 3i)) {
        /* test compiles */
    }
}

#[test]
fn fn_map() {
    let xs = [0, 1, 2i];
    fn mapper(x: &int) -> String { x.to_string() }
    let it = xs.iter().fn_map(mapper);
    let jt = it.clone();
    assert!(it.zip(jt).all(|(x,y)| x == y));
}

#[test]
fn map_unboxed() {
    let xs = [0, 1, 2i];
    fn mapper(x: &int) -> String { x.to_string() }
    let it = xs.iter().map_unboxed(mapper);
    let jt = it.clone();
    assert!(it.zip(jt).all(|(x,y)| x == y));

    let mut sum = 0i;
    xs.iter().map_unboxed(|x| sum += *x).drain();
    assert_eq!(sum, 3);
}

#[test]
fn write_to() {
    let xs = [7i, 9, 8];
    let mut ys = [0i, ..5];
    let cnt = it::write(ys.iter_mut(), xs.iter().map(|x| *x));
    assert!(cnt == xs.len());
    assert!(ys == [7i, 9, 8, 0, 0]);

    let cnt = it::write(ys.iter_mut(), range(0,10i));
    assert!(cnt == ys.len());
    assert!(ys == [0, 1, 2, 3, 4]);
}

#[test]
fn interleave() {
    let xs: [u8, ..0]  = [];
    let ys = [7u8, 9, 8, 10];
    let zs = [2u8, 77];
    let it = Interleave::new(xs.iter(), ys.iter());
    assert!(order::eq(it, ys.iter()));

    let rs = [7u8, 2, 9, 77, 8, 10];
    let it = Interleave::new(ys.iter(), zs.iter());
    assert!(order::eq(it, rs.iter()));
}

#[test]
fn times() {
    assert!(it::times(0).count() == 0);
    assert!(it::times(5).count() == 5);
}

#[test]
fn drain() {
    let xs = [1i,2,3];
    let mut sum = 0;
    xs.iter().map(|elt| sum += *elt).drain();
    assert!(sum == 6);
}

#[test]
fn apply() {
    let xs = [1i, 2, 3];
    let mut sum = 0;
    xs.iter().apply(|elt| sum += *elt);
    assert!(sum == 6);
}

#[test]
fn dropn() {
    let xs = [1i, 2, 3];
    let mut it = xs.iter();
    assert!(it.dropn(2) == 2);
    assert!(it.next().is_some());
    assert!(it.next().is_none());
    let mut it = xs.iter();
    assert!(it.dropn(5) == 3);
    assert!(it.next().is_none());
}

#[test]
fn intersperse() {
    let xs = ["a", "", "b", "c"];
    let v: Vec<&str> = xs.iter().map(|x| x.clone()).intersperse(", ").collect();
    let text = v.concat();
    assert_eq!(text, "a, , b, c".to_string());

    let ys = [0, 1, 2, 3i];
    let mut it = ys.slice_to(0).iter().map(|x| *x).intersperse(1i);
    assert!(it.next() == None);
}

#[test]
fn linspace() {
    let mut iter = it::linspace::<f32>(0., 2., 3);
    assert_eq!(iter.next(), Some(0.0));
    assert_eq!(iter.next(), Some(1.0));
    assert_eq!(iter.next(), Some(2.0));
    assert_eq!(iter.next(), None);

    let mut iter = it::linspace::<f32>(0., -2., 4);
    assert_eq!(iter.next(), Some(0.));
    assert_eq!(iter.next(), Some(-0.666666666667));
    assert_eq!(iter.next(), Some(-1.333333333333));
    assert_eq!(iter.next(), Some(-2.));
    assert_eq!(iter.next(), None);

    let mut iter = it::linspace::<f32>(0., 1., 1);
    assert_eq!(iter.next(), Some(0.));
    assert_eq!(iter.next(), None);

    let mut iter = it::linspace::<f32>(0., 1., 0);
    assert_eq!(iter.next(), None);
}

#[test]
fn dedup() {
    let xs = [0i, 1, 1, 1, 2, 1, 3, 3];
    let ys = [0i, 1, 2, 1, 3];
    assert_iters_equal(ys.iter(), xs.iter().dedup());
    let xs = [0i, 0, 0, 0, 0];
    let ys = [0i];
    assert_iters_equal(ys.iter(), xs.iter().dedup());
}

#[test]
fn batching() {
    let xs = [0i, 1, 2, 1, 3];
    let ys = [(0i, 1i), (2, 1)];

    // An iterator that gathers elements up in pairs
    let pit = xs.iter().cloned().batching(|mut it| {
               match it.next() {
                   None => None,
                   Some(x) => match it.next() {
                       None => None,
                       Some(y) => Some((x, y)),
                   }
               }
           });
    assert_iters_equal(pit, ys.iter().cloned());
}

#[test]
fn group_by() {
    let xs = [0i, 1, 1, 1, 2, 1, 3, 3];
    let ans = vec![(0, vec![0]), (1, vec![1, 1, 1]),
                   (2, vec![2]), (1, vec![1]), (3, vec![3, 3])];

    let gb = xs.iter().cloned().group_by(|elt| *elt);
    assert_iters_equal(gb, ans.into_iter());
}

#[test]
fn put_back() {
    let xs = [0i, 1, 1, 1, 2, 1, 3, 3];
    let mut pb = it::PutBack::new(xs.iter().cloned());
    pb.next();
    pb.put_back(1);
    pb.put_back(0);
    assert_iters_equal(pb, xs.iter().cloned());
}

#[test]
fn tee() {
    let xs  = [0, 1, 2, 3i];
    let (mut t1, mut t2) = xs.iter().cloned().tee();
    assert_eq!(t1.next(), Some(0));
    assert_eq!(t2.next(), Some(0));
    assert_eq!(t1.next(), Some(1));
    assert_eq!(t1.next(), Some(2));
    assert_eq!(t1.next(), Some(3));
    assert_eq!(t1.next(), None);
    assert_eq!(t2.next(), Some(1));
    assert_eq!(t2.next(), Some(2));
    assert_eq!(t1.next(), None);
    assert_eq!(t2.next(), Some(3));
    assert_eq!(t2.next(), None);
    assert_eq!(t1.next(), None);
    assert_eq!(t2.next(), None);

    let (t1, t2) = xs.iter().cloned().tee();
    assert_iters_equal(t1, xs.iter().cloned());
    assert_iters_equal(t2, xs.iter().cloned());

    let (t1, t2) = xs.iter().cloned().tee();
    assert_iters_equal(t1.zip(t2), xs.iter().cloned().zip(xs.iter().cloned()));
}

#[test]
fn rciter() {
    let xs = [0i, 1, 1, 1, 2, 1, 3, 5, 6];

    let mut r1 = xs.iter().cloned().into_rc();
    let mut r2 = r1.clone();
    assert_eq!(r1.next(), Some(0));
    assert_eq!(r2.next(), Some(1));
    let mut z = r1.zip(r2);
    assert_eq!(z.next(), Some((1, 1)));
    assert_eq!(z.next(), Some((2, 1)));
    assert_eq!(z.next(), Some((3, 5)));
    assert_eq!(z.next(), None);
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

//! Utilities for providing the goto definition feature

use crate::{
    location::to_lsp_location_of_graphql_literal,
    lsp::GotoDefinitionResponse,
    lsp_runtime_error::{LSPRuntimeError, LSPRuntimeResult},
    resolution_path::utils::find_selection_parent_type,
    resolution_path::{
        IdentParent, IdentPath, LinkedFieldPath, ResolutionPath, ResolvePosition, ScalarFieldPath,
        SelectionParent, TypeConditionPath,
    },
    server::LSPState,
    server::SourcePrograms,
    FieldDefinitionSourceInfo, LSPExtraDataProvider,
};
use common::{NamedItem, PerfLogger};

use graphql_syntax::ConstantValue;
use interner::{Intern, StringKey};
use lsp_types::{
    request::{GotoDefinition, Request},
    Url,
};
use relay_transforms::{RELAY_RESOLVER_DIRECTIVE_NAME, RELAY_RESOLVER_IMPORT_PATH_ARGUMENT_NAME};
use schema::{SDLSchema, Schema, Type};
use schema_documentation::SchemaDocumentation;
use serde::{Deserialize, Serialize};
use std::{
    path::{Path, PathBuf},
    str,
};

fn get_goto_definition_response<'a>(
    node_path: ResolutionPath<'a>,
    project_name: StringKey,
    source_programs: &SourcePrograms,
    root_dir: &Path,
    extra_data_provider: &(dyn LSPExtraDataProvider + 'static),
) -> LSPRuntimeResult<GotoDefinitionResponse> {
    match node_path {
        ResolutionPath::Ident(IdentPath {
            inner: fragment_name,
            parent: IdentParent::FragmentSpreadName(_),
        }) => {
            if let Some(source_program) = source_programs.get(&project_name) {
                let fragment = source_program
                    .fragment(fragment_name.value)
                    .ok_or_else(|| {
                        LSPRuntimeError::UnexpectedError(format!(
                            "Could not find fragment with name {}",
                            fragment_name
                        ))
                    })?;

                Ok(GotoDefinitionResponse::Scalar(
                    to_lsp_location_of_graphql_literal(fragment.name.location, root_dir)?,
                ))
            } else {
                Err(LSPRuntimeError::UnexpectedError(format!(
                    "Project name {} not found",
                    project_name
                )))
            }
        }
        ResolutionPath::Ident(IdentPath {
            inner: field_name,
            parent:
                IdentParent::LinkedFieldName(LinkedFieldPath {
                    inner: _,
                    parent: selection_path,
                }),
        }) => resolve_field(
            field_name.value.to_string(),
            selection_path.parent,
            project_name,
            source_programs,
            root_dir,
            extra_data_provider,
        ),
        ResolutionPath::Ident(IdentPath {
            inner: field_name,
            parent:
                IdentParent::ScalarFieldName(ScalarFieldPath {
                    inner: _,
                    parent: selection_path,
                }),
        }) => resolve_field(
            field_name.value.to_string(),
            selection_path.parent,
            project_name,
            source_programs,
            root_dir,
            extra_data_provider,
        ),
        ResolutionPath::Ident(IdentPath {
            inner: _,
            parent:
                IdentParent::TypeConditionType(TypeConditionPath {
                    inner: type_condition,
                    parent: _,
                }),
        }) => {
            let provider_response = extra_data_provider.resolve_field_definition(
                project_name.to_string(),
                type_condition.type_.value.to_string(),
                None,
            );
            let FieldDefinitionSourceInfo {
                file_path,
                line_number,
                is_local,
            } = provider_response.map_err(|e| -> LSPRuntimeError {
                LSPRuntimeError::UnexpectedError(format!(
                    "Error resolving field definition location: {}",
                    e
                ))
            })?;
            if is_local {
                Ok(GotoDefinitionResponse::Scalar(get_location(
                    &file_path,
                    line_number,
                )?))
            } else {
                Err(LSPRuntimeError::ExpectedError)
            }
        }
        _ => Err(LSPRuntimeError::ExpectedError),
    }
}

fn resolve_field<'a>(
    field_name: String,
    selection_parent: SelectionParent<'a>,
    project_name: StringKey,
    source_programs: &SourcePrograms,
    root_dir: &Path,
    extra_data_provider: &(dyn LSPExtraDataProvider + 'static),
) -> LSPRuntimeResult<GotoDefinitionResponse> {
    let source_program = source_programs.get(&project_name).ok_or_else(|| {
        LSPRuntimeError::UnexpectedError(format!("Project name {} not found", project_name))
    })?;

    let parent_type = find_selection_parent_type(selection_parent, &source_program.schema)
        .ok_or(LSPRuntimeError::ExpectedError)?;

    let field_name_key = field_name.intern();

    if let Some(response) = get_relay_resolver_location(
        &source_program.schema,
        parent_type,
        field_name_key,
        root_dir,
    )? {
        return Ok(response);
    }

    let parent_name = source_program.schema.get_type_name(parent_type);

    let provider_response = extra_data_provider.resolve_field_definition(
        project_name.to_string(),
        parent_name.to_string(),
        Some(field_name_key.to_string()),
    );
    let FieldDefinitionSourceInfo {
        file_path,
        line_number,
        is_local,
    } = provider_response.map_err(|e| -> LSPRuntimeError {
        LSPRuntimeError::UnexpectedError(format!(
            "Error resolving field definition location: {}",
            e
        ))
    })?;
    if is_local {
        Ok(GotoDefinitionResponse::Scalar(get_location(
            &file_path,
            line_number,
        )?))
    } else {
        Err(LSPRuntimeError::ExpectedError)
    }
}

fn get_relay_resolver_location(
    schema: &SDLSchema,
    parent_type: Type,
    field_name: StringKey,
    root_dir: &Path,
) -> LSPRuntimeResult<Option<GotoDefinitionResponse>> {
    let maybe_resolver_directive =
        schema
            .named_field(parent_type, field_name)
            .and_then(|field_id| {
                schema
                    .field(field_id)
                    .directives
                    .named(*RELAY_RESOLVER_DIRECTIVE_NAME)
            });

    Ok(if let Some(resolver_directive) = maybe_resolver_directive {
        let resolver_path = resolver_directive
            .arguments
            .named(*RELAY_RESOLVER_IMPORT_PATH_ARGUMENT_NAME)
            .and_then(|argument| match &argument.value {
                ConstantValue::String(import_path) => Some(import_path.value),
                _ => None,
            })
            .ok_or_else(|| {
                LSPRuntimeError::UnexpectedError(
                "Error resolving field definition location. Malformed schema for Relay Resolver."
                    .to_string(),
            )
            })?;

        let absolute_resolver_path = root_dir.join(PathBuf::from(resolver_path.lookup()));
        Some(GotoDefinitionResponse::Scalar(get_location(
            &absolute_resolver_path.to_string_lossy(),
            0,
        )?))
    } else {
        None
    })
}

pub(crate) fn on_goto_definition<
    TPerfLogger: PerfLogger + 'static,
    TSchemaDocumentation: SchemaDocumentation,
>(
    state: &mut LSPState<TPerfLogger, TSchemaDocumentation>,
    params: <GotoDefinition as Request>::Params,
) -> LSPRuntimeResult<<GotoDefinition as Request>::Result> {
    let (document, position_span, project_name) =
        state.extract_executable_document_from_text(&params.text_document_position_params, 1)?;
    let path = document.resolve((), position_span);

    let goto_definition_response = get_goto_definition_response(
        path,
        project_name,
        state.get_source_programs_ref(),
        state.root_dir(),
        state.extra_data_provider.as_ref(),
    )?;

    Ok(Some(goto_definition_response))
}

fn get_location(path: &str, line: u64) -> Result<lsp_types::Location, LSPRuntimeError> {
    let start = lsp_types::Position {
        line: line as u32,
        character: 0,
    };
    let range = lsp_types::Range { start, end: start };

    let uri = Url::parse(&format!("file://{}", path)).map_err(|e| {
        LSPRuntimeError::UnexpectedError(format!("Could not parse path as URL: {}", e))
    })?;

    Ok(lsp_types::Location { uri, range })
}

pub(crate) enum GetSourceLocationOfTypeDefinition {}

#[derive(Deserialize, Serialize)]
pub(crate) struct GetSourceLocationOfTypeDefinitionParams {
    type_name: String,
    field_name: Option<String>,
    schema_name: String,
}

#[derive(Deserialize, Serialize)]
pub(crate) struct GetSourceLocationOfTypeDefinitionResult {
    field_definition_source_info: FieldDefinitionSourceInfo,
}

impl Request for GetSourceLocationOfTypeDefinition {
    type Params = GetSourceLocationOfTypeDefinitionParams;
    type Result = GetSourceLocationOfTypeDefinitionResult;
    const METHOD: &'static str = "$/getSourceLocationOfTypeDefinition";
}

pub(crate) fn on_get_source_location_of_type_definition<
    TPerfLogger: PerfLogger + 'static,
    TSchemaDocumentation: SchemaDocumentation,
>(
    state: &mut LSPState<TPerfLogger, TSchemaDocumentation>,
    params: <GetSourceLocationOfTypeDefinition as Request>::Params,
) -> LSPRuntimeResult<<GetSourceLocationOfTypeDefinition as Request>::Result> {
    let field_definition_source_info = state
        .extra_data_provider
        .resolve_field_definition(params.schema_name, params.type_name, params.field_name)
        .map_err(LSPRuntimeError::UnexpectedError)?;
    Ok(GetSourceLocationOfTypeDefinitionResult {
        field_definition_source_info,
    })
}

#[cfg(test)]
mod test {
    use std::{path::PathBuf, sync::Arc};

    use common::{SourceLocationKey, Span};
    use dashmap::DashMap;
    use fnv::FnvBuildHasher;
    use graphql_ir::Program;
    use graphql_syntax::{parse_executable_with_features, ParserFeatures};
    use interner::Intern;
    use lsp_types::{GotoDefinitionResponse, Location};
    use relay_test_schema::get_test_schema_with_extensions;

    use crate::{
        resolution_path::ResolvePosition, server::SourcePrograms, FieldDefinitionSourceInfo,
        LSPExtraDataProvider,
    };

    use super::get_goto_definition_response;

    struct DummyExtraDataProvider {}

    impl LSPExtraDataProvider for DummyExtraDataProvider {
        fn fetch_query_stats(&self, _search_token: String) -> Vec<String> {
            Vec::new()
        }

        fn resolve_field_definition(
            &self,
            _project_name: String,
            _parent_type: String,
            _field_name: Option<String>,
        ) -> Result<FieldDefinitionSourceInfo, String> {
            Err("Not implemented".to_string())
        }
    }

    #[test]
    fn resolver_field() {
        let source = r#"
    query Foo {
        me {
            greeting
        }
    }
"#;
        let sub_str = "greeting";
        let document = parse_executable_with_features(
            source,
            SourceLocationKey::standalone("/test/file"),
            ParserFeatures {
                enable_variable_definitions: true,
            },
        )
        .unwrap();

        let pos = source.find(sub_str).unwrap() as u32;

        // Select the `uri` field
        let position_span = Span {
            start: pos,
            end: pos,
        };

        let resolved = document.resolve((), position_span);

        let project_name = "test".intern();
        let program_map = DashMap::with_hasher(FnvBuildHasher::default());
        let program = Program::new(get_test_schema_with_extensions(
            r#"
        extend type User {
            greeting: String @relay_resolver(fragment_name: "resolverFragment", import_path: "path/to/resolver.js")
          }
        "#,
        ));
        program_map.insert(project_name, program);
        let programs: SourcePrograms = Arc::new(program_map);
        let root_dir = PathBuf::from("/config/root/");
        let extra_data_provider = DummyExtraDataProvider {};

        let goto_definition_response = get_goto_definition_response(
            resolved,
            project_name,
            &programs,
            &root_dir,
            &extra_data_provider,
        );

        let uri = match goto_definition_response {
            Ok(GotoDefinitionResponse::Scalar(Location { uri, .. })) => uri.path().to_string(),
            _ => panic!("Invalid go to definition response."),
        };

        assert_eq!(uri, "/config/root/path/to/resolver.js");
    }
}
<commit_msg>Fix go to phps def<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

//! Utilities for providing the goto definition feature

use crate::{
    location::to_lsp_location_of_graphql_literal,
    lsp::GotoDefinitionResponse,
    lsp_runtime_error::{LSPRuntimeError, LSPRuntimeResult},
    resolution_path::utils::find_selection_parent_type,
    resolution_path::{
        IdentParent, IdentPath, LinkedFieldPath, ResolutionPath, ResolvePosition, ScalarFieldPath,
        SelectionParent, TypeConditionPath,
    },
    server::LSPState,
    server::SourcePrograms,
    FieldDefinitionSourceInfo, LSPExtraDataProvider,
};
use common::{NamedItem, PerfLogger};

use graphql_syntax::ConstantValue;
use interner::{Intern, StringKey};
use lsp_types::{
    request::{GotoDefinition, Request},
    Url,
};
use relay_transforms::{RELAY_RESOLVER_DIRECTIVE_NAME, RELAY_RESOLVER_IMPORT_PATH_ARGUMENT_NAME};
use schema::{SDLSchema, Schema, Type};
use schema_documentation::SchemaDocumentation;
use serde::{Deserialize, Serialize};
use std::{
    path::{Path, PathBuf},
    str,
};

fn get_goto_definition_response<'a>(
    node_path: ResolutionPath<'a>,
    project_name: StringKey,
    source_programs: &SourcePrograms,
    root_dir: &Path,
    extra_data_provider: &(dyn LSPExtraDataProvider + 'static),
) -> LSPRuntimeResult<GotoDefinitionResponse> {
    match node_path {
        ResolutionPath::Ident(IdentPath {
            inner: fragment_name,
            parent: IdentParent::FragmentSpreadName(_),
        }) => {
            if let Some(source_program) = source_programs.get(&project_name) {
                let fragment = source_program
                    .fragment(fragment_name.value)
                    .ok_or_else(|| {
                        LSPRuntimeError::UnexpectedError(format!(
                            "Could not find fragment with name {}",
                            fragment_name
                        ))
                    })?;

                Ok(GotoDefinitionResponse::Scalar(
                    to_lsp_location_of_graphql_literal(fragment.name.location, root_dir)?,
                ))
            } else {
                Err(LSPRuntimeError::UnexpectedError(format!(
                    "Project name {} not found",
                    project_name
                )))
            }
        }
        ResolutionPath::Ident(IdentPath {
            inner: field_name,
            parent:
                IdentParent::LinkedFieldName(LinkedFieldPath {
                    inner: _,
                    parent: selection_path,
                }),
        }) => resolve_field(
            field_name.value.to_string(),
            selection_path.parent,
            project_name,
            source_programs,
            root_dir,
            extra_data_provider,
        ),
        ResolutionPath::Ident(IdentPath {
            inner: field_name,
            parent:
                IdentParent::ScalarFieldName(ScalarFieldPath {
                    inner: _,
                    parent: selection_path,
                }),
        }) => resolve_field(
            field_name.value.to_string(),
            selection_path.parent,
            project_name,
            source_programs,
            root_dir,
            extra_data_provider,
        ),
        ResolutionPath::Ident(IdentPath {
            inner: _,
            parent:
                IdentParent::TypeConditionType(TypeConditionPath {
                    inner: type_condition,
                    parent: _,
                }),
        }) => {
            let provider_response = extra_data_provider.resolve_field_definition(
                project_name.to_string(),
                type_condition.type_.value.to_string(),
                None,
            );
            let FieldDefinitionSourceInfo {
                file_path,
                line_number,
                is_local,
            } = provider_response.map_err(|e| -> LSPRuntimeError {
                LSPRuntimeError::UnexpectedError(format!(
                    "Error resolving field definition location: {}",
                    e
                ))
            })?;
            if is_local {
                Ok(GotoDefinitionResponse::Scalar(get_location(
                    &file_path,
                    line_number,
                )?))
            } else {
                Err(LSPRuntimeError::ExpectedError)
            }
        }
        _ => Err(LSPRuntimeError::ExpectedError),
    }
}

fn resolve_field<'a>(
    field_name: String,
    selection_parent: SelectionParent<'a>,
    project_name: StringKey,
    source_programs: &SourcePrograms,
    root_dir: &Path,
    extra_data_provider: &(dyn LSPExtraDataProvider + 'static),
) -> LSPRuntimeResult<GotoDefinitionResponse> {
    let source_program = source_programs.get(&project_name).ok_or_else(|| {
        LSPRuntimeError::UnexpectedError(format!("Project name {} not found", project_name))
    })?;

    let parent_type = find_selection_parent_type(selection_parent, &source_program.schema)
        .ok_or(LSPRuntimeError::ExpectedError)?;

    let field_name_key = field_name.intern();

    if let Some(response) = get_relay_resolver_location(
        &source_program.schema,
        parent_type,
        field_name_key,
        root_dir,
    )? {
        return Ok(response);
    }

    let parent_name = source_program.schema.get_type_name(parent_type);

    let provider_response = extra_data_provider.resolve_field_definition(
        project_name.to_string(),
        parent_name.to_string(),
        Some(field_name_key.to_string()),
    );
    let FieldDefinitionSourceInfo {
        file_path,
        line_number,
        is_local,
    } = provider_response.map_err(|e| -> LSPRuntimeError {
        LSPRuntimeError::UnexpectedError(format!(
            "Error resolving field definition location: {}",
            e
        ))
    })?;
    if is_local {
        Ok(GotoDefinitionResponse::Scalar(get_location(
            &file_path,
            line_number,
        )?))
    } else {
        Err(LSPRuntimeError::ExpectedError)
    }
}

fn get_relay_resolver_location(
    schema: &SDLSchema,
    parent_type: Type,
    field_name: StringKey,
    root_dir: &Path,
) -> LSPRuntimeResult<Option<GotoDefinitionResponse>> {
    let maybe_resolver_directive =
        schema
            .named_field(parent_type, field_name)
            .and_then(|field_id| {
                schema
                    .field(field_id)
                    .directives
                    .named(*RELAY_RESOLVER_DIRECTIVE_NAME)
            });

    Ok(if let Some(resolver_directive) = maybe_resolver_directive {
        let resolver_path = resolver_directive
            .arguments
            .named(*RELAY_RESOLVER_IMPORT_PATH_ARGUMENT_NAME)
            .and_then(|argument| match &argument.value {
                ConstantValue::String(import_path) => Some(import_path.value),
                _ => None,
            })
            .ok_or_else(|| {
                LSPRuntimeError::UnexpectedError(
                "Error resolving field definition location. Malformed schema for Relay Resolver."
                    .to_string(),
            )
            })?;

        let absolute_resolver_path = root_dir.join(PathBuf::from(resolver_path.lookup()));
        Some(GotoDefinitionResponse::Scalar(get_location(
            &absolute_resolver_path.to_string_lossy(),
            0,
        )?))
    } else {
        None
    })
}

pub(crate) fn on_goto_definition<
    TPerfLogger: PerfLogger + 'static,
    TSchemaDocumentation: SchemaDocumentation,
>(
    state: &mut LSPState<TPerfLogger, TSchemaDocumentation>,
    params: <GotoDefinition as Request>::Params,
) -> LSPRuntimeResult<<GotoDefinition as Request>::Result> {
    let (document, position_span, project_name) =
        state.extract_executable_document_from_text(&params.text_document_position_params, 1)?;
    let path = document.resolve((), position_span);

    let goto_definition_response = get_goto_definition_response(
        path,
        project_name,
        state.get_source_programs_ref(),
        state.root_dir(),
        state.extra_data_provider.as_ref(),
    )?;

    Ok(Some(goto_definition_response))
}

fn get_location(path: &str, line: u64) -> Result<lsp_types::Location, LSPRuntimeError> {
    let start = lsp_types::Position {
        line: line as u32,
        character: 0,
    };
    let range = lsp_types::Range { start, end: start };

    let uri = Url::parse(&format!("file://{}", path)).map_err(|e| {
        LSPRuntimeError::UnexpectedError(format!("Could not parse path as URL: {}", e))
    })?;

    Ok(lsp_types::Location { uri, range })
}

pub(crate) enum GetSourceLocationOfTypeDefinition {}

#[derive(Deserialize, Serialize)]
pub(crate) struct GetSourceLocationOfTypeDefinitionParams {
    type_name: String,
    field_name: Option<String>,
    schema_name: String,
}

#[derive(Deserialize, Serialize)]
pub(crate) struct GetSourceLocationOfTypeDefinitionResult {
    field_definition_source_info: FieldDefinitionSourceInfo,
}

impl Request for GetSourceLocationOfTypeDefinition {
    type Params = GetSourceLocationOfTypeDefinitionParams;
    type Result = GetSourceLocationOfTypeDefinitionResult;
    const METHOD: &'static str = "relay/getSourceLocationOfTypeDefinition";
}

pub(crate) fn on_get_source_location_of_type_definition<
    TPerfLogger: PerfLogger + 'static,
    TSchemaDocumentation: SchemaDocumentation,
>(
    state: &mut LSPState<TPerfLogger, TSchemaDocumentation>,
    params: <GetSourceLocationOfTypeDefinition as Request>::Params,
) -> LSPRuntimeResult<<GetSourceLocationOfTypeDefinition as Request>::Result> {
    let field_definition_source_info = state
        .extra_data_provider
        .resolve_field_definition(params.schema_name, params.type_name, params.field_name)
        .map_err(LSPRuntimeError::UnexpectedError)?;
    Ok(GetSourceLocationOfTypeDefinitionResult {
        field_definition_source_info,
    })
}

#[cfg(test)]
mod test {
    use std::{path::PathBuf, sync::Arc};

    use common::{SourceLocationKey, Span};
    use dashmap::DashMap;
    use fnv::FnvBuildHasher;
    use graphql_ir::Program;
    use graphql_syntax::{parse_executable_with_features, ParserFeatures};
    use interner::Intern;
    use lsp_types::{GotoDefinitionResponse, Location};
    use relay_test_schema::get_test_schema_with_extensions;

    use crate::{
        resolution_path::ResolvePosition, server::SourcePrograms, FieldDefinitionSourceInfo,
        LSPExtraDataProvider,
    };

    use super::get_goto_definition_response;

    struct DummyExtraDataProvider {}

    impl LSPExtraDataProvider for DummyExtraDataProvider {
        fn fetch_query_stats(&self, _search_token: String) -> Vec<String> {
            Vec::new()
        }

        fn resolve_field_definition(
            &self,
            _project_name: String,
            _parent_type: String,
            _field_name: Option<String>,
        ) -> Result<FieldDefinitionSourceInfo, String> {
            Err("Not implemented".to_string())
        }
    }

    #[test]
    fn resolver_field() {
        let source = r#"
    query Foo {
        me {
            greeting
        }
    }
"#;
        let sub_str = "greeting";
        let document = parse_executable_with_features(
            source,
            SourceLocationKey::standalone("/test/file"),
            ParserFeatures {
                enable_variable_definitions: true,
            },
        )
        .unwrap();

        let pos = source.find(sub_str).unwrap() as u32;

        // Select the `uri` field
        let position_span = Span {
            start: pos,
            end: pos,
        };

        let resolved = document.resolve((), position_span);

        let project_name = "test".intern();
        let program_map = DashMap::with_hasher(FnvBuildHasher::default());
        let program = Program::new(get_test_schema_with_extensions(
            r#"
        extend type User {
            greeting: String @relay_resolver(fragment_name: "resolverFragment", import_path: "path/to/resolver.js")
          }
        "#,
        ));
        program_map.insert(project_name, program);
        let programs: SourcePrograms = Arc::new(program_map);
        let root_dir = PathBuf::from("/config/root/");
        let extra_data_provider = DummyExtraDataProvider {};

        let goto_definition_response = get_goto_definition_response(
            resolved,
            project_name,
            &programs,
            &root_dir,
            &extra_data_provider,
        );

        let uri = match goto_definition_response {
            Ok(GotoDefinitionResponse::Scalar(Location { uri, .. })) => uri.path().to_string(),
            _ => panic!("Invalid go to definition response."),
        };

        assert_eq!(uri, "/config/root/path/to/resolver.js");
    }
}
<|endoftext|>