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

use language_tags::LanguageTag;

/// Contextual configuration data.
#[derive(Clone)]
pub struct Context {
    /// The language being localized for.
    pub language_tag: LanguageTag,
    /// The value to use in a `PlaceholderFormat`.
    pub placeholder_value: Option<i64>,
}

impl Context {
    /// Create a new instance of `Context`.
    pub fn new(language: LanguageTag, placeholder_value: Option<i64>) -> Self {
        Context {
            language_tag: language,
            placeholder_value: placeholder_value,
        }
    }
}

impl Default for Context {
    fn default() -> Self {
        Context {
            language_tag: Default::default(),
            placeholder_value: None,
        }
    }
}
<commit_msg>Add Context::format, Context::write.<commit_after>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use language_tags::LanguageTag;
use std::fmt;

use {Args, Message};

/// Contextual configuration data.
#[derive(Clone)]
pub struct Context {
    /// The language being localized for.
    pub language_tag: LanguageTag,
    /// The value to use in a `PlaceholderFormat`.
    pub placeholder_value: Option<i64>,
}

impl Context {
    /// Create a new instance of `Context`.
    pub fn new(language: LanguageTag, placeholder_value: Option<i64>) -> Self {
        Context {
            language_tag: language,
            placeholder_value: placeholder_value,
        }
    }

    /// Format a message, returning a string.
    pub fn format<'f>(&self, message: &'f Message, args: &'f Args<'f>) -> String {
        let mut output = String::new();
        let _ = message.write_message(self, &mut output, args);
        output
    }

    /// Write a message to a stream.
    pub fn write<'f>(&self,
                     message: &'f Message,
                     stream: &mut fmt::Write,
                     args: &'f Args<'f>)
                     -> fmt::Result {
        message.write_message(self, stream, args)
    }
}

impl Default for Context {
    fn default() -> Self {
        Context {
            language_tag: Default::default(),
            placeholder_value: None,
        }
    }
}
<|endoftext|>


<commit_before>use netcdf;
use netcdf::file::File as NcFile;
use tile::{Tile,LonLatBbox,lat_wgs84_to_meters,lon_wgs84_to_meters};
use tiledata::TileData;

pub struct Dataset {
    lat: Vec<f64>,
    lon: Vec<f64>,
    variable_name: String,
    file: NcFile,
}

impl Dataset {
    pub fn new(latitude: &str, longitude: &str, variable: &str, file_name: &str) -> Result<Self,String> {
        let file = netcdf::open(file_name)?;
        let lat: Vec<f64> = file.root.variables
            .get(latitude)
            .ok_or("No latitude")?
            .values()?;
        let lon: Vec<f64> = file.root.variables
            .get(longitude)
            .ok_or("No longitude")?
            .values()?;
        Ok(
            Self {
                lat: lat,
                lon: lon,
                variable_name: variable.into(),
                file: file,
            }
        )
    }

    /**
     * Get the fill value of the dataset
     */
    pub fn get_fill_value(&self) -> Option<f32> {
        if let Some(var) =  self.file.root.variables.get(&self.variable_name) {
            if let Some(attr) = var.attributes.get("_FillValue") {
                 return attr.get_float(true).ok();
            }
        }
        None
    }

    /**
     * Check if the bounding box is not strictly outside
     * the lon/lat range of the dataset
     */
    fn contains_bbox(&self, bbox: &LonLatBbox) -> bool {
        let (lon_min, lon_max) = (self.lon[0], self.lon[self.lon.len() -1 ]);
        let (lat_min, lat_max) = (self.lat[0], self.lat[self.lat.len() -1 ]);
        if bbox.west <= lon_min && bbox.east <= lon_min {
            return false;
        }
        if bbox.west >= lon_max && bbox.east >= lon_max {
            return false;
        }
        if bbox.south <= lat_min && bbox.north <= lat_min {
            return false;
        }
        if bbox.south >= lat_max && bbox.north >= lat_max  {
            return false;
        }
        return true;
    }

    /**
     * Extract data from the netCDF dataset
     * and pack it into a TileData
     */
    pub fn get_tile_data(&self, tile: &Tile) -> Result<TileData, String> {
        let bbox = tile.bounds();
        if !self.contains_bbox(&bbox) {
            return Err("tile outside range".into());
        }

        // get longitude indices containing the tile data
        let (mut i_lon_min, mut i_lon_max) = (0, self.lon.len() - 1);
        for i in 0..self.lon.len() {
            if bbox.west == self.lon[i] {
                i_lon_min = i;
                break;
            } else if bbox.west > self.lon[i] {
                i_lon_min = if i != 0 { i - 1 } else { 0 };
                break;
            }
        }
        for i in i_lon_min..self.lon.len() {
            if bbox.east <= self.lon[i] {
                i_lon_max = i;
                break;
            }

        }
        // get latitude indices containing the tile data
        let (mut i_lat_min, mut i_lat_max) = (0, self.lat.len() - 1);
        for i in 0..self.lat.len() {
            if bbox.south == self.lat[i] {
                i_lat_min = i;
                break;
            } else if bbox.south > self.lat[i] {
                i_lat_min = if i != 0 { i - 1 } else { 0 };
                break;
            }
        }
        for i in i_lat_min..self.lat.len() {
            if bbox.north <= self.lat[i] {
                i_lat_max = i;
                break;
            }

        }
        // Extract data from the netCDF Dataset
        if let Some(variable) = self.file.root.variables.get(&self.variable_name) {

            // Compute values slice size (must be > 0)
            let slice_size = [
                i_lat_max - i_lat_min + 1,
                i_lon_max - i_lon_min + 1
            ];

            let tile_values = variable.values_at(&[i_lat_min, i_lon_min], &slice_size)?;
            // Convert longitude and latitude into meters
            let lon: Vec<f64> = self.lon[i_lon_min..i_lon_max + 1]
                .iter().map(|x| lon_wgs84_to_meters(*x)).collect();
            let lat: Vec<f64> = self.lat[i_lat_min..i_lat_max + 1]
                .iter().map(|x| lat_wgs84_to_meters(*x)).collect();

            return Ok(
                TileData {
                    lon: lon,
                    lat: lat,
                    values: tile_values,
                    bbox: tile.xy_bounds()
                }
            );
        }
        Err("Error while fetching tile, no variable found".into())
    }
}

#[test]
fn dataset_creation() {
    let dataset_path = "./dataset/wind_magnitude_reduced.nc";
    let dataset = Dataset::new(
        "latitude",
        "longitude",
        "wind_magnitude",
        dataset_path
    );
    assert!(dataset.is_ok());
}

#[test]
fn test_data_fetch() {
    let dataset_path = "./dataset/wind_magnitude_reduced.nc";
    let dataset = Dataset::new(
        "latitude",
        "longitude",
        "wind_magnitude",
        dataset_path
    ).unwrap();
    let tile = Tile {
        x: 15,
        y: 15,
        z: 9,
    };
    let values = dataset.get_tile_data(&tile);
    assert!(&values.is_ok());
}
<commit_msg>Fix dataset path in test<commit_after>use netcdf;
use netcdf::file::File as NcFile;
use tile::{Tile,LonLatBbox,lat_wgs84_to_meters,lon_wgs84_to_meters};
use tiledata::TileData;

pub struct Dataset {
    lat: Vec<f64>,
    lon: Vec<f64>,
    variable_name: String,
    file: NcFile,
}

impl Dataset {
    pub fn new(latitude: &str, longitude: &str, variable: &str, file_name: &str) -> Result<Self,String> {
        let file = netcdf::open(file_name)?;
        let lat: Vec<f64> = file.root.variables
            .get(latitude)
            .ok_or("No latitude")?
            .values()?;
        let lon: Vec<f64> = file.root.variables
            .get(longitude)
            .ok_or("No longitude")?
            .values()?;
        Ok(
            Self {
                lat: lat,
                lon: lon,
                variable_name: variable.into(),
                file: file,
            }
        )
    }

    /**
     * Get the fill value of the dataset
     */
    pub fn get_fill_value(&self) -> Option<f32> {
        if let Some(var) =  self.file.root.variables.get(&self.variable_name) {
            if let Some(attr) = var.attributes.get("_FillValue") {
                 return attr.get_float(true).ok();
            }
        }
        None
    }

    /**
     * Check if the bounding box is not strictly outside
     * the lon/lat range of the dataset
     */
    fn contains_bbox(&self, bbox: &LonLatBbox) -> bool {
        let (lon_min, lon_max) = (self.lon[0], self.lon[self.lon.len() -1 ]);
        let (lat_min, lat_max) = (self.lat[0], self.lat[self.lat.len() -1 ]);
        if bbox.west <= lon_min && bbox.east <= lon_min {
            return false;
        }
        if bbox.west >= lon_max && bbox.east >= lon_max {
            return false;
        }
        if bbox.south <= lat_min && bbox.north <= lat_min {
            return false;
        }
        if bbox.south >= lat_max && bbox.north >= lat_max  {
            return false;
        }
        return true;
    }

    /**
     * Extract data from the netCDF dataset
     * and pack it into a TileData
     */
    pub fn get_tile_data(&self, tile: &Tile) -> Result<TileData, String> {
        let bbox = tile.bounds();
        if !self.contains_bbox(&bbox) {
            return Err("tile outside range".into());
        }

        // get longitude indices containing the tile data
        let (mut i_lon_min, mut i_lon_max) = (0, self.lon.len() - 1);
        for i in 0..self.lon.len() {
            if bbox.west == self.lon[i] {
                i_lon_min = i;
                break;
            } else if bbox.west > self.lon[i] {
                i_lon_min = if i != 0 { i - 1 } else { 0 };
                break;
            }
        }
        for i in i_lon_min..self.lon.len() {
            if bbox.east <= self.lon[i] {
                i_lon_max = i;
                break;
            }

        }
        // get latitude indices containing the tile data
        let (mut i_lat_min, mut i_lat_max) = (0, self.lat.len() - 1);
        for i in 0..self.lat.len() {
            if bbox.south == self.lat[i] {
                i_lat_min = i;
                break;
            } else if bbox.south > self.lat[i] {
                i_lat_min = if i != 0 { i - 1 } else { 0 };
                break;
            }
        }
        for i in i_lat_min..self.lat.len() {
            if bbox.north <= self.lat[i] {
                i_lat_max = i;
                break;
            }

        }
        // Extract data from the netCDF Dataset
        if let Some(variable) = self.file.root.variables.get(&self.variable_name) {

            // Compute values slice size (must be > 0)
            let slice_size = [
                i_lat_max - i_lat_min + 1,
                i_lon_max - i_lon_min + 1
            ];

            let tile_values = variable.values_at(&[i_lat_min, i_lon_min], &slice_size)?;
            // Convert longitude and latitude into meters
            let lon: Vec<f64> = self.lon[i_lon_min..i_lon_max + 1]
                .iter().map(|x| lon_wgs84_to_meters(*x)).collect();
            let lat: Vec<f64> = self.lat[i_lat_min..i_lat_max + 1]
                .iter().map(|x| lat_wgs84_to_meters(*x)).collect();

            return Ok(
                TileData {
                    lon: lon,
                    lat: lat,
                    values: tile_values,
                    bbox: tile.xy_bounds()
                }
            );
        }
        Err("Error while fetching tile, no variable found".into())
    }
}

#[test]
fn dataset_creation() {
    let dataset_path = "./examples_data/wind_magnitude_reduced.nc";
    let dataset = Dataset::new(
        "latitude",
        "longitude",
        "wind_magnitude",
        dataset_path
    );
    assert!(dataset.is_ok());
}

#[test]
fn test_data_fetch() {
    let dataset_path = "./examples_data/wind_magnitude_reduced.nc";
    let dataset = Dataset::new(
        "latitude",
        "longitude",
        "wind_magnitude",
        dataset_path
    ).unwrap();
    let tile = Tile {
        x: 15,
        y: 15,
        z: 9,
    };
    let values = dataset.get_tile_data(&tile);
    assert!(&values.is_ok());
}
<|endoftext|>


<commit_before>use std::thread;
use std::io;
use std::io::Read;
use std::sync::mpsc;
use std::sync::mpsc::{SyncSender, Receiver, RecvError};
use std::default::Default;
use std::marker::Send;
use std::option::Option::{None, Some};
use libc::types::common::c95::c_void;
use libc::types::common::c99::*;
use libc::types::os::arch::c95::*;

enum Error {
    Mad(MadError),
    Recv(RecvError),
}

struct Decoder {
    rx: Box<Receiver<Result<Frame, MadError>>>,
}

impl Decoder {
    fn new(reader: Box<io::Read + Send + 'static>) -> Decoder {
        Decoder {
            rx: Box::new(decode(reader)),
        }
    }

    pub fn get_frame(&self) -> Result<Frame, Error> {
        match self.rx.recv() {
            Err(e) => Err(Error::Recv(e)),
            Ok(Err(e)) => Err(Error::Mad(e)),
            Ok(Ok(frame)) => Ok(frame),
        }
    }
}

impl Iterator for Decoder {
    type Item = Result<Frame, MadError>;
    fn next(&mut self) -> Option<Result<Frame, MadError>> {
        match self.get_frame() {
            Err(Error::Recv(e)) => None,
            Err(Error::Mad(e)) => Some(Err(e)),
            Ok(frame) => Some(Ok(frame)),
        }
    }
}

#[allow(unused, improper_ctypes)]
#[link(name = "mad")]
extern {
    fn mad_decoder_init(decoder: *mut MadDecoder,
                        message: *mut c_void,
                        input_callback: extern fn(message: *mut MadMessage,
                                                  stream: &MadStream) -> MadFlow,
                        header_callback: extern fn(),
                        filter_callback: extern fn(),
                        output_callback: extern fn(message: *mut MadMessage,
                                                   header: c_int,
                                                   pcm: &MadPcm) -> MadFlow,
                        error_callback: extern fn(message: *mut MadMessage,
                                                  stream: &MadStream,
                                                  frame: c_int) -> MadFlow,
                        message_callback: extern fn());
    #[allow(dead_code)]
    fn mad_decoder_run(input: &mut MadDecoder, mode: MadDecoderMode) -> c_int;
    fn mad_stream_buffer(stream: &MadStream, buf_start: *const u8, buf_length: size_t);
}

#[allow(unused)]
#[repr(C)]
enum MadFlow {
    Continue = 0x0000,    /* continue normally */
    Stop     = 0x0010,    /* stop decoding normally */
    Break    = 0x0011,    /* stop decoding and signal an error */
    Ignore   = 0x0020    /* ignore the current frame */
}

#[allow(unused)]
#[derive(Debug, Clone)]
#[repr(C)]
pub enum MadError {
  None           = 0x0000,    /* no error */

  BufLen         = 0x0001,    /* input buffer too small (or eof) */
  BufPtr         = 0x0002,    /* invalid (null) buffer pointer */

  NoMem          = 0x0031,    /* not enough memory */

  LostSync       = 0x0101,    /* lost synchronization */
  BadLayer       = 0x0102,    /* reserved header layer value */
  BadBitRate     = 0x0103,    /* forbidden bitrate value */
  BadSampleRate  = 0x0104,    /* reserved sample frequency value */
  BadEmphasis    = 0x0105,    /* reserved emphasis value */

  BadCRC         = 0x0201,    /* crc check failed */
  BadBitAlloc    = 0x0211,    /* forbidden bit allocation value */
  BadScaleFactor = 0x0221,    /* bad scalefactor index */
  BadMode        = 0x0222,    /* bad bitrate/mode combination */
  BadFrameLen    = 0x0231,    /* bad frame length */
  BadBigValues   = 0x0232,    /* bad big_values count */
  BadBlockType   = 0x0233,    /* reserved block_type */
  BadScFSI       = 0x0234,    /* bad scalefactor selection info */
  BadDataPtr     = 0x0235,    /* bad main_data_begin pointer */
  BadPart3Len    = 0x0236,    /* bad audio data length */
  BadHuffTable   = 0x0237,    /* bad huffman table select */
  BadHuffData    = 0x0238,    /* huffman data overrun */
  BadStereo      = 0x0239,    /* incompatible block_type for js */
}

#[allow(unused)]
#[repr(C)]
struct MadBitPtr {
    byte: size_t,
    cache: uint16_t,
    left: uint16_t,
}

#[allow(unused)]
#[repr(C)]
struct MadStream {
    buffer: size_t,
    buff_end: size_t,
    skip_len: c_ulong,
    sync: c_int,
    free_rate: c_ulong,
    this_frame: size_t,
    next_frame: size_t,
    ptr: MadBitPtr,
    anc_ptr: MadBitPtr,
    anc_bitlen: c_uint,
    buffer_mdlen: size_t,
    md_len: c_uint,
    options: c_int,
    error: MadError,
}

#[allow(unused)]
#[repr(C)]
struct MadPcm {
    sample_rate: c_uint,
    channels: uint16_t,
    length: uint16_t,
    samples: [[int32_t; 1152]; 2],
}

#[allow(unused)]
struct MadMessage<'a> {
    buffer: Box<[u8; 16384]>,
    reader: &'a mut (io::Read + 'a),
    sender: &'a SyncSender<Result<Frame, MadError>>,
}

#[allow(unused)]
#[repr(C)]
enum MadDecoderMode {
    Sync = 0,
    Async
}

impl Default for MadDecoderMode {
    fn default() -> MadDecoderMode {MadDecoderMode::Sync}
}

#[derive(Default)]
#[repr(C)]
struct MadAsyncParameters {
    pid: c_long,
    ain: c_int,
    aout: c_int,
}

#[derive(Default)]
#[repr(C)]
struct MadDecoder {
    mode: MadDecoderMode,
    options: c_int,
    async: MadAsyncParameters,
    sync: size_t,
    cb_data: size_t,
    input_func: size_t,
    header_func: size_t,
    filter_func: size_t,
    output_func: size_t,
    error_func: size_t,
    message_func: size_t,
}

#[allow(unused)]
pub struct Frame {
    pub sample_rate: u32,
    pub channels: uint16_t,
    pub length: uint16_t,
    pub samples: [[i32; 1152]; 2],
}

#[allow(unused)]
extern fn empty_callback() {

}

#[allow(unused)]
extern fn input_callback (msg: *mut MadMessage, stream: &MadStream) -> MadFlow {
    unsafe {
        let buffer_size = (*msg).buffer.len();
        let next_frame_position = (stream.next_frame - stream.buffer) as usize;
        let unused_byte_count = buffer_size - next_frame_position;

        if unused_byte_count > 0 {
            for idx in 0 .. unused_byte_count {
                (*msg).buffer[idx] = (*msg).buffer[idx + next_frame_position];
            }
        }

        let mut bytes_read = None;

        if next_frame_position == 0 {
            bytes_read = Some((*msg).reader.read(&mut *(*msg).buffer).unwrap());
        } else {
            let slice = &mut (*msg).buffer[unused_byte_count .. buffer_size];
            bytes_read = Some((*msg).reader.read(slice).unwrap());
        }

        match bytes_read {
            None    => return MadFlow::Stop,
            Some(0) => return MadFlow::Stop,
            Some(n) => mad_stream_buffer(stream, (*msg).buffer.as_ptr(), n as u64),
        }
    }

    MadFlow::Continue
}

#[allow(unused)]
extern fn error_callback(msg: *mut MadMessage,
                         stream: &MadStream,
                         frame: c_int) -> MadFlow
{
    unsafe {
        let error_type = stream.error.clone();
        (*msg).sender.send(Err(error_type));
    }
    MadFlow::Continue
}

#[allow(unused)]
extern fn output_callback(msg: *mut MadMessage,
                          header: c_int,
                          pcm: &MadPcm) -> MadFlow
{
    unsafe {
        let frame = Ok(Frame {sample_rate: pcm.sample_rate,
                              channels: pcm.channels,
                              length: pcm.length,
                              samples: pcm.samples});
        (*msg).sender.send(frame);
    }
    MadFlow::Continue
}

#[allow(unused)]
pub fn decode<T>(mut reader: T) -> Receiver<Result<Frame, MadError>>
    where T: io::Read + Send + 'static {
    let input_buffer = Box::new([0u8; 16384]);
    let (tx, rx) = mpsc::sync_channel::<Result<Frame, MadError>>(2);
    thread::spawn(move || {
        unsafe {
            let mut message = MadMessage {
                buffer: input_buffer,
                reader: &mut reader,
                sender: &tx,
            };
            let message_ptr = &mut message as *mut _ as *mut c_void;
            let mut decoder: MadDecoder = Default::default();
            mad_decoder_init(&mut decoder,
                             message_ptr,
                             input_callback,
                             empty_callback,
                             empty_callback,
                             output_callback,
                             error_callback,
                             empty_callback);
            mad_decoder_run(&mut decoder, MadDecoderMode::Sync);
        }
    });
    rx
}

#[test]
fn data_sizes() {
    use std::mem::size_of;
    assert_eq!(size_of::<MadError>(), 4);
    assert_eq!(size_of::<MadBitPtr>(), 16);
    assert_eq!(size_of::<MadDecoder>(), 88);
    assert_eq!(size_of::<MadPcm>(), 9224);
    assert_eq!(size_of::<MadStream>(), 120);
}

#[test]
fn test_short_file() {
    use std::path::Path;
    use std::fs::File;
    let path = Path::new("test_samples/tailtoddle_lo.mp3");
    let f = File::open(&path).unwrap();
    let decoder = Decoder::new(Box::new(f));
    let mut frame_count = 0;
    let mut error_count = 0;

    for item in decoder {
        match item {
            Err(_) => error_count += 1,
            Ok(f) => {
                frame_count += 1;
                println!("Frame data: {}, {}, {}", f.sample_rate, f.channels, f.length);
                for sample in f.samples[0].iter() {
                    println!("{}", sample);
                }
            }
        }
    }
    assert_eq!(frame_count, 1656);
    assert_eq!(error_count, 1);
}

<commit_msg>General improvements<commit_after>use std::thread;
use std::io;
use std::io::Read;
use std::sync::mpsc;
use std::sync::mpsc::{SyncSender, Receiver, RecvError};
use std::default::Default;
use std::marker::Send;
use std::option::Option::{None, Some};
use libc::types::common::c95::c_void;
use libc::types::common::c99::*;
use libc::types::os::arch::c95::*;

enum Error {
    Mad(MadError),
    Recv(RecvError),
}

struct Decoder {
    rx: Box<Receiver<Result<Frame, MadError>>>,
}

impl Decoder {
    #[allow(dead_code)]
    fn new(reader: Box<io::Read + Send + 'static>) -> Decoder {
        Decoder {
            rx: Box::new(decode(reader)),
        }
    }

    pub fn get_frame(&self) -> Result<Frame, Error> {
        match self.rx.recv() {
            Err(e) => Err(Error::Recv(e)),
            Ok(Err(e)) => Err(Error::Mad(e)),
            Ok(Ok(frame)) => Ok(frame),
        }
    }
}

impl Iterator for Decoder {
    type Item = Result<Frame, MadError>;
    fn next(&mut self) -> Option<Result<Frame, MadError>> {
        match self.get_frame() {
            Err(Error::Recv(_)) => None,
            Err(Error::Mad(e)) => Some(Err(e)),
            Ok(frame) => Some(Ok(frame)),
        }
    }
}

#[allow(unused, improper_ctypes)]
#[link(name = "mad")]
extern {
    fn mad_decoder_init(decoder: *mut MadDecoder,
                        message: *mut c_void,
                        input_cb: extern fn(message: *mut MadMessage,
                                                  stream: &MadStream) -> MadFlow,
                        header_cb: extern fn(),
                        filter_cb: extern fn(),
                        output_cb: extern fn(message: *mut MadMessage,
                                                   header: c_int,
                                                   pcm: &MadPcm) -> MadFlow,
                        error_cb: extern fn(message: *mut MadMessage,
                                                  stream: &MadStream,
                                                  frame: c_int) -> MadFlow,
                        message_cb: extern fn());
    #[allow(dead_code)]
    fn mad_decoder_run(input: &mut MadDecoder, mode: MadDecoderMode) -> c_int;
    fn mad_stream_buffer(stream: &MadStream, buf_start: *const u8, buf_length: size_t);
}

#[allow(unused)]
#[repr(C)]
enum MadFlow {
    Continue = 0x0000,    /* continue normally */
    Stop     = 0x0010,    /* stop decoding normally */
    Break    = 0x0011,    /* stop decoding and signal an error */
    Ignore   = 0x0020    /* ignore the current frame */
}

#[allow(unused)]
#[derive(Debug, Clone)]
#[repr(C)]
pub enum MadError {
  None           = 0x0000,    /* no error */

  BufLen         = 0x0001,    /* input buffer too small (or eof) */
  BufPtr         = 0x0002,    /* invalid (null) buffer pointer */

  NoMem          = 0x0031,    /* not enough memory */

  LostSync       = 0x0101,    /* lost synchronization */
  BadLayer       = 0x0102,    /* reserved header layer value */
  BadBitRate     = 0x0103,    /* forbidden bitrate value */
  BadSampleRate  = 0x0104,    /* reserved sample frequency value */
  BadEmphasis    = 0x0105,    /* reserved emphasis value */

  BadCRC         = 0x0201,    /* crc check failed */
  BadBitAlloc    = 0x0211,    /* forbidden bit allocation value */
  BadScaleFactor = 0x0221,    /* bad scalefactor index */
  BadMode        = 0x0222,    /* bad bitrate/mode combination */
  BadFrameLen    = 0x0231,    /* bad frame length */
  BadBigValues   = 0x0232,    /* bad big_values count */
  BadBlockType   = 0x0233,    /* reserved block_type */
  BadScFSI       = 0x0234,    /* bad scalefactor selection info */
  BadDataPtr     = 0x0235,    /* bad main_data_begin pointer */
  BadPart3Len    = 0x0236,    /* bad audio data length */
  BadHuffTable   = 0x0237,    /* bad huffman table select */
  BadHuffData    = 0x0238,    /* huffman data overrun */
  BadStereo      = 0x0239,    /* incompatible block_type for js */
}

#[allow(unused)]
#[repr(C)]
struct MadBitPtr {
    byte: size_t,
    cache: uint16_t,
    left: uint16_t,
}

#[allow(unused)]
#[repr(C)]
struct MadStream {
    buffer: size_t,
    buff_end: size_t,
    skip_len: c_ulong,
    sync: c_int,
    free_rate: c_ulong,
    this_frame: size_t,
    next_frame: size_t,
    ptr: MadBitPtr,
    anc_ptr: MadBitPtr,
    anc_bitlen: c_uint,
    buffer_mdlen: size_t,
    md_len: c_uint,
    options: c_int,
    error: MadError,
}

#[allow(unused)]
#[repr(C)]
struct MadPcm {
    sample_rate: c_uint,
    channels: uint16_t,
    length: uint16_t,
    samples: [[int32_t; 1152]; 2],
}

#[allow(unused)]
struct MadMessage<'a> {
    buffer: Box<[u8; 16384]>,
    reader: &'a mut (io::Read + 'a),
    sender: &'a SyncSender<Result<Frame, MadError>>,
}

#[allow(unused)]
#[repr(C)]
enum MadDecoderMode {
    Sync = 0,
    Async
}

impl Default for MadDecoderMode {
    fn default() -> MadDecoderMode {MadDecoderMode::Sync}
}

#[derive(Default)]
#[repr(C)]
struct MadAsyncParameters {
    pid: c_long,
    ain: c_int,
    aout: c_int,
}

#[derive(Default)]
#[repr(C)]
struct MadDecoder {
    mode: MadDecoderMode,
    options: c_int,
    async: MadAsyncParameters,
    sync: size_t,
    cb_data: size_t,
    input_func: size_t,
    header_func: size_t,
    filter_func: size_t,
    output_func: size_t,
    error_func: size_t,
    message_func: size_t,
}

#[allow(unused)]
pub struct Frame {
    pub sample_rate: u32,
    pub channels: uint16_t,
    pub length: uint16_t,
    pub samples: Vec<Vec<i32>>,
}

#[allow(unused)]
extern fn empty_cb() {

}

#[allow(unused)]
extern fn input_cb (msg: *mut MadMessage, stream: &MadStream) -> MadFlow {
    unsafe {
        let buffer_size = (*msg).buffer.len();
        let next_frame_position = (stream.next_frame - stream.buffer) as usize;
        let unused_byte_count = buffer_size - next_frame_position;

        if unused_byte_count > 0 {
            for idx in 0 .. unused_byte_count {
                (*msg).buffer[idx] = (*msg).buffer[idx + next_frame_position];
            }
        }

        let mut bytes_read = None;

        if next_frame_position == 0 {
            bytes_read = Some((*msg).reader.read(&mut *(*msg).buffer).unwrap());
        } else {
            let slice = &mut (*msg).buffer[unused_byte_count .. buffer_size];
            bytes_read = Some((*msg).reader.read(slice).unwrap());
        }

        match bytes_read {
            None    => return MadFlow::Stop,
            Some(0) => return MadFlow::Stop,
            Some(n) => mad_stream_buffer(stream, (*msg).buffer.as_ptr(), n as u64),
        }
    }

    MadFlow::Continue
}

#[allow(unused)]
extern fn error_cb(msg: *mut MadMessage,
                         stream: &MadStream,
                         frame: c_int) -> MadFlow
{
    unsafe {
        let error_type = stream.error.clone();
        (*msg).sender.send(Err(error_type));
    }
    MadFlow::Continue
}

#[allow(unused)]
extern fn output_cb(msg: *mut MadMessage, header: c_int, pcm: &MadPcm) -> MadFlow {
    let mut samples: Vec<Vec<i32>> = Vec::new();
    for channel_idx in 0..pcm.channels as usize {
        let mut channel: Vec<i32> = Vec::new();
        for sample_idx in 0 .. pcm.length as usize {
            channel.push(pcm.samples[channel_idx][sample_idx]);
        }
        samples.push(channel);
    }
    let frame = Ok(Frame {sample_rate: pcm.sample_rate,
                          channels: pcm.channels,
                          length: pcm.length,
                          samples: samples});
    unsafe {
        (*msg).sender.send(frame);
    }
    MadFlow::Continue
}

fn decode<T>(mut reader: T) -> Receiver<Result<Frame, MadError>>
    where T: io::Read + Send + 'static {
    let input_buffer = Box::new([0u8; 16384]);
    let (tx, rx) = mpsc::sync_channel::<Result<Frame, MadError>>(2);
    thread::spawn(move || {
        unsafe {
            let mut message = MadMessage {
                buffer: input_buffer,
                reader: &mut reader,
                sender: &tx,
            };
            let message_ptr = &mut message as *mut _ as *mut c_void;
            let mut decoder: MadDecoder = Default::default();
            mad_decoder_init(&mut decoder,
                             message_ptr,
                             input_cb,
                             empty_cb,
                             empty_cb,
                             output_cb,
                             error_cb,
                             empty_cb);
            mad_decoder_run(&mut decoder, MadDecoderMode::Sync);
        }
    });
    rx
}

#[test]
fn data_sizes() {
    use std::mem::size_of;
    assert_eq!(size_of::<MadError>(), 4);
    assert_eq!(size_of::<MadBitPtr>(), 16);
    assert_eq!(size_of::<MadDecoder>(), 88);
    assert_eq!(size_of::<MadPcm>(), 9224);
    assert_eq!(size_of::<MadStream>(), 120);
}

#[test]
fn test_short_file() {
    use std::path::Path;
    use std::fs::File;
    let path = Path::new("test_samples/tailtoddle_lo.mp3");
    let f = File::open(&path).unwrap();
    let decoder = Decoder::new(Box::new(f));
    let mut frame_count = 0;
    let mut error_count = 0;

    for item in decoder {
        match item {
            Err(_) => error_count += 1,
            Ok(f) => {
                frame_count += 1;
                assert_eq!(f.sample_rate, 11025);
                assert_eq!(f.channels, 2);
                assert_eq!(f.length, 576);
            }
        }
    }
    assert_eq!(frame_count, 1656);
    assert_eq!(error_count, 1);
}

<|endoftext|>


<commit_before>use DecodeError;

pub struct AsciiDecoder;
pub struct Utf8Decoder;

macro_rules! decode {
    ($alpha:ident, $input:ident, $iter:ident, $c:pat => $carry:expr) => ({
        if $input.len() == 0 {
            return Ok(Vec::new());
        }

        let base = $alpha.len() as u16;

        let mut bytes = Vec::with_capacity($input.len());
        bytes.push(0u8);

        for $c in $input.$iter() {
            let mut carry = $carry as u16;

            for byte in bytes.iter_mut() {
                carry += base * *byte as u16;
                *byte = carry as u8;
                carry >>= 8;
            }

            while carry > 0 {
                bytes.push(carry as u8);
                carry >>= 8;
            }
        }

        let leader = $alpha[0];

        let leaders = $input
            .$iter()
            .take($input.len() - 1)
            .take_while(|byte| *byte == leader)
            .map(|_| 0);

        bytes.extend(leaders);
        bytes.reverse();
        Ok(bytes)
    })
}

impl AsciiDecoder {
    #[inline(always)]
    pub fn decode(alphabet: &[u8], lookup: [u8; 256], input: &str) -> Result<Vec<u8>, DecodeError> {
        decode!(alphabet, input, bytes, c => match lookup[c as usize] {
            0xFF => return Err(DecodeError),
            index => index
        })
    }
}

impl Utf8Decoder {
    #[inline(always)]
    pub fn decode(alphabet: &[char], input: &str) -> Result<Vec<u8>, DecodeError> {
        decode!(alphabet, input, chars, c => alphabet.iter()
                                                    .enumerate()
                                                    .find(|&(_, ch)| *ch == c)
                                                    .map(|(i, _)| i)
                                                    .ok_or(DecodeError)?)
    }
}
<commit_msg>formatting<commit_after>use DecodeError;

pub struct AsciiDecoder;
pub struct Utf8Decoder;

macro_rules! decode {
    ($alpha:ident, $input:ident, $iter:ident, $c:pat => $carry:expr) => ({
        if $input.len() == 0 {
            return Ok(Vec::new());
        }

        let base = $alpha.len() as u16;

        let mut bytes = Vec::with_capacity($input.len());
        bytes.push(0u8);

        for $c in $input.$iter() {
            let mut carry = $carry as u16;

            for byte in bytes.iter_mut() {
                carry += base * *byte as u16;
                *byte = carry as u8;
                carry >>= 8;
            }

            while carry > 0 {
                bytes.push(carry as u8);
                carry >>= 8;
            }
        }

        let leader = $alpha[0];

        let leaders = $input
            .$iter()
            .take($input.len() - 1)
            .take_while(|byte| *byte == leader)
            .map(|_| 0);

        bytes.extend(leaders);
        bytes.reverse();
        Ok(bytes)
    })
}

impl AsciiDecoder {
    #[inline(always)]
    pub fn decode(alphabet: &[u8], lookup: [u8; 256], input: &str) -> Result<Vec<u8>, DecodeError> {
        decode!(
            alphabet,
            input,
            bytes,
            c => match lookup[c as usize] {
                0xFF => return Err(DecodeError),
                index => index
            }
        )
    }
}

impl Utf8Decoder {
    #[inline(always)]
    pub fn decode(alphabet: &[char], input: &str) -> Result<Vec<u8>, DecodeError> {
        decode!(
            alphabet,
            input,
            chars,
            // Vector find is faster than HashMap even for Base58
            c => alphabet
                .iter()
                .enumerate()
                .find(|&(_, ch)| *ch == c)
                .map(|(i, _)| i)
                .ok_or(DecodeError)?
        )
    }
}
<|endoftext|>


<commit_before>use crate::{dns_probe_udp, DnsUDPParser};
use crate::rparser::{RBuilder, RParser, R_STATUS_FAIL};
use nom::error::ErrorKind;
use nom::number::streaming::be_u16;

pub struct DnsTCPBuilder {}
impl RBuilder for DnsTCPBuilder {
    fn new(&self) -> Box<dyn RParser> {
        Box::new(DnsTCPParser::new(b"DNS/TCP"))
    }
    fn probe(&self, i: &[u8]) -> bool {
        dns_probe_tcp(i)
    }
}

pub struct DnsTCPParser<'a> {
    _name: Option<&'a [u8]>,
    parser: DnsUDPParser<'a>,
}

impl<'a> DnsTCPParser<'a> {
    pub fn new(name: &'a [u8]) -> DnsTCPParser<'a> {
        DnsTCPParser {
            _name: Some(name),
            parser: DnsUDPParser::new(name),
        }
    }
}

impl<'a> RParser for DnsTCPParser<'a> {
    fn parse(&mut self, buf: &[u8], direction: u8) -> u32 {
        match be_u16::<(&[u8],ErrorKind)>(buf) {
            Ok((rem,l)) => {
                if l > rem.len() as u16 {
                    return R_STATUS_FAIL;
                }
                self.parser.parse(rem, direction)
            }
            _ => R_STATUS_FAIL
        }
    }
}

pub fn dns_probe_tcp(i: &[u8]) -> bool {
    if i.len() <= 14 {
        return false;
    }
    match be_u16::<(&[u8],ErrorKind)>(i) {
        Ok((rem, record_len)) => {
            if record_len < i.len() as u16 {
                return false;
            }
            if record_len > rem.len() as u16 {
                return false;
            }
            return dns_probe_udp(rem);
        }
        _ => {
            return false;
        }
    }
}
<commit_msg>dns_tcp: fix probing of DNS/TCP<commit_after>use crate::{dns_probe_udp, DnsUDPParser};
use crate::rparser::{RBuilder, RParser, R_STATUS_FAIL};
use nom::error::ErrorKind;
use nom::number::streaming::be_u16;

pub struct DnsTCPBuilder {}
impl RBuilder for DnsTCPBuilder {
    fn new(&self) -> Box<dyn RParser> {
        Box::new(DnsTCPParser::new(b"DNS/TCP"))
    }
    fn probe(&self, i: &[u8]) -> bool {
        dns_probe_tcp(i)
    }
}

pub struct DnsTCPParser<'a> {
    _name: Option<&'a [u8]>,
    parser: DnsUDPParser<'a>,
}

impl<'a> DnsTCPParser<'a> {
    pub fn new(name: &'a [u8]) -> DnsTCPParser<'a> {
        DnsTCPParser {
            _name: Some(name),
            parser: DnsUDPParser::new(name),
        }
    }
}

impl<'a> RParser for DnsTCPParser<'a> {
    fn parse(&mut self, buf: &[u8], direction: u8) -> u32 {
        match be_u16::<(&[u8],ErrorKind)>(buf) {
            Ok((rem,l)) => {
                if l > rem.len() as u16 {
                    return R_STATUS_FAIL;
                }
                self.parser.parse(rem, direction)
            }
            _ => R_STATUS_FAIL
        }
    }
}

pub fn dns_probe_tcp(i: &[u8]) -> bool {
    if i.len() <= 14 {
        return false;
    }
    match be_u16::<(&[u8],ErrorKind)>(i) {
        Ok((rem, record_len)) => {
            if record_len < rem.len() as u16 {
                return false;
            }
            if record_len > rem.len() as u16 {
                return false;
            }
            return dns_probe_udp(rem);
        }
        _ => {
            return false;
        }
    }
}
<|endoftext|>


<commit_before>//! In certain situations, rust automatically inserts derefs as necessary: for
//! example, field accesses `foo.bar` still work when `foo` is actually a
//! reference to a type with the field `bar`. This is an approximation of the
//! logic in rustc (which lives in librustc_typeck/check/autoderef.rs).

use std::iter::successors;

use base_db::CrateId;
use chalk_ir::{cast::Cast, fold::Fold, interner::HasInterner, VariableKind};
use hir_def::lang_item::LangItemTarget;
use hir_expand::name::name;
use limit::Limit;
use tracing::{info, warn};

use crate::{
    db::HirDatabase, static_lifetime, AliasEq, AliasTy, BoundVar, Canonical, CanonicalVarKinds,
    ConstrainedSubst, DebruijnIndex, Environment, Guidance, InEnvironment, Interner,
    ProjectionTyExt, Solution, Substitution, Ty, TyBuilder, TyKind,
};

const AUTODEREF_RECURSION_LIMIT: Limit = Limit::new(10);

pub(crate) enum AutoderefKind {
    Builtin,
    Overloaded,
}

pub(crate) struct Autoderef<'db> {
    db: &'db dyn HirDatabase,
    ty: Canonical<Ty>,
    at_start: bool,
    krate: Option<CrateId>,
    environment: Environment,
    steps: Vec<(AutoderefKind, Ty)>,
}

impl<'db> Autoderef<'db> {
    pub(crate) fn new(
        db: &'db dyn HirDatabase,
        krate: Option<CrateId>,
        ty: InEnvironment<Canonical<Ty>>,
    ) -> Self {
        let InEnvironment { goal: ty, environment } = ty;
        Autoderef { db, ty, at_start: true, environment, krate, steps: Vec::new() }
    }

    pub(crate) fn step_count(&self) -> usize {
        self.steps.len()
    }

    pub(crate) fn steps(&self) -> &[(AutoderefKind, chalk_ir::Ty<Interner>)] {
        &self.steps
    }

    pub(crate) fn final_ty(&self) -> Ty {
        self.ty.value.clone()
    }
}

impl Iterator for Autoderef<'_> {
    type Item = (Canonical<Ty>, usize);

    fn next(&mut self) -> Option<Self::Item> {
        if self.at_start {
            self.at_start = false;
            return Some((self.ty.clone(), 0));
        }

        if AUTODEREF_RECURSION_LIMIT.check(self.steps.len() + 1).is_err() {
            return None;
        }

        let (kind, new_ty) = if let Some(derefed) = builtin_deref(&self.ty.value) {
            (AutoderefKind::Builtin, Canonical { value: derefed, binders: self.ty.binders.clone() })
        } else {
            (
                AutoderefKind::Overloaded,
                deref_by_trait(
                    self.db,
                    self.krate?,
                    InEnvironment { goal: &self.ty, environment: self.environment.clone() },
                )?,
            )
        };

        self.steps.push((kind, self.ty.value.clone()));
        self.ty = new_ty;

        Some((self.ty.clone(), self.step_count()))
    }
}

// FIXME: replace uses of this with Autoderef above
pub fn autoderef<'a>(
    db: &'a dyn HirDatabase,
    krate: Option<CrateId>,
    ty: InEnvironment<Canonical<Ty>>,
) -> impl Iterator<Item = Canonical<Ty>> + 'a {
    let InEnvironment { goal: ty, environment } = ty;
    successors(Some(ty), move |ty| {
        deref(db, krate?, InEnvironment { goal: ty, environment: environment.clone() })
    })
    .take(AUTODEREF_RECURSION_LIMIT.inner())
}

pub(crate) fn deref(
    db: &dyn HirDatabase,
    krate: CrateId,
    ty: InEnvironment<&Canonical<Ty>>,
) -> Option<Canonical<Ty>> {
    let _p = profile::span("deref");
    if let Some(derefed) = builtin_deref(&ty.goal.value) {
        Some(Canonical { value: derefed, binders: ty.goal.binders.clone() })
    } else {
        deref_by_trait(db, krate, ty)
    }
}

fn builtin_deref(ty: &Ty) -> Option<Ty> {
    match ty.kind(&Interner) {
        TyKind::Ref(.., ty) => Some(ty.clone()),
        TyKind::Raw(.., ty) => Some(ty.clone()),
        _ => None,
    }
}

fn deref_by_trait(
    db: &dyn HirDatabase,
    krate: CrateId,
    ty: InEnvironment<&Canonical<Ty>>,
) -> Option<Canonical<Ty>> {
    let _p = profile::span("deref_by_trait");
    let deref_trait = match db.lang_item(krate, "deref".into())? {
        LangItemTarget::TraitId(it) => it,
        _ => return None,
    };
    let target = db.trait_data(deref_trait).associated_type_by_name(&name![Target])?;

    let projection = {
        let b = TyBuilder::assoc_type_projection(db, target);
        if b.remaining() != 1 {
            // the Target type + Deref trait should only have one generic parameter,
            // namely Deref's Self type
            return None;
        }
        b.push(ty.goal.value.clone()).build()
    };

    // FIXME make the Canonical / bound var handling nicer

    // Check that the type implements Deref at all
    let trait_ref = projection.trait_ref(db);
    let implements_goal = Canonical {
        binders: ty.goal.binders.clone(),
        value: InEnvironment {
            goal: trait_ref.cast(&Interner),
            environment: ty.environment.clone(),
        },
    };
    if db.trait_solve(krate, implements_goal).is_none() {
        return None;
    }

    // Now do the assoc type projection
    let alias_eq = AliasEq {
        alias: AliasTy::Projection(projection),
        ty: TyKind::BoundVar(BoundVar::new(
            DebruijnIndex::INNERMOST,
            ty.goal.binders.len(&Interner),
        ))
        .intern(&Interner),
    };

    let in_env = InEnvironment { goal: alias_eq.cast(&Interner), environment: ty.environment };

    let canonical = Canonical {
        value: in_env,
        binders: CanonicalVarKinds::from_iter(
            &Interner,
            ty.goal.binders.iter(&Interner).cloned().chain(Some(chalk_ir::WithKind::new(
                VariableKind::Ty(chalk_ir::TyVariableKind::General),
                chalk_ir::UniverseIndex::ROOT,
            ))),
        ),
    };

    let solution = db.trait_solve(krate, canonical)?;

    match &solution {
        Solution::Unique(Canonical { value: ConstrainedSubst { subst, .. }, binders })
        | Solution::Ambig(Guidance::Definite(Canonical { value: subst, binders })) => {
            // FIXME: vars may contain solutions for any inference variables
            // that happened to be inside ty. To correctly handle these, we
            // would have to pass the solution up to the inference context, but
            // that requires a larger refactoring (especially if the deref
            // happens during method resolution). So for the moment, we just
            // check that we're not in the situation we're we would actually
            // need to handle the values of the additional variables, i.e.
            // they're just being 'passed through'. In the 'standard' case where
            // we have `impl<T> Deref for Foo<T> { Target = T }`, that should be
            // the case.

            // FIXME: if the trait solver decides to truncate the type, these
            // assumptions will be broken. We would need to properly introduce
            // new variables in that case

            for i in 1..binders.len(&Interner) {
                if subst.at(&Interner, i - 1).assert_ty_ref(&Interner).kind(&Interner)
                    != &TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, i - 1))
                {
                    warn!("complex solution for derefing {:?}: {:?}, ignoring", ty.goal, solution);
                    return None;
                }
            }
            // FIXME: we remove lifetime variables here since they can confuse
            // the method resolution code later
            Some(fixup_lifetime_variables(Canonical {
                value: subst
                    .at(&Interner, subst.len(&Interner) - 1)
                    .assert_ty_ref(&Interner)
                    .clone(),
                binders: binders.clone(),
            }))
        }
        Solution::Ambig(_) => {
            info!("Ambiguous solution for derefing {:?}: {:?}", ty.goal, solution);
            None
        }
    }
}

fn fixup_lifetime_variables<T: Fold<Interner, Result = T> + HasInterner<Interner = Interner>>(
    c: Canonical<T>,
) -> Canonical<T> {
    // Removes lifetime variables from the Canonical, replacing them by static lifetimes.
    let mut i = 0;
    let subst = Substitution::from_iter(
        &Interner,
        c.binders.iter(&Interner).map(|vk| match vk.kind {
            VariableKind::Ty(_) => {
                let index = i;
                i += 1;
                BoundVar::new(DebruijnIndex::INNERMOST, index).to_ty(&Interner).cast(&Interner)
            }
            VariableKind::Lifetime => static_lifetime().cast(&Interner),
            VariableKind::Const(_) => unimplemented!(),
        }),
    );
    let binders = CanonicalVarKinds::from_iter(
        &Interner,
        c.binders.iter(&Interner).filter(|vk| match vk.kind {
            VariableKind::Ty(_) => true,
            VariableKind::Lifetime => false,
            VariableKind::Const(_) => true,
        }),
    );
    let value = subst.apply(c.value, &Interner);
    Canonical { binders, value }
}
<commit_msg>Fix a comment typo in autoderef.rs<commit_after>//! In certain situations, rust automatically inserts derefs as necessary: for
//! example, field accesses `foo.bar` still work when `foo` is actually a
//! reference to a type with the field `bar`. This is an approximation of the
//! logic in rustc (which lives in librustc_typeck/check/autoderef.rs).

use std::iter::successors;

use base_db::CrateId;
use chalk_ir::{cast::Cast, fold::Fold, interner::HasInterner, VariableKind};
use hir_def::lang_item::LangItemTarget;
use hir_expand::name::name;
use limit::Limit;
use tracing::{info, warn};

use crate::{
    db::HirDatabase, static_lifetime, AliasEq, AliasTy, BoundVar, Canonical, CanonicalVarKinds,
    ConstrainedSubst, DebruijnIndex, Environment, Guidance, InEnvironment, Interner,
    ProjectionTyExt, Solution, Substitution, Ty, TyBuilder, TyKind,
};

const AUTODEREF_RECURSION_LIMIT: Limit = Limit::new(10);

pub(crate) enum AutoderefKind {
    Builtin,
    Overloaded,
}

pub(crate) struct Autoderef<'db> {
    db: &'db dyn HirDatabase,
    ty: Canonical<Ty>,
    at_start: bool,
    krate: Option<CrateId>,
    environment: Environment,
    steps: Vec<(AutoderefKind, Ty)>,
}

impl<'db> Autoderef<'db> {
    pub(crate) fn new(
        db: &'db dyn HirDatabase,
        krate: Option<CrateId>,
        ty: InEnvironment<Canonical<Ty>>,
    ) -> Self {
        let InEnvironment { goal: ty, environment } = ty;
        Autoderef { db, ty, at_start: true, environment, krate, steps: Vec::new() }
    }

    pub(crate) fn step_count(&self) -> usize {
        self.steps.len()
    }

    pub(crate) fn steps(&self) -> &[(AutoderefKind, chalk_ir::Ty<Interner>)] {
        &self.steps
    }

    pub(crate) fn final_ty(&self) -> Ty {
        self.ty.value.clone()
    }
}

impl Iterator for Autoderef<'_> {
    type Item = (Canonical<Ty>, usize);

    fn next(&mut self) -> Option<Self::Item> {
        if self.at_start {
            self.at_start = false;
            return Some((self.ty.clone(), 0));
        }

        if AUTODEREF_RECURSION_LIMIT.check(self.steps.len() + 1).is_err() {
            return None;
        }

        let (kind, new_ty) = if let Some(derefed) = builtin_deref(&self.ty.value) {
            (AutoderefKind::Builtin, Canonical { value: derefed, binders: self.ty.binders.clone() })
        } else {
            (
                AutoderefKind::Overloaded,
                deref_by_trait(
                    self.db,
                    self.krate?,
                    InEnvironment { goal: &self.ty, environment: self.environment.clone() },
                )?,
            )
        };

        self.steps.push((kind, self.ty.value.clone()));
        self.ty = new_ty;

        Some((self.ty.clone(), self.step_count()))
    }
}

// FIXME: replace uses of this with Autoderef above
pub fn autoderef<'a>(
    db: &'a dyn HirDatabase,
    krate: Option<CrateId>,
    ty: InEnvironment<Canonical<Ty>>,
) -> impl Iterator<Item = Canonical<Ty>> + 'a {
    let InEnvironment { goal: ty, environment } = ty;
    successors(Some(ty), move |ty| {
        deref(db, krate?, InEnvironment { goal: ty, environment: environment.clone() })
    })
    .take(AUTODEREF_RECURSION_LIMIT.inner())
}

pub(crate) fn deref(
    db: &dyn HirDatabase,
    krate: CrateId,
    ty: InEnvironment<&Canonical<Ty>>,
) -> Option<Canonical<Ty>> {
    let _p = profile::span("deref");
    if let Some(derefed) = builtin_deref(&ty.goal.value) {
        Some(Canonical { value: derefed, binders: ty.goal.binders.clone() })
    } else {
        deref_by_trait(db, krate, ty)
    }
}

fn builtin_deref(ty: &Ty) -> Option<Ty> {
    match ty.kind(&Interner) {
        TyKind::Ref(.., ty) => Some(ty.clone()),
        TyKind::Raw(.., ty) => Some(ty.clone()),
        _ => None,
    }
}

fn deref_by_trait(
    db: &dyn HirDatabase,
    krate: CrateId,
    ty: InEnvironment<&Canonical<Ty>>,
) -> Option<Canonical<Ty>> {
    let _p = profile::span("deref_by_trait");
    let deref_trait = match db.lang_item(krate, "deref".into())? {
        LangItemTarget::TraitId(it) => it,
        _ => return None,
    };
    let target = db.trait_data(deref_trait).associated_type_by_name(&name![Target])?;

    let projection = {
        let b = TyBuilder::assoc_type_projection(db, target);
        if b.remaining() != 1 {
            // the Target type + Deref trait should only have one generic parameter,
            // namely Deref's Self type
            return None;
        }
        b.push(ty.goal.value.clone()).build()
    };

    // FIXME make the Canonical / bound var handling nicer

    // Check that the type implements Deref at all
    let trait_ref = projection.trait_ref(db);
    let implements_goal = Canonical {
        binders: ty.goal.binders.clone(),
        value: InEnvironment {
            goal: trait_ref.cast(&Interner),
            environment: ty.environment.clone(),
        },
    };
    if db.trait_solve(krate, implements_goal).is_none() {
        return None;
    }

    // Now do the assoc type projection
    let alias_eq = AliasEq {
        alias: AliasTy::Projection(projection),
        ty: TyKind::BoundVar(BoundVar::new(
            DebruijnIndex::INNERMOST,
            ty.goal.binders.len(&Interner),
        ))
        .intern(&Interner),
    };

    let in_env = InEnvironment { goal: alias_eq.cast(&Interner), environment: ty.environment };

    let canonical = Canonical {
        value: in_env,
        binders: CanonicalVarKinds::from_iter(
            &Interner,
            ty.goal.binders.iter(&Interner).cloned().chain(Some(chalk_ir::WithKind::new(
                VariableKind::Ty(chalk_ir::TyVariableKind::General),
                chalk_ir::UniverseIndex::ROOT,
            ))),
        ),
    };

    let solution = db.trait_solve(krate, canonical)?;

    match &solution {
        Solution::Unique(Canonical { value: ConstrainedSubst { subst, .. }, binders })
        | Solution::Ambig(Guidance::Definite(Canonical { value: subst, binders })) => {
            // FIXME: vars may contain solutions for any inference variables
            // that happened to be inside ty. To correctly handle these, we
            // would have to pass the solution up to the inference context, but
            // that requires a larger refactoring (especially if the deref
            // happens during method resolution). So for the moment, we just
            // check that we're not in the situation where we would actually
            // need to handle the values of the additional variables, i.e.
            // they're just being 'passed through'. In the 'standard' case where
            // we have `impl<T> Deref for Foo<T> { Target = T }`, that should be
            // the case.

            // FIXME: if the trait solver decides to truncate the type, these
            // assumptions will be broken. We would need to properly introduce
            // new variables in that case

            for i in 1..binders.len(&Interner) {
                if subst.at(&Interner, i - 1).assert_ty_ref(&Interner).kind(&Interner)
                    != &TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, i - 1))
                {
                    warn!("complex solution for derefing {:?}: {:?}, ignoring", ty.goal, solution);
                    return None;
                }
            }
            // FIXME: we remove lifetime variables here since they can confuse
            // the method resolution code later
            Some(fixup_lifetime_variables(Canonical {
                value: subst
                    .at(&Interner, subst.len(&Interner) - 1)
                    .assert_ty_ref(&Interner)
                    .clone(),
                binders: binders.clone(),
            }))
        }
        Solution::Ambig(_) => {
            info!("Ambiguous solution for derefing {:?}: {:?}", ty.goal, solution);
            None
        }
    }
}

fn fixup_lifetime_variables<T: Fold<Interner, Result = T> + HasInterner<Interner = Interner>>(
    c: Canonical<T>,
) -> Canonical<T> {
    // Removes lifetime variables from the Canonical, replacing them by static lifetimes.
    let mut i = 0;
    let subst = Substitution::from_iter(
        &Interner,
        c.binders.iter(&Interner).map(|vk| match vk.kind {
            VariableKind::Ty(_) => {
                let index = i;
                i += 1;
                BoundVar::new(DebruijnIndex::INNERMOST, index).to_ty(&Interner).cast(&Interner)
            }
            VariableKind::Lifetime => static_lifetime().cast(&Interner),
            VariableKind::Const(_) => unimplemented!(),
        }),
    );
    let binders = CanonicalVarKinds::from_iter(
        &Interner,
        c.binders.iter(&Interner).filter(|vk| match vk.kind {
            VariableKind::Ty(_) => true,
            VariableKind::Lifetime => false,
            VariableKind::Const(_) => true,
        }),
    );
    let value = subst.apply(c.value, &Interner);
    Canonical { binders, value }
}
<|endoftext|>


<commit_before>use std::mem;

use ra_syntax::{
    TextUnit, TextRange, SyntaxNodeRef, File, AstNode, SyntaxKind,
    ast,
    algo::{
        find_covering_node, find_leaf_at_offset, LeafAtOffset,
    },
    text_utils::{intersect, contains_offset_nonstrict},
    SyntaxKind::*,
};

use {LocalEdit, EditBuilder, find_node_at_offset};

pub fn join_lines(file: &File, range: TextRange) -> LocalEdit {
    let range = if range.is_empty() {
        let syntax = file.syntax();
        let text = syntax.text().slice(range.start()..);
        let pos = match text.find('\n') {
            None => return LocalEdit {
                edit: EditBuilder::new().finish(),
                cursor_position: None
            },
            Some(pos) => pos
        };
        TextRange::offset_len(
            range.start() + pos,
            TextUnit::of_char('\n'),
        )
    } else {
        range
    };

    let node = find_covering_node(file.syntax(), range);
    let mut edit = EditBuilder::new();
    for node in node.descendants() {
        let text = match node.leaf_text() {
            Some(text) => text,
            None => continue,
        };
        let range = match intersect(range, node.range()) {
            Some(range) => range,
            None => continue,
        } - node.range().start();
        for (pos, _) in text[range].bytes().enumerate().filter(|&(_, b)| b == b'\n') {
            let pos: TextUnit = (pos as u32).into();
            let off = node.range().start() + range.start() + pos;
            if !edit.invalidates_offset(off) {
                remove_newline(&mut edit, node, text.as_str(), off);
            }
        }
    }

    LocalEdit {
        edit: edit.finish(),
        cursor_position: None,
    }
}

pub fn on_enter(file: &File, offset: TextUnit) -> Option<LocalEdit> {
    let comment = find_leaf_at_offset(file.syntax(), offset).left_biased().and_then(|it| ast::Comment::cast(it))?;

    if let ast::CommentFlavor::Multiline = comment.flavor() {
        return None;
    }

    let prefix = comment.prefix();
    if offset < comment.syntax().range().start() + TextUnit::of_str(prefix) + TextUnit::from(1) {
        return None;
    }

    let indent = node_indent(file, comment.syntax())?;
    let inserted = format!("\n{}{} ", indent, prefix);
    let cursor_position = offset + TextUnit::of_str(&inserted);
    let mut edit = EditBuilder::new();
    edit.insert(offset, inserted);
    Some(LocalEdit {
        edit: edit.finish(),
        cursor_position: Some(cursor_position),
    })
}

fn node_indent<'a>(file: &'a File, node: SyntaxNodeRef) -> Option<&'a str> {
    let ws = match find_leaf_at_offset(file.syntax(), node.range().start()) {
        LeafAtOffset::Between(l, r) => {
            assert!(r == node);
            l
        }
        LeafAtOffset::Single(n) => {
            assert!(n == node);
            return Some("")
        }
        LeafAtOffset::None => unreachable!(),
    };
    if ws.kind() != WHITESPACE {
        return None;
    }
    let text = ws.leaf_text().unwrap();
    let pos = text.as_str().rfind('\n').map(|it| it + 1).unwrap_or(0);
    Some(&text[pos..])
}

pub fn on_eq_typed(file: &File, offset: TextUnit) -> Option<LocalEdit> {
    let let_stmt: ast::LetStmt = find_node_at_offset(file.syntax(), offset)?;
    if let_stmt.has_semi() {
        return None;
    }
    if let Some(expr) = let_stmt.initializer() {
        let expr_range = expr.syntax().range();
        if contains_offset_nonstrict(expr_range, offset) && offset != expr_range.start() {
            return None;
        }
        if file.syntax().text().slice(offset..expr_range.start()).contains('\n') {
            return None;
        }
    } else {
        return None;
    }
    let offset = let_stmt.syntax().range().end();
    let mut edit = EditBuilder::new();
    edit.insert(offset, ";".to_string());
    Some(LocalEdit {
        edit: edit.finish(),
        cursor_position: None,
    })
}

fn remove_newline(
    edit: &mut EditBuilder,
    node: SyntaxNodeRef,
    node_text: &str,
    offset: TextUnit,
) {
    if node.kind() != WHITESPACE || node_text.bytes().filter(|&b| b == b'\n').count() != 1 {
        // The node is either the first or the last in the file
        let suff = &node_text[TextRange::from_to(
            offset - node.range().start() + TextUnit::of_char('\n'),
            TextUnit::of_str(node_text),
        )];
        let spaces = suff.bytes().take_while(|&b| b == b' ').count();

        edit.replace(
            TextRange::offset_len(offset, ((spaces + 1) as u32).into()),
            " ".to_string(),
        );
        return;
    }

    // Special case that turns something like:
    //
    // ```
    // my_function({<|>
    //    <some-expr>
    // })
    // ```
    //
    // into `my_function(<some-expr>)`
    if join_single_expr_block(edit, node).is_some() {
        return
    }

    // The node is between two other nodes
    let prev = node.prev_sibling().unwrap();
    let next = node.next_sibling().unwrap();
    if is_trailing_comma(prev.kind(), next.kind()) {
        // Removes: trailing comma, newline (incl. surrounding whitespace)
        edit.delete(TextRange::from_to(prev.range().start(), node.range().end()));
    } else if prev.kind() == COMMA && next.kind() == R_CURLY {
        // Removes: comma, newline (incl. surrounding whitespace)
        // Adds: a single whitespace
        edit.replace(
            TextRange::from_to(prev.range().start(), node.range().end()),
            " ".to_string()
        );
    } else if let (Some(_), Some(next)) = (ast::Comment::cast(prev), ast::Comment::cast(next)) {
        // Removes: newline (incl. surrounding whitespace), start of the next comment
        let comment_text = next.text();
        if let Some(newline_pos) = comment_text.find('\n') {
            // Special case for multiline comments: join the comment content but
            // keep the leading `/*`

            let newline_offset = next.syntax().range().start()
                                + TextUnit::from(newline_pos as u32)
                                + TextUnit::of_char('\n');

            edit.insert(newline_offset, "/*".to_string());
            edit.delete(TextRange::from_to(
                node.range().start(),
                next.syntax().range().start() + TextUnit::of_str(next.prefix())
            ));
        } else {
            // Single-line comments
            edit.delete(TextRange::from_to(
                node.range().start(),
                next.syntax().range().start() + TextUnit::of_str(next.prefix())
            ));
        }
    } else {
        // Remove newline but add a computed amount of whitespace characters
        edit.replace(
            node.range(),
            compute_ws(prev, next).to_string(),
        );
    }
}

fn is_trailing_comma(left: SyntaxKind, right: SyntaxKind) -> bool {
    match (left, right) {
       (COMMA, R_PAREN) | (COMMA, R_BRACK) => true,
       _ => false
    }
}

fn join_single_expr_block(
    edit: &mut EditBuilder,
    node: SyntaxNodeRef,
) -> Option<()> {
    let block = ast::Block::cast(node.parent()?)?;
    let block_expr = ast::BlockExpr::cast(block.syntax().parent()?)?;
    let expr = single_expr(block)?;
    edit.replace(
        block_expr.syntax().range(),
        expr.syntax().text().to_string(),
    );
    Some(())
}

fn single_expr(block: ast::Block) -> Option<ast::Expr> {
    let mut res = None;
    for child in block.syntax().children() {
        if let Some(expr) = ast::Expr::cast(child) {
            if expr.syntax().text().contains('\n') {
                return None;
            }
            if mem::replace(&mut res, Some(expr)).is_some() {
                return None;
            }
        } else {
            match child.kind() {
                WHITESPACE | L_CURLY | R_CURLY => (),
                _ => return None,
            }
        }
    }
    res
}

fn compute_ws(left: SyntaxNodeRef, right: SyntaxNodeRef) -> &'static str {
    match left.kind() {
        L_PAREN | L_BRACK => return "",
        _ => (),
    }
    match right.kind() {
        R_PAREN | R_BRACK => return "",
        DOT => return "",
        _ => (),
    }
    " "
}

#[cfg(test)]
mod tests {
    use super::*;
    use test_utils::{check_action, extract_range, extract_offset, add_cursor};

    fn check_join_lines(before: &str, after: &str) {
        check_action(before, after, |file, offset| {
            let range = TextRange::offset_len(offset, 0.into());
            let res = join_lines(file, range);
            Some(res)
        })
    }

    #[test]
    fn test_join_lines_comma() {
        check_join_lines(r"
fn foo() {
    <|>foo(1,
    )
}
", r"
fn foo() {
    <|>foo(1)
}
");
    }

    #[test]
    fn test_join_lines_lambda_block() {
        check_join_lines(r"
pub fn reparse(&self, edit: &AtomEdit) -> File {
    <|>self.incremental_reparse(edit).unwrap_or_else(|| {
        self.full_reparse(edit)
    })
}
", r"
pub fn reparse(&self, edit: &AtomEdit) -> File {
    <|>self.incremental_reparse(edit).unwrap_or_else(|| self.full_reparse(edit))
}
");
    }

    #[test]
    fn test_join_lines_block() {
        check_join_lines(r"
fn foo() {
    foo(<|>{
        92
    })
}", r"
fn foo() {
    foo(<|>92)
}");
    }

    fn check_join_lines_sel(before: &str, after: &str) {
        let (sel, before) = extract_range(before);
        let file = File::parse(&before);
        let result = join_lines(&file, sel);
        let actual = result.edit.apply(&before);
        assert_eq_text!(after, &actual);
    }

    #[test]
    fn test_join_lines_selection_fn_args() {
        check_join_lines_sel(r"
fn foo() {
    <|>foo(1,
        2,
        3,
    <|>)
}
    ", r"
fn foo() {
    foo(1, 2, 3)
}
    ");
    }

    #[test]
    fn test_join_lines_selection_struct() {
        check_join_lines_sel(r"
struct Foo <|>{
    f: u32,
}<|>
    ", r"
struct Foo { f: u32 }
    ");
    }

    #[test]
    fn test_join_lines_selection_dot_chain() {
        check_join_lines_sel(r"
fn foo() {
    join(<|>type_params.type_params()
            .filter_map(|it| it.name())
            .map(|it| it.text())<|>)
}", r"
fn foo() {
    join(type_params.type_params().filter_map(|it| it.name()).map(|it| it.text()))
}");
    }

    #[test]
    fn test_join_lines_selection_lambda_block_body() {
        check_join_lines_sel(r"
pub fn handle_find_matching_brace() {
    params.offsets
        .map(|offset| <|>{
            world.analysis().matching_brace(&file, offset).unwrap_or(offset)
        }<|>)
        .collect();
}", r"
pub fn handle_find_matching_brace() {
    params.offsets
        .map(|offset| world.analysis().matching_brace(&file, offset).unwrap_or(offset))
        .collect();
}");
    }

    #[test]
    fn test_on_eq_typed() {
        fn do_check(before: &str, after: &str) {
            let (offset, before) = extract_offset(before);
            let file = File::parse(&before);
            let result = on_eq_typed(&file, offset).unwrap();
            let actual = result.edit.apply(&before);
            assert_eq_text!(after, &actual);
        }

        //     do_check(r"
        // fn foo() {
        //     let foo =<|>
        // }
        // ", r"
        // fn foo() {
        //     let foo =;
        // }
        // ");
        do_check(r"
fn foo() {
    let foo =<|> 1 + 1
}
", r"
fn foo() {
    let foo = 1 + 1;
}
");
        //     do_check(r"
        // fn foo() {
        //     let foo =<|>
        //     let bar = 1;
        // }
        // ", r"
        // fn foo() {
        //     let foo =;
        //     let bar = 1;
        // }
        // ");
    }

    #[test]
    fn test_on_enter() {
        fn apply_on_enter(before: &str) -> Option<String> {
            let (offset, before) = extract_offset(before);
            let file = File::parse(&before);
            let result = on_enter(&file, offset)?;
            let actual = result.edit.apply(&before);
            let actual = add_cursor(&actual, result.cursor_position.unwrap());
            Some(actual)
        }

        fn do_check(before: &str, after: &str) {
            let actual = apply_on_enter(before).unwrap();
            assert_eq_text!(after, &actual);
        }

        fn do_check_noop(text: &str) {
            assert!(apply_on_enter(text).is_none())
        }

        do_check(r"
/// Some docs<|>
fn foo() {
}
", r"
/// Some docs
/// <|>
fn foo() {
}
");
        do_check(r"
impl S {
    /// Some<|> docs.
    fn foo() {}
}
", r"
impl S {
    /// Some
    /// <|> docs.
    fn foo() {}
}
");
        do_check_noop(r"<|>//! docz");
    }
}
<commit_msg>Add tests<commit_after>use std::mem;

use ra_syntax::{
    TextUnit, TextRange, SyntaxNodeRef, File, AstNode, SyntaxKind,
    ast,
    algo::{
        find_covering_node, find_leaf_at_offset, LeafAtOffset,
    },
    text_utils::{intersect, contains_offset_nonstrict},
    SyntaxKind::*,
};

use {LocalEdit, EditBuilder, find_node_at_offset};

pub fn join_lines(file: &File, range: TextRange) -> LocalEdit {
    let range = if range.is_empty() {
        let syntax = file.syntax();
        let text = syntax.text().slice(range.start()..);
        let pos = match text.find('\n') {
            None => return LocalEdit {
                edit: EditBuilder::new().finish(),
                cursor_position: None
            },
            Some(pos) => pos
        };
        TextRange::offset_len(
            range.start() + pos,
            TextUnit::of_char('\n'),
        )
    } else {
        range
    };

    let node = find_covering_node(file.syntax(), range);
    let mut edit = EditBuilder::new();
    for node in node.descendants() {
        let text = match node.leaf_text() {
            Some(text) => text,
            None => continue,
        };
        let range = match intersect(range, node.range()) {
            Some(range) => range,
            None => continue,
        } - node.range().start();
        for (pos, _) in text[range].bytes().enumerate().filter(|&(_, b)| b == b'\n') {
            let pos: TextUnit = (pos as u32).into();
            let off = node.range().start() + range.start() + pos;
            if !edit.invalidates_offset(off) {
                remove_newline(&mut edit, node, text.as_str(), off);
            }
        }
    }

    LocalEdit {
        edit: edit.finish(),
        cursor_position: None,
    }
}

pub fn on_enter(file: &File, offset: TextUnit) -> Option<LocalEdit> {
    let comment = find_leaf_at_offset(file.syntax(), offset).left_biased().and_then(|it| ast::Comment::cast(it))?;

    if let ast::CommentFlavor::Multiline = comment.flavor() {
        return None;
    }

    let prefix = comment.prefix();
    if offset < comment.syntax().range().start() + TextUnit::of_str(prefix) + TextUnit::from(1) {
        return None;
    }

    let indent = node_indent(file, comment.syntax())?;
    let inserted = format!("\n{}{} ", indent, prefix);
    let cursor_position = offset + TextUnit::of_str(&inserted);
    let mut edit = EditBuilder::new();
    edit.insert(offset, inserted);
    Some(LocalEdit {
        edit: edit.finish(),
        cursor_position: Some(cursor_position),
    })
}

fn node_indent<'a>(file: &'a File, node: SyntaxNodeRef) -> Option<&'a str> {
    let ws = match find_leaf_at_offset(file.syntax(), node.range().start()) {
        LeafAtOffset::Between(l, r) => {
            assert!(r == node);
            l
        }
        LeafAtOffset::Single(n) => {
            assert!(n == node);
            return Some("")
        }
        LeafAtOffset::None => unreachable!(),
    };
    if ws.kind() != WHITESPACE {
        return None;
    }
    let text = ws.leaf_text().unwrap();
    let pos = text.as_str().rfind('\n').map(|it| it + 1).unwrap_or(0);
    Some(&text[pos..])
}

pub fn on_eq_typed(file: &File, offset: TextUnit) -> Option<LocalEdit> {
    let let_stmt: ast::LetStmt = find_node_at_offset(file.syntax(), offset)?;
    if let_stmt.has_semi() {
        return None;
    }
    if let Some(expr) = let_stmt.initializer() {
        let expr_range = expr.syntax().range();
        if contains_offset_nonstrict(expr_range, offset) && offset != expr_range.start() {
            return None;
        }
        if file.syntax().text().slice(offset..expr_range.start()).contains('\n') {
            return None;
        }
    } else {
        return None;
    }
    let offset = let_stmt.syntax().range().end();
    let mut edit = EditBuilder::new();
    edit.insert(offset, ";".to_string());
    Some(LocalEdit {
        edit: edit.finish(),
        cursor_position: None,
    })
}

fn remove_newline(
    edit: &mut EditBuilder,
    node: SyntaxNodeRef,
    node_text: &str,
    offset: TextUnit,
) {
    if node.kind() != WHITESPACE || node_text.bytes().filter(|&b| b == b'\n').count() != 1 {
        // The node is either the first or the last in the file
        let suff = &node_text[TextRange::from_to(
            offset - node.range().start() + TextUnit::of_char('\n'),
            TextUnit::of_str(node_text),
        )];
        let spaces = suff.bytes().take_while(|&b| b == b' ').count();

        edit.replace(
            TextRange::offset_len(offset, ((spaces + 1) as u32).into()),
            " ".to_string(),
        );
        return;
    }

    // Special case that turns something like:
    //
    // ```
    // my_function({<|>
    //    <some-expr>
    // })
    // ```
    //
    // into `my_function(<some-expr>)`
    if join_single_expr_block(edit, node).is_some() {
        return
    }

    // The node is between two other nodes
    let prev = node.prev_sibling().unwrap();
    let next = node.next_sibling().unwrap();
    if is_trailing_comma(prev.kind(), next.kind()) {
        // Removes: trailing comma, newline (incl. surrounding whitespace)
        edit.delete(TextRange::from_to(prev.range().start(), node.range().end()));
    } else if prev.kind() == COMMA && next.kind() == R_CURLY {
        // Removes: comma, newline (incl. surrounding whitespace)
        // Adds: a single whitespace
        edit.replace(
            TextRange::from_to(prev.range().start(), node.range().end()),
            " ".to_string()
        );
    } else if let (Some(_), Some(next)) = (ast::Comment::cast(prev), ast::Comment::cast(next)) {
        // Removes: newline (incl. surrounding whitespace), start of the next comment
        let comment_text = next.text();
        if let Some(newline_pos) = comment_text.find('\n') {
            // Special case for multiline comments: join the comment content but
            // keep the leading `/*`

            let newline_offset = next.syntax().range().start()
                                + TextUnit::from(newline_pos as u32)
                                + TextUnit::of_char('\n');

            edit.insert(newline_offset, "/*".to_string());
            edit.delete(TextRange::from_to(
                node.range().start(),
                next.syntax().range().start() + TextUnit::of_str(next.prefix())
            ));
        } else {
            // Single-line comments
            edit.delete(TextRange::from_to(
                node.range().start(),
                next.syntax().range().start() + TextUnit::of_str(next.prefix())
            ));
        }
    } else {
        // Remove newline but add a computed amount of whitespace characters
        edit.replace(
            node.range(),
            compute_ws(prev, next).to_string(),
        );
    }
}

fn is_trailing_comma(left: SyntaxKind, right: SyntaxKind) -> bool {
    match (left, right) {
       (COMMA, R_PAREN) | (COMMA, R_BRACK) => true,
       _ => false
    }
}

fn join_single_expr_block(
    edit: &mut EditBuilder,
    node: SyntaxNodeRef,
) -> Option<()> {
    let block = ast::Block::cast(node.parent()?)?;
    let block_expr = ast::BlockExpr::cast(block.syntax().parent()?)?;
    let expr = single_expr(block)?;
    edit.replace(
        block_expr.syntax().range(),
        expr.syntax().text().to_string(),
    );
    Some(())
}

fn single_expr(block: ast::Block) -> Option<ast::Expr> {
    let mut res = None;
    for child in block.syntax().children() {
        if let Some(expr) = ast::Expr::cast(child) {
            if expr.syntax().text().contains('\n') {
                return None;
            }
            if mem::replace(&mut res, Some(expr)).is_some() {
                return None;
            }
        } else {
            match child.kind() {
                WHITESPACE | L_CURLY | R_CURLY => (),
                _ => return None,
            }
        }
    }
    res
}

fn compute_ws(left: SyntaxNodeRef, right: SyntaxNodeRef) -> &'static str {
    match left.kind() {
        L_PAREN | L_BRACK => return "",
        _ => (),
    }
    match right.kind() {
        R_PAREN | R_BRACK => return "",
        DOT => return "",
        _ => (),
    }
    " "
}

#[cfg(test)]
mod tests {
    use super::*;
    use test_utils::{check_action, extract_range, extract_offset, add_cursor};

    fn check_join_lines(before: &str, after: &str) {
        check_action(before, after, |file, offset| {
            let range = TextRange::offset_len(offset, 0.into());
            let res = join_lines(file, range);
            Some(res)
        })
    }

    #[test]
    fn test_join_lines_comma() {
        check_join_lines(r"
fn foo() {
    <|>foo(1,
    )
}
", r"
fn foo() {
    <|>foo(1)
}
");
    }

    #[test]
    fn test_join_lines_lambda_block() {
        check_join_lines(r"
pub fn reparse(&self, edit: &AtomEdit) -> File {
    <|>self.incremental_reparse(edit).unwrap_or_else(|| {
        self.full_reparse(edit)
    })
}
", r"
pub fn reparse(&self, edit: &AtomEdit) -> File {
    <|>self.incremental_reparse(edit).unwrap_or_else(|| self.full_reparse(edit))
}
");
    }

    #[test]
    fn test_join_lines_block() {
        check_join_lines(r"
fn foo() {
    foo(<|>{
        92
    })
}", r"
fn foo() {
    foo(<|>92)
}");
    }

    #[test]
    fn test_join_lines_normal_comments() {
        check_join_lines(r"
fn foo() {
    // Hello<|>
    // world!
}
", r"
fn foo() {
    // Hello<|> world!
}
");
    }

    #[test]
    fn test_join_lines_doc_comments() {
        check_join_lines(r"
fn foo() {
    /// Hello<|>
    /// world!
}
", r"
fn foo() {
    /// Hello<|> world!
}
");
    }

    #[test]
    fn test_join_lines_mod_comments() {
        check_join_lines(r"
fn foo() {
    //! Hello<|>
    //! world!
}
", r"
fn foo() {
    //! Hello<|> world!
}
");
    }

    #[test]
    fn test_join_lines_multiline_comments() {
        check_join_lines(r"
fn foo() {
    // Hello<|>
    /* world! */
}
", r"
fn foo() {
    // Hello<|> world! */
}
");
    }

    fn check_join_lines_sel(before: &str, after: &str) {
        let (sel, before) = extract_range(before);
        let file = File::parse(&before);
        let result = join_lines(&file, sel);
        let actual = result.edit.apply(&before);
        assert_eq_text!(after, &actual);
    }

    #[test]
    fn test_join_lines_selection_fn_args() {
        check_join_lines_sel(r"
fn foo() {
    <|>foo(1,
        2,
        3,
    <|>)
}
    ", r"
fn foo() {
    foo(1, 2, 3)
}
    ");
    }

    #[test]
    fn test_join_lines_selection_struct() {
        check_join_lines_sel(r"
struct Foo <|>{
    f: u32,
}<|>
    ", r"
struct Foo { f: u32 }
    ");
    }

    #[test]
    fn test_join_lines_selection_dot_chain() {
        check_join_lines_sel(r"
fn foo() {
    join(<|>type_params.type_params()
            .filter_map(|it| it.name())
            .map(|it| it.text())<|>)
}", r"
fn foo() {
    join(type_params.type_params().filter_map(|it| it.name()).map(|it| it.text()))
}");
    }

    #[test]
    fn test_join_lines_selection_lambda_block_body() {
        check_join_lines_sel(r"
pub fn handle_find_matching_brace() {
    params.offsets
        .map(|offset| <|>{
            world.analysis().matching_brace(&file, offset).unwrap_or(offset)
        }<|>)
        .collect();
}", r"
pub fn handle_find_matching_brace() {
    params.offsets
        .map(|offset| world.analysis().matching_brace(&file, offset).unwrap_or(offset))
        .collect();
}");
    }

    #[test]
    fn test_on_eq_typed() {
        fn do_check(before: &str, after: &str) {
            let (offset, before) = extract_offset(before);
            let file = File::parse(&before);
            let result = on_eq_typed(&file, offset).unwrap();
            let actual = result.edit.apply(&before);
            assert_eq_text!(after, &actual);
        }

        //     do_check(r"
        // fn foo() {
        //     let foo =<|>
        // }
        // ", r"
        // fn foo() {
        //     let foo =;
        // }
        // ");
        do_check(r"
fn foo() {
    let foo =<|> 1 + 1
}
", r"
fn foo() {
    let foo = 1 + 1;
}
");
        //     do_check(r"
        // fn foo() {
        //     let foo =<|>
        //     let bar = 1;
        // }
        // ", r"
        // fn foo() {
        //     let foo =;
        //     let bar = 1;
        // }
        // ");
    }

    #[test]
    fn test_on_enter() {
        fn apply_on_enter(before: &str) -> Option<String> {
            let (offset, before) = extract_offset(before);
            let file = File::parse(&before);
            let result = on_enter(&file, offset)?;
            let actual = result.edit.apply(&before);
            let actual = add_cursor(&actual, result.cursor_position.unwrap());
            Some(actual)
        }

        fn do_check(before: &str, after: &str) {
            let actual = apply_on_enter(before).unwrap();
            assert_eq_text!(after, &actual);
        }

        fn do_check_noop(text: &str) {
            assert!(apply_on_enter(text).is_none())
        }

        do_check(r"
/// Some docs<|>
fn foo() {
}
", r"
/// Some docs
/// <|>
fn foo() {
}
");
        do_check(r"
impl S {
    /// Some<|> docs.
    fn foo() {}
}
", r"
impl S {
    /// Some
    /// <|> docs.
    fn foo() {}
}
");
        do_check_noop(r"<|>//! docz");
    }
}
<|endoftext|>


<commit_before>//! Draw ellipse

pub use rectangle::centered;
pub use rectangle::centered_square as circle;

use current::{ Get, Modifier, Set };
use internal;
use triangulation;
use BackEnd;
use Context;
use ImageSize;
use Color;

/// Ellipse border
pub struct Border {
    /// The border color
    pub color: internal::Color,
    /// The border radius
    pub radius: internal::Radius,
}

/// Wrapper trait for `Get<Border>`
pub trait GetBorder: Get<Border> {
    /// Get border
    #[inline(always)]
    fn get_border(&self) -> Border {
        self.get()
    }
}

impl<T: Get<Border>> GetBorder for T {}

/// Wrapper trait for `Set<Border>`
pub trait SetBorder: Set<Border> {
    /// Set border
    #[inline(always)]
    fn set_border(&mut self, val: Border) {
        self.set_mut(val);
    }
}

impl<T: Set<Border>> SetBorder for T {}

/// An ellipse with filled color
#[deriving(Copy)]
pub struct Ellipse {
    /// The ellipse color
    pub color: internal::Color,
    /// The ellipse border
    pub border: Option<Border>,
}

impl Ellipse {
    /// Creates a new ellipse
    pub fn new(color: internal::Color) -> Ellipse {
        Ellipse {
            color: color,
            border: None
        }
    }

    /// Draws the ellipse.
    pub fn draw<B: BackEnd<I>, I: ImageSize>(
        &self,
        rectangle: internal::Rectangle,
        c: &Context,
        back_end: &mut B
    ) {
        if self.color[3] != 0.0 {
            back_end.color(self.color);
            triangulation::with_ellipse_tri_list(
                128,
                c.transform,
                rectangle,
                |vertices| {
                    back_end.tri_list(vertices)
                }
            );
        }

        if let Some(Border { color, radius: border_radius }) = self.border {
            if color[3] == 0.0 { return; }
            back_end.color(self.color);
            triangulation::with_ellipse_border_tri_list(
                128,
                c.transform,
                rectangle,
                border_radius,
                |vertices| back_end.tri_list(vertices)
            );
        }
    }
}

impl Modifier<Ellipse> for Color {
    #[inline(always)]
    fn modify(self, e: &mut Ellipse) {
        let Color(val) = self;
        e.color = val;
    }
}

impl Get<Color> for Ellipse {
    #[inline(always)]
    fn get(&self) -> Color {
        Color(self.color)
    }
}

impl Modifier<Ellipse> for Border {
    #[inline(always)]
    fn modify(self, e: &mut Ellipse) {
        e.border = Some(self);
    }
}

#[cfg(test)]
mod test {
    use super::Ellipse;
    use super::Border;
    use Color;
    use current::Set;

    #[test]
    fn test_ellipse() {
        let _ellipse = Ellipse::new([1.0, ..4])
            .set(Color([0.0, ..4]))
            .set(Border { color: [1.0, ..4], radius: 3.0 });
    }
}

<commit_msg>Added MaybeBorder for Ellipse<commit_after>//! Draw ellipse

pub use rectangle::centered;
pub use rectangle::centered_square as circle;

use current::{ Get, Modifier, Set };
use internal;
use triangulation;
use BackEnd;
use Context;
use ImageSize;
use Color;

/// Ellipse border
pub struct Border {
    /// The border color
    pub color: internal::Color,
    /// The border radius
    pub radius: internal::Radius,
}

/// Wrapper trait for `Get<Border>`
pub trait GetBorder: Get<Border> {
    /// Get border
    #[inline(always)]
    fn get_border(&self) -> Border {
        self.get()
    }
}

impl<T: Get<Border>> GetBorder for T {}

/// Wrapper trait for `Set<Border>`
pub trait SetBorder: Set<Border> {
    /// Set border
    #[inline(always)]
    fn set_border(&mut self, val: Border) {
        self.set_mut(val);
    }
}

impl<T: Set<Border>> SetBorder for T {}

/// Maybe border property
pub struct MaybeBorder(pub Option<Border>);

/// Wrapper trait for `Get<MaybeBorder>`
pub trait GetMaybeBorder: Get<MaybeBorder> {
    /// Get maybe border
    #[inline(always)]
    fn get_maybe_border(&self) -> MaybeBorder {
        self.get()
    }
}

impl<T: Get<MaybeBorder>> GetMaybeBorder for T {}

/// Wrapper trait for `Set<MaybeBorder>`
pub trait SetMaybeBorder: Set<MaybeBorder> {
    /// Set maybe border
    #[inline(always)]
    fn set_maybe_border(&mut self, val: MaybeBorder) {
        self.set_mut(val);
    }
}

impl<T: Set<MaybeBorder>> SetMaybeBorder for T {}

/// An ellipse with filled color
#[deriving(Copy)]
pub struct Ellipse {
    /// The ellipse color
    pub color: internal::Color,
    /// The ellipse border
    pub border: Option<Border>,
}

impl Ellipse {
    /// Creates a new ellipse
    pub fn new(color: internal::Color) -> Ellipse {
        Ellipse {
            color: color,
            border: None
        }
    }

    /// Draws the ellipse.
    pub fn draw<B: BackEnd<I>, I: ImageSize>(
        &self,
        rectangle: internal::Rectangle,
        c: &Context,
        back_end: &mut B
    ) {
        if self.color[3] != 0.0 {
            back_end.color(self.color);
            triangulation::with_ellipse_tri_list(
                128,
                c.transform,
                rectangle,
                |vertices| {
                    back_end.tri_list(vertices)
                }
            );
        }

        if let Some(Border { color, radius: border_radius }) = self.border {
            if color[3] == 0.0 { return; }
            back_end.color(self.color);
            triangulation::with_ellipse_border_tri_list(
                128,
                c.transform,
                rectangle,
                border_radius,
                |vertices| back_end.tri_list(vertices)
            );
        }
    }
}

impl Modifier<Ellipse> for Color {
    #[inline(always)]
    fn modify(self, e: &mut Ellipse) {
        let Color(val) = self;
        e.color = val;
    }
}

impl Get<Color> for Ellipse {
    #[inline(always)]
    fn get(&self) -> Color {
        Color(self.color)
    }
}

impl Modifier<Ellipse> for Border {
    #[inline(always)]
    fn modify(self, e: &mut Ellipse) {
        e.border = Some(self);
    }
}

impl Modifier<Ellipse> for MaybeBorder {
    #[inline(always)]
    fn modify(self, e: &mut Ellipse) {
        let MaybeBorder(val) = self;
        e.border = val;
    }
}

impl Get<MaybeBorder> for Ellipse {
    #[inline(always)]
    fn get(&self) -> MaybeBorder {
        MaybeBorder(self.border)
    }
}

#[cfg(test)]
mod test {
    use super::Ellipse;
    use super::Border;
    use Color;
    use current::Set;

    #[test]
    fn test_ellipse() {
        let _ellipse = Ellipse::new([1.0, ..4])
            .set(Color([0.0, ..4]))
            .set(Border { color: [1.0, ..4], radius: 3.0 });
    }
}

<|endoftext|>


<commit_before>// Copyright 2015 The tiny-http Contributors
// Copyright 2015 The rust-chunked-transfer Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::io::Result as IoResult;
use std::io::Write;

/// Splits the incoming data into HTTP chunks.
///
/// # Example
///
/// ```
/// use chunked_transfer::Encoder;
/// use std::io::Write;
///
/// let mut decoded = "hello world";
/// let mut encoded: Vec<u8> = vec![];
///
/// {
///     let mut encoder = Encoder::with_chunks_size(&mut encoded, 5);
///     encoder.write_all(decoded.as_bytes());
/// }
///
/// assert_eq!(encoded, b"5\r\nhello\r\n5\r\n worl\r\n1\r\nd\r\n0\r\n\r\n");
/// ```
pub struct Encoder<W>
where
    W: Write,
{
    // where to send the result
    output: W,

    // size of each chunk
    chunks_size: usize,

    // data waiting to be sent is stored here
    buffer: Vec<u8>,
}

impl<W> Encoder<W>
where
    W: Write,
{
    pub fn new(output: W) -> Encoder<W> {
        Encoder::with_chunks_size(output, 8192)
    }

    pub fn with_chunks_size(output: W, chunks: usize) -> Encoder<W> {
        Encoder {
            output,
            chunks_size: chunks,
            buffer: Vec::with_capacity(0),
        }
    }
}

fn send<W>(output: &mut W, data: &[u8]) -> IoResult<()>
where
    W: Write,
{
    write!(output, "{:x}\r\n", data.len())?;
    output.write_all(data)?;
    write!(output, "\r\n")?;
    Ok(())
}

impl<W> Write for Encoder<W>
where
    W: Write,
{
    fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
        self.buffer.write_all(buf)?;

        while self.buffer.len() >= self.chunks_size {
            let rest = {
                let (to_send, rest) = self.buffer.split_at_mut(self.chunks_size);
                send(&mut self.output, to_send)?;
                rest.to_vec()
            };
            self.buffer = rest;
        }

        Ok(buf.len())
    }

    fn flush(&mut self) -> IoResult<()> {
        if self.buffer.len() == 0 {
            return Ok(());
        }

        send(&mut self.output, &self.buffer)?;
        self.buffer.clear();
        Ok(())
    }
}

impl<W> Drop for Encoder<W>
where
    W: Write,
{
    fn drop(&mut self) {
        self.flush().ok();
        send(&mut self.output, &[]).ok();
    }
}

#[cfg(test)]
mod test {
    use super::Encoder;
    use std::io;
    use std::io::Write;
    use std::str::from_utf8;

    #[test]
    fn test() {
        let mut source = io::Cursor::new("hello world".to_string().into_bytes());
        let mut dest: Vec<u8> = vec![];

        {
            let mut encoder = Encoder::with_chunks_size(dest.by_ref(), 5);
            io::copy(&mut source, &mut encoder).unwrap();
        }

        let output = from_utf8(&dest).unwrap();

        assert_eq!(output, "5\r\nhello\r\n5\r\n worl\r\n1\r\nd\r\n0\r\n\r\n");
    }
}
<commit_msg>prefer is_empty<commit_after>// Copyright 2015 The tiny-http Contributors
// Copyright 2015 The rust-chunked-transfer Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::io::Result as IoResult;
use std::io::Write;

/// Splits the incoming data into HTTP chunks.
///
/// # Example
///
/// ```
/// use chunked_transfer::Encoder;
/// use std::io::Write;
///
/// let mut decoded = "hello world";
/// let mut encoded: Vec<u8> = vec![];
///
/// {
///     let mut encoder = Encoder::with_chunks_size(&mut encoded, 5);
///     encoder.write_all(decoded.as_bytes());
/// }
///
/// assert_eq!(encoded, b"5\r\nhello\r\n5\r\n worl\r\n1\r\nd\r\n0\r\n\r\n");
/// ```
pub struct Encoder<W>
where
    W: Write,
{
    // where to send the result
    output: W,

    // size of each chunk
    chunks_size: usize,

    // data waiting to be sent is stored here
    buffer: Vec<u8>,
}

impl<W> Encoder<W>
where
    W: Write,
{
    pub fn new(output: W) -> Encoder<W> {
        Encoder::with_chunks_size(output, 8192)
    }

    pub fn with_chunks_size(output: W, chunks: usize) -> Encoder<W> {
        Encoder {
            output,
            chunks_size: chunks,
            buffer: Vec::with_capacity(0),
        }
    }
}

fn send<W>(output: &mut W, data: &[u8]) -> IoResult<()>
where
    W: Write,
{
    write!(output, "{:x}\r\n", data.len())?;
    output.write_all(data)?;
    write!(output, "\r\n")?;
    Ok(())
}

impl<W> Write for Encoder<W>
where
    W: Write,
{
    fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
        self.buffer.write_all(buf)?;

        while self.buffer.len() >= self.chunks_size {
            let rest = {
                let (to_send, rest) = self.buffer.split_at_mut(self.chunks_size);
                send(&mut self.output, to_send)?;
                rest.to_vec()
            };
            self.buffer = rest;
        }

        Ok(buf.len())
    }

    fn flush(&mut self) -> IoResult<()> {
        if self.buffer.is_empty() {
            return Ok(());
        }

        send(&mut self.output, &self.buffer)?;
        self.buffer.clear();
        Ok(())
    }
}

impl<W> Drop for Encoder<W>
where
    W: Write,
{
    fn drop(&mut self) {
        self.flush().ok();
        send(&mut self.output, &[]).ok();
    }
}

#[cfg(test)]
mod test {
    use super::Encoder;
    use std::io;
    use std::io::Write;
    use std::str::from_utf8;

    #[test]
    fn test() {
        let mut source = io::Cursor::new("hello world".to_string().into_bytes());
        let mut dest: Vec<u8> = vec![];

        {
            let mut encoder = Encoder::with_chunks_size(dest.by_ref(), 5);
            io::copy(&mut source, &mut encoder).unwrap();
        }

        let output = from_utf8(&dest).unwrap();

        assert_eq!(output, "5\r\nhello\r\n5\r\n worl\r\n1\r\nd\r\n0\r\n\r\n");
    }
}
<|endoftext|>