<commit_before>extern crate libc;

use array::Array;
use defines::AfError;
use dim4::Dim4;
use seq::Seq;
use defines::Aftype;
use self::libc::{c_int, c_uint, c_longlong};

type MutAfArray    = *mut self::libc::c_longlong;
type MutMutAfIndex = *mut *mut self::libc::c_longlong;
type MutAfIndex    = *mut self::libc::c_longlong;
type AfArray       = self::libc::c_longlong;
type AfIndex       = self::libc::c_longlong;
type DimT          = self::libc::c_longlong;
type IndexT        = self::libc::c_longlong;

#[allow(dead_code)]
extern {
    fn af_create_seq_index(result: MutMutAfIndex, input: *const Seq, is_batch: c_int) -> c_int;
    fn af_create_array_index(result: MutMutAfIndex, input: AfArray) -> c_int;
    fn af_release_index(indexer: MutAfIndex) -> c_int;
    fn af_index(out: MutAfArray, input: AfArray, ndims: c_uint, index: *const Seq) -> c_int;
    fn af_lookup(out: MutAfArray, arr: AfArray, indices: AfArray, dim: c_uint) -> c_int;
    fn af_assign_seq(out: MutAfArray, lhs: AfArray, ndims: c_uint, indices: *const IndexT, rhs: AfArray) -> c_int;
    fn af_index_gen(out: MutAfArray, input: AfArray, ndims: DimT, indices: *const IndexT) -> c_int;
    fn af_assign_gen(out: MutAfArray, lhs: AfArray, ndims: DimT, indices: *const IndexT, rhs: AfArray) -> c_int;
}

pub struct Index {
    handle: i64,
    is_batch: bool,
    is_seq: bool,
}

impl Index {
    #[allow(unused_mut)]
    pub fn new(arr: Option<Array>, seq: Option<Seq>, is_batch: bool) -> Result<Index, AfError> {
        unsafe {
            let mut err_val: c_int = 0;
            let mut temp: i64 = 0;
            let mut is_seq = false;
            err_val = match arr {
                //c_func(&mut (x as *mut libc::c_void)); --> (&mut x) as *mut _ as *mut *mut libc::c_void.
                //&mut temp as MutMutAfIndex, x),
                Some(mut x) => { is_seq = false; af_create_array_index((&mut temp) as *mut _ as MutMutAfIndex, x.get() as AfArray) },
                None    => 0,
            };

            err_val = match seq {
                Some(mut x) => { is_seq = true; af_create_seq_index((&mut temp) as *mut _ as MutMutAfIndex, &mut x, is_batch as c_int) },
                None    => AfError::ERR_UNKNOWN as c_int,
            };

            match err_val {
                0 => Ok(Index {handle: temp, is_batch: is_batch, is_seq: is_seq}),
                _ => Err(AfError::from(err_val)),
            }
        }
    }

    pub fn get(&self) -> i64{
        self.handle
    }

    pub fn is_seq(&self) -> bool{
        self.is_seq
    }

    pub fn is_batch(&self) -> bool{
        self.is_batch
    }
}

impl Drop for Index {
    fn drop(&mut self) {
        unsafe {
            let ret_val = af_release_index(self.handle as MutAfIndex);
            match ret_val {
                0 => (),
                _ => panic!("Failed to destruct Index: {}", ret_val),
            }
        }
    }
}

pub fn index(input: &Array, seqs: &[Seq]) -> Result<Array, AfError> {
    unsafe {
        let mut temp: i64 = 0;
        println!("size is: {}", seqs.len() as u32);
        let err_val = af_index(&mut temp as MutAfArray
                                , input.get() as AfArray
                                , seqs.len() as u32
                                , seqs.clone().as_ptr() as *const Seq);
        match err_val {
            0 => Ok(Array::from(temp)),
            _ => Err(AfError::from(err_val)),
        }
    }
}

pub fn row(input: &Array, row_num: u64) -> Result<Array, AfError> {
    let dims_err = input.dims();
    let mut dims = Dim4::default();
    match dims_err {
        Ok(dim) =>  dims = dim.clone(),
        Err(e)  =>  panic!("Error unwrapping dims in row(): {}", e),
    }

    index(input, &[Seq::new(row_num as f64, row_num as f64, 1.0)
                    ,Seq::new(0.0, dims[1] as f64 - 1.0, 1.0)])
}

pub fn col(input: &Array, col_num: u64) -> Result<Array, AfError> {
    let dims_err = input.dims();
    let mut dims = Dim4::default();
    match dims_err {
        Ok(dim) =>  dims = dim.clone(),
        Err(e)  =>  panic!("Error unwrapping dims in row(): {}", e),
    }

    index(input, &[Seq::new(0.0, dims[0] as f64 - 1.0, 1.0)
                    ,Seq::new(col_num as f64, col_num as f64, 1.0)])
}

pub fn lookup(input: &Array, indices: &Array, seq_dim: i32) -> Result<Array, AfError> {
    unsafe {
        let mut temp: i64 = 0;
        let err_val = af_lookup(&mut temp as MutAfArray
                                , input.get() as AfArray
                                , indices.get() as AfArray
                                , seq_dim as c_uint);
        match err_val {
            0 => Ok(Array::from(temp)),
            _ => Err(AfError::from(err_val)),
        }
    }
}

pub fn assign_seq(lhs: &Array, ndims: usize, seqs: &[Seq], rhs: &Array) -> Result<Array, AfError> {
    unsafe{
        let mut temp: i64 = 0;
        let err_val = af_assign_seq(&mut temp as MutAfArray
                                    , lhs.get() as AfArray
                                    , ndims as c_uint, seqs.as_ptr() as *const IndexT
                                    , rhs.get() as AfArray);
        match err_val {
            0 => Ok(Array::from(temp)),
            _ => Err(AfError::from(err_val)),
        }
    }
}

pub fn index_gen(input: &Array, ndims: Dim4, indices: &mut [Index]) -> Result<Array, AfError> {
    unsafe{
        let mut temp: i64 = 0;
        let mut index_ptrs = Vec::new();
        for index_struct in &mut indices[..] {
            index_ptrs.push(index_struct.get());
        }

        let err_val = af_index_gen(&mut temp as MutAfArray
                                  , input.get() as AfArray
                                  , ndims.get().as_ptr() as DimT
                                  , index_ptrs.as_ptr() as *const IndexT);
        match err_val {
            0 => Ok(Array::from(temp)),
            _ => Err(AfError::from(err_val)),
        }
    }
}

pub fn assign_gen(lhs: &Array, ndims: Dim4, indices: &[Index], rhs: &Array) -> Result<Array, AfError> {
    unsafe{
        let mut temp: i64 = 0;
        let err_val = af_assign_gen(&mut temp as MutAfArray
                                    , lhs.get() as AfArray
                                    , ndims.get().as_ptr() as DimT
                                    , indices.as_ptr() as *const IndexT
                                    , rhs.get() as AfArray);
        match err_val {
            0 => Ok(Array::from(temp)),
            _ => Err(AfError::from(err_val)),
        }
    }
}<commit_msg>remove errenous println<commit_after>extern crate libc;

use array::Array;
use defines::AfError;
use dim4::Dim4;
use seq::Seq;
use defines::Aftype;
use self::libc::{c_int, c_uint, c_longlong};

type MutAfArray    = *mut self::libc::c_longlong;
type MutMutAfIndex = *mut *mut self::libc::c_longlong;
type MutAfIndex    = *mut self::libc::c_longlong;
type AfArray       = self::libc::c_longlong;
type AfIndex       = self::libc::c_longlong;
type DimT          = self::libc::c_longlong;
type IndexT        = self::libc::c_longlong;

#[allow(dead_code)]
extern {
    fn af_create_seq_index(result: MutMutAfIndex, input: *const Seq, is_batch: c_int) -> c_int;
    fn af_create_array_index(result: MutMutAfIndex, input: AfArray) -> c_int;
    fn af_release_index(indexer: MutAfIndex) -> c_int;
    fn af_index(out: MutAfArray, input: AfArray, ndims: c_uint, index: *const Seq) -> c_int;
    fn af_lookup(out: MutAfArray, arr: AfArray, indices: AfArray, dim: c_uint) -> c_int;
    fn af_assign_seq(out: MutAfArray, lhs: AfArray, ndims: c_uint, indices: *const IndexT, rhs: AfArray) -> c_int;
    fn af_index_gen(out: MutAfArray, input: AfArray, ndims: DimT, indices: *const IndexT) -> c_int;
    fn af_assign_gen(out: MutAfArray, lhs: AfArray, ndims: DimT, indices: *const IndexT, rhs: AfArray) -> c_int;
}

pub struct Index {
    handle: i64,
    is_batch: bool,
    is_seq: bool,
}

impl Index {
    #[allow(unused_mut)]
    pub fn new(arr: Option<Array>, seq: Option<Seq>, is_batch: bool) -> Result<Index, AfError> {
        unsafe {
            let mut err_val: c_int = 0;
            let mut temp: i64 = 0;
            let mut is_seq = false;
            err_val = match arr {
                //c_func(&mut (x as *mut libc::c_void)); --> (&mut x) as *mut _ as *mut *mut libc::c_void.
                //&mut temp as MutMutAfIndex, x),
                Some(mut x) => { is_seq = false; af_create_array_index((&mut temp) as *mut _ as MutMutAfIndex, x.get() as AfArray) },
                None    => 0,
            };

            err_val = match seq {
                Some(mut x) => { is_seq = true; af_create_seq_index((&mut temp) as *mut _ as MutMutAfIndex, &mut x, is_batch as c_int) },
                None    => AfError::ERR_UNKNOWN as c_int,
            };

            match err_val {
                0 => Ok(Index {handle: temp, is_batch: is_batch, is_seq: is_seq}),
                _ => Err(AfError::from(err_val)),
            }
        }
    }

    pub fn get(&self) -> i64{
        self.handle
    }

    pub fn is_seq(&self) -> bool{
        self.is_seq
    }

    pub fn is_batch(&self) -> bool{
        self.is_batch
    }
}

impl Drop for Index {
    fn drop(&mut self) {
        unsafe {
            let ret_val = af_release_index(self.handle as MutAfIndex);
            match ret_val {
                0 => (),
                _ => panic!("Failed to destruct Index: {}", ret_val),
            }
        }
    }
}

pub fn index(input: &Array, seqs: &[Seq]) -> Result<Array, AfError> {
    unsafe {
        let mut temp: i64 = 0;
        let err_val = af_index(&mut temp as MutAfArray
                                , input.get() as AfArray
                                , seqs.len() as u32
                                , seqs.clone().as_ptr() as *const Seq);
        match err_val {
            0 => Ok(Array::from(temp)),
            _ => Err(AfError::from(err_val)),
        }
    }
}

pub fn row(input: &Array, row_num: u64) -> Result<Array, AfError> {
    let dims_err = input.dims();
    let mut dims = Dim4::default();
    match dims_err {
        Ok(dim) =>  dims = dim.clone(),
        Err(e)  =>  panic!("Error unwrapping dims in row(): {}", e),
    }

    index(input, &[Seq::new(row_num as f64, row_num as f64, 1.0)
                    ,Seq::new(0.0, dims[1] as f64 - 1.0, 1.0)])
}

pub fn col(input: &Array, col_num: u64) -> Result<Array, AfError> {
    let dims_err = input.dims();
    let mut dims = Dim4::default();
    match dims_err {
        Ok(dim) =>  dims = dim.clone(),
        Err(e)  =>  panic!("Error unwrapping dims in row(): {}", e),
    }

    index(input, &[Seq::new(0.0, dims[0] as f64 - 1.0, 1.0)
                    ,Seq::new(col_num as f64, col_num as f64, 1.0)])
}

pub fn lookup(input: &Array, indices: &Array, seq_dim: i32) -> Result<Array, AfError> {
    unsafe {
        let mut temp: i64 = 0;
        let err_val = af_lookup(&mut temp as MutAfArray
                                , input.get() as AfArray
                                , indices.get() as AfArray
                                , seq_dim as c_uint);
        match err_val {
            0 => Ok(Array::from(temp)),
            _ => Err(AfError::from(err_val)),
        }
    }
}

pub fn assign_seq(lhs: &Array, ndims: usize, seqs: &[Seq], rhs: &Array) -> Result<Array, AfError> {
    unsafe{
        let mut temp: i64 = 0;
        let err_val = af_assign_seq(&mut temp as MutAfArray
                                    , lhs.get() as AfArray
                                    , ndims as c_uint, seqs.as_ptr() as *const IndexT
                                    , rhs.get() as AfArray);
        match err_val {
            0 => Ok(Array::from(temp)),
            _ => Err(AfError::from(err_val)),
        }
    }
}

pub fn index_gen(input: &Array, ndims: Dim4, indices: &mut [Index]) -> Result<Array, AfError> {
    unsafe{
        let mut temp: i64 = 0;
        let mut index_ptrs = Vec::new();
        for index_struct in &mut indices[..] {
            index_ptrs.push(index_struct.get());
        }

        let err_val = af_index_gen(&mut temp as MutAfArray
                                  , input.get() as AfArray
                                  , ndims.get().as_ptr() as DimT
                                  , index_ptrs.as_ptr() as *const IndexT);
        match err_val {
            0 => Ok(Array::from(temp)),
            _ => Err(AfError::from(err_val)),
        }
    }
}

pub fn assign_gen(lhs: &Array, ndims: Dim4, indices: &[Index], rhs: &Array) -> Result<Array, AfError> {
    unsafe{
        let mut temp: i64 = 0;
        let err_val = af_assign_gen(&mut temp as MutAfArray
                                    , lhs.get() as AfArray
                                    , ndims.get().as_ptr() as DimT
                                    , indices.as_ptr() as *const IndexT
                                    , rhs.get() as AfArray);
        match err_val {
            0 => Ok(Array::from(temp)),
            _ => Err(AfError::from(err_val)),
        }
    }
}
<|endoftext|>


<commit_before>//! Module for built-in pixel data adapters.

use dicom_core::value::C;
use snafu::Snafu;

pub mod jpeg;
pub mod rle_lossless;

/// Error conditions when decoding pixel data.
#[derive(Debug, Snafu)]
#[non_exhaustive]
pub enum DecodeError {
    /// A custom error occurred when decoding,
    /// reported as a dynamic error value
    #[snafu(display("Error decoding pixel data"))]
    Custom {
        source: Box<dyn std::error::Error + Send + 'static>,
    },

    /// A custom error occurred when decoding,
    /// reported as a static message
    #[snafu(display("Error decoding pixel data: {}", message))]
    CustomMessage { 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`],
/// 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`.
///
/// [`dicom_object`]: https://docs.rs/dicom_object
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 lossless compression,
    /// 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>,

    /// The amount of effort that the encoder may take to encode the pixel data,
    /// as a number between 0 and 100.
    /// If supported, higher values result in better compression,
    /// at the expense of more processing time.
    /// Encoders are not required to support this option.
    /// If this option is not specified,
    /// the actual effort is decided by the underlying adapter.
    pub effort: 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!();
    }
}
<commit_msg>Clarify documentation of PixelRWAdapter::decode<commit_after>//! Module for built-in pixel data adapters.

use dicom_core::value::C;
use snafu::Snafu;

pub mod jpeg;
pub mod rle_lossless;

/// Error conditions when decoding pixel data.
#[derive(Debug, Snafu)]
#[non_exhaustive]
pub enum DecodeError {
    /// A custom error occurred when decoding,
    /// reported as a dynamic error value
    #[snafu(display("Error decoding pixel data"))]
    Custom {
        source: Box<dyn std::error::Error + Send + 'static>,
    },

    /// A custom error occurred when decoding,
    /// reported as a static message
    #[snafu(display("Error decoding pixel data: {}", message))]
    CustomMessage { 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`],
/// 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`.
///
/// [`dicom_object`]: https://docs.rs/dicom_object
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 lossless compression,
    /// 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>,

    /// The amount of effort that the encoder may take to encode the pixel data,
    /// as a number between 0 and 100.
    /// If supported, higher values result in better compression,
    /// at the expense of more processing time.
    /// Encoders are not required to support this option.
    /// If this option is not specified,
    /// the actual effort is decided by the underlying adapter.
    pub effort: 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 in little endian,
    /// resizing the given vector `dst` to contain exactly these bytes.
    ///
    /// 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
    /// _save for the photometric interpretation_.
    /// The output of an image with 1 sample per pixel
    /// is expected to be interpreted as `MONOCHROME2`,
    /// and for a 3-channel images, the output must be in RGB.
    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>use std;
use std::ffi::OsStr;
use std::os::windows::ffi::OsStrExt;
use uuid;
use winapi;
use winapi::um::{shellapi, winuser};
use winapi::shared::minwindef::{DWORD, LOWORD, UINT, WPARAM, LPARAM, LRESULT};
use winapi::shared::windef::HWND;

const IDI_POLARIS_TRAY: isize = 0x102;
const UID_NOTIFICATION_ICON: u32 = 0;
const MESSAGE_NOTIFICATION_ICON: u32 = winuser::WM_USER + 1;
const MESSAGE_NOTIFICATION_ICON_QUIT: u32 = winuser::WM_USER + 2;

pub trait ToWin {
	type Out;
	fn to_win(&self) -> Self::Out;
}

impl<'a> ToWin for &'a str {
	type Out = Vec<u16>;

	fn to_win(&self) -> Self::Out {
		OsStr::new(self)
			.encode_wide()
			.chain(std::iter::once(0))
			.collect()
	}
}

impl ToWin for uuid::Uuid {
	type Out = winapi::shared::guiddef::GUID;

	fn to_win(&self) -> Self::Out {
		let bytes = self.as_bytes();
		let end = [bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14],
		           bytes[15]];

		winapi::shared::guiddef::GUID {
			Data1: ((bytes[0] as u32) << 24 | (bytes[1] as u32) << 16 | (bytes[2] as u32) << 8 |
			        (bytes[3] as u32)),
			Data2: ((bytes[4] as u16) << 8 | (bytes[5] as u16)),
			Data3: ((bytes[6] as u16) << 8 | (bytes[7] as u16)),
			Data4: end,
		}
	}
}

pub trait Constructible {
	type Out;
	fn new() -> Self::Out;
}

impl Constructible for shellapi::NOTIFYICONDATAW {
	type Out = shellapi::NOTIFYICONDATAW;

	fn new() -> Self::Out {

		let mut version_union: shellapi::NOTIFYICONDATAW_u = unsafe { std::mem::zeroed() };
		unsafe {
			let version = version_union.uVersion_mut();
			*version = shellapi::NOTIFYICON_VERSION_4;
		}

		shellapi::NOTIFYICONDATAW {
			cbSize: std::mem::size_of::<shellapi::NOTIFYICONDATAW>() as u32,
			hWnd: std::ptr::null_mut(),
			uFlags: 0,
			guidItem: uuid::Uuid::nil().to_win(),
			hIcon: std::ptr::null_mut(),
			uID: 0,
			uCallbackMessage: 0,
			szTip: [0; 128],
			dwState: 0,
			dwStateMask: 0,
			szInfo: [0; 256],
			u: version_union,
			szInfoTitle: [0; 64],
			dwInfoFlags: 0,
			hBalloonIcon: std::ptr::null_mut(),
		}
	}
}

fn create_window() -> Option<HWND> {

	let class_name = "Polaris-class".to_win();
	let window_name = "Polaris-window".to_win();

	unsafe {
		let module_handle = winapi::um::libloaderapi::GetModuleHandleW(std::ptr::null());
		let wnd = winuser::WNDCLASSW {
			style: 0,
			lpfnWndProc: Some(window_proc),
			hInstance: module_handle,
			hIcon: std::ptr::null_mut(),
			hCursor: std::ptr::null_mut(),
			lpszClassName: class_name.as_ptr(),
			hbrBackground: winuser::COLOR_WINDOW as winapi::shared::windef::HBRUSH,
			lpszMenuName: std::ptr::null_mut(),
			cbClsExtra: 0,
			cbWndExtra: 0,
		};

		let atom = winuser::RegisterClassW(&wnd);
		if atom == 0 {
			return None;
		}

		let window_handle = winuser::CreateWindowExW(0,
		                                            atom as winapi::shared::ntdef::LPCWSTR,
		                                            window_name.as_ptr(),
		                                            winuser::WS_DISABLED,
		                                            0,
		                                            0,
		                                            0,
		                                            0,
		                                            winuser::GetDesktopWindow(),
		                                            std::ptr::null_mut(),
		                                            std::ptr::null_mut(),
		                                            std::ptr::null_mut());

		if window_handle.is_null() {
			return None;
		}

		return Some(window_handle);
	}
}

fn add_notification_icon(window: HWND) {

	let mut tooltip = [0 as winapi::um::winnt::WCHAR; 128];
	for (&x, p) in "Polaris".to_win().iter().zip(tooltip.iter_mut()) {
		*p = x;
	}

	unsafe {
		let module = winapi::um::libloaderapi::GetModuleHandleW(std::ptr::null());
		let icon = winuser::LoadIconW(module, std::mem::transmute(IDI_POLARIS_TRAY));
		let mut flags = shellapi::NIF_MESSAGE | shellapi::NIF_TIP;
		if !icon.is_null() {
			flags |= shellapi::NIF_ICON;
		}

		let mut icon_data = shellapi::NOTIFYICONDATAW::new();
		icon_data.hWnd = window;
		icon_data.uID = UID_NOTIFICATION_ICON;
		icon_data.uFlags = flags;
		icon_data.hIcon = icon;
		icon_data.uCallbackMessage = MESSAGE_NOTIFICATION_ICON;
		icon_data.szTip = tooltip;

		shellapi::Shell_NotifyIconW(shellapi::NIM_ADD, &mut icon_data);
	}
}

fn remove_notification_icon(window: HWND) {
	let mut icon_data = shellapi::NOTIFYICONDATAW::new();
	icon_data.hWnd = window;
	icon_data.uID = UID_NOTIFICATION_ICON;
	unsafe {
		shellapi::Shell_NotifyIconW(shellapi::NIM_DELETE, &mut icon_data);
	}
}

fn open_notification_context_menu(window: HWND) {
	info!("Opening notification icon context menu");
	let quit_string = "Quit Polaris".to_win();

	unsafe {
		let context_menu = winuser::CreatePopupMenu();
		if context_menu.is_null() {
			return;
		}
		winuser::InsertMenuW(context_menu,
		                    0,
		                    winuser::MF_STRING,
		                    MESSAGE_NOTIFICATION_ICON_QUIT as usize,
		                    quit_string.as_ptr());

		let mut cursor_position = winapi::shared::windef::POINT { x: 0, y: 0 };
		winuser::GetCursorPos(&mut cursor_position);

		winuser::SetForegroundWindow(window);
		let flags = winuser::TPM_RIGHTALIGN | winuser::TPM_BOTTOMALIGN |
		            winuser::TPM_RIGHTBUTTON;
		winuser::TrackPopupMenu(context_menu,
		                       flags,
		                       cursor_position.x,
		                       cursor_position.y,
		                       0,
		                       window,
		                       std::ptr::null_mut());
		winuser::PostMessageW(window, 0, 0, 0);

		info!("Closing notification context menu");
		winuser::DestroyMenu(context_menu);
	}
}

fn quit(window: HWND) {
	info!("Shutting down UI");
	unsafe {
		winuser::PostMessageW(window, winuser::WM_CLOSE, 0, 0);
	}
}

pub fn run() {
	info!("Starting up UI (Windows)");

	create_window().expect("Could not initialize window");

	let mut message = winuser::MSG {
		hwnd: std::ptr::null_mut(),
		message: 0,
		wParam: 0,
		lParam: 0,
		time: 0,
		pt: winapi::shared::windef::POINT { x: 0, y: 0 },
	};

	loop {
		let status: i32;
		unsafe {
			status = winuser::GetMessageW(&mut message, std::ptr::null_mut(), 0, 0);
			if status == -1 {
				panic!("GetMessageW error: {}", winapi::um::errhandlingapi::GetLastError());
			}
			if status == 0 {
				break;
			}
			winuser::TranslateMessage(&message);
			winuser::DispatchMessageW(&message);
		}
	}
}

pub unsafe extern "system" fn window_proc(window: HWND,
                                          msg: UINT,
                                          w_param: WPARAM,
                                          l_param: LPARAM)
                                          -> LRESULT {
	match msg {

		winuser::WM_CREATE => {
			add_notification_icon(window);
		}

		MESSAGE_NOTIFICATION_ICON => {
			match LOWORD(l_param as DWORD) as u32 {
				winuser::WM_RBUTTONUP => {
					open_notification_context_menu(window);
				}
				_ => (),
			}
		}

		winuser::WM_COMMAND => {
			match LOWORD(w_param as DWORD) as u32 {
				MESSAGE_NOTIFICATION_ICON_QUIT => {
					quit(window);
				}
				_ => (),
			}
		}

		winuser::WM_DESTROY => {
			remove_notification_icon(window);
			winuser::PostQuitMessage(0);
		}

		_ => (),
	};

	return winuser::DefWindowProcW(window, msg, w_param, l_param);
}
<commit_msg>Autoformat<commit_after>use std;
use std::ffi::OsStr;
use std::os::windows::ffi::OsStrExt;
use uuid;
use winapi;
use winapi::um::{shellapi, winuser};
use winapi::shared::minwindef::{DWORD, LOWORD, UINT, WPARAM, LPARAM, LRESULT};
use winapi::shared::windef::HWND;

const IDI_POLARIS_TRAY: isize = 0x102;
const UID_NOTIFICATION_ICON: u32 = 0;
const MESSAGE_NOTIFICATION_ICON: u32 = winuser::WM_USER + 1;
const MESSAGE_NOTIFICATION_ICON_QUIT: u32 = winuser::WM_USER + 2;

pub trait ToWin {
	type Out;
	fn to_win(&self) -> Self::Out;
}

impl<'a> ToWin for &'a str {
	type Out = Vec<u16>;

	fn to_win(&self) -> Self::Out {
		OsStr::new(self)
			.encode_wide()
			.chain(std::iter::once(0))
			.collect()
	}
}

impl ToWin for uuid::Uuid {
	type Out = winapi::shared::guiddef::GUID;

	fn to_win(&self) -> Self::Out {
		let bytes = self.as_bytes();
		let end = [bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14],
		           bytes[15]];

		winapi::shared::guiddef::GUID {
			Data1: ((bytes[0] as u32) << 24 | (bytes[1] as u32) << 16 | (bytes[2] as u32) << 8 |
			        (bytes[3] as u32)),
			Data2: ((bytes[4] as u16) << 8 | (bytes[5] as u16)),
			Data3: ((bytes[6] as u16) << 8 | (bytes[7] as u16)),
			Data4: end,
		}
	}
}

pub trait Constructible {
	type Out;
	fn new() -> Self::Out;
}

impl Constructible for shellapi::NOTIFYICONDATAW {
	type Out = shellapi::NOTIFYICONDATAW;

	fn new() -> Self::Out {

		let mut version_union: shellapi::NOTIFYICONDATAW_u = unsafe { std::mem::zeroed() };
		unsafe {
			let version = version_union.uVersion_mut();
			*version = shellapi::NOTIFYICON_VERSION_4;
		}

		shellapi::NOTIFYICONDATAW {
			cbSize: std::mem::size_of::<shellapi::NOTIFYICONDATAW>() as u32,
			hWnd: std::ptr::null_mut(),
			uFlags: 0,
			guidItem: uuid::Uuid::nil().to_win(),
			hIcon: std::ptr::null_mut(),
			uID: 0,
			uCallbackMessage: 0,
			szTip: [0; 128],
			dwState: 0,
			dwStateMask: 0,
			szInfo: [0; 256],
			u: version_union,
			szInfoTitle: [0; 64],
			dwInfoFlags: 0,
			hBalloonIcon: std::ptr::null_mut(),
		}
	}
}

fn create_window() -> Option<HWND> {

	let class_name = "Polaris-class".to_win();
	let window_name = "Polaris-window".to_win();

	unsafe {
		let module_handle = winapi::um::libloaderapi::GetModuleHandleW(std::ptr::null());
		let wnd = winuser::WNDCLASSW {
			style: 0,
			lpfnWndProc: Some(window_proc),
			hInstance: module_handle,
			hIcon: std::ptr::null_mut(),
			hCursor: std::ptr::null_mut(),
			lpszClassName: class_name.as_ptr(),
			hbrBackground: winuser::COLOR_WINDOW as winapi::shared::windef::HBRUSH,
			lpszMenuName: std::ptr::null_mut(),
			cbClsExtra: 0,
			cbWndExtra: 0,
		};

		let atom = winuser::RegisterClassW(&wnd);
		if atom == 0 {
			return None;
		}

		let window_handle = winuser::CreateWindowExW(0,
		                                             atom as winapi::shared::ntdef::LPCWSTR,
		                                             window_name.as_ptr(),
		                                             winuser::WS_DISABLED,
		                                             0,
		                                             0,
		                                             0,
		                                             0,
		                                             winuser::GetDesktopWindow(),
		                                             std::ptr::null_mut(),
		                                             std::ptr::null_mut(),
		                                             std::ptr::null_mut());

		if window_handle.is_null() {
			return None;
		}

		return Some(window_handle);
	}
}

fn add_notification_icon(window: HWND) {

	let mut tooltip = [0 as winapi::um::winnt::WCHAR; 128];
	for (&x, p) in "Polaris".to_win().iter().zip(tooltip.iter_mut()) {
		*p = x;
	}

	unsafe {
		let module = winapi::um::libloaderapi::GetModuleHandleW(std::ptr::null());
		let icon = winuser::LoadIconW(module, std::mem::transmute(IDI_POLARIS_TRAY));
		let mut flags = shellapi::NIF_MESSAGE | shellapi::NIF_TIP;
		if !icon.is_null() {
			flags |= shellapi::NIF_ICON;
		}

		let mut icon_data = shellapi::NOTIFYICONDATAW::new();
		icon_data.hWnd = window;
		icon_data.uID = UID_NOTIFICATION_ICON;
		icon_data.uFlags = flags;
		icon_data.hIcon = icon;
		icon_data.uCallbackMessage = MESSAGE_NOTIFICATION_ICON;
		icon_data.szTip = tooltip;

		shellapi::Shell_NotifyIconW(shellapi::NIM_ADD, &mut icon_data);
	}
}

fn remove_notification_icon(window: HWND) {
	let mut icon_data = shellapi::NOTIFYICONDATAW::new();
	icon_data.hWnd = window;
	icon_data.uID = UID_NOTIFICATION_ICON;
	unsafe {
		shellapi::Shell_NotifyIconW(shellapi::NIM_DELETE, &mut icon_data);
	}
}

fn open_notification_context_menu(window: HWND) {
	info!("Opening notification icon context menu");
	let quit_string = "Quit Polaris".to_win();

	unsafe {
		let context_menu = winuser::CreatePopupMenu();
		if context_menu.is_null() {
			return;
		}
		winuser::InsertMenuW(context_menu,
		                     0,
		                     winuser::MF_STRING,
		                     MESSAGE_NOTIFICATION_ICON_QUIT as usize,
		                     quit_string.as_ptr());

		let mut cursor_position = winapi::shared::windef::POINT { x: 0, y: 0 };
		winuser::GetCursorPos(&mut cursor_position);

		winuser::SetForegroundWindow(window);
		let flags = winuser::TPM_RIGHTALIGN | winuser::TPM_BOTTOMALIGN | winuser::TPM_RIGHTBUTTON;
		winuser::TrackPopupMenu(context_menu,
		                        flags,
		                        cursor_position.x,
		                        cursor_position.y,
		                        0,
		                        window,
		                        std::ptr::null_mut());
		winuser::PostMessageW(window, 0, 0, 0);

		info!("Closing notification context menu");
		winuser::DestroyMenu(context_menu);
	}
}

fn quit(window: HWND) {
	info!("Shutting down UI");
	unsafe {
		winuser::PostMessageW(window, winuser::WM_CLOSE, 0, 0);
	}
}

pub fn run() {
	info!("Starting up UI (Windows)");

	create_window().expect("Could not initialize window");

	let mut message = winuser::MSG {
		hwnd: std::ptr::null_mut(),
		message: 0,
		wParam: 0,
		lParam: 0,
		time: 0,
		pt: winapi::shared::windef::POINT { x: 0, y: 0 },
	};

	loop {
		let status: i32;
		unsafe {
			status = winuser::GetMessageW(&mut message, std::ptr::null_mut(), 0, 0);
			if status == -1 {
				panic!("GetMessageW error: {}",
				       winapi::um::errhandlingapi::GetLastError());
			}
			if status == 0 {
				break;
			}
			winuser::TranslateMessage(&message);
			winuser::DispatchMessageW(&message);
		}
	}
}

pub unsafe extern "system" fn window_proc(window: HWND,
                                          msg: UINT,
                                          w_param: WPARAM,
                                          l_param: LPARAM)
                                          -> LRESULT {
	match msg {

		winuser::WM_CREATE => {
			add_notification_icon(window);
		}

		MESSAGE_NOTIFICATION_ICON => {
			match LOWORD(l_param as DWORD) as u32 {
				winuser::WM_RBUTTONUP => {
					open_notification_context_menu(window);
				}
				_ => (),
			}
		}

		winuser::WM_COMMAND => {
			match LOWORD(w_param as DWORD) as u32 {
				MESSAGE_NOTIFICATION_ICON_QUIT => {
					quit(window);
				}
				_ => (),
			}
		}

		winuser::WM_DESTROY => {
			remove_notification_icon(window);
			winuser::PostQuitMessage(0);
		}

		_ => (),
	};

	return winuser::DefWindowProcW(window, msg, w_param, l_param);
}
<|endoftext|>


<commit_before>use super::utils::{LspPositionConversion, TupleToPosition};
use crate::{
    compiler::{
        cst::{Cst, CstKind, UnwrapWhitespaceAndComment},
        rcst_to_cst::RcstToCst,
    },
    input::Input,
};
use lsp_types::{FoldingRange, FoldingRangeKind};

#[salsa::query_group(FoldingRangeDbStorage)]
pub trait FoldingRangeDb: LspPositionConversion + RcstToCst {
    fn folding_ranges(&self, input: Input) -> Vec<FoldingRange>;
}

fn folding_ranges(db: &dyn FoldingRangeDb, input: Input) -> Vec<FoldingRange> {
    let mut context = Context::new(db, input.clone());
    let cst = db.cst(input).unwrap();
    context.visit_csts(&cst);
    context.ranges
}

struct Context<'a> {
    db: &'a dyn FoldingRangeDb,
    input: Input,
    ranges: Vec<FoldingRange>,
}
impl<'a> Context<'a> {
    fn new(db: &'a dyn FoldingRangeDb, input: Input) -> Self {
        Context {
            db,
            input,
            ranges: vec![],
        }
    }

    fn visit_csts(&mut self, csts: &[Cst]) {
        for cst in csts {
            self.visit_cst(cst);
        }
    }
    fn visit_cst(&mut self, cst: &Cst) {
        match &cst.kind {
            CstKind::EqualsSign => {}
            CstKind::Comma => {}
            CstKind::Dot => {}
            CstKind::Colon => {}
            CstKind::OpeningParenthesis => {}
            CstKind::ClosingParenthesis => {}
            CstKind::OpeningBracket => {}
            CstKind::ClosingBracket => {}
            CstKind::OpeningCurlyBrace => {}
            CstKind::ClosingCurlyBrace => {}
            CstKind::Arrow => {}
            CstKind::DoubleQuote => {}
            CstKind::Octothorpe => {}
            CstKind::Whitespace(_) => {}
            CstKind::Newline(_) => {}
            // TODO: support folding ranges for comments
            CstKind::Comment { .. } => {}
            CstKind::TrailingWhitespace { child, .. } => self.visit_cst(child),
            CstKind::Identifier(_) => {}
            CstKind::Symbol(_) => {}
            CstKind::Int { .. } => {}
            // TODO: support folding ranges for multiline texts
            CstKind::Text { .. } => {}
            CstKind::TextPart(_) => {}
            CstKind::Parenthesized { inner, .. } => self.visit_cst(inner),
            CstKind::Call { name, arguments } => {
                if !arguments.is_empty() {
                    let name = name.unwrap_whitespace_and_comment();
                    assert!(matches!(name.kind, CstKind::Identifier { .. }));

                    let last_argument = arguments.last().unwrap().unwrap_whitespace_and_comment();

                    self.push(
                        name.span.end,
                        last_argument.span.end,
                        FoldingRangeKind::Region,
                    );
                }

                self.visit_cst(name);
                self.visit_csts(&arguments);
            }
            // TODO: support folding ranges for structs
            CstKind::Struct { fields, .. } => self.visit_csts(fields),
            CstKind::StructField { key, value, .. } => {
                self.visit_cst(key);
                self.visit_cst(value);
            }
            CstKind::StructAccess { struct_, dot, key } => {
                self.visit_cst(struct_);
                self.visit_cst(dot);
                self.visit_cst(key);
            }
            CstKind::Lambda {
                opening_curly_brace,
                parameters_and_arrow,
                body,
                closing_curly_brace,
            } => {
                let opening_curly_brace = opening_curly_brace.unwrap_whitespace_and_comment();
                assert!(matches!(
                    opening_curly_brace.kind,
                    CstKind::OpeningCurlyBrace { .. }
                ));

                let closing_curly_brace = closing_curly_brace.unwrap_whitespace_and_comment();
                assert!(matches!(
                    closing_curly_brace.kind,
                    CstKind::ClosingCurlyBrace { .. }
                ));

                self.push(
                    opening_curly_brace.span.end,
                    closing_curly_brace.span.start,
                    FoldingRangeKind::Region,
                );
                if let Some((parameters, _)) = parameters_and_arrow {
                    self.visit_csts(&parameters);
                }
                self.visit_csts(&body);
            }
            CstKind::Assignment {
                name,
                equals_sign,
                parameters,
                body,
            } => {
                if !body.is_empty() {
                    let equals_sign = equals_sign.unwrap_whitespace_and_comment();
                    assert!(matches!(equals_sign.kind, CstKind::EqualsSign { .. }));

                    let last_expression = body.last().unwrap().unwrap_whitespace_and_comment();

                    self.push(
                        equals_sign.span.end,
                        last_expression.span.end,
                        FoldingRangeKind::Region,
                    );
                }

                self.visit_cst(name);
                self.visit_csts(&parameters);
                self.visit_csts(&body);
            }
            CstKind::Error { .. } => {}
        }
    }

    fn push(&mut self, start: usize, end: usize, kind: FoldingRangeKind) {
        let start = self
            .db
            .offset_to_lsp(self.input.clone(), start)
            .to_position();
        let end = self.db.offset_to_lsp(self.input.clone(), end).to_position();

        self.ranges.push(FoldingRange {
            start_line: start.line,
            start_character: Some(start.character),
            end_line: end.line,
            end_character: Some(end.character),
            kind: Some(kind),
        });
    }
}
<commit_msg>Handle calls with complex receivers in folding ranges<commit_after>use super::utils::{LspPositionConversion, TupleToPosition};
use crate::{
    compiler::{
        cst::{Cst, CstKind, UnwrapWhitespaceAndComment},
        rcst_to_cst::RcstToCst,
    },
    input::Input,
};
use lsp_types::{FoldingRange, FoldingRangeKind};

#[salsa::query_group(FoldingRangeDbStorage)]
pub trait FoldingRangeDb: LspPositionConversion + RcstToCst {
    fn folding_ranges(&self, input: Input) -> Vec<FoldingRange>;
}

fn folding_ranges(db: &dyn FoldingRangeDb, input: Input) -> Vec<FoldingRange> {
    let mut context = Context::new(db, input.clone());
    let cst = db.cst(input).unwrap();
    context.visit_csts(&cst);
    context.ranges
}

struct Context<'a> {
    db: &'a dyn FoldingRangeDb,
    input: Input,
    ranges: Vec<FoldingRange>,
}
impl<'a> Context<'a> {
    fn new(db: &'a dyn FoldingRangeDb, input: Input) -> Self {
        Context {
            db,
            input,
            ranges: vec![],
        }
    }

    fn visit_csts(&mut self, csts: &[Cst]) {
        for cst in csts {
            self.visit_cst(cst);
        }
    }
    fn visit_cst(&mut self, cst: &Cst) {
        match &cst.kind {
            CstKind::EqualsSign => {}
            CstKind::Comma => {}
            CstKind::Dot => {}
            CstKind::Colon => {}
            CstKind::OpeningParenthesis => {}
            CstKind::ClosingParenthesis => {}
            CstKind::OpeningBracket => {}
            CstKind::ClosingBracket => {}
            CstKind::OpeningCurlyBrace => {}
            CstKind::ClosingCurlyBrace => {}
            CstKind::Arrow => {}
            CstKind::DoubleQuote => {}
            CstKind::Octothorpe => {}
            CstKind::Whitespace(_) => {}
            CstKind::Newline(_) => {}
            // TODO: support folding ranges for comments
            CstKind::Comment { .. } => {}
            CstKind::TrailingWhitespace { child, .. } => self.visit_cst(child),
            CstKind::Identifier(_) => {}
            CstKind::Symbol(_) => {}
            CstKind::Int { .. } => {}
            // TODO: support folding ranges for multiline texts
            CstKind::Text { .. } => {}
            CstKind::TextPart(_) => {}
            CstKind::Parenthesized { inner, .. } => self.visit_cst(inner),
            CstKind::Call { name, arguments } => {
                if !arguments.is_empty() {
                    let name = name.unwrap_whitespace_and_comment();
                    let last_argument = arguments.last().unwrap().unwrap_whitespace_and_comment();
                    self.push(
                        name.span.end,
                        last_argument.span.end,
                        FoldingRangeKind::Region,
                    );
                }

                self.visit_cst(name);
                self.visit_csts(&arguments);
            }
            // TODO: support folding ranges for structs
            CstKind::Struct { fields, .. } => self.visit_csts(fields),
            CstKind::StructField { key, value, .. } => {
                self.visit_cst(key);
                self.visit_cst(value);
            }
            CstKind::StructAccess { struct_, dot, key } => {
                self.visit_cst(struct_);
                self.visit_cst(dot);
                self.visit_cst(key);
            }
            CstKind::Lambda {
                opening_curly_brace,
                parameters_and_arrow,
                body,
                closing_curly_brace,
            } => {
                let opening_curly_brace = opening_curly_brace.unwrap_whitespace_and_comment();
                assert!(matches!(
                    opening_curly_brace.kind,
                    CstKind::OpeningCurlyBrace { .. }
                ));

                let closing_curly_brace = closing_curly_brace.unwrap_whitespace_and_comment();
                assert!(matches!(
                    closing_curly_brace.kind,
                    CstKind::ClosingCurlyBrace { .. }
                ));

                self.push(
                    opening_curly_brace.span.end,
                    closing_curly_brace.span.start,
                    FoldingRangeKind::Region,
                );
                if let Some((parameters, _)) = parameters_and_arrow {
                    self.visit_csts(&parameters);
                }
                self.visit_csts(&body);
            }
            CstKind::Assignment {
                name,
                equals_sign,
                parameters,
                body,
            } => {
                if !body.is_empty() {
                    let equals_sign = equals_sign.unwrap_whitespace_and_comment();
                    assert!(matches!(equals_sign.kind, CstKind::EqualsSign { .. }));

                    let last_expression = body.last().unwrap().unwrap_whitespace_and_comment();

                    self.push(
                        equals_sign.span.end,
                        last_expression.span.end,
                        FoldingRangeKind::Region,
                    );
                }

                self.visit_cst(name);
                self.visit_csts(&parameters);
                self.visit_csts(&body);
            }
            CstKind::Error { .. } => {}
        }
    }

    fn push(&mut self, start: usize, end: usize, kind: FoldingRangeKind) {
        let start = self
            .db
            .offset_to_lsp(self.input.clone(), start)
            .to_position();
        let end = self.db.offset_to_lsp(self.input.clone(), end).to_position();

        self.ranges.push(FoldingRange {
            start_line: start.line,
            start_character: Some(start.character),
            end_line: end.line,
            end_character: Some(end.character),
            kind: Some(kind),
        });
    }
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

//! A handler and associated types for the filesystems action.
//!
//! The filesystems action lists all mounted filesystems on the client,
//! collecting device name, mount point, filesystem type and its options.
//! Current implementation works only in Linux systems.

use rrg_proto::{Filesystem, KeyValue, AttributedDict};
use crate::session::{self, Session};

use log::error;
use std::fmt::{Display, Formatter};

/// Enum of possible errors, which can occur during collecting filesystems data.
#[derive(Debug)]
enum Error {
    /// Missing mtab-like file error.
    MissingFile(std::io::Error),
    /// Parsing mtab-like file error.
    MountInfoParse(std::io::Error),
}

impl std::error::Error for Error {

    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        use Error::*;

        match *self {
            MissingFile(ref error) => Some(error),
            MountInfoParse(ref error) => Some(error),
        }
    }
}

impl Display for Error {

    fn fmt(&self, fmt: &mut Formatter) -> std::fmt::Result {
        use Error::*;

        match *self {
            MissingFile(ref error) => {
                write!(fmt, "missed file error: {}", error)
            },
            MountInfoParse(ref error) => {
                write!(fmt, "failed to obtain mount information: {}", error)
            },
        }
    }
}

impl From<Error> for session::Error {

    fn from(error: Error) -> session::Error {
        session::Error::action(error)
    }
}

/// A response type for the filesystems action.
pub struct Response {
    /// Information about the filesystem.
    mount_info: proc_mounts::MountInfo,
}

/// Handles requests for the filesystems action.
///
/// Initially searches in `/proc/mounts`. If it's missing, falls back to
/// `/etc/mtab`.
pub fn handle<S: Session>(session: &mut S, _: ()) -> session::Result<()> {
    use proc_mounts::MountIter;

    // Check whether `/proc/mounts` exists.
    let mount_iter = match MountIter::new() {
        Ok(mount_iter) => mount_iter,
        Err(_) => {
            // `/proc/mounts` doesn't exist. Try to fall back to `/etc/mtab`.
            MountIter::new_from_file("/etc/mtab").map_err(Error::MissingFile)?
        },
    };

    for mount_info in mount_iter {
        let mount_info = mount_info.map_err(Error::MountInfoParse)?;
        session.reply(Response {
           mount_info,
        })?;
    }

    Ok(())
}

/// Converts filesystem mount option in `String` representation to
/// GRR's `KeyValue` protobuf struct representation.
fn option_to_key_value(option: String) -> KeyValue {
    match &option.split('=').collect::<Vec<&str>>()[..] {
        &[key] => KeyValue::key(String::from(key)),
        &[key, value] => KeyValue::pair(String::from(key), String::from(value)),
        _ => {
            error!("invalid mount option syntax: {}", option);
            KeyValue::empty()
        },
    }
}

/// Converts a `Vec` of filesystem mount options in `String` representation to
/// GRR's `AttributedDict` protobuf struct representation.
fn options_to_dict(options: Vec<String>) -> AttributedDict {
    AttributedDict {
        dat: options.into_iter().map(option_to_key_value).collect(),
    }
}

impl super::Response for Response {

    const RDF_NAME: Option<&'static str> = Some("Filesystem");

    type Proto = rrg_proto::Filesystem;

    fn into_proto(self) -> Filesystem {
        // TODO: Remove lossy conversion of `PathBuf` to `String`
        // when `mount_point` and `device` fields of `Filesystem` message
        // will have `bytes` type instead of `string`.
        Filesystem {
            device: Some(self.mount_info.source.to_string_lossy()
                .into_owned()),
            mount_point: Some(self.mount_info.dest.to_string_lossy()
                .into_owned()),
            r#type: Some(self.mount_info.fstype),
            label: None,
            options: Some(options_to_dict(self.mount_info.options)),
        }
    }
}

#[cfg(test)]
mod tests {

    use super::*;
    use std::path::PathBuf;

    #[test]
    fn test_if_any_filesystem_exists() {
        let mut session = session::test::Fake::new();
        assert!(handle(&mut session, ()).is_ok());
        assert_ne!(session.reply_count(), 0);
    }

    /// Unit-like struct, representing a filesystem for testing with `fuse`.
    struct FuseFilesystem;

    impl fuse::Filesystem for FuseFilesystem {}

    #[test]
    fn test_fuse_filesystem() {
        use users::{get_current_uid, get_current_gid};

        let fs_name = PathBuf::from("fuse-test-fs");

        let tmp_dir = tempfile::tempdir().unwrap();
        let mountpoint = tmp_dir.path();

        let fs_name_option = format!("fsname={}", fs_name.to_str().unwrap());
        let options = [
            "-o", "ro",
            "-o", "nosuid",
            "-o", "nodev",
            "-o", "relatime",
            "-o", "subtype=custom-type",
            "-o", &fs_name_option,
        ];
        let options = options.iter().map(|opt| opt.as_ref())
            .collect::<Vec<&std::ffi::OsStr>>();

        // Spawn a background thread to handle filesystem operations.
        // When `_background_session` is dropped, filesystem will be unmounted.
        let background_session = unsafe {
            fuse::spawn_mount(FuseFilesystem, &mountpoint, &options).unwrap()
        };

        let mut session = session::test::Fake::new();
        assert!(handle(&mut session, ()).is_ok());

        let fuse_mounted_fs = session.replies::<Response>()
            .find(|reply| reply.mount_info.source == fs_name)
            .expect("no reply with a mounted FUSE filesystem");

        let mount_info = &fuse_mounted_fs.mount_info;
        assert_eq!(mount_info.source, fs_name);
        assert_eq!(mount_info.dest, tmp_dir.path());
        assert_eq!(mount_info.fstype, "fuse.custom-type");

        let options = &mount_info.options;
        assert!(options.iter().any(|opt| opt == "ro"));
        assert!(options.iter().any(|opt| opt == "nosuid"));
        assert!(options.iter().any(|opt| opt == "nodev"));
        assert!(options.iter().any(|opt| opt == "relatime"));

        // `user_id` and `group_id` are set by libfuse.
        // http://man7.org/linux/man-pages/man8/mount.fuse.8.html
        let current_uid_option = format!("user_id={}", get_current_uid());
        assert!(options.iter().any(|opt| *opt == current_uid_option));

        let current_gid_option = format!("group_id={}", get_current_gid());
        assert!(options.iter().any(|opt| *opt == current_gid_option));

        drop(background_session);
    }
}
<commit_msg>Apply new conversions in the filesystems action.<commit_after>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

//! A handler and associated types for the filesystems action.
//!
//! The filesystems action lists all mounted filesystems on the client,
//! collecting device name, mount point, filesystem type and its options.
//! Current implementation works only in Linux systems.

use rrg_proto::{Filesystem, KeyValue, AttributedDict};
use crate::session::{self, Session};

use log::error;
use std::fmt::{Display, Formatter};

/// Enum of possible errors, which can occur during collecting filesystems data.
#[derive(Debug)]
enum Error {
    /// Missing mtab-like file error.
    MissingFile(std::io::Error),
    /// Parsing mtab-like file error.
    MountInfoParse(std::io::Error),
}

impl std::error::Error for Error {

    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        use Error::*;

        match *self {
            MissingFile(ref error) => Some(error),
            MountInfoParse(ref error) => Some(error),
        }
    }
}

impl Display for Error {

    fn fmt(&self, fmt: &mut Formatter) -> std::fmt::Result {
        use Error::*;

        match *self {
            MissingFile(ref error) => {
                write!(fmt, "missed file error: {}", error)
            },
            MountInfoParse(ref error) => {
                write!(fmt, "failed to obtain mount information: {}", error)
            },
        }
    }
}

impl From<Error> for session::Error {

    fn from(error: Error) -> session::Error {
        session::Error::action(error)
    }
}

/// A response type for the filesystems action.
pub struct Response {
    /// Information about the filesystem.
    mount_info: proc_mounts::MountInfo,
}

/// Handles requests for the filesystems action.
///
/// Initially searches in `/proc/mounts`. If it's missing, falls back to
/// `/etc/mtab`.
pub fn handle<S: Session>(session: &mut S, _: ()) -> session::Result<()> {
    use proc_mounts::MountIter;

    // Check whether `/proc/mounts` exists.
    let mount_iter = match MountIter::new() {
        Ok(mount_iter) => mount_iter,
        Err(_) => {
            // `/proc/mounts` doesn't exist. Try to fall back to `/etc/mtab`.
            MountIter::new_from_file("/etc/mtab").map_err(Error::MissingFile)?
        },
    };

    for mount_info in mount_iter {
        let mount_info = mount_info.map_err(Error::MountInfoParse)?;
        session.reply(Response {
           mount_info,
        })?;
    }

    Ok(())
}

/// Converts filesystem mount option in `String` representation to
/// GRR's `KeyValue` protobuf struct representation.
fn option_to_key_value(option: String) -> KeyValue {
    match &option.split('=').collect::<Vec<&str>>()[..] {
        &[key] => KeyValue::key(String::from(key)),
        &[key, value] => KeyValue::pair(String::from(key), String::from(value)),
        _ => {
            error!("invalid mount option syntax: {}", option);
            KeyValue::empty()
        },
    }
}

impl super::Response for Response {

    const RDF_NAME: Option<&'static str> = Some("Filesystem");

    type Proto = rrg_proto::Filesystem;

    fn into_proto(self) -> Filesystem {
        let options = self.mount_info.options.into_iter()
            .map(option_to_key_value)
            .collect();

        // TODO: Remove lossy conversion of `PathBuf` to `String`
        // when `mount_point` and `device` fields of `Filesystem` message
        // will have `bytes` type instead of `string`.
        Filesystem {
            device: Some(self.mount_info.source.to_string_lossy()
                .into_owned()),
            mount_point: Some(self.mount_info.dest.to_string_lossy()
                .into_owned()),
            r#type: Some(self.mount_info.fstype),
            label: None,
            options: Some(options),
        }
    }
}

#[cfg(test)]
mod tests {

    use super::*;
    use std::path::PathBuf;

    #[test]
    fn test_if_any_filesystem_exists() {
        let mut session = session::test::Fake::new();
        assert!(handle(&mut session, ()).is_ok());
        assert_ne!(session.reply_count(), 0);
    }

    /// Unit-like struct, representing a filesystem for testing with `fuse`.
    struct FuseFilesystem;

    impl fuse::Filesystem for FuseFilesystem {}

    #[test]
    fn test_fuse_filesystem() {
        use users::{get_current_uid, get_current_gid};

        let fs_name = PathBuf::from("fuse-test-fs");

        let tmp_dir = tempfile::tempdir().unwrap();
        let mountpoint = tmp_dir.path();

        let fs_name_option = format!("fsname={}", fs_name.to_str().unwrap());
        let options = [
            "-o", "ro",
            "-o", "nosuid",
            "-o", "nodev",
            "-o", "relatime",
            "-o", "subtype=custom-type",
            "-o", &fs_name_option,
        ];
        let options = options.iter().map(|opt| opt.as_ref())
            .collect::<Vec<&std::ffi::OsStr>>();

        // Spawn a background thread to handle filesystem operations.
        // When `_background_session` is dropped, filesystem will be unmounted.
        let background_session = unsafe {
            fuse::spawn_mount(FuseFilesystem, &mountpoint, &options).unwrap()
        };

        let mut session = session::test::Fake::new();
        assert!(handle(&mut session, ()).is_ok());

        let fuse_mounted_fs = session.replies::<Response>()
            .find(|reply| reply.mount_info.source == fs_name)
            .expect("no reply with a mounted FUSE filesystem");

        let mount_info = &fuse_mounted_fs.mount_info;
        assert_eq!(mount_info.source, fs_name);
        assert_eq!(mount_info.dest, tmp_dir.path());
        assert_eq!(mount_info.fstype, "fuse.custom-type");

        let options = &mount_info.options;
        assert!(options.iter().any(|opt| opt == "ro"));
        assert!(options.iter().any(|opt| opt == "nosuid"));
        assert!(options.iter().any(|opt| opt == "nodev"));
        assert!(options.iter().any(|opt| opt == "relatime"));

        // `user_id` and `group_id` are set by libfuse.
        // http://man7.org/linux/man-pages/man8/mount.fuse.8.html
        let current_uid_option = format!("user_id={}", get_current_uid());
        assert!(options.iter().any(|opt| *opt == current_uid_option));

        let current_gid_option = format!("group_id={}", get_current_gid());
        assert!(options.iter().any(|opt| *opt == current_gid_option));

        drop(background_session);
    }
}
<|endoftext|>


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

use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeBinding::NodeMethods;
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::num::Finite;
use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::element::Element;
use crate::dom::htmlelement::HTMLElement;
use crate::dom::htmlmetaelement::HTMLMetaElement;
use crate::dom::node;
use crate::dom::window::Window;
use euclid::Point2D;
use js::jsapi::JS_GetRuntime;
use script_layout_interface::message::{Msg, NodesFromPointQueryType, QueryMsg};
use script_traits::UntrustedNodeAddress;
use servo_arc::Arc;
use std::fmt;
use style::context::QuirksMode;
use style::invalidation::media_queries::{MediaListKey, ToMediaListKey};
use style::media_queries::MediaList;
use style::shared_lock::{SharedRwLock as StyleSharedRwLock, SharedRwLockReadGuard};
use style::stylesheet_set::StylesheetSet;
use style::stylesheets::{CssRule, Origin, Stylesheet};

#[derive(Clone, JSTraceable, MallocSizeOf)]
#[must_root]
pub struct StyleSheetInDocument {
    #[ignore_malloc_size_of = "Arc"]
    pub sheet: Arc<Stylesheet>,
    pub owner: Dom<Element>,
}

impl fmt::Debug for StyleSheetInDocument {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        self.sheet.fmt(formatter)
    }
}

impl PartialEq for StyleSheetInDocument {
    fn eq(&self, other: &Self) -> bool {
        Arc::ptr_eq(&self.sheet, &other.sheet)
    }
}

impl ToMediaListKey for StyleSheetInDocument {
    fn to_media_list_key(&self) -> MediaListKey {
        self.sheet.to_media_list_key()
    }
}

impl ::style::stylesheets::StylesheetInDocument for StyleSheetInDocument {
    fn origin(&self, guard: &SharedRwLockReadGuard) -> Origin {
        self.sheet.origin(guard)
    }

    fn quirks_mode(&self, guard: &SharedRwLockReadGuard) -> QuirksMode {
        self.sheet.quirks_mode(guard)
    }

    fn enabled(&self) -> bool {
        self.sheet.enabled()
    }

    fn media<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> Option<&'a MediaList> {
        self.sheet.media(guard)
    }

    fn rules<'a, 'b: 'a>(&'a self, guard: &'b SharedRwLockReadGuard) -> &'a [CssRule] {
        self.sheet.rules(guard)
    }
}

// https://w3c.github.io/webcomponents/spec/shadow/#extensions-to-the-documentorshadowroot-mixin
#[must_root]
#[derive(JSTraceable, MallocSizeOf)]
pub struct DocumentOrShadowRoot {
    window: Dom<Window>,
}

impl DocumentOrShadowRoot {
    pub fn new(window: &Window) -> Self {
        Self {
            window: Dom::from_ref(window),
        }
    }

    pub fn nodes_from_point(
        &self,
        client_point: &Point2D<f32>,
        reflow_goal: NodesFromPointQueryType,
    ) -> Vec<UntrustedNodeAddress> {
        if !self
            .window
            .layout_reflow(QueryMsg::NodesFromPointQuery(*client_point, reflow_goal))
        {
            return vec![];
        };

        self.window.layout().nodes_from_point_response()
    }

    #[allow(unsafe_code)]
    // https://drafts.csswg.org/cssom-view/#dom-document-elementfrompoint
    pub fn element_from_point(
        &self,
        x: Finite<f64>,
        y: Finite<f64>,
        document_element: Option<DomRoot<Element>>,
        has_browsing_context: bool,
    ) -> Option<DomRoot<Element>> {
        let x = *x as f32;
        let y = *y as f32;
        let point = &Point2D::new(x, y);
        let viewport = self.window.window_size().initial_viewport;

        if has_browsing_context {
            return None;
        }

        if x < 0.0 || y < 0.0 || x > viewport.width || y > viewport.height {
            return None;
        }

        match self
            .nodes_from_point(point, NodesFromPointQueryType::Topmost)
            .first()
        {
            Some(address) => {
                let js_runtime = unsafe { JS_GetRuntime(self.window.get_cx()) };
                let node = unsafe { node::from_untrusted_node_address(js_runtime, *address) };
                let parent_node = node.GetParentNode().unwrap();
                let element_ref = node
                    .downcast::<Element>()
                    .unwrap_or_else(|| parent_node.downcast::<Element>().unwrap());

                Some(DomRoot::from_ref(element_ref))
            },
            None => document_element,
        }
    }

    #[allow(unsafe_code)]
    // https://drafts.csswg.org/cssom-view/#dom-document-elementsfrompoint
    pub fn elements_from_point(
        &self,
        x: Finite<f64>,
        y: Finite<f64>,
        document_element: Option<DomRoot<Element>>,
        has_browsing_context: bool,
    ) -> Vec<DomRoot<Element>> {
        let x = *x as f32;
        let y = *y as f32;
        let point = &Point2D::new(x, y);
        let viewport = self.window.window_size().initial_viewport;

        if has_browsing_context {
            return vec![];
        }

        // Step 2
        if x < 0.0 || y < 0.0 || x > viewport.width || y > viewport.height {
            return vec![];
        }

        let js_runtime = unsafe { JS_GetRuntime(self.window.get_cx()) };

        // Step 1 and Step 3
        let nodes = self.nodes_from_point(point, NodesFromPointQueryType::All);
        let mut elements: Vec<DomRoot<Element>> = nodes
            .iter()
            .flat_map(|&untrusted_node_address| {
                let node = unsafe {
                    node::from_untrusted_node_address(js_runtime, untrusted_node_address)
                };
                DomRoot::downcast::<Element>(node)
            })
            .collect();

        // Step 4
        if let Some(root_element) = document_element {
            if elements.last() != Some(&root_element) {
                elements.push(root_element);
            }
        }

        // Step 5
        elements
    }

    // https://html.spec.whatwg.org/multipage/#dom-document-activeelement
    pub fn get_active_element(
        &self,
        focused_element: Option<DomRoot<Element>>,
        body: Option<DomRoot<HTMLElement>>,
        document_element: Option<DomRoot<Element>>,
    ) -> Option<DomRoot<Element>> {
        // TODO: Step 2.

        match focused_element {
            Some(element) => Some(element), // Step 3. and 4.
            None => match body {
                // Step 5.
                Some(body) => Some(DomRoot::upcast(body)),
                None => document_element,
            },
        }
    }

    /// Remove a stylesheet owned by `owner` from the list of document sheets.
    #[allow(unrooted_must_root)] // Owner needs to be rooted already necessarily.
    pub fn remove_stylesheet(
        &self,
        owner: &Element,
        s: &Arc<Stylesheet>,
        stylesheets: &mut StylesheetSet<StyleSheetInDocument>,
    ) {
        self.window
            .layout_chan()
            .send(Msg::RemoveStylesheet(s.clone()))
            .unwrap();

        let guard = s.shared_lock.read();

        // FIXME(emilio): Would be nice to remove the clone, etc.
        stylesheets.remove_stylesheet(
            None,
            StyleSheetInDocument {
                sheet: s.clone(),
                owner: Dom::from_ref(owner),
            },
            &guard,
        );
    }

    /// Add a stylesheet owned by `owner` to the list of document sheets, in the
    /// correct tree position.
    #[allow(unrooted_must_root)] // Owner needs to be rooted already necessarily.
    pub fn add_stylesheet(
        &self,
        owner: &Element,
        stylesheets: &mut StylesheetSet<StyleSheetInDocument>,
        sheet: Arc<Stylesheet>,
        insertion_point: Option<StyleSheetInDocument>,
        style_shared_lock: &StyleSharedRwLock,
    ) {
        // FIXME(emilio): It'd be nice to unify more code between the elements
        // that own stylesheets, but StylesheetOwner is more about loading
        // them...
        debug_assert!(
            owner.as_stylesheet_owner().is_some() || owner.is::<HTMLMetaElement>(),
            "Wat"
        );

        let sheet = StyleSheetInDocument {
            sheet,
            owner: Dom::from_ref(owner),
        };

        let guard = style_shared_lock.read();

        match insertion_point {
            Some(ip) => {
                stylesheets.insert_stylesheet_before(None, sheet, ip, &guard);
            },
            None => {
                stylesheets.append_stylesheet(None, sheet, &guard);
            },
        }
    }
}
<commit_msg>Fix Document.Element(s)FromPoint<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeBinding::NodeMethods;
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::num::Finite;
use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::element::Element;
use crate::dom::htmlelement::HTMLElement;
use crate::dom::htmlmetaelement::HTMLMetaElement;
use crate::dom::node;
use crate::dom::window::Window;
use euclid::Point2D;
use js::jsapi::JS_GetRuntime;
use script_layout_interface::message::{Msg, NodesFromPointQueryType, QueryMsg};
use script_traits::UntrustedNodeAddress;
use servo_arc::Arc;
use std::fmt;
use style::context::QuirksMode;
use style::invalidation::media_queries::{MediaListKey, ToMediaListKey};
use style::media_queries::MediaList;
use style::shared_lock::{SharedRwLock as StyleSharedRwLock, SharedRwLockReadGuard};
use style::stylesheet_set::StylesheetSet;
use style::stylesheets::{CssRule, Origin, Stylesheet};

#[derive(Clone, JSTraceable, MallocSizeOf)]
#[must_root]
pub struct StyleSheetInDocument {
    #[ignore_malloc_size_of = "Arc"]
    pub sheet: Arc<Stylesheet>,
    pub owner: Dom<Element>,
}

impl fmt::Debug for StyleSheetInDocument {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        self.sheet.fmt(formatter)
    }
}

impl PartialEq for StyleSheetInDocument {
    fn eq(&self, other: &Self) -> bool {
        Arc::ptr_eq(&self.sheet, &other.sheet)
    }
}

impl ToMediaListKey for StyleSheetInDocument {
    fn to_media_list_key(&self) -> MediaListKey {
        self.sheet.to_media_list_key()
    }
}

impl ::style::stylesheets::StylesheetInDocument for StyleSheetInDocument {
    fn origin(&self, guard: &SharedRwLockReadGuard) -> Origin {
        self.sheet.origin(guard)
    }

    fn quirks_mode(&self, guard: &SharedRwLockReadGuard) -> QuirksMode {
        self.sheet.quirks_mode(guard)
    }

    fn enabled(&self) -> bool {
        self.sheet.enabled()
    }

    fn media<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> Option<&'a MediaList> {
        self.sheet.media(guard)
    }

    fn rules<'a, 'b: 'a>(&'a self, guard: &'b SharedRwLockReadGuard) -> &'a [CssRule] {
        self.sheet.rules(guard)
    }
}

// https://w3c.github.io/webcomponents/spec/shadow/#extensions-to-the-documentorshadowroot-mixin
#[must_root]
#[derive(JSTraceable, MallocSizeOf)]
pub struct DocumentOrShadowRoot {
    window: Dom<Window>,
}

impl DocumentOrShadowRoot {
    pub fn new(window: &Window) -> Self {
        Self {
            window: Dom::from_ref(window),
        }
    }

    pub fn nodes_from_point(
        &self,
        client_point: &Point2D<f32>,
        reflow_goal: NodesFromPointQueryType,
    ) -> Vec<UntrustedNodeAddress> {
        if !self
            .window
            .layout_reflow(QueryMsg::NodesFromPointQuery(*client_point, reflow_goal))
        {
            return vec![];
        };

        self.window.layout().nodes_from_point_response()
    }

    #[allow(unsafe_code)]
    // https://drafts.csswg.org/cssom-view/#dom-document-elementfrompoint
    pub fn element_from_point(
        &self,
        x: Finite<f64>,
        y: Finite<f64>,
        document_element: Option<DomRoot<Element>>,
        has_browsing_context: bool,
    ) -> Option<DomRoot<Element>> {
        let x = *x as f32;
        let y = *y as f32;
        let point = &Point2D::new(x, y);
        let viewport = self.window.window_size().initial_viewport;

        if !has_browsing_context {
            return None;
        }

        if x < 0.0 || y < 0.0 || x > viewport.width || y > viewport.height {
            return None;
        }

        match self
            .nodes_from_point(point, NodesFromPointQueryType::Topmost)
            .first()
        {
            Some(address) => {
                let js_runtime = unsafe { JS_GetRuntime(self.window.get_cx()) };
                let node = unsafe { node::from_untrusted_node_address(js_runtime, *address) };
                let parent_node = node.GetParentNode().unwrap();
                let element_ref = node
                    .downcast::<Element>()
                    .unwrap_or_else(|| parent_node.downcast::<Element>().unwrap());

                Some(DomRoot::from_ref(element_ref))
            },
            None => document_element,
        }
    }

    #[allow(unsafe_code)]
    // https://drafts.csswg.org/cssom-view/#dom-document-elementsfrompoint
    pub fn elements_from_point(
        &self,
        x: Finite<f64>,
        y: Finite<f64>,
        document_element: Option<DomRoot<Element>>,
        has_browsing_context: bool,
    ) -> Vec<DomRoot<Element>> {
        let x = *x as f32;
        let y = *y as f32;
        let point = &Point2D::new(x, y);
        let viewport = self.window.window_size().initial_viewport;

        if has_browsing_context {
            return vec![];
        }

        // Step 2
        if x < 0.0 || y < 0.0 || x > viewport.width || y > viewport.height {
            return vec![];
        }

        let js_runtime = unsafe { JS_GetRuntime(self.window.get_cx()) };

        // Step 1 and Step 3
        let nodes = self.nodes_from_point(point, NodesFromPointQueryType::All);
        let mut elements: Vec<DomRoot<Element>> = nodes
            .iter()
            .flat_map(|&untrusted_node_address| {
                let node = unsafe {
                    node::from_untrusted_node_address(js_runtime, untrusted_node_address)
                };
                DomRoot::downcast::<Element>(node)
            })
            .collect();

        // Step 4
        if let Some(root_element) = document_element {
            if elements.last() != Some(&root_element) {
                elements.push(root_element);
            }
        }

        // Step 5
        elements
    }

    // https://html.spec.whatwg.org/multipage/#dom-document-activeelement
    pub fn get_active_element(
        &self,
        focused_element: Option<DomRoot<Element>>,
        body: Option<DomRoot<HTMLElement>>,
        document_element: Option<DomRoot<Element>>,
    ) -> Option<DomRoot<Element>> {
        // TODO: Step 2.

        match focused_element {
            Some(element) => Some(element), // Step 3. and 4.
            None => match body {
                // Step 5.
                Some(body) => Some(DomRoot::upcast(body)),
                None => document_element,
            },
        }
    }

    /// Remove a stylesheet owned by `owner` from the list of document sheets.
    #[allow(unrooted_must_root)] // Owner needs to be rooted already necessarily.
    pub fn remove_stylesheet(
        &self,
        owner: &Element,
        s: &Arc<Stylesheet>,
        stylesheets: &mut StylesheetSet<StyleSheetInDocument>,
    ) {
        self.window
            .layout_chan()
            .send(Msg::RemoveStylesheet(s.clone()))
            .unwrap();

        let guard = s.shared_lock.read();

        // FIXME(emilio): Would be nice to remove the clone, etc.
        stylesheets.remove_stylesheet(
            None,
            StyleSheetInDocument {
                sheet: s.clone(),
                owner: Dom::from_ref(owner),
            },
            &guard,
        );
    }

    /// Add a stylesheet owned by `owner` to the list of document sheets, in the
    /// correct tree position.
    #[allow(unrooted_must_root)] // Owner needs to be rooted already necessarily.
    pub fn add_stylesheet(
        &self,
        owner: &Element,
        stylesheets: &mut StylesheetSet<StyleSheetInDocument>,
        sheet: Arc<Stylesheet>,
        insertion_point: Option<StyleSheetInDocument>,
        style_shared_lock: &StyleSharedRwLock,
    ) {
        // FIXME(emilio): It'd be nice to unify more code between the elements
        // that own stylesheets, but StylesheetOwner is more about loading
        // them...
        debug_assert!(
            owner.as_stylesheet_owner().is_some() || owner.is::<HTMLMetaElement>(),
            "Wat"
        );

        let sheet = StyleSheetInDocument {
            sheet,
            owner: Dom::from_ref(owner),
        };

        let guard = style_shared_lock.read();

        match insertion_point {
            Some(ip) => {
                stylesheets.insert_stylesheet_before(None, sheet, ip, &guard);
            },
            None => {
                stylesheets.append_stylesheet(None, sheet, &guard);
            },
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>Use static variables for the IRIS for int_step = 1 and 2. Also increase them<commit_after><|endoftext|>


<commit_before>use std::sync::mpsc;
use std::thread;
use std::path::PathBuf;
use std::fs::{File, OpenOptions};
use std::io::{Seek, SeekFrom, Write, Read};

pub struct Writer {
    thread: thread::JoinHandle<()>,
    tx: mpsc::SyncSender<WriteMsg>,
}

pub struct Reader {
    pub rx: mpsc::Receiver<ReadMsg>,
}

pub enum WriteMsg {
    Seek(SeekFrom),
    Write(Vec<u8>),
    Finish,
}

pub enum ReadMsg {
    Read(Vec<u8>),
    Finish,
    Error,
}

impl Writer {
    pub fn new(filename: PathBuf) -> Writer {
        let (tx, rx) = mpsc::sync_channel(1024);
        let builder = thread::Builder::new().name("file_writer".into());
        let t = builder.spawn(move || {
            let mut f = OpenOptions::new()
                .write(true)
                .create(true)
                .truncate(false)
                .open(filename)
                .unwrap();

            loop {
                match rx.recv().unwrap() {
                    WriteMsg::Seek(from) => {
                        f.seek(from).unwrap();
                    }
                    WriteMsg::Write(buf) => {
                        f.write_all(&buf[..]).unwrap();
                    }
                    WriteMsg::Finish => {
                        break;
                    }
                }
            }
        }).unwrap();
        Writer {
            thread: t,
            tx: tx,
        }
    }

    pub fn seek(&self, from: SeekFrom) {
        self.tx.send(WriteMsg::Seek(from)).unwrap();
    }

    pub fn write_all(&self, buf: Vec<u8>) {
        self.tx.send(WriteMsg::Write(buf)).unwrap();
    }

    pub fn close(self) {
        self.tx.send(WriteMsg::Finish).unwrap_or_else(|e| error!("{:?}", e));
        if let Err(e) = self.thread.join() {
            error!("\n\n{:?}\n\n", e);
        }
    }
}

impl Reader {
    pub fn new(filename: String) -> Reader {
        let (tx, rx) = mpsc::sync_channel(1024);
        let builder = thread::Builder::new().name("file_reader".into());
        let _ = builder.spawn(move || {
            let mut f = File::open(filename).unwrap();
            let mut payload = vec![0; 1300];
            f.seek(SeekFrom::Start(0)).unwrap();
            loop {
                match f.read(&mut payload) {
                    Ok(0) => {
                        tx.send(ReadMsg::Finish).unwrap();
                        break;
                    }
                    Ok(read) => {
                        let mut owned = Vec::with_capacity(read);
                        owned.extend_from_slice(&payload[..read]);
                        tx.send(ReadMsg::Read(owned)).unwrap();
                    }
                    Err(_) => {
                        tx.send(ReadMsg::Error).unwrap();
                        panic!("ruh roh");
                    }
                }
            }
        });

        Reader {
            rx: rx,
        }
    }
}

<commit_msg>1350-byte chunks<commit_after>use std::sync::mpsc;
use std::thread;
use std::path::PathBuf;
use std::fs::{File, OpenOptions};
use std::io::{Seek, SeekFrom, Write, Read};

pub struct Writer {
    thread: thread::JoinHandle<()>,
    tx: mpsc::SyncSender<WriteMsg>,
}

pub struct Reader {
    pub rx: mpsc::Receiver<ReadMsg>,
}

pub enum WriteMsg {
    Seek(SeekFrom),
    Write(Vec<u8>),
    Finish,
}

pub enum ReadMsg {
    Read(Vec<u8>),
    Finish,
    Error,
}

impl Writer {
    pub fn new(filename: PathBuf) -> Writer {
        let (tx, rx) = mpsc::sync_channel(1024);
        let builder = thread::Builder::new().name("file_writer".into());
        let t = builder.spawn(move || {
            let mut f = OpenOptions::new()
                .write(true)
                .create(true)
                .truncate(false)
                .open(filename)
                .unwrap();

            loop {
                match rx.recv().unwrap() {
                    WriteMsg::Seek(from) => {
                        f.seek(from).unwrap();
                    }
                    WriteMsg::Write(buf) => {
                        f.write_all(&buf[..]).unwrap();
                    }
                    WriteMsg::Finish => {
                        break;
                    }
                }
            }
        }).unwrap();
        Writer {
            thread: t,
            tx: tx,
        }
    }

    pub fn seek(&self, from: SeekFrom) {
        self.tx.send(WriteMsg::Seek(from)).unwrap();
    }

    pub fn write_all(&self, buf: Vec<u8>) {
        self.tx.send(WriteMsg::Write(buf)).unwrap();
    }

    pub fn close(self) {
        self.tx.send(WriteMsg::Finish).unwrap_or_else(|e| error!("{:?}", e));
        if let Err(e) = self.thread.join() {
            error!("\n\n{:?}\n\n", e);
        }
    }
}

impl Reader {
    pub fn new(filename: String) -> Reader {
        let (tx, rx) = mpsc::sync_channel(1024);
        let builder = thread::Builder::new().name("file_reader".into());
        let _ = builder.spawn(move || {
            let mut f = File::open(filename).unwrap();
            let mut payload = vec![0; 1350];
            f.seek(SeekFrom::Start(0)).unwrap();
            loop {
                match f.read(&mut payload) {
                    Ok(0) => {
                        tx.send(ReadMsg::Finish).unwrap();
                        break;
                    }
                    Ok(read) => {
                        let mut owned = Vec::with_capacity(read);
                        owned.extend_from_slice(&payload[..read]);
                        tx.send(ReadMsg::Read(owned)).unwrap();
                    }
                    Err(_) => {
                        tx.send(ReadMsg::Error).unwrap();
                        panic!("ruh roh");
                    }
                }
            }
        });

        Reader {
            rx: rx,
        }
    }
}

<|endoftext|>


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

// Explicitly `use` each name so they are available without
// manual scoping.
use Status::{Poor, Rich};

// Automatically `use` each name inside `Work`.
use Work::*;

enum Status {
    Rich,
    Poor,
}

enum Work {
    Civilian,
    Soldier,
}

fn main() {
    // Equivalent to `Status::Poor`.
    let status = Poor;
    // Equivalent to `Work::Civilian`.
    let work = Civilian;

    match status {
        Rich => println!("The rich have lots of money!"),
        Poor => println!("The poor have no money..."),
    }

    match work {
        Civilian => println!("Civilians work!"),
        Soldier  => println!("Soldiers fight!"),
    }
}
<commit_msg>Move `use` into main<commit_after>// An attribute to hide warnings for unused code.
#![allow(dead_code)]

enum Status {
    Rich,
    Poor,
}

enum Work {
    Civilian,
    Soldier,
}

fn main() {
    // Explicitly `use` each name so they are available without
    // manual scoping.
    use Status::{Poor, Rich};
    // Automatically `use` each name inside `Work`.
    use Work::*;

    // Equivalent to `Status::Poor`.
    let status = Poor;
    // Equivalent to `Work::Civilian`.
    let work = Civilian;

    match status {
        // Note the lack of scoping because of the explicit `use` above.
        Rich => println!("The rich have lots of money!"),
        Poor => println!("The poor have no money..."),
    }

    match work {
        // Note again the lack of scoping.
        Civilian => println!("Civilians work!"),
        Soldier  => println!("Soldiers fight!"),
    }
}
<|endoftext|>


<commit_before><commit_msg>Fixed bad panic message<commit_after><|endoftext|>


<commit_before>//! Functions to be used for clap::Arg::validator()
//! to validate arguments

use std::path::PathBuf;
use boolinator::Boolinator;

pub fn is_file(s: String) -> Result<(), String> {
    PathBuf::from(s.clone()).is_file().as_result((), format!("Not a File: {}", s))
}

pub fn is_directory(s: String) -> Result<(), String> {
    PathBuf::from(s.clone()).is_dir().as_result((), format!("Not a Directory: {}", s))
}

pub fn is_integer(s: String) -> Result<(), String> {
    use std::str::FromStr;

    let i : Result<i64, _> = FromStr::from_str(&s);
    i.map(|_| ()).map_err(|_| format!("Not an integer: {}", s))
}

pub fn is_url(s: String) -> Result<(), String> {
    use url::Url;
    Url::parse(&s).map(|_| ()).map_err(|_| format!("Not a URL: {}", s))
}

pub fn is_tag(s: String) -> Result<(), String> {
    use regex::Regex;
    lazy_static! { static ref TAG_RE : Regex = Regex::new("[:alpha:][:word:]*").unwrap(); }

    TAG_RE
        .is_match(&s)
        .as_result((), format!("Not a valid Tag: '{}' - Valid is [a-zA-Z][0-9a-zA-Z]*", s))
}

<commit_msg>Add cli validator: is_existing_path()<commit_after>//! Functions to be used for clap::Arg::validator()
//! to validate arguments

use std::path::PathBuf;
use boolinator::Boolinator;

pub fn is_existing_path(s: String) -> Result<(), String> {
    PathBuf::from(s.clone()).exists().as_result((), format!("Not a File or Directory: {}", s))
}

pub fn is_file(s: String) -> Result<(), String> {
    PathBuf::from(s.clone()).is_file().as_result((), format!("Not a File: {}", s))
}

pub fn is_directory(s: String) -> Result<(), String> {
    PathBuf::from(s.clone()).is_dir().as_result((), format!("Not a Directory: {}", s))
}

pub fn is_integer(s: String) -> Result<(), String> {
    use std::str::FromStr;

    let i : Result<i64, _> = FromStr::from_str(&s);
    i.map(|_| ()).map_err(|_| format!("Not an integer: {}", s))
}

pub fn is_url(s: String) -> Result<(), String> {
    use url::Url;
    Url::parse(&s).map(|_| ()).map_err(|_| format!("Not a URL: {}", s))
}

pub fn is_tag(s: String) -> Result<(), String> {
    use regex::Regex;
    lazy_static! { static ref TAG_RE : Regex = Regex::new("[:alpha:][:word:]*").unwrap(); }

    TAG_RE
        .is_match(&s)
        .as_result((), format!("Not a valid Tag: '{}' - Valid is [a-zA-Z][0-9a-zA-Z]*", s))
}

<|endoftext|>