<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! C definitions used by libnative that don't belong in liblibc

#![allow(dead_code)]
#![allow(non_camel_case_types)]

pub use self::select::fd_set;
pub use self::signal::{sigaction, siginfo, sigset_t};
pub use self::signal::{SA_ONSTACK, SA_RESTART, SA_RESETHAND, SA_NOCLDSTOP};
pub use self::signal::{SA_NODEFER, SA_NOCLDWAIT, SA_SIGINFO, SIGCHLD};

use libc;

#[cfg(any(target_os = "macos",
          target_os = "ios",
          target_os = "freebsd",
          target_os = "dragonfly"))]
pub const FIONBIO: libc::c_ulong = 0x8004667e;
#[cfg(any(all(target_os = "linux",
              any(target_arch = "x86",
                  target_arch = "x86_64",
                  target_arch = "arm")),
          target_os = "android"))]
pub const FIONBIO: libc::c_ulong = 0x5421;
#[cfg(all(target_os = "linux",
          any(target_arch = "mips", target_arch = "mipsel")))]
pub const FIONBIO: libc::c_ulong = 0x667e;

#[cfg(any(target_os = "macos",
          target_os = "ios",
          target_os = "freebsd",
          target_os = "dragonfly"))]
pub const FIOCLEX: libc::c_ulong = 0x20006601;
#[cfg(any(all(target_os = "linux",
              any(target_arch = "x86",
                  target_arch = "x86_64",
                  target_arch = "arm")),
          target_os = "android"))]
pub const FIOCLEX: libc::c_ulong = 0x5451;
#[cfg(all(target_os = "linux",
          any(target_arch = "mips", target_arch = "mipsel")))]
pub const FIOCLEX: libc::c_ulong = 0x6601;

#[cfg(any(target_os = "macos",
          target_os = "ios",
          target_os = "freebsd",
          target_os = "dragonfly"))]
pub const MSG_DONTWAIT: libc::c_int = 0x80;
#[cfg(any(target_os = "linux", target_os = "android"))]
pub const MSG_DONTWAIT: libc::c_int = 0x40;

pub const WNOHANG: libc::c_int = 1;

extern {
    pub fn gettimeofday(timeval: *mut libc::timeval,
                        tzp: *mut libc::c_void) -> libc::c_int;
    pub fn select(nfds: libc::c_int,
                  readfds: *mut fd_set,
                  writefds: *mut fd_set,
                  errorfds: *mut fd_set,
                  timeout: *mut libc::timeval) -> libc::c_int;
    pub fn getsockopt(sockfd: libc::c_int,
                      level: libc::c_int,
                      optname: libc::c_int,
                      optval: *mut libc::c_void,
                      optlen: *mut libc::socklen_t) -> libc::c_int;
    pub fn ioctl(fd: libc::c_int, req: libc::c_ulong, ...) -> libc::c_int;

    pub fn waitpid(pid: libc::pid_t, status: *mut libc::c_int,
                   options: libc::c_int) -> libc::pid_t;

    pub fn sigaction(signum: libc::c_int,
                     act: *const sigaction,
                     oldact: *mut sigaction) -> libc::c_int;

    pub fn sigaddset(set: *mut sigset_t, signum: libc::c_int) -> libc::c_int;
    pub fn sigdelset(set: *mut sigset_t, signum: libc::c_int) -> libc::c_int;
    pub fn sigemptyset(set: *mut sigset_t) -> libc::c_int;
}

#[cfg(any(target_os = "macos", target_os = "ios"))]
mod select {
    pub const FD_SETSIZE: uint = 1024;

    #[repr(C)]
    pub struct fd_set {
        fds_bits: [i32, ..(FD_SETSIZE / 32)]
    }

    pub fn fd_set(set: &mut fd_set, fd: i32) {
        set.fds_bits[(fd / 32) as uint] |= 1 << ((fd % 32) as uint);
    }
}

#[cfg(any(target_os = "android",
          target_os = "freebsd",
          target_os = "dragonfly",
          target_os = "linux"))]
mod select {
    use uint;
    use libc;

    pub const FD_SETSIZE: uint = 1024;

    #[repr(C)]
    pub struct fd_set {
        // FIXME: shouldn't this be a c_ulong?
        fds_bits: [libc::uintptr_t, ..(FD_SETSIZE / uint::BITS)]
    }

    pub fn fd_set(set: &mut fd_set, fd: i32) {
        let fd = fd as uint;
        set.fds_bits[fd / uint::BITS] |= 1 << (fd % uint::BITS);
    }
}

#[cfg(any(all(target_os = "linux",
              any(target_arch = "x86",
                  target_arch = "x86_64",
                  target_arch = "arm")),
          target_os = "android"))]
mod signal {
    use libc;

    pub const SA_NOCLDSTOP: libc::c_ulong = 0x00000001;
    pub const SA_NOCLDWAIT: libc::c_ulong = 0x00000002;
    pub const SA_NODEFER: libc::c_ulong = 0x40000000;
    pub const SA_ONSTACK: libc::c_ulong = 0x08000000;
    pub const SA_RESETHAND: libc::c_ulong = 0x80000000;
    pub const SA_RESTART: libc::c_ulong = 0x10000000;
    pub const SA_SIGINFO: libc::c_ulong = 0x00000004;
    pub const SIGCHLD: libc::c_int = 17;

    // This definition is not as accurate as it could be, {pid, uid, status} is
    // actually a giant union. Currently we're only interested in these fields,
    // however.
    #[repr(C)]
    pub struct siginfo {
        si_signo: libc::c_int,
        si_errno: libc::c_int,
        si_code: libc::c_int,
        pub pid: libc::pid_t,
        pub uid: libc::uid_t,
        pub status: libc::c_int,
    }

    #[repr(C)]
    pub struct sigaction {
        pub sa_handler: extern fn(libc::c_int),
        pub sa_mask: sigset_t,
        pub sa_flags: libc::c_ulong,
        sa_restorer: *mut libc::c_void,
    }

    unsafe impl ::kinds::Send for sigaction { }
    unsafe impl ::kinds::Sync for sigaction { }

    #[repr(C)]
    #[cfg(target_word_size = "32")]
    pub struct sigset_t {
        __val: [libc::c_ulong, ..32],
    }

    #[repr(C)]
    #[cfg(target_word_size = "64")]
    pub struct sigset_t {
        __val: [libc::c_ulong, ..16],
    }
}

#[cfg(all(target_os = "linux",
          any(target_arch = "mips", target_arch = "mipsel")))]
mod signal {
    use libc;

    pub const SA_NOCLDSTOP: libc::c_ulong = 0x00000001;
    pub const SA_NOCLDWAIT: libc::c_ulong = 0x00010000;
    pub const SA_NODEFER: libc::c_ulong = 0x40000000;
    pub const SA_ONSTACK: libc::c_ulong = 0x08000000;
    pub const SA_RESETHAND: libc::c_ulong = 0x80000000;
    pub const SA_RESTART: libc::c_ulong = 0x10000000;
    pub const SA_SIGINFO: libc::c_ulong = 0x00000008;
    pub const SIGCHLD: libc::c_int = 18;

    // This definition is not as accurate as it could be, {pid, uid, status} is
    // actually a giant union. Currently we're only interested in these fields,
    // however.
    #[repr(C)]
    pub struct siginfo {
        si_signo: libc::c_int,
        si_code: libc::c_int,
        si_errno: libc::c_int,
        pub pid: libc::pid_t,
        pub uid: libc::uid_t,
        pub status: libc::c_int,
    }

    #[repr(C)]
    pub struct sigaction {
        pub sa_flags: libc::c_uint,
        pub sa_handler: extern fn(libc::c_int),
        pub sa_mask: sigset_t,
        sa_restorer: *mut libc::c_void,
        sa_resv: [libc::c_int, ..1],
    }

    impl ::kinds::Send for sigaction { }
    impl ::kinds::Sync for sigaction { }

    #[repr(C)]
    pub struct sigset_t {
        __val: [libc::c_ulong, ..32],
    }
}

#[cfg(any(target_os = "macos",
          target_os = "ios",
          target_os = "freebsd",
          target_os = "dragonfly"))]
mod signal {
    use libc;

    pub const SA_ONSTACK: libc::c_int = 0x0001;
    pub const SA_RESTART: libc::c_int = 0x0002;
    pub const SA_RESETHAND: libc::c_int = 0x0004;
    pub const SA_NOCLDSTOP: libc::c_int = 0x0008;
    pub const SA_NODEFER: libc::c_int = 0x0010;
    pub const SA_NOCLDWAIT: libc::c_int = 0x0020;
    pub const SA_SIGINFO: libc::c_int = 0x0040;
    pub const SIGCHLD: libc::c_int = 20;

    #[cfg(any(target_os = "macos", target_os = "ios"))]
    pub type sigset_t = u32;
    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
    #[repr(C)]
    pub struct sigset_t {
        bits: [u32, ..4],
    }

    // This structure has more fields, but we're not all that interested in
    // them.
    #[repr(C)]
    pub struct siginfo {
        pub si_signo: libc::c_int,
        pub si_errno: libc::c_int,
        pub si_code: libc::c_int,
        pub pid: libc::pid_t,
        pub uid: libc::uid_t,
        pub status: libc::c_int,
    }

    #[repr(C)]
    pub struct sigaction {
        pub sa_handler: extern fn(libc::c_int),
        pub sa_flags: libc::c_int,
        pub sa_mask: sigset_t,
    }
}
<commit_msg>Fix impl of Send and Sync for mips<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! C definitions used by libnative that don't belong in liblibc

#![allow(dead_code)]
#![allow(non_camel_case_types)]

pub use self::select::fd_set;
pub use self::signal::{sigaction, siginfo, sigset_t};
pub use self::signal::{SA_ONSTACK, SA_RESTART, SA_RESETHAND, SA_NOCLDSTOP};
pub use self::signal::{SA_NODEFER, SA_NOCLDWAIT, SA_SIGINFO, SIGCHLD};

use libc;

#[cfg(any(target_os = "macos",
          target_os = "ios",
          target_os = "freebsd",
          target_os = "dragonfly"))]
pub const FIONBIO: libc::c_ulong = 0x8004667e;
#[cfg(any(all(target_os = "linux",
              any(target_arch = "x86",
                  target_arch = "x86_64",
                  target_arch = "arm")),
          target_os = "android"))]
pub const FIONBIO: libc::c_ulong = 0x5421;
#[cfg(all(target_os = "linux",
          any(target_arch = "mips", target_arch = "mipsel")))]
pub const FIONBIO: libc::c_ulong = 0x667e;

#[cfg(any(target_os = "macos",
          target_os = "ios",
          target_os = "freebsd",
          target_os = "dragonfly"))]
pub const FIOCLEX: libc::c_ulong = 0x20006601;
#[cfg(any(all(target_os = "linux",
              any(target_arch = "x86",
                  target_arch = "x86_64",
                  target_arch = "arm")),
          target_os = "android"))]
pub const FIOCLEX: libc::c_ulong = 0x5451;
#[cfg(all(target_os = "linux",
          any(target_arch = "mips", target_arch = "mipsel")))]
pub const FIOCLEX: libc::c_ulong = 0x6601;

#[cfg(any(target_os = "macos",
          target_os = "ios",
          target_os = "freebsd",
          target_os = "dragonfly"))]
pub const MSG_DONTWAIT: libc::c_int = 0x80;
#[cfg(any(target_os = "linux", target_os = "android"))]
pub const MSG_DONTWAIT: libc::c_int = 0x40;

pub const WNOHANG: libc::c_int = 1;

extern {
    pub fn gettimeofday(timeval: *mut libc::timeval,
                        tzp: *mut libc::c_void) -> libc::c_int;
    pub fn select(nfds: libc::c_int,
                  readfds: *mut fd_set,
                  writefds: *mut fd_set,
                  errorfds: *mut fd_set,
                  timeout: *mut libc::timeval) -> libc::c_int;
    pub fn getsockopt(sockfd: libc::c_int,
                      level: libc::c_int,
                      optname: libc::c_int,
                      optval: *mut libc::c_void,
                      optlen: *mut libc::socklen_t) -> libc::c_int;
    pub fn ioctl(fd: libc::c_int, req: libc::c_ulong, ...) -> libc::c_int;

    pub fn waitpid(pid: libc::pid_t, status: *mut libc::c_int,
                   options: libc::c_int) -> libc::pid_t;

    pub fn sigaction(signum: libc::c_int,
                     act: *const sigaction,
                     oldact: *mut sigaction) -> libc::c_int;

    pub fn sigaddset(set: *mut sigset_t, signum: libc::c_int) -> libc::c_int;
    pub fn sigdelset(set: *mut sigset_t, signum: libc::c_int) -> libc::c_int;
    pub fn sigemptyset(set: *mut sigset_t) -> libc::c_int;
}

#[cfg(any(target_os = "macos", target_os = "ios"))]
mod select {
    pub const FD_SETSIZE: uint = 1024;

    #[repr(C)]
    pub struct fd_set {
        fds_bits: [i32, ..(FD_SETSIZE / 32)]
    }

    pub fn fd_set(set: &mut fd_set, fd: i32) {
        set.fds_bits[(fd / 32) as uint] |= 1 << ((fd % 32) as uint);
    }
}

#[cfg(any(target_os = "android",
          target_os = "freebsd",
          target_os = "dragonfly",
          target_os = "linux"))]
mod select {
    use uint;
    use libc;

    pub const FD_SETSIZE: uint = 1024;

    #[repr(C)]
    pub struct fd_set {
        // FIXME: shouldn't this be a c_ulong?
        fds_bits: [libc::uintptr_t, ..(FD_SETSIZE / uint::BITS)]
    }

    pub fn fd_set(set: &mut fd_set, fd: i32) {
        let fd = fd as uint;
        set.fds_bits[fd / uint::BITS] |= 1 << (fd % uint::BITS);
    }
}

#[cfg(any(all(target_os = "linux",
              any(target_arch = "x86",
                  target_arch = "x86_64",
                  target_arch = "arm")),
          target_os = "android"))]
mod signal {
    use libc;

    pub const SA_NOCLDSTOP: libc::c_ulong = 0x00000001;
    pub const SA_NOCLDWAIT: libc::c_ulong = 0x00000002;
    pub const SA_NODEFER: libc::c_ulong = 0x40000000;
    pub const SA_ONSTACK: libc::c_ulong = 0x08000000;
    pub const SA_RESETHAND: libc::c_ulong = 0x80000000;
    pub const SA_RESTART: libc::c_ulong = 0x10000000;
    pub const SA_SIGINFO: libc::c_ulong = 0x00000004;
    pub const SIGCHLD: libc::c_int = 17;

    // This definition is not as accurate as it could be, {pid, uid, status} is
    // actually a giant union. Currently we're only interested in these fields,
    // however.
    #[repr(C)]
    pub struct siginfo {
        si_signo: libc::c_int,
        si_errno: libc::c_int,
        si_code: libc::c_int,
        pub pid: libc::pid_t,
        pub uid: libc::uid_t,
        pub status: libc::c_int,
    }

    #[repr(C)]
    pub struct sigaction {
        pub sa_handler: extern fn(libc::c_int),
        pub sa_mask: sigset_t,
        pub sa_flags: libc::c_ulong,
        sa_restorer: *mut libc::c_void,
    }

    unsafe impl ::kinds::Send for sigaction { }
    unsafe impl ::kinds::Sync for sigaction { }

    #[repr(C)]
    #[cfg(target_word_size = "32")]
    pub struct sigset_t {
        __val: [libc::c_ulong, ..32],
    }

    #[repr(C)]
    #[cfg(target_word_size = "64")]
    pub struct sigset_t {
        __val: [libc::c_ulong, ..16],
    }
}

#[cfg(all(target_os = "linux",
          any(target_arch = "mips", target_arch = "mipsel")))]
mod signal {
    use libc;

    pub const SA_NOCLDSTOP: libc::c_ulong = 0x00000001;
    pub const SA_NOCLDWAIT: libc::c_ulong = 0x00010000;
    pub const SA_NODEFER: libc::c_ulong = 0x40000000;
    pub const SA_ONSTACK: libc::c_ulong = 0x08000000;
    pub const SA_RESETHAND: libc::c_ulong = 0x80000000;
    pub const SA_RESTART: libc::c_ulong = 0x10000000;
    pub const SA_SIGINFO: libc::c_ulong = 0x00000008;
    pub const SIGCHLD: libc::c_int = 18;

    // This definition is not as accurate as it could be, {pid, uid, status} is
    // actually a giant union. Currently we're only interested in these fields,
    // however.
    #[repr(C)]
    pub struct siginfo {
        si_signo: libc::c_int,
        si_code: libc::c_int,
        si_errno: libc::c_int,
        pub pid: libc::pid_t,
        pub uid: libc::uid_t,
        pub status: libc::c_int,
    }

    #[repr(C)]
    pub struct sigaction {
        pub sa_flags: libc::c_uint,
        pub sa_handler: extern fn(libc::c_int),
        pub sa_mask: sigset_t,
        sa_restorer: *mut libc::c_void,
        sa_resv: [libc::c_int, ..1],
    }

    unsafe impl ::kinds::Send for sigaction { }
    unsafe impl ::kinds::Sync for sigaction { }

    #[repr(C)]
    pub struct sigset_t {
        __val: [libc::c_ulong, ..32],
    }
}

#[cfg(any(target_os = "macos",
          target_os = "ios",
          target_os = "freebsd",
          target_os = "dragonfly"))]
mod signal {
    use libc;

    pub const SA_ONSTACK: libc::c_int = 0x0001;
    pub const SA_RESTART: libc::c_int = 0x0002;
    pub const SA_RESETHAND: libc::c_int = 0x0004;
    pub const SA_NOCLDSTOP: libc::c_int = 0x0008;
    pub const SA_NODEFER: libc::c_int = 0x0010;
    pub const SA_NOCLDWAIT: libc::c_int = 0x0020;
    pub const SA_SIGINFO: libc::c_int = 0x0040;
    pub const SIGCHLD: libc::c_int = 20;

    #[cfg(any(target_os = "macos", target_os = "ios"))]
    pub type sigset_t = u32;
    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
    #[repr(C)]
    pub struct sigset_t {
        bits: [u32, ..4],
    }

    // This structure has more fields, but we're not all that interested in
    // them.
    #[repr(C)]
    pub struct siginfo {
        pub si_signo: libc::c_int,
        pub si_errno: libc::c_int,
        pub si_code: libc::c_int,
        pub pid: libc::pid_t,
        pub uid: libc::uid_t,
        pub status: libc::c_int,
    }

    #[repr(C)]
    pub struct sigaction {
        pub sa_handler: extern fn(libc::c_int),
        pub sa_flags: libc::c_int,
        pub sa_mask: sigset_t,
    }
}
<|endoftext|>


<commit_before>use dicom_core::value::C;
use snafu::Snafu;

pub mod rle_lossless;

/// Error conditions when decoding pixel data.
#[derive(Debug, Snafu)]
#[non_exhaustive]
pub enum DecodeError {
    /// A custom error when decoding fails
    #[snafu(display("Error decoding pixel data: {}", message))]
    CustomDecodeError { message: &'static str },

    /// Input pixel data is not encapsulated
    NotEncapsulated,

    /// A required attribute is missing from the DICOM
    #[snafu(display("Missing required attribute: {}", name))]
    MissingAttribute { name: &'static str },
}

/// Error conditions when encoding pixel data.
#[derive(Debug, Snafu)]
#[non_exhaustive]
pub enum EncodeError {
    /// A custom error when encoding fails
    #[snafu(display("Error encoding pixel data {}", message))]
    CustomEncodeError {
        message: &'static str,
    },

    /// Input pixel data is not native
    NotNative,

    /// Encoding is not implemented
    NotImplemented,
}

pub type DecodeResult<T, E = DecodeError> = Result<T, E>;

pub type EncodeResult<T, E = EncodeError> = Result<T, E>;

#[derive(Debug)]
pub struct RawPixelData {
    /// Either a byte slice/vector if native pixel data
    /// or byte fragments if encapsulated
    pub fragments: C<Vec<u8>>,

    /// The offset table for the fragments,
    /// or empty if there is none
    pub offset_table: C<u32>,
}

/// A DICOM object trait to be interpreted as pixel data.
///
/// This trait extends the concept of DICOM object
/// as defined in [`dicom_object`](::dicom_object),
/// in order to retrieve important pieces of the object
/// for pixel data decoding into images or multi-dimensional arrays.
///
/// It is defined in this crate so that
/// transfer syntax implementers only have to depend on `dicom_encoding`.
pub trait PixelDataObject {
    /// Return the Rows attribute or None if it is not found
    fn rows(&self) -> Option<u16>;

    /// Return the Columns attribute or None if it is not found
    fn cols(&self) -> Option<u16>;

    /// Return the SamplesPerPixel attribute or None if it is not found
    fn samples_per_pixel(&self) -> Option<u16>;

    /// Return the BitsAllocated attribute or None if it is not set
    fn bits_allocated(&self) -> Option<u16>;

    /// Return the NumberOfFrames attribute or None if it is not set
    fn number_of_frames(&self) -> Option<u16>;

    /// Returns the number of fragments or None for native pixel data
    fn number_of_fragments(&self) -> Option<u32>;

    /// Return a specific encoded pixel fragment by index as Vec<u8>
    /// or None if no pixel data is found
    fn fragment(&self, fragment: usize) -> Option<Vec<u8>>;

    /// Should return either a byte slice/vector if native pixel data
    /// or byte fragments if encapsulated.
    /// Returns None if no pixel data is found
    fn raw_pixel_data(&self) -> Option<RawPixelData>;
}

/// Trait object responsible for decoding and encoding
/// pixel data based on the Transfersyntax.
///
/// Every transfer syntax with encapsulated pixel data
/// should implement these methods.
///
pub trait PixelRWAdapter {
    /// Decode the given DICOM object
    /// containing encapsulated pixel data
    /// into native pixel data as a byte stream.
    ///
    /// It is a necessary precondition that the object's pixel data
    /// is encoded in accordance to the transfer syntax(es)
    /// supported by this adapter.
    /// A `NotEncapsulated` error is returned otherwise.
    ///
    /// The output is a sequence of native pixel values
    /// which follow the image properties of the given object.
    ///
    fn decode(&self, src: &dyn PixelDataObject, dst: &mut Vec<u8>) -> DecodeResult<()>;

    /// Encode a DICOM object's image into the format supported by this adapter,
    /// writing a byte stream of pixel data fragment values
    /// into the given destination.
    ///
    /// It is a necessary precondition that the object's pixel data
    /// is in a _native encoding_.
    /// A `NotNative` error is returned otherwise.
    ///
    /// It is possible that
    /// image encoding is not actually supported by this adapter,
    /// in which case a `NotImplemented` error is returned.
    /// Implementers leave the default method implementation
    /// for this behavior.
    #[allow(unused_variables)]
    fn encode(&self, src: &dyn PixelDataObject, dst: &mut Vec<u8>) -> EncodeResult<()> {
        Err(EncodeError::NotImplemented)
    }
}

/// Alias type for a dynamically dispatched data adapter.
pub type DynPixelRWAdapter = Box<dyn PixelRWAdapter + Send + Sync>;

/// An immaterial type representing an adapter which is never required.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum NeverPixelAdapter {}

impl PixelRWAdapter for NeverPixelAdapter {
    fn decode(&self, _src: &dyn PixelDataObject, _dst: &mut Vec<u8>) -> DecodeResult<()> {
        unreachable!();
    }

    fn encode(&self, _src: &dyn PixelDataObject, _dst: &mut Vec<u8>) -> EncodeResult<()> {
        unreachable!();
    }
}
<commit_msg>[encoding] add pixel data encoding options<commit_after>use dicom_core::value::C;
use snafu::Snafu;

pub mod rle_lossless;

/// Error conditions when decoding pixel data.
#[derive(Debug, Snafu)]
#[non_exhaustive]
pub enum DecodeError {
    /// A custom error when decoding fails
    #[snafu(display("Error decoding pixel data: {}", message))]
    CustomDecodeError { message: &'static str },

    /// Input pixel data is not encapsulated
    NotEncapsulated,

    /// A required attribute is missing from the DICOM
    #[snafu(display("Missing required attribute: {}", name))]
    MissingAttribute { name: &'static str },
}

/// Error conditions when encoding pixel data.
#[derive(Debug, Snafu)]
#[non_exhaustive]
pub enum EncodeError {
    /// A custom error when encoding fails
    #[snafu(display("Error encoding pixel data {}", message))]
    CustomEncodeError {
        message: &'static str,
    },

    /// Input pixel data is not native
    NotNative,

    /// Encoding is not implemented
    NotImplemented,
}

pub type DecodeResult<T, E = DecodeError> = Result<T, E>;

pub type EncodeResult<T, E = EncodeError> = Result<T, E>;

#[derive(Debug)]
pub struct RawPixelData {
    /// Either a byte slice/vector if native pixel data
    /// or byte fragments if encapsulated
    pub fragments: C<Vec<u8>>,

    /// The offset table for the fragments,
    /// or empty if there is none
    pub offset_table: C<u32>,
}

/// A DICOM object trait to be interpreted as pixel data.
///
/// This trait extends the concept of DICOM object
/// as defined in [`dicom_object`](::dicom_object),
/// in order to retrieve important pieces of the object
/// for pixel data decoding into images or multi-dimensional arrays.
///
/// It is defined in this crate so that
/// transfer syntax implementers only have to depend on `dicom_encoding`.
pub trait PixelDataObject {
    /// Return the Rows attribute or None if it is not found
    fn rows(&self) -> Option<u16>;

    /// Return the Columns attribute or None if it is not found
    fn cols(&self) -> Option<u16>;

    /// Return the SamplesPerPixel attribute or None if it is not found
    fn samples_per_pixel(&self) -> Option<u16>;

    /// Return the BitsAllocated attribute or None if it is not set
    fn bits_allocated(&self) -> Option<u16>;

    /// Return the NumberOfFrames attribute or None if it is not set
    fn number_of_frames(&self) -> Option<u16>;

    /// Returns the number of fragments or None for native pixel data
    fn number_of_fragments(&self) -> Option<u32>;

    /// Return a specific encoded pixel fragment by index as Vec<u8>
    /// or None if no pixel data is found
    fn fragment(&self, fragment: usize) -> Option<Vec<u8>>;

    /// Should return either a byte slice/vector if native pixel data
    /// or byte fragments if encapsulated.
    /// Returns None if no pixel data is found
    fn raw_pixel_data(&self) -> Option<RawPixelData>;
}

/// Custom options when encoding pixel data into an encapsulated form.
#[derive(Debug, Default, Clone)]
#[non_exhaustive]
pub struct EncodeOptions {
    /// The quality of the output image as a number between 0 and 100,
    /// where 100 is the best quality that the encapsulated form can achieve
    /// and smaller values represent smaller data size
    /// with an increasingly higher error.
    /// It is ignored if the transfer syntax only supports lossless compression.
    /// If it does support however,
    /// it is expected that a quality of 100 results in a lossless encoding.
    ///
    /// If this option is not specified,
    /// the output quality is decided automatically by the underlying adapter.
    pub quality: Option<u8>,
}

impl EncodeOptions {
    pub fn new() -> Self {
        Self::default()
    }
}

/// Trait object responsible for decoding and encoding
/// pixel data based on the Transfersyntax.
///
/// Every transfer syntax with encapsulated pixel data
/// should implement these methods.
///
pub trait PixelRWAdapter {
    /// Decode the given DICOM object
    /// containing encapsulated pixel data
    /// into native pixel data as a byte stream.
    ///
    /// It is a necessary precondition that the object's pixel data
    /// is encoded in accordance to the transfer syntax(es)
    /// supported by this adapter.
    /// A `NotEncapsulated` error is returned otherwise.
    ///
    /// The output is a sequence of native pixel values
    /// which follow the image properties of the given object.
    ///
    fn decode(&self, src: &dyn PixelDataObject, dst: &mut Vec<u8>) -> DecodeResult<()>;

    /// Encode a DICOM object's image into the format supported by this adapter,
    /// writing a byte stream of pixel data fragment values
    /// into the given destination.
    ///
    /// It is a necessary precondition that the object's pixel data
    /// is in a _native encoding_.
    /// A `NotNative` error is returned otherwise.
    ///
    /// It is possible that
    /// image encoding is not actually supported by this adapter,
    /// in which case a `NotImplemented` error is returned.
    /// Implementers leave the default method implementation
    /// for this behavior.
    #[allow(unused_variables)]
    fn encode(&self, src: &dyn PixelDataObject, options: EncodeOptions, dst: &mut Vec<u8>) -> EncodeResult<()> {
        Err(EncodeError::NotImplemented)
    }
}

/// Alias type for a dynamically dispatched data adapter.
pub type DynPixelRWAdapter = Box<dyn PixelRWAdapter + Send + Sync>;

/// An immaterial type representing an adapter which is never required.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum NeverPixelAdapter {}

impl PixelRWAdapter for NeverPixelAdapter {
    fn decode(&self, _src: &dyn PixelDataObject, _dst: &mut Vec<u8>) -> DecodeResult<()> {
        unreachable!();
    }

    fn encode(&self, _src: &dyn PixelDataObject, _options: EncodeOptions, _dst: &mut Vec<u8>) -> EncodeResult<()> {
        unreachable!();
    }
}
<|endoftext|>


<commit_before>// An attribute to hide warnings for unused code.
#![allow(dead_code)]

// Create an `enum` to classify someone. Note how both names
// and type information together specify the variant:
// `Skinny != Fat` and `Height(i32) != Weight(i32)`. Each
// is different and independent.
enum Person {
    // An `enum` may either be `unit-like`,
    Skinny,
    Fat,
    // like tuple structs,
    Height(i32),
    Weight(i32),
    // or like structures.
    Info { name: String, height: i32 }
}

// A function which takes a `Person` enum as an argument and
// returns nothing.
fn inspect(p: Person) {
    // Usage of an `enum` must cover all cases (irrefutable)
    // so a `match` is used to branch over it.
    match p {
        Person::Skinny    => println!("Is skinny!"),
        Person::Fat       => println!("Is fat!"),
        // Destructure `i` from inside the `enum`.
        Person::Height(i) => println!("Has a height of {}.", i),
        Person::Weight(i) => println!("Has a weight of {}.", i),
        // Destructure `Info` into `name` and `height`.
        Person::Info { name, height } => {
            println!("{} is {} tall!", name, height);
        },
    }
}

fn main() {
    let person = Person::Height(18);
    // `to_owned()` creates an owned `String` from a string slice.
    let dave   = Person::Info { name: "Dave".to_owned(), height: 72 };
    // ^ TODO: Try changing these to a different variants.

    inspect(person);
    inspect(dave);
}
<commit_msg>Add enum variants to cover all cases<commit_after>// An attribute to hide warnings for unused code.
#![allow(dead_code)]

// Create an `enum` to classify someone. Note how both names
// and type information together specify the variant:
// `Skinny != Fat` and `Height(i32) != Weight(i32)`. Each
// is different and independent.
enum Person {
    // An `enum` may either be `unit-like`,
    Skinny,
    Fat,
    // like tuple structs,
    Height(i32),
    Weight(i32),
    // or like structures.
    Info { name: String, height: i32 }
}

// A function which takes a `Person` enum as an argument and
// returns nothing.
fn inspect(p: Person) {
    // Usage of an `enum` must cover all cases (irrefutable)
    // so a `match` is used to branch over it.
    match p {
        Person::Skinny    => println!("Is skinny!"),
        Person::Fat       => println!("Is fat!"),
        // Destructure `i` from inside the `enum`.
        Person::Height(i) => println!("Has a height of {}.", i),
        Person::Weight(i) => println!("Has a weight of {}.", i),
        // Destructure `Info` into `name` and `height`.
        Person::Info { name, height } => {
            println!("{} is {} tall!", name, height);
        },
    }
}

fn main() {
    let person = Person::Height(18);
    let danny  = Person::Weight(10);
    // `to_owned()` creates an owned `String` from a string slice.
    let dave   = Person::Info { name: "Dave".to_owned(), height: 72 };
    let john   = Person::Fat;
    let larry  = Person::Skinny;

    inspect(person);
    inspect(danny);
    inspect(dave);
    inspect(john);
    inspect(larry);
}
<|endoftext|>


<commit_before>use proc_macro2::{Ident, Span, TokenStream};
use shared::{map_type_params, split_for_impl};
use syn::{self, Data, DeriveInput, Fields, GenericParam, Generics};

use attr::{Container, CrateName};

pub fn derive(input: TokenStream) -> TokenStream {
    let derive_input = syn::parse2(input).expect("Input is checked by rustc");

    let container = Container::from_ast(&derive_input);

    let DeriveInput {
        ident,
        data,
        generics,
        ..
    } = derive_input;

    let tokens = match data {
        Data::Struct(_) | Data::Enum(_) => gen_impl(&container, ident, generics, &data),
        Data::Union(_) => panic!("Unions are not supported"),
    };

    tokens.into()
}

fn gen_impl(container: &Container, ident: Ident, generics: Generics, data: &Data) -> TokenStream {
    let trait_bounds = &map_type_params(&generics, |ty| {
        quote! { #ty: _gluon_api::VmType, #ty::Type: Sized }
    });

    let (impl_generics, ty_generics, where_clause) = split_for_impl(&generics, &[]);

    let gluon = match container.crate_name {
        CrateName::Some(ref ident) => quote! {
            use #ident::base as _gluon_base;
            use #ident::api as _gluon_api;
            use #ident::thread as _gluon_thread;
        },
        CrateName::GluonVm => quote! {
            use base as _gluon_base;
            use api as _gluon_api;
            use thread as _gluon_thread;
        },
        CrateName::None => quote! {
            use gluon::base as _gluon_base;
            use gluon::vm::api as _gluon_api;
            use gluon::vm::thread as _gluon_thread;
        },
    };

    let make_type_impl = match container.vm_type {
        Some(ref gluon_type) => {
            let type_application = gen_type_application(&generics);
            quote! {
                let ty = match vm.find_type_info(#gluon_type) {
                    Ok(info) => info.into_type(),
                    Err(_) => panic!("Could not find type '{}'. Is the module defining the type loaded?", #gluon_type),
                };

                #type_application
            }
        }
        None => match *data {
            Data::Struct(ref struct_) => match struct_.fields {
                Fields::Named(ref fields) => {
                    let fields = fields.named.iter().map(|field| {
                        let ident = field.ident.as_ref().unwrap().to_string();
                        let typ = &field.ty;
                        quote! {
                            _gluon_base::types::Field {
                                name: _gluon_base::symbol::Symbol::from(#ident),
                                typ: <#typ as _gluon_api::VmType>::make_type(vm),
                            }
                        }
                    });
                    quote! {
                        _gluon_base::types::Type::record(
                            vec![],
                            vec![#(#fields),*],
                        )
                    }
                }
                Fields::Unnamed(ref fields) => {
                    if fields.unnamed.len() == 1 {
                        let typ = &fields.unnamed[0].ty;
                        quote! {
                            <#typ as _gluon_api::VmType>::make_type(vm)
                        }
                    } else {
                        let fields = fields.unnamed.iter().map(|field| &field.ty);
                        quote! {
                            _gluon_base::types::Type::tuple(vec![#(
                                <#fields as _gluon_api::VmType>::make_type(vm)
                            ),*])
                        }
                    }
                }
                Fields::Unit => quote!(_gluon_base::types::Type::unit()),
            },
            Data::Enum(ref enum_) => {
                let variants = enum_.variants.iter().map(|variant| {
                    let ident = variant.ident.to_string();
                    let args = variant.fields.iter().map(|field| {
                        let typ = &field.ty;
                        quote! {
                            <#typ as _gluon_api::VmType>::make_type(vm)
                        }
                    });
                    quote! {{
                        let name = _gluon_base::symbol::Symbol::from(#ident);
                        _gluon_base::types::Field {
                            name: name.clone(),
                            typ: _gluon_base::types::Type::tuple(
                                &mut _gluon_base::symbol::Symbols::new(),
                                vec![#(#args),*],
                            ),
                        }
                    }}
                });
                quote! {
                    _gluon_base::types::Type::variant(
                        vec![#(#variants),*]
                    )
                }
            }
            _ => panic!(
                "Only structs and enums can derive `VmType` without using the `vm_type` attribute"
            ),
        },
    };

    let associated_type_generics = generics.params.iter().map(|param| match param {
        GenericParam::Type(ty) => quote!( #ty :: Type ),
        GenericParam::Lifetime(_) => quote!( 'static ),
        GenericParam::Const(c) => quote!( #c ),
    });

    let dummy_const = Ident::new(&format!("_IMPL_VM_TYPE_FOR_{}", ident), Span::call_site());

    quote! {
        #[allow(non_upper_case_globals)]
        const #dummy_const: () = {
            #gluon

            #[automatically_derived]
            #[allow(unused_attributes, unused_variables)]
            impl #impl_generics _gluon_api::VmType for #ident #ty_generics
            #where_clause #(#trait_bounds,)*
            {
                type Type = #ident<
                        #(#associated_type_generics),*
                    >;

                fn make_type(vm: &_gluon_thread::Thread) -> _gluon_base::types::ArcType {
                    #make_type_impl
                }
            }
        };
    }
}

fn gen_type_application(generics: &Generics) -> TokenStream {
    let applications = map_type_params(generics, |param| {
        quote! {
            vec.push(<#param as _gluon_api::VmType>::make_type(vm));
        }
    });

    // if there are generic parameters, we use their types and apply them
    // to the type of the derive target to construct the concrete type
    if applications.is_empty() {
        quote! {
            ty
        }
    } else {
        quote! {
            let mut vec = _gluon_base::types::AppVec::new();
            #(#applications)*
            _gluon_base::types::Type::app(ty, vec)
        }
    }
}
<commit_msg>fix(codegen): Return exactly the same type on VmType derive on enum<commit_after>use proc_macro2::{Ident, Span, TokenStream};
use shared::{map_type_params, split_for_impl};
use syn::{self, Data, DeriveInput, Fields, GenericParam, Generics};

use attr::{Container, CrateName};

pub fn derive(input: TokenStream) -> TokenStream {
    let derive_input = syn::parse2(input).expect("Input is checked by rustc");

    let container = Container::from_ast(&derive_input);

    let DeriveInput {
        ident,
        data,
        generics,
        ..
    } = derive_input;

    let tokens = match data {
        Data::Struct(_) | Data::Enum(_) => gen_impl(&container, ident, generics, &data),
        Data::Union(_) => panic!("Unions are not supported"),
    };

    tokens.into()
}

fn gen_impl(container: &Container, ident: Ident, generics: Generics, data: &Data) -> TokenStream {
    let trait_bounds = &map_type_params(&generics, |ty| {
        quote! { #ty: _gluon_api::VmType, #ty::Type: Sized }
    });

    let (impl_generics, ty_generics, where_clause) = split_for_impl(&generics, &[]);

    let gluon = match container.crate_name {
        CrateName::Some(ref ident) => quote! {
            use #ident::base as _gluon_base;
            use #ident::api as _gluon_api;
            use #ident::thread as _gluon_thread;
        },
        CrateName::GluonVm => quote! {
            use base as _gluon_base;
            use api as _gluon_api;
            use thread as _gluon_thread;
        },
        CrateName::None => quote! {
            use gluon::base as _gluon_base;
            use gluon::vm::api as _gluon_api;
            use gluon::vm::thread as _gluon_thread;
        },
    };

    let make_type_impl = match container.vm_type {
        Some(ref gluon_type) => {
            let type_application = gen_type_application(&generics);
            quote! {
                let ty = match vm.find_type_info(#gluon_type) {
                    Ok(info) => info.into_type(),
                    Err(_) => panic!("Could not find type '{}'. Is the module defining the type loaded?", #gluon_type),
                };

                #type_application
            }
        }
        None => match *data {
            Data::Struct(ref struct_) => match struct_.fields {
                Fields::Named(ref fields) => {
                    let fields = fields.named.iter().map(|field| {
                        let ident = field.ident.as_ref().unwrap().to_string();
                        let typ = &field.ty;
                        quote! {
                            _gluon_base::types::Field {
                                name: _gluon_base::symbol::Symbol::from(#ident),
                                typ: <#typ as _gluon_api::VmType>::make_type(vm),
                            }
                        }
                    });
                    quote! {
                        _gluon_base::types::Type::record(
                            vec![],
                            vec![#(#fields),*],
                        )
                    }
                }
                Fields::Unnamed(ref fields) => {
                    if fields.unnamed.len() == 1 {
                        let typ = &fields.unnamed[0].ty;
                        quote! {
                            <#typ as _gluon_api::VmType>::make_type(vm)
                        }
                    } else {
                        let fields = fields.unnamed.iter().map(|field| &field.ty);
                        quote! {
                            _gluon_base::types::Type::tuple(vec![#(
                                <#fields as _gluon_api::VmType>::make_type(vm)
                            ),*])
                        }
                    }
                }
                Fields::Unit => quote!(_gluon_base::types::Type::unit()),
            },
            Data::Enum(ref enum_) => {
                let enum_ident = ident.to_string();
                let ty_params = map_type_params(&generics, |ty| {
                    quote! { _gluon_base::types::Generic::new(#ty) }
                });
                let variants = enum_.variants.iter().map(|variant| {
                    let ident = variant.ident.to_string();
                    let args = variant.fields.iter().map(|field| {
                        let typ = &field.ty;
                        quote! {
                            <#typ as _gluon_api::VmType>::make_type(vm)
                        }
                    });
                    quote! {{
                        let ctor_name = _gluon_base::symbol::Symbol::from(#ident);
                        _gluon_base::types::Field::ctor(
                            enum_name.clone(),
                            ty_params.iter().cloned(),
                            ctor_name.clone(),
                            vec![#(#args),*],
                        )
                    }}
                });
                quote! {
                    if let Some(typ) = vm.get_type::<Self::Type>() {
                        typ
                    } else {
                        let enum_name = _gluon_base::symbol::Symbol::from(#enum_ident);
                        let ty_params = [#(#ty_params),*];
                        let typ = _gluon_base::types::Alias::new(
                            enum_name.clone(),
                            ty_params.iter().cloned().collect(),
                            _gluon_base::types::Type::variant(
                                vec![#(#variants),*]
                            )
                        );
                        vm.register_type_as(enum_name, typ, ::std::any::TypeId::of::<Self::Type>()).unwrap()
                    }
                }
            }
            _ => panic!(
                "Only structs and enums can derive `VmType` without using the `vm_type` attribute"
            ),
        },
    };

    let associated_type_generics = generics.params.iter().map(|param| match param {
        GenericParam::Type(ty) => quote!( #ty :: Type ),
        GenericParam::Lifetime(_) => quote!( 'static ),
        GenericParam::Const(c) => quote!( #c ),
    });

    let dummy_const = Ident::new(&format!("_IMPL_VM_TYPE_FOR_{}", ident), Span::call_site());

    quote! {
        #[allow(non_upper_case_globals)]
        const #dummy_const: () = {
            #gluon

            #[automatically_derived]
            #[allow(unused_attributes, unused_variables)]
            impl #impl_generics _gluon_api::VmType for #ident #ty_generics
            #where_clause #(#trait_bounds,)*
            {
                type Type = #ident<
                        #(#associated_type_generics),*
                    >;

                fn make_type(vm: &_gluon_thread::Thread) -> _gluon_base::types::ArcType {
                    #make_type_impl
                }
            }
        };
    }
}

fn gen_type_application(generics: &Generics) -> TokenStream {
    let applications = map_type_params(generics, |param| {
        quote! {
            vec.push(<#param as _gluon_api::VmType>::make_type(vm));
        }
    });

    // if there are generic parameters, we use their types and apply them
    // to the type of the derive target to construct the concrete type
    if applications.is_empty() {
        quote! {
            ty
        }
    } else {
        quote! {
            let mut vec = _gluon_base::types::AppVec::new();
            #(#applications)*
            _gluon_base::types::Type::app(ty, vec)
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! This module implements the check that the lifetime of a borrow
//! does not exceed the lifetime of the value being borrowed.

use core::prelude::*;
use middle::borrowck::*;
use mc = middle::mem_categorization;
use middle::ty;
use syntax::ast::{m_const, m_imm, m_mutbl};
use syntax::ast;
use syntax::codemap::span;
use util::ppaux::{note_and_explain_region};

pub fn guarantee_lifetime(bccx: @BorrowckCtxt,
                          item_scope_id: ast::node_id,
                          root_scope_id: ast::node_id,
                          span: span,
                          cmt: mc::cmt,
                          loan_region: ty::Region,
                          loan_mutbl: ast::mutability) {
    debug!("guarantee_lifetime(cmt=%s, loan_region=%s)",
           cmt.repr(bccx.tcx), loan_region.repr(bccx.tcx));
    let ctxt = GuaranteeLifetimeContext {bccx: bccx,
                                         item_scope_id: item_scope_id,
                                         span: span,
                                         loan_region: loan_region,
                                         loan_mutbl: loan_mutbl,
                                         cmt_original: cmt,
                                         root_scope_id: root_scope_id};
    ctxt.check(cmt, None);
}

///////////////////////////////////////////////////////////////////////////
// Private

struct GuaranteeLifetimeContext {
    bccx: @BorrowckCtxt,

    // the node id of the function body for the enclosing item
    item_scope_id: ast::node_id,

    // the node id of the innermost loop / function body; this is the
    // longest scope for which we can root managed boxes
    root_scope_id: ast::node_id,

    span: span,
    loan_region: ty::Region,
    loan_mutbl: ast::mutability,
    cmt_original: mc::cmt
}

impl GuaranteeLifetimeContext {
    fn tcx(&self) -> ty::ctxt {
        self.bccx.tcx
    }

    fn check(&self, cmt: mc::cmt, discr_scope: Option<ast::node_id>) {
        //! Main routine. Walks down `cmt` until we find the "guarantor".

        match cmt.cat {
            mc::cat_rvalue |
            mc::cat_implicit_self |
            mc::cat_copied_upvar(*) |
            mc::cat_local(*) |
            mc::cat_arg(*) |
            mc::cat_self(*) |
            mc::cat_deref(_, _, mc::region_ptr(*)) |
            mc::cat_deref(_, _, mc::unsafe_ptr) => {
                let scope = self.scope(cmt);
                self.check_scope(scope)
            }

            mc::cat_stack_upvar(cmt) => {
                self.check(cmt, discr_scope)
            }

            mc::cat_static_item => {
            }

            mc::cat_deref(base, derefs, mc::gc_ptr(ptr_mutbl)) => {
                let base_scope = self.scope(base);

                // See rule Freeze-Imm-Managed-Ptr-2 in doc.rs
                let omit_root = (
                    ptr_mutbl == m_imm &&
                    self.bccx.is_subregion_of(self.loan_region, base_scope) &&
                    self.is_rvalue_or_immutable(base) &&
                    !self.is_moved(base)
                );

                if !omit_root {
                    self.check_root(cmt, base, derefs, ptr_mutbl, discr_scope);
                } else {
                    debug!("omitting root, base=%s, base_scope=%?",
                           base.repr(self.tcx()), base_scope);
                }
            }

            mc::cat_deref(base, _, mc::uniq_ptr(*)) |
            mc::cat_interior(base, _) => {
                self.check(base, discr_scope)
            }

            mc::cat_discr(base, new_discr_scope) => {
                // Subtle: in a match, we must ensure that each binding
                // variable remains valid for the duration of the arm in
                // which it appears, presuming that this arm is taken.
                // But it is inconvenient in trans to root something just
                // for one arm.  Therefore, we insert a cat_discr(),
                // basically a special kind of category that says "if this
                // value must be dynamically rooted, root it for the scope
                // `match_id`.
                //
                // As an example, consider this scenario:
                //
                //    let mut x = @Some(3);
                //    match *x { Some(y) {...} None {...} }
                //
                // Technically, the value `x` need only be rooted
                // in the `some` arm.  However, we evaluate `x` in trans
                // before we know what arm will be taken, so we just
                // always root it for the duration of the match.
                //
                // As a second example, consider *this* scenario:
                //
                //    let x = @mut @Some(3);
                //    match x { @@Some(y) {...} @@None {...} }
                //
                // Here again, `x` need only be rooted in the `some` arm.
                // In this case, the value which needs to be rooted is
                // found only when checking which pattern matches: but
                // this check is done before entering the arm.  Therefore,
                // even in this case we just choose to keep the value
                // rooted for the entire match.  This means the value will be
                // rooted even if the none arm is taken.  Oh well.
                //
                // At first, I tried to optimize the second case to only
                // root in one arm, but the result was suboptimal: first,
                // it interfered with the construction of phi nodes in the
                // arm, as we were adding code to root values before the
                // phi nodes were added.  This could have been addressed
                // with a second basic block.  However, the naive approach
                // also yielded suboptimal results for patterns like:
                //
                //    let x = @mut @...;
                //    match x { @@some_variant(y) | @@some_other_variant(y) =>
                //
                // The reason is that we would root the value once for
                // each pattern and not once per arm.  This is also easily
                // fixed, but it's yet more code for what is really quite
                // the corner case.
                //
                // Nonetheless, if you decide to optimize this case in the
                // future, you need only adjust where the cat_discr()
                // node appears to draw the line between what will be rooted
                // in the *arm* vs the *match*.
                self.check(base, Some(new_discr_scope))
            }
        }
    }

    fn is_rvalue_or_immutable(&self,
                              cmt: mc::cmt) -> bool {
        cmt.mutbl.is_immutable() || match cmt.guarantor().cat {
            mc::cat_rvalue => true,
            _ => false
        }
    }

    fn check_root(&self,
                  cmt_deref: mc::cmt,
                  cmt_base: mc::cmt,
                  derefs: uint,
                  ptr_mutbl: ast::mutability,
                  discr_scope: Option<ast::node_id>) {
        debug!("check_root(cmt_deref=%s, cmt_base=%s, derefs=%?, ptr_mutbl=%?, \
                discr_scope=%?)",
               cmt_deref.repr(self.tcx()),
               cmt_base.repr(self.tcx()),
               derefs,
               ptr_mutbl,
               discr_scope);

        // Make sure that the loan does not exceed the maximum time
        // that we can root the value, dynamically.
        let root_region = ty::re_scope(self.root_scope_id);
        if !self.bccx.is_subregion_of(self.loan_region, root_region) {
            self.report_error(
                err_out_of_root_scope(root_region, self.loan_region));
            return;
        }

        // Extract the scope id that indicates how long the rooting is required
        let root_scope = match self.loan_region {
            ty::re_scope(id) => id,
            _ => {
                // the check above should fail for anything is not re_scope
                self.bccx.tcx.sess.span_bug(
                    cmt_base.span,
                    fmt!("Cannot issue root for scope region: %?",
                         self.loan_region));
            }
        };

        // If inside of a match arm, expand the rooting to the entire
        // match. See the detailed discussion in `check()` above.
        let mut root_scope = match discr_scope {
            None => root_scope,
            Some(id) => {
                if self.bccx.is_subscope_of(root_scope, id) {
                    id
                } else {
                    root_scope
                }
            }
        };

        // If we are borrowing the inside of an `@mut` box,
        // we need to dynamically mark it to prevent incompatible
        // borrows from happening later.
        let opt_dyna = match ptr_mutbl {
            m_imm | m_const => None,
            m_mutbl => {
                match self.loan_mutbl {
                    m_mutbl => Some(DynaMut),
                    m_imm | m_const => Some(DynaImm)
                }
            }
        };

        // FIXME(#3511) grow to the nearest cleanup scope---this can
        // cause observable errors if freezing!
        if !self.bccx.tcx.region_maps.is_cleanup_scope(root_scope) {
            debug!("%? is not a cleanup scope, adjusting", root_scope);

            let cleanup_scope =
                self.bccx.tcx.region_maps.cleanup_scope(root_scope);

            if opt_dyna.is_some() {
                self.tcx().sess.span_warn(
                    self.span,
                    fmt!("Dynamic freeze scope artifically extended \
                          (see Issue #6248)"));
                note_and_explain_region(
                    self.bccx.tcx,
                    "managed value only needs to be frozen for ",
                    ty::re_scope(root_scope),
                    "...");
                note_and_explain_region(
                    self.bccx.tcx,
                    "...but due to Issue #6248, it will be frozen for ",
                    ty::re_scope(cleanup_scope),
                    "");
            }

            root_scope = cleanup_scope;
        }

        // Add a record of what is required
        let rm_key = root_map_key {id: cmt_deref.id, derefs: derefs};
        let root_info = RootInfo {scope: root_scope, freeze: opt_dyna};
        self.bccx.root_map.insert(rm_key, root_info);

        debug!("root_key: %? root_info: %?", rm_key, root_info);
    }

    fn check_scope(&self, max_scope: ty::Region) {
        //! Reports an error if `loan_region` is larger than `valid_scope`

        if !self.bccx.is_subregion_of(self.loan_region, max_scope) {
            self.report_error(err_out_of_scope(max_scope, self.loan_region));
        }
    }

    fn is_moved(&self, cmt: mc::cmt) -> bool {
        //! True if `cmt` is something that is potentially moved
        //! out of the current stack frame.

        match cmt.guarantor().cat {
            mc::cat_local(id) |
            mc::cat_self(id) |
            mc::cat_arg(id) => {
                self.bccx.moved_variables_set.contains(&id)
            }
            mc::cat_rvalue |
            mc::cat_static_item |
            mc::cat_implicit_self |
            mc::cat_copied_upvar(*) |
            mc::cat_deref(*) => {
                false
            }
            r @ mc::cat_interior(*) |
            r @ mc::cat_stack_upvar(*) |
            r @ mc::cat_discr(*) => {
                self.tcx().sess.span_bug(
                    cmt.span,
                    fmt!("illegal guarantor category: %?", r));
            }
        }
    }

    fn scope(&self, cmt: mc::cmt) -> ty::Region {
        //! Returns the maximal region scope for the which the
        //! lvalue `cmt` is guaranteed to be valid without any
        //! rooting etc, and presuming `cmt` is not mutated.

        match cmt.cat {
            mc::cat_rvalue => {
                ty::re_scope(self.bccx.tcx.region_maps.cleanup_scope(cmt.id))
            }
            mc::cat_implicit_self |
            mc::cat_copied_upvar(_) => {
                ty::re_scope(self.item_scope_id)
            }
            mc::cat_static_item => {
                ty::re_static
            }
            mc::cat_local(local_id) |
            mc::cat_arg(local_id) |
            mc::cat_self(local_id) => {
                self.bccx.tcx.region_maps.encl_region(local_id)
            }
            mc::cat_deref(_, _, mc::unsafe_ptr(*)) => {
                ty::re_static
            }
            mc::cat_deref(_, _, mc::region_ptr(_, r)) => {
                r
            }
            mc::cat_deref(cmt, _, mc::uniq_ptr(*)) |
            mc::cat_deref(cmt, _, mc::gc_ptr(*)) |
            mc::cat_interior(cmt, _) |
            mc::cat_stack_upvar(cmt) |
            mc::cat_discr(cmt, _) => {
                self.scope(cmt)
            }
        }
    }

    fn report_error(&self, code: bckerr_code) {
        self.bccx.report(BckError {
            cmt: self.cmt_original,
            span: self.span,
            code: code
        });
    }
}
<commit_msg>Add explanatory comment to is_rvalue_or_immutable()<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! This module implements the check that the lifetime of a borrow
//! does not exceed the lifetime of the value being borrowed.

use core::prelude::*;
use middle::borrowck::*;
use mc = middle::mem_categorization;
use middle::ty;
use syntax::ast::{m_const, m_imm, m_mutbl};
use syntax::ast;
use syntax::codemap::span;
use util::ppaux::{note_and_explain_region};

pub fn guarantee_lifetime(bccx: @BorrowckCtxt,
                          item_scope_id: ast::node_id,
                          root_scope_id: ast::node_id,
                          span: span,
                          cmt: mc::cmt,
                          loan_region: ty::Region,
                          loan_mutbl: ast::mutability) {
    debug!("guarantee_lifetime(cmt=%s, loan_region=%s)",
           cmt.repr(bccx.tcx), loan_region.repr(bccx.tcx));
    let ctxt = GuaranteeLifetimeContext {bccx: bccx,
                                         item_scope_id: item_scope_id,
                                         span: span,
                                         loan_region: loan_region,
                                         loan_mutbl: loan_mutbl,
                                         cmt_original: cmt,
                                         root_scope_id: root_scope_id};
    ctxt.check(cmt, None);
}

///////////////////////////////////////////////////////////////////////////
// Private

struct GuaranteeLifetimeContext {
    bccx: @BorrowckCtxt,

    // the node id of the function body for the enclosing item
    item_scope_id: ast::node_id,

    // the node id of the innermost loop / function body; this is the
    // longest scope for which we can root managed boxes
    root_scope_id: ast::node_id,

    span: span,
    loan_region: ty::Region,
    loan_mutbl: ast::mutability,
    cmt_original: mc::cmt
}

impl GuaranteeLifetimeContext {
    fn tcx(&self) -> ty::ctxt {
        self.bccx.tcx
    }

    fn check(&self, cmt: mc::cmt, discr_scope: Option<ast::node_id>) {
        //! Main routine. Walks down `cmt` until we find the "guarantor".

        match cmt.cat {
            mc::cat_rvalue |
            mc::cat_implicit_self |
            mc::cat_copied_upvar(*) |
            mc::cat_local(*) |
            mc::cat_arg(*) |
            mc::cat_self(*) |
            mc::cat_deref(_, _, mc::region_ptr(*)) |
            mc::cat_deref(_, _, mc::unsafe_ptr) => {
                let scope = self.scope(cmt);
                self.check_scope(scope)
            }

            mc::cat_stack_upvar(cmt) => {
                self.check(cmt, discr_scope)
            }

            mc::cat_static_item => {
            }

            mc::cat_deref(base, derefs, mc::gc_ptr(ptr_mutbl)) => {
                let base_scope = self.scope(base);

                // See rule Freeze-Imm-Managed-Ptr-2 in doc.rs
                let omit_root = (
                    ptr_mutbl == m_imm &&
                    self.bccx.is_subregion_of(self.loan_region, base_scope) &&
                    self.is_rvalue_or_immutable(base) &&
                    !self.is_moved(base)
                );

                if !omit_root {
                    self.check_root(cmt, base, derefs, ptr_mutbl, discr_scope);
                } else {
                    debug!("omitting root, base=%s, base_scope=%?",
                           base.repr(self.tcx()), base_scope);
                }
            }

            mc::cat_deref(base, _, mc::uniq_ptr(*)) |
            mc::cat_interior(base, _) => {
                self.check(base, discr_scope)
            }

            mc::cat_discr(base, new_discr_scope) => {
                // Subtle: in a match, we must ensure that each binding
                // variable remains valid for the duration of the arm in
                // which it appears, presuming that this arm is taken.
                // But it is inconvenient in trans to root something just
                // for one arm.  Therefore, we insert a cat_discr(),
                // basically a special kind of category that says "if this
                // value must be dynamically rooted, root it for the scope
                // `match_id`.
                //
                // As an example, consider this scenario:
                //
                //    let mut x = @Some(3);
                //    match *x { Some(y) {...} None {...} }
                //
                // Technically, the value `x` need only be rooted
                // in the `some` arm.  However, we evaluate `x` in trans
                // before we know what arm will be taken, so we just
                // always root it for the duration of the match.
                //
                // As a second example, consider *this* scenario:
                //
                //    let x = @mut @Some(3);
                //    match x { @@Some(y) {...} @@None {...} }
                //
                // Here again, `x` need only be rooted in the `some` arm.
                // In this case, the value which needs to be rooted is
                // found only when checking which pattern matches: but
                // this check is done before entering the arm.  Therefore,
                // even in this case we just choose to keep the value
                // rooted for the entire match.  This means the value will be
                // rooted even if the none arm is taken.  Oh well.
                //
                // At first, I tried to optimize the second case to only
                // root in one arm, but the result was suboptimal: first,
                // it interfered with the construction of phi nodes in the
                // arm, as we were adding code to root values before the
                // phi nodes were added.  This could have been addressed
                // with a second basic block.  However, the naive approach
                // also yielded suboptimal results for patterns like:
                //
                //    let x = @mut @...;
                //    match x { @@some_variant(y) | @@some_other_variant(y) =>
                //
                // The reason is that we would root the value once for
                // each pattern and not once per arm.  This is also easily
                // fixed, but it's yet more code for what is really quite
                // the corner case.
                //
                // Nonetheless, if you decide to optimize this case in the
                // future, you need only adjust where the cat_discr()
                // node appears to draw the line between what will be rooted
                // in the *arm* vs the *match*.
                self.check(base, Some(new_discr_scope))
            }
        }
    }

    fn is_rvalue_or_immutable(&self,
                              cmt: mc::cmt) -> bool {
        //! We can omit the root on an `@T` value if the location
        //! that holds the box is either (1) an rvalue, in which case
        //! is is in a non-user-accessible temporary, or (2) an immutable
        //! lvalue.

        cmt.mutbl.is_immutable() || match cmt.guarantor().cat {
            mc::cat_rvalue => true,
            _ => false
        }
    }

    fn check_root(&self,
                  cmt_deref: mc::cmt,
                  cmt_base: mc::cmt,
                  derefs: uint,
                  ptr_mutbl: ast::mutability,
                  discr_scope: Option<ast::node_id>) {
        debug!("check_root(cmt_deref=%s, cmt_base=%s, derefs=%?, ptr_mutbl=%?, \
                discr_scope=%?)",
               cmt_deref.repr(self.tcx()),
               cmt_base.repr(self.tcx()),
               derefs,
               ptr_mutbl,
               discr_scope);

        // Make sure that the loan does not exceed the maximum time
        // that we can root the value, dynamically.
        let root_region = ty::re_scope(self.root_scope_id);
        if !self.bccx.is_subregion_of(self.loan_region, root_region) {
            self.report_error(
                err_out_of_root_scope(root_region, self.loan_region));
            return;
        }

        // Extract the scope id that indicates how long the rooting is required
        let root_scope = match self.loan_region {
            ty::re_scope(id) => id,
            _ => {
                // the check above should fail for anything is not re_scope
                self.bccx.tcx.sess.span_bug(
                    cmt_base.span,
                    fmt!("Cannot issue root for scope region: %?",
                         self.loan_region));
            }
        };

        // If inside of a match arm, expand the rooting to the entire
        // match. See the detailed discussion in `check()` above.
        let mut root_scope = match discr_scope {
            None => root_scope,
            Some(id) => {
                if self.bccx.is_subscope_of(root_scope, id) {
                    id
                } else {
                    root_scope
                }
            }
        };

        // If we are borrowing the inside of an `@mut` box,
        // we need to dynamically mark it to prevent incompatible
        // borrows from happening later.
        let opt_dyna = match ptr_mutbl {
            m_imm | m_const => None,
            m_mutbl => {
                match self.loan_mutbl {
                    m_mutbl => Some(DynaMut),
                    m_imm | m_const => Some(DynaImm)
                }
            }
        };

        // FIXME(#3511) grow to the nearest cleanup scope---this can
        // cause observable errors if freezing!
        if !self.bccx.tcx.region_maps.is_cleanup_scope(root_scope) {
            debug!("%? is not a cleanup scope, adjusting", root_scope);

            let cleanup_scope =
                self.bccx.tcx.region_maps.cleanup_scope(root_scope);

            if opt_dyna.is_some() {
                self.tcx().sess.span_warn(
                    self.span,
                    fmt!("Dynamic freeze scope artifically extended \
                          (see Issue #6248)"));
                note_and_explain_region(
                    self.bccx.tcx,
                    "managed value only needs to be frozen for ",
                    ty::re_scope(root_scope),
                    "...");
                note_and_explain_region(
                    self.bccx.tcx,
                    "...but due to Issue #6248, it will be frozen for ",
                    ty::re_scope(cleanup_scope),
                    "");
            }

            root_scope = cleanup_scope;
        }

        // Add a record of what is required
        let rm_key = root_map_key {id: cmt_deref.id, derefs: derefs};
        let root_info = RootInfo {scope: root_scope, freeze: opt_dyna};
        self.bccx.root_map.insert(rm_key, root_info);

        debug!("root_key: %? root_info: %?", rm_key, root_info);
    }

    fn check_scope(&self, max_scope: ty::Region) {
        //! Reports an error if `loan_region` is larger than `valid_scope`

        if !self.bccx.is_subregion_of(self.loan_region, max_scope) {
            self.report_error(err_out_of_scope(max_scope, self.loan_region));
        }
    }

    fn is_moved(&self, cmt: mc::cmt) -> bool {
        //! True if `cmt` is something that is potentially moved
        //! out of the current stack frame.

        match cmt.guarantor().cat {
            mc::cat_local(id) |
            mc::cat_self(id) |
            mc::cat_arg(id) => {
                self.bccx.moved_variables_set.contains(&id)
            }
            mc::cat_rvalue |
            mc::cat_static_item |
            mc::cat_implicit_self |
            mc::cat_copied_upvar(*) |
            mc::cat_deref(*) => {
                false
            }
            r @ mc::cat_interior(*) |
            r @ mc::cat_stack_upvar(*) |
            r @ mc::cat_discr(*) => {
                self.tcx().sess.span_bug(
                    cmt.span,
                    fmt!("illegal guarantor category: %?", r));
            }
        }
    }

    fn scope(&self, cmt: mc::cmt) -> ty::Region {
        //! Returns the maximal region scope for the which the
        //! lvalue `cmt` is guaranteed to be valid without any
        //! rooting etc, and presuming `cmt` is not mutated.

        match cmt.cat {
            mc::cat_rvalue => {
                ty::re_scope(self.bccx.tcx.region_maps.cleanup_scope(cmt.id))
            }
            mc::cat_implicit_self |
            mc::cat_copied_upvar(_) => {
                ty::re_scope(self.item_scope_id)
            }
            mc::cat_static_item => {
                ty::re_static
            }
            mc::cat_local(local_id) |
            mc::cat_arg(local_id) |
            mc::cat_self(local_id) => {
                self.bccx.tcx.region_maps.encl_region(local_id)
            }
            mc::cat_deref(_, _, mc::unsafe_ptr(*)) => {
                ty::re_static
            }
            mc::cat_deref(_, _, mc::region_ptr(_, r)) => {
                r
            }
            mc::cat_deref(cmt, _, mc::uniq_ptr(*)) |
            mc::cat_deref(cmt, _, mc::gc_ptr(*)) |
            mc::cat_interior(cmt, _) |
            mc::cat_stack_upvar(cmt) |
            mc::cat_discr(cmt, _) => {
                self.scope(cmt)
            }
        }
    }

    fn report_error(&self, code: bckerr_code) {
        self.bccx.report(BckError {
            cmt: self.cmt_original,
            span: self.span,
            code: code
        });
    }
}
<|endoftext|>


<commit_before>use std::iter::successors;

use ra_syntax::{
    algo::neighbor,
    ast::{self, edit::AstNodeEdit, make},
    AstNode, AstToken, Direction, InsertPosition, SyntaxElement, TextRange, T,
};

use crate::{Assist, AssistCtx, AssistId};

// Assist: merge_imports
//
// Merges two imports with a common prefix.
//
// ```
// use std::<|>fmt::Formatter;
// use std::io;
// ```
// ->
// ```
// use std::{fmt::Formatter, io};
// ```
pub(crate) fn merge_imports(ctx: AssistCtx) -> Option<Assist> {
    let tree: ast::UseTree = ctx.find_node_at_offset()?;
    let (new_tree, to_delete) = if let Some(use_item) =
        tree.syntax().parent().and_then(ast::UseItem::cast)
    {
        let (merged, to_delete) = next_prev()
            .filter_map(|dir| neighbor(&use_item, dir))
            .filter_map(|it| Some((it.clone(), it.use_tree()?)))
            .find_map(|(use_item, use_tree)| {
                Some((try_merge_trees(&tree, &use_tree)?, use_item.clone()))
            })?;

        let mut range = to_delete.syntax().text_range();
        let next_ws = to_delete
            .syntax()
            .next_sibling_or_token()
            .and_then(|it| it.into_token())
            .and_then(ast::Whitespace::cast);
        if let Some(ws) = next_ws {
            range = range.extend_to(&ws.syntax().text_range())
        }
        (merged, range)
    } else {
        let (merged, to_delete) = next_prev()
            .filter_map(|dir| neighbor(&tree, dir))
            .find_map(|use_tree| Some((try_merge_trees(&tree, &use_tree)?, use_tree.clone())))?;

        let mut range = to_delete.syntax().text_range();
        if let Some((dir, nb)) = next_prev().find_map(|dir| Some((dir, neighbor(&to_delete, dir)?)))
        {
            let nb_range = nb.syntax().text_range();
            if dir == Direction::Prev {
                range = TextRange::from_to(nb_range.end(), range.end());
            } else {
                range = TextRange::from_to(range.start(), nb_range.start());
            }
        }
        (merged, range)
    };

    let mut offset = ctx.frange.range.start();
    ctx.add_assist(AssistId("merge_imports"), "Merge imports", |edit| {
        edit.replace_ast(tree, new_tree);
        edit.delete(to_delete);

        if to_delete.end() <= offset {
            offset -= to_delete.len();
        }
        edit.set_cursor(offset);
    })
}

fn next_prev() -> impl Iterator<Item = Direction> {
    [Direction::Next, Direction::Prev].iter().copied()
}

fn try_merge_trees(old: &ast::UseTree, new: &ast::UseTree) -> Option<ast::UseTree> {
    let lhs_path = old.path()?;
    let rhs_path = new.path()?;

    let (lhs_prefix, rhs_prefix) = common_prefix(&lhs_path, &rhs_path)?;

    let lhs = old.split_prefix(&lhs_prefix);
    let rhs = new.split_prefix(&rhs_prefix);

    let mut to_insert: Vec<SyntaxElement> = Vec::new();
    to_insert.push(make::token(T![,]).into());
    to_insert.push(make::tokens::single_space().into());
    to_insert.extend(
        rhs.use_tree_list()?
            .syntax()
            .children_with_tokens()
            .filter(|it| it.kind() != T!['{'] && it.kind() != T!['}']),
    );
    let use_tree_list = lhs.use_tree_list()?;
    let pos = InsertPosition::Before(use_tree_list.r_curly()?.into());
    let use_tree_list = use_tree_list.insert_children(pos, to_insert);
    Some(lhs.with_use_tree_list(use_tree_list))
}

fn common_prefix(lhs: &ast::Path, rhs: &ast::Path) -> Option<(ast::Path, ast::Path)> {
    let mut res = None;
    let mut lhs_curr = first_path(&lhs);
    let mut rhs_curr = first_path(&rhs);
    loop {
        match (lhs_curr.segment(), rhs_curr.segment()) {
            (Some(lhs), Some(rhs)) if lhs.syntax().text() == rhs.syntax().text() => (),
            _ => break,
        }
        res = Some((lhs_curr.clone(), rhs_curr.clone()));

        match (lhs_curr.parent_path(), rhs_curr.parent_path()) {
            (Some(lhs), Some(rhs)) => {
                lhs_curr = lhs;
                rhs_curr = rhs;
            }
            _ => break,
        }
    }

    res
}

fn first_path(path: &ast::Path) -> ast::Path {
    successors(Some(path.clone()), |it| it.qualifier()).last().unwrap()
}

#[cfg(test)]
mod tests {
    use crate::helpers::check_assist;

    use super::*;

    #[test]
    fn test_merge_first() {
        check_assist(
            merge_imports,
            r"
use std::fmt<|>::Debug;
use std::fmt::Display;
",
            r"
use std::fmt<|>::{Debug, Display};
",
        )
    }

    #[test]
    fn test_merge_second() {
        check_assist(
            merge_imports,
            r"
use std::fmt::Debug;
use std::fmt<|>::Display;
",
            r"
use std::fmt<|>::{Display, Debug};
",
        );
    }

    #[test]
    fn test_merge_nested() {
        check_assist(
            merge_imports,
            r"
use std::{fmt<|>::Debug, fmt::Display};
",
            r"
use std::{fmt<|>::{Debug, Display}};
",
        );
        check_assist(
            merge_imports,
            r"
use std::{fmt::Debug, fmt<|>::Display};
",
            r"
use std::{fmt<|>::{Display, Debug}};
",
        );
    }
}
<commit_msg>Add a test<commit_after>use std::iter::successors;

use ra_syntax::{
    algo::neighbor,
    ast::{self, edit::AstNodeEdit, make},
    AstNode, AstToken, Direction, InsertPosition, SyntaxElement, TextRange, T,
};

use crate::{Assist, AssistCtx, AssistId};

// Assist: merge_imports
//
// Merges two imports with a common prefix.
//
// ```
// use std::<|>fmt::Formatter;
// use std::io;
// ```
// ->
// ```
// use std::{fmt::Formatter, io};
// ```
pub(crate) fn merge_imports(ctx: AssistCtx) -> Option<Assist> {
    let tree: ast::UseTree = ctx.find_node_at_offset()?;
    let (new_tree, to_delete) = if let Some(use_item) =
        tree.syntax().parent().and_then(ast::UseItem::cast)
    {
        let (merged, to_delete) = next_prev()
            .filter_map(|dir| neighbor(&use_item, dir))
            .filter_map(|it| Some((it.clone(), it.use_tree()?)))
            .find_map(|(use_item, use_tree)| {
                Some((try_merge_trees(&tree, &use_tree)?, use_item.clone()))
            })?;

        let mut range = to_delete.syntax().text_range();
        let next_ws = to_delete
            .syntax()
            .next_sibling_or_token()
            .and_then(|it| it.into_token())
            .and_then(ast::Whitespace::cast);
        if let Some(ws) = next_ws {
            range = range.extend_to(&ws.syntax().text_range())
        }
        (merged, range)
    } else {
        let (merged, to_delete) = next_prev()
            .filter_map(|dir| neighbor(&tree, dir))
            .find_map(|use_tree| Some((try_merge_trees(&tree, &use_tree)?, use_tree.clone())))?;

        let mut range = to_delete.syntax().text_range();
        if let Some((dir, nb)) = next_prev().find_map(|dir| Some((dir, neighbor(&to_delete, dir)?)))
        {
            let nb_range = nb.syntax().text_range();
            if dir == Direction::Prev {
                range = TextRange::from_to(nb_range.end(), range.end());
            } else {
                range = TextRange::from_to(range.start(), nb_range.start());
            }
        }
        (merged, range)
    };

    let mut offset = ctx.frange.range.start();
    ctx.add_assist(AssistId("merge_imports"), "Merge imports", |edit| {
        edit.replace_ast(tree, new_tree);
        edit.delete(to_delete);

        if to_delete.end() <= offset {
            offset -= to_delete.len();
        }
        edit.set_cursor(offset);
    })
}

fn next_prev() -> impl Iterator<Item = Direction> {
    [Direction::Next, Direction::Prev].iter().copied()
}

fn try_merge_trees(old: &ast::UseTree, new: &ast::UseTree) -> Option<ast::UseTree> {
    let lhs_path = old.path()?;
    let rhs_path = new.path()?;

    let (lhs_prefix, rhs_prefix) = common_prefix(&lhs_path, &rhs_path)?;

    let lhs = old.split_prefix(&lhs_prefix);
    let rhs = new.split_prefix(&rhs_prefix);

    let mut to_insert: Vec<SyntaxElement> = Vec::new();
    to_insert.push(make::token(T![,]).into());
    to_insert.push(make::tokens::single_space().into());
    to_insert.extend(
        rhs.use_tree_list()?
            .syntax()
            .children_with_tokens()
            .filter(|it| it.kind() != T!['{'] && it.kind() != T!['}']),
    );
    let use_tree_list = lhs.use_tree_list()?;
    let pos = InsertPosition::Before(use_tree_list.r_curly()?.into());
    let use_tree_list = use_tree_list.insert_children(pos, to_insert);
    Some(lhs.with_use_tree_list(use_tree_list))
}

fn common_prefix(lhs: &ast::Path, rhs: &ast::Path) -> Option<(ast::Path, ast::Path)> {
    let mut res = None;
    let mut lhs_curr = first_path(&lhs);
    let mut rhs_curr = first_path(&rhs);
    loop {
        match (lhs_curr.segment(), rhs_curr.segment()) {
            (Some(lhs), Some(rhs)) if lhs.syntax().text() == rhs.syntax().text() => (),
            _ => break,
        }
        res = Some((lhs_curr.clone(), rhs_curr.clone()));

        match (lhs_curr.parent_path(), rhs_curr.parent_path()) {
            (Some(lhs), Some(rhs)) => {
                lhs_curr = lhs;
                rhs_curr = rhs;
            }
            _ => break,
        }
    }

    res
}

fn first_path(path: &ast::Path) -> ast::Path {
    successors(Some(path.clone()), |it| it.qualifier()).last().unwrap()
}

#[cfg(test)]
mod tests {
    use crate::helpers::check_assist;

    use super::*;

    #[test]
    fn test_merge_first() {
        check_assist(
            merge_imports,
            r"
use std::fmt<|>::Debug;
use std::fmt::Display;
",
            r"
use std::fmt<|>::{Debug, Display};
",
        )
    }

    #[test]
    fn test_merge_second() {
        check_assist(
            merge_imports,
            r"
use std::fmt::Debug;
use std::fmt<|>::Display;
",
            r"
use std::fmt<|>::{Display, Debug};
",
        );
    }

    #[test]
    fn test_merge_nested() {
        check_assist(
            merge_imports,
            r"
use std::{fmt<|>::Debug, fmt::Display};
",
            r"
use std::{fmt<|>::{Debug, Display}};
",
        );
        check_assist(
            merge_imports,
            r"
use std::{fmt::Debug, fmt<|>::Display};
",
            r"
use std::{fmt<|>::{Display, Debug}};
",
        );
    }

    #[test]
    fn removes_just_enough_whitespace() {
        check_assist(
            merge_imports,
            r"
use foo<|>::bar;
use foo::baz;

/// Doc comment
",
            r"
use foo<|>::{bar, baz};

/// Doc comment
",
        );
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

//! A 3dsMax / Blender style camera that orbits about a target position

use vecmath::{ Vector3, vec3_add, vec3_scale };
use vecmath::traits::Float;

use quaternion;
use quaternion::Quaternion;

use input;
use input::{ GenericEvent, Key, MouseButton };
use input::Button::{ Keyboard, Mouse };

use Camera;

bitflags!(
    pub flags Keys: u8 {
        const ZOOM  = 0b00000001,
        const PAN   = 0b00000010,
        const ORBIT = 0b00000100,
    }
);

/// Specifies key bindings and speed modifiers for OrbitZoomCamera
pub struct OrbitZoomCameraSettings<T=f32> {

    /// Which button to press to orbit with mouse
    pub orbit_button: input::Button,

    /// Which button to press to zoom with mouse
    pub zoom_button: input::Button,

    /// Which button to press to pan with mouse
    pub pan_button: input::Button,

    /// Modifier for orbiting speed (arbitrary unit)
    pub orbit_speed: T,

    /// Modifier for pitch speed relative to orbiting speed (arbitrary unit).
    /// To reverse pitch direction, set this to -1.
    pub pitch_speed: T,

    /// Modifier for panning speed (arbitrary unit)
    pub pan_speed: T,

    /// Modifier for zoom speed (arbitrary unit)
    pub zoom_speed: T,
}

impl<T: Float> OrbitZoomCameraSettings<T> {

    /// Clicking and dragging OR two-finger scrolling will orbit camera,
    /// with LShift as pan modifer and LCtrl as zoom modifier
    pub fn default() -> OrbitZoomCameraSettings<T> {
        OrbitZoomCameraSettings {
            orbit_button : Mouse(MouseButton::Left),
            zoom_button : Keyboard(Key::LCtrl),
            pan_button : Keyboard(Key::LShift),
            orbit_speed: T::from_f32(0.05),
            pitch_speed: T::from_f32(0.1),
            pan_speed: T::from_f32(0.1),
            zoom_speed: T::from_f32(0.1),
        }
    }

    /// Set the button for orbiting
    pub fn orbit_button(self, button: input::Button) -> OrbitZoomCameraSettings<T> {
        OrbitZoomCameraSettings {
            orbit_button: button,
            .. self
        }
    }

    /// Set the button for zooming
    pub fn zoom_button(self, button: input::Button) -> OrbitZoomCameraSettings<T> {
        OrbitZoomCameraSettings {
            zoom_button: button,
            .. self
        }
    }

    /// Set the button for panning
    pub fn pan_button(self, button: input::Button) -> OrbitZoomCameraSettings<T> {
        OrbitZoomCameraSettings {
            pan_button: button,
            .. self
        }
    }

    /// Set the orbit speed modifier
    pub fn orbit_speed(self, s: T) -> OrbitZoomCameraSettings<T> {
        OrbitZoomCameraSettings {
            orbit_speed: s,
            .. self
        }
    }

    /// Set the pitch speed modifier
    pub fn pitch_speed(self, s: T) -> OrbitZoomCameraSettings<T> {
        OrbitZoomCameraSettings {
            pitch_speed: s,
            .. self
        }
    }

    /// Set the pan speed modifier
    pub fn pan_speed(self, s: T) -> OrbitZoomCameraSettings<T> {
        OrbitZoomCameraSettings {
            pan_speed: s,
            .. self
        }
    }

    /// Set the zoom speed modifier
    pub fn zoom_speed(self, s: T) -> OrbitZoomCameraSettings<T> {
        OrbitZoomCameraSettings {
            zoom_speed: s,
            .. self
        }
    }
}

/// A 3dsMax / Blender-style camera that orbits around a target point
pub struct OrbitZoomCamera<T=f32> {

    /// origin of camera rotation
    pub target: Vector3<T>,

    /// Rotation of camera
    pub rotation: Quaternion<T>,

    /// Pitch up/down from target
    pub pitch: T,

    /// Yaw left/right from target
    pub yaw: T,

    /// camera distance from target
    pub distance: T,

    /// Settings for the camera
    pub settings: OrbitZoomCameraSettings<T>,

    /// Current keys that are pressed
    keys: Keys,
}

impl<T: Float>
OrbitZoomCamera<T> {

    /// Create a new OrbitZoomCamera targeting the given coordinates
    pub fn new(target: [T; 3], settings: OrbitZoomCameraSettings<T>) -> OrbitZoomCamera<T> {
        OrbitZoomCamera {
            target: target,
            rotation: quaternion::id(),
            distance: T::from_f32(10.0),
            pitch: T::zero(),
            yaw: T::zero(),
            keys: Keys::empty(),
            settings: settings
        }
    }

    /// Return a Camera for the current OrbitZoomCamera configuration
    pub fn camera(&self, _dt: f64) -> Camera<T> {
        let target_to_camera = quaternion::rotate_vector(
            self.rotation,
            [T::zero(), T::zero(), self.distance]
        );
        let mut camera = Camera::new(vec3_add(self.target, target_to_camera));
        camera.set_rotation(self.rotation);
        camera
    }

    /// Orbit the camera using the given horizontal and vertical params,
    /// or zoom or pan if the appropriate modifier keys are pressed
    fn control_camera(&mut self, dx: T, dy: T) {

        let _1 = T::one();
        let _0 = T::zero();

        if self.keys.contains(PAN) {

            // Pan target position along plane normal to camera direction
            let dx = dx * self.settings.pan_speed;
            let dy = dy * self.settings.pan_speed;

            let right = quaternion::rotate_vector(self.rotation, [_1, _0, _0]);
            let up = quaternion::rotate_vector(self.rotation, [_0, _1, _0]);
            self.target = vec3_add(
                vec3_add(self.target, vec3_scale(up, dy)),
                vec3_scale(right,dx)
            );

        } else if self.keys.contains(ZOOM) {

            // Zoom to / from target
            self.distance = self.distance + dy * self.settings.zoom_speed;

        } else {

            // Orbit around target
            let dx = dx * self.settings.orbit_speed;
            let dy = dy * self.settings.orbit_speed;

            self.yaw = self.yaw + dx;
            self.pitch = self.pitch + dy*self.settings.pitch_speed;
            self.rotation = quaternion::mul(
                quaternion::axis_angle([_0, _1, _0], self.yaw),
                quaternion::axis_angle([_1, _0, _0], self.pitch)
            );

        }
    }

    /// Respond to scroll and key press/release events
    pub fn event<E: GenericEvent>(&mut self, e: &E) {
        e.mouse_scroll(|dx, dy| {
            let dx = T::from_f64(dx);
            let dy = T::from_f64(dy);
            self.control_camera(dx, dy);
        });

        e.mouse_relative(|dx, dy| {
            let dx = T::from_f64(dx);
            let dy = T::from_f64(dy);
            if self.keys.contains(ORBIT){
                self.control_camera(-dx, dy);
            }
        });

        e.press(|button| {
            match button {
                x if x == self.settings.orbit_button => self.keys.insert(ORBIT),
                x if x == self.settings.pan_button => self.keys.insert(PAN),
                x if x == self.settings.zoom_button => self.keys.insert(ZOOM),
                _ => {}
            }
        });

        e.release(|button| {
            match button {
                x if x == self.settings.orbit_button => self.keys.remove(ORBIT),
                x if x == self.settings.pan_button => self.keys.remove(PAN),
                x if x == self.settings.zoom_button => self.keys.remove(ZOOM),
                _ => {}
            }
        });
    }
}
<commit_msg>Added a method to orbit_zoom_camera to initialize the camera in the specified configuration<commit_after>#![allow(dead_code)]

//! A 3dsMax / Blender style camera that orbits about a target position

use vecmath::{ Vector3, vec3_add, vec3_scale };
use vecmath::traits::Float;

use quaternion;
use quaternion::Quaternion;

use input;
use input::{ GenericEvent, Key, MouseButton };
use input::Button::{ Keyboard, Mouse };

use Camera;

bitflags!(
    pub flags Keys: u8 {
        const ZOOM  = 0b00000001,
        const PAN   = 0b00000010,
        const ORBIT = 0b00000100,
    }
);

/// Specifies key bindings and speed modifiers for OrbitZoomCamera
pub struct OrbitZoomCameraSettings<T=f32> {

    /// Which button to press to orbit with mouse
    pub orbit_button: input::Button,

    /// Which button to press to zoom with mouse
    pub zoom_button: input::Button,

    /// Which button to press to pan with mouse
    pub pan_button: input::Button,

    /// Modifier for orbiting speed (arbitrary unit)
    pub orbit_speed: T,

    /// Modifier for pitch speed relative to orbiting speed (arbitrary unit).
    /// To reverse pitch direction, set this to -1.
    pub pitch_speed: T,

    /// Modifier for panning speed (arbitrary unit)
    pub pan_speed: T,

    /// Modifier for zoom speed (arbitrary unit)
    pub zoom_speed: T,
}

impl<T: Float> OrbitZoomCameraSettings<T> {

    /// Clicking and dragging OR two-finger scrolling will orbit camera,
    /// with LShift as pan modifer and LCtrl as zoom modifier
    pub fn default() -> OrbitZoomCameraSettings<T> {
        OrbitZoomCameraSettings {
            orbit_button : Mouse(MouseButton::Left),
            zoom_button : Keyboard(Key::LCtrl),
            pan_button : Keyboard(Key::LShift),
            orbit_speed: T::from_f32(0.05),
            pitch_speed: T::from_f32(0.1),
            pan_speed: T::from_f32(0.1),
            zoom_speed: T::from_f32(0.1),
        }
    }

    /// Set the button for orbiting
    pub fn orbit_button(self, button: input::Button) -> OrbitZoomCameraSettings<T> {
        OrbitZoomCameraSettings {
            orbit_button: button,
            .. self
        }
    }

    /// Set the button for zooming
    pub fn zoom_button(self, button: input::Button) -> OrbitZoomCameraSettings<T> {
        OrbitZoomCameraSettings {
            zoom_button: button,
            .. self
        }
    }

    /// Set the button for panning
    pub fn pan_button(self, button: input::Button) -> OrbitZoomCameraSettings<T> {
        OrbitZoomCameraSettings {
            pan_button: button,
            .. self
        }
    }

    /// Set the orbit speed modifier
    pub fn orbit_speed(self, s: T) -> OrbitZoomCameraSettings<T> {
        OrbitZoomCameraSettings {
            orbit_speed: s,
            .. self
        }
    }

    /// Set the pitch speed modifier
    pub fn pitch_speed(self, s: T) -> OrbitZoomCameraSettings<T> {
        OrbitZoomCameraSettings {
            pitch_speed: s,
            .. self
        }
    }

    /// Set the pan speed modifier
    pub fn pan_speed(self, s: T) -> OrbitZoomCameraSettings<T> {
        OrbitZoomCameraSettings {
            pan_speed: s,
            .. self
        }
    }

    /// Set the zoom speed modifier
    pub fn zoom_speed(self, s: T) -> OrbitZoomCameraSettings<T> {
        OrbitZoomCameraSettings {
            zoom_speed: s,
            .. self
        }
    }
}

/// A 3dsMax / Blender-style camera that orbits around a target point
pub struct OrbitZoomCamera<T=f32> {

    /// origin of camera rotation
    pub target: Vector3<T>,

    /// Rotation of camera
    pub rotation: Quaternion<T>,

    /// Pitch up/down from target
    pub pitch: T,

    /// Yaw left/right from target
    pub yaw: T,

    /// camera distance from target
    pub distance: T,

    /// Settings for the camera
    pub settings: OrbitZoomCameraSettings<T>,

    /// Current keys that are pressed
    keys: Keys,
}

impl<T: Float>
OrbitZoomCamera<T> {

    /// Create a new OrbitZoomCamera targeting the given coordinates
    pub fn new(target: [T; 3], settings: OrbitZoomCameraSettings<T>) -> OrbitZoomCamera<T> {
        OrbitZoomCamera {
            target: target,
            rotation: quaternion::id(),
            distance: T::from_f32(10.0),
            pitch: T::zero(),
            yaw: T::zero(),
            keys: Keys::empty(),
            settings: settings
        }
    }

    /// Return a Camera for the current OrbitZoomCamera configuration
    pub fn camera(&self, _dt: f64) -> Camera<T> {
        let target_to_camera = quaternion::rotate_vector(
            self.rotation,
            [T::zero(), T::zero(), self.distance]
        );
        let mut camera = Camera::new(vec3_add(self.target, target_to_camera));
        camera.set_rotation(self.rotation);
        camera
    }

    /// Initialize the camera configuration, such that next call to camera() gives the correct
    /// camera configuration
    pub fn init(&mut self) {
        self.control_camera(T::zero(), T::zero());
    }

    /// Orbit the camera using the given horizontal and vertical params,
    /// or zoom or pan if the appropriate modifier keys are pressed
    fn control_camera(&mut self, dx: T, dy: T) {

        let _1 = T::one();
        let _0 = T::zero();

        if self.keys.contains(PAN) {

            // Pan target position along plane normal to camera direction
            let dx = dx * self.settings.pan_speed;
            let dy = dy * self.settings.pan_speed;

            let right = quaternion::rotate_vector(self.rotation, [_1, _0, _0]);
            let up = quaternion::rotate_vector(self.rotation, [_0, _1, _0]);
            self.target = vec3_add(
                vec3_add(self.target, vec3_scale(up, dy)),
                vec3_scale(right,dx)
            );

        } else if self.keys.contains(ZOOM) {

            // Zoom to / from target
            self.distance = self.distance + dy * self.settings.zoom_speed;

        } else {

            // Orbit around target
            let dx = dx * self.settings.orbit_speed;
            let dy = dy * self.settings.orbit_speed;

            self.yaw = self.yaw + dx;
            self.pitch = self.pitch + dy*self.settings.pitch_speed;
            self.rotation = quaternion::mul(
                quaternion::axis_angle([_0, _1, _0], self.yaw),
                quaternion::axis_angle([_1, _0, _0], self.pitch)
            );

        }
    }

    /// Respond to scroll and key press/release events
    pub fn event<E: GenericEvent>(&mut self, e: &E) {
        e.mouse_scroll(|dx, dy| {
            let dx = T::from_f64(dx);
            let dy = T::from_f64(dy);
            self.control_camera(dx, dy);
        });

        e.mouse_relative(|dx, dy| {
            let dx = T::from_f64(dx);
            let dy = T::from_f64(dy);
            if self.keys.contains(ORBIT){
                self.control_camera(-dx, dy);
            }
        });

        e.press(|button| {
            match button {
                x if x == self.settings.orbit_button => self.keys.insert(ORBIT),
                x if x == self.settings.pan_button => self.keys.insert(PAN),
                x if x == self.settings.zoom_button => self.keys.insert(ZOOM),
                _ => {}
            }
        });

        e.release(|button| {
            match button {
                x if x == self.settings.orbit_button => self.keys.remove(ORBIT),
                x if x == self.settings.pan_button => self.keys.remove(PAN),
                x if x == self.settings.zoom_button => self.keys.remove(ZOOM),
                _ => {}
            }
        });
    }
}
<|endoftext|>