<commit_before>extern crate ogg_sys;
extern crate vorbis_sys;
extern crate vorbisfile_sys;
extern crate libc;

use std::io::{self, Read, Seek};

/// Allows you to decode a sound file stream into packets.
pub struct Decoder<R> where R: Read + Seek {
    // further informations are boxed so that a pointer can be passed to callbacks
    data: Box<DecoderData<R>>,
}

///
pub struct PacketsIter<'a, R: 'a + Read + Seek>(&'a mut DecoderData<R>);

/// Errors that can happen while decoding
#[derive(Debug)]
pub enum VorbisError {
    ReadError(io::Error),
    NotVorbis,
    VersionMismatch,
    BadHeader,
    InitialFileHeadersCorrupt,
    Hole,
}

impl std::error::Error for VorbisError {
    fn description(&self) -> &str {
        match self {
            &VorbisError::ReadError(_) => "A read from media returned an error",
            &VorbisError::NotVorbis => "Bitstream does not contain any Vorbis data",
            &VorbisError::VersionMismatch => "Vorbis version mismatch",
            &VorbisError::BadHeader => "Invalid Vorbis bitstream header",
            &VorbisError::InitialFileHeadersCorrupt => "Initial file headers are corrupt",
            &VorbisError::Hole => "Interruption of data",
        }
    }

    fn cause(&self) -> Option<&std::error::Error> {
        match self {
            &VorbisError::ReadError(ref err) => Some(err as &std::error::Error),
            _ => None
        }
    }
}

impl std::fmt::Display for VorbisError {
    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        write!(fmt, "{}", std::error::Error::description(self))
    }
}

impl From<io::Error> for VorbisError {
    fn from(err: io::Error) -> VorbisError {
        VorbisError::ReadError(err)
    }
}

struct DecoderData<R> where R: Read + Seek {
    vorbis: vorbisfile_sys::OggVorbis_File,
    reader: R,
    current_logical_bitstream: libc::c_int,
    read_error: Option<io::Error>,
}

unsafe impl<R: Read + Seek + Send> Send for DecoderData<R> {}

/// Packet of data.
///
/// Each sample is an `i16` ranging from I16_MIN to I16_MAX.
///
/// The channels are interleaved in the data. For example if you have two channels, you will
/// get a sample from channel 1, then a sample from channel 2, than a sample from channel 1, etc.
#[derive(Clone, Debug)]
pub struct Packet {
    pub data: Vec<i16>,
    pub channels: u16,
    pub rate: u64,
    pub bitrate_upper: u64,
    pub bitrate_nominal: u64,
    pub bitrate_lower: u64,
    pub bitrate_window: u64,
}

impl<R> Decoder<R> where R: Read + Seek {
    pub fn new(input: R) -> Result<Decoder<R>, VorbisError> {
        extern fn read_func<R>(ptr: *mut libc::c_void, size: libc::size_t, nmemb: libc::size_t,
            datasource: *mut libc::c_void) -> libc::size_t where R: Read + Seek
        {
            use std::slice;

            let mut ptr = ptr as *mut u8;

            let data: &mut DecoderData<R> = unsafe { std::mem::transmute(datasource) };

            loop {
                let buffer = ptr.clone();
                let buffer = unsafe { slice::from_raw_parts_mut(buffer, size as usize * nmemb as usize) };

                match data.reader.read(buffer) {
                    Ok(0) => return 0,
                    Ok(nb) => {
                        if buffer.len() == nb {
                            return nmemb;
                        } else {
                            unsafe { ptr = ptr.offset(nb as isize) };
                        }
                    },
                    Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {
                        return 0
                    },
                    Err(e) => {
                        data.read_error = Some(e);
                        return 0;
                    }
                };
            }
        }

        extern fn seek_func<R>(datasource: *mut libc::c_void, offset: ogg_sys::ogg_int64_t,
            whence: libc::c_int) -> libc::c_int where R: Read + Seek
        {
            let data: &mut DecoderData<R> = unsafe { std::mem::transmute(datasource) };

            let result = match whence {
                libc::SEEK_SET => data.reader.seek(io::SeekFrom::Start(offset as u64)),
                libc::SEEK_CUR => data.reader.seek(io::SeekFrom::Current(offset)),
                libc::SEEK_END => data.reader.seek(io::SeekFrom::End(offset)),
                _ => unreachable!()
            };

            match result {
                Ok(_) => 0,
                Err(_) => -1
            }
        }

        extern fn tell_func<R>(datasource: *mut libc::c_void) -> libc::c_long
            where R: Read + Seek
        {
            let data: &mut DecoderData<R> = unsafe { std::mem::transmute(datasource) };
            data.reader.seek(io::SeekFrom::Current(0)).map(|v| v as libc::c_long).unwrap_or(-1)
        }

        let callbacks = {
            let mut callbacks: vorbisfile_sys::ov_callbacks = unsafe { std::mem::zeroed() };
            callbacks.read_func = read_func::<R>;
            callbacks.seek_func = seek_func::<R>;
            callbacks.tell_func = tell_func::<R>;
            callbacks
        };

        let mut data = Box::new(DecoderData {
            vorbis: unsafe { std::mem::uninitialized() },
            reader: input,
            current_logical_bitstream: 0,
            read_error: None,
        });

        // initializing
        unsafe {
            let data_ptr = &mut *data as *mut DecoderData<R>;
            let data_ptr = data_ptr as *mut libc::c_void;
            try!(check_errors(vorbisfile_sys::ov_open_callbacks(data_ptr, &mut data.vorbis,
                std::ptr::null(), 0, callbacks)));
        }

        Ok(Decoder {
            data: data,
        })
    }

    pub fn packets(&mut self) -> PacketsIter<R> {
        PacketsIter(&mut *self.data)
    }
}

impl<'a, R> Iterator for PacketsIter<'a, R> where R: 'a + Read + Seek {
    type Item = Result<Packet, VorbisError>;

    fn next(&mut self) -> Option<Result<Packet, VorbisError>> {
        let mut buffer = std::iter::repeat(0i16).take(2048).collect::<Vec<_>>();
        let buffer_len = buffer.len() * 2;

        match unsafe {
            vorbisfile_sys::ov_read(&mut self.0.vorbis, buffer.as_mut_ptr() as *mut i8,
                buffer_len as libc::c_int, 0, 2, 1, &mut self.0.current_logical_bitstream)
        } {
            0 => {
                match self.0.read_error.take() {
                    Some(err) => Some(Err(VorbisError::ReadError(err))),
                    None => None,
                }
            },

            err if err < 0 => {
                match check_errors(err as libc::c_int) {
                    Err(e) => Some(Err(e)),
                    Ok(_) => unreachable!()
                }
            },

            len => {
                buffer.truncate(len as usize / 2);

                let infos = unsafe { vorbisfile_sys::ov_info(&mut self.0.vorbis,
                    self.0.current_logical_bitstream) };

                let infos: &vorbis_sys::vorbis_info = unsafe { std::mem::transmute(infos) };

                Some(Ok(Packet {
                    data: buffer,
                    channels: infos.channels as u16,
                    rate: infos.rate as u64,
                    bitrate_upper: infos.bitrate_upper as u64,
                    bitrate_nominal: infos.bitrate_nominal as u64,
                    bitrate_lower: infos.bitrate_lower as u64,
                    bitrate_window: infos.bitrate_window as u64,
                }))
            }
        }
    }
}

impl<R> Drop for Decoder<R> where R: Read + Seek {
    fn drop(&mut self) {
        unsafe {
            vorbisfile_sys::ov_clear(&mut self.data.vorbis);
        }
    }
}

fn check_errors(code: libc::c_int) -> Result<(), VorbisError> {
    match code {
        0 => Ok(()),

        vorbis_sys::OV_ENOTVORBIS => Err(VorbisError::NotVorbis),
        vorbis_sys::OV_EVERSION => Err(VorbisError::VersionMismatch),
        vorbis_sys::OV_EBADHEADER => Err(VorbisError::BadHeader),
        vorbis_sys::OV_EINVAL => Err(VorbisError::InitialFileHeadersCorrupt),
        vorbis_sys::OV_HOLE => Err(VorbisError::Hole),

        vorbis_sys::OV_EREAD => unimplemented!(),

        // indicates a bug or heap/stack corruption
        vorbis_sys::OV_EFAULT => panic!("Internal libvorbis error"),
        _ => panic!("Unknown vorbis error")
    }
}
<commit_msg>Add seeking support.<commit_after>extern crate ogg_sys;
extern crate vorbis_sys;
extern crate vorbisfile_sys;
extern crate libc;

use std::io::{self, Read, Seek};

/// Allows you to decode a sound file stream into packets.
pub struct Decoder<R> where R: Read + Seek {
    // further informations are boxed so that a pointer can be passed to callbacks
    data: Box<DecoderData<R>>,
}

///
pub struct PacketsIter<'a, R: 'a + Read + Seek>(&'a mut DecoderData<R>);

/// Errors that can happen while decoding
#[derive(Debug)]
pub enum VorbisError {
    ReadError(io::Error),
    NotVorbis,
    VersionMismatch,
    BadHeader,
    InitialFileHeadersCorrupt,
    Hole,
}

impl std::error::Error for VorbisError {
    fn description(&self) -> &str {
        match self {
            &VorbisError::ReadError(_) => "A read from media returned an error",
            &VorbisError::NotVorbis => "Bitstream does not contain any Vorbis data",
            &VorbisError::VersionMismatch => "Vorbis version mismatch",
            &VorbisError::BadHeader => "Invalid Vorbis bitstream header",
            &VorbisError::InitialFileHeadersCorrupt => "Initial file headers are corrupt",
            &VorbisError::Hole => "Interruption of data",
        }
    }

    fn cause(&self) -> Option<&std::error::Error> {
        match self {
            &VorbisError::ReadError(ref err) => Some(err as &std::error::Error),
            _ => None
        }
    }
}

impl std::fmt::Display for VorbisError {
    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        write!(fmt, "{}", std::error::Error::description(self))
    }
}

impl From<io::Error> for VorbisError {
    fn from(err: io::Error) -> VorbisError {
        VorbisError::ReadError(err)
    }
}

struct DecoderData<R> where R: Read + Seek {
    vorbis: vorbisfile_sys::OggVorbis_File,
    reader: R,
    current_logical_bitstream: libc::c_int,
    read_error: Option<io::Error>,
}

unsafe impl<R: Read + Seek + Send> Send for DecoderData<R> {}

/// Packet of data.
///
/// Each sample is an `i16` ranging from I16_MIN to I16_MAX.
///
/// The channels are interleaved in the data. For example if you have two channels, you will
/// get a sample from channel 1, then a sample from channel 2, than a sample from channel 1, etc.
#[derive(Clone, Debug)]
pub struct Packet {
    pub data: Vec<i16>,
    pub channels: u16,
    pub rate: u64,
    pub bitrate_upper: u64,
    pub bitrate_nominal: u64,
    pub bitrate_lower: u64,
    pub bitrate_window: u64,
}

impl<R> Decoder<R> where R: Read + Seek {
    pub fn new(input: R) -> Result<Decoder<R>, VorbisError> {
        extern fn read_func<R>(ptr: *mut libc::c_void, size: libc::size_t, nmemb: libc::size_t,
            datasource: *mut libc::c_void) -> libc::size_t where R: Read + Seek
        {
            use std::slice;

            let mut ptr = ptr as *mut u8;

            let data: &mut DecoderData<R> = unsafe { std::mem::transmute(datasource) };

            loop {
                let buffer = ptr.clone();
                let buffer = unsafe { slice::from_raw_parts_mut(buffer, size as usize * nmemb as usize) };

                match data.reader.read(buffer) {
                    Ok(0) => return 0,
                    Ok(nb) => {
                        if buffer.len() == nb {
                            return nmemb;
                        } else {
                            unsafe { ptr = ptr.offset(nb as isize) };
                        }
                    },
                    Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {
                        return 0
                    },
                    Err(e) => {
                        data.read_error = Some(e);
                        return 0;
                    }
                };
            }
        }

        extern fn seek_func<R>(datasource: *mut libc::c_void, offset: ogg_sys::ogg_int64_t,
            whence: libc::c_int) -> libc::c_int where R: Read + Seek
        {
            let data: &mut DecoderData<R> = unsafe { std::mem::transmute(datasource) };

            let result = match whence {
                libc::SEEK_SET => data.reader.seek(io::SeekFrom::Start(offset as u64)),
                libc::SEEK_CUR => data.reader.seek(io::SeekFrom::Current(offset)),
                libc::SEEK_END => data.reader.seek(io::SeekFrom::End(offset)),
                _ => unreachable!()
            };

            match result {
                Ok(_) => 0,
                Err(_) => -1
            }
        }

        extern fn tell_func<R>(datasource: *mut libc::c_void) -> libc::c_long
            where R: Read + Seek
        {
            let data: &mut DecoderData<R> = unsafe { std::mem::transmute(datasource) };
            data.reader.seek(io::SeekFrom::Current(0)).map(|v| v as libc::c_long).unwrap_or(-1)
        }

        let callbacks = {
            let mut callbacks: vorbisfile_sys::ov_callbacks = unsafe { std::mem::zeroed() };
            callbacks.read_func = read_func::<R>;
            callbacks.seek_func = seek_func::<R>;
            callbacks.tell_func = tell_func::<R>;
            callbacks
        };

        let mut data = Box::new(DecoderData {
            vorbis: unsafe { std::mem::uninitialized() },
            reader: input,
            current_logical_bitstream: 0,
            read_error: None,
        });

        // initializing
        unsafe {
            let data_ptr = &mut *data as *mut DecoderData<R>;
            let data_ptr = data_ptr as *mut libc::c_void;
            try!(check_errors(vorbisfile_sys::ov_open_callbacks(data_ptr, &mut data.vorbis,
                std::ptr::null(), 0, callbacks)));
        }

        Ok(Decoder {
            data: data,
        })
    }

    pub fn time_seek(&mut self, s: f64) -> Result<(), VorbisError> {
        unsafe {
            check_errors(vorbisfile_sys::ov_time_seek(&mut self.data.vorbis, s))
        }
    }

    pub fn packets(&mut self) -> PacketsIter<R> {
        PacketsIter(&mut *self.data)
    }
}

impl<'a, R> Iterator for PacketsIter<'a, R> where R: 'a + Read + Seek {
    type Item = Result<Packet, VorbisError>;

    fn next(&mut self) -> Option<Result<Packet, VorbisError>> {
        let mut buffer = std::iter::repeat(0i16).take(2048).collect::<Vec<_>>();
        let buffer_len = buffer.len() * 2;

        match unsafe {
            vorbisfile_sys::ov_read(&mut self.0.vorbis, buffer.as_mut_ptr() as *mut i8,
                buffer_len as libc::c_int, 0, 2, 1, &mut self.0.current_logical_bitstream)
        } {
            0 => {
                match self.0.read_error.take() {
                    Some(err) => Some(Err(VorbisError::ReadError(err))),
                    None => None,
                }
            },

            err if err < 0 => {
                match check_errors(err as libc::c_int) {
                    Err(e) => Some(Err(e)),
                    Ok(_) => unreachable!()
                }
            },

            len => {
                buffer.truncate(len as usize / 2);

                let infos = unsafe { vorbisfile_sys::ov_info(&mut self.0.vorbis,
                    self.0.current_logical_bitstream) };

                let infos: &vorbis_sys::vorbis_info = unsafe { std::mem::transmute(infos) };

                Some(Ok(Packet {
                    data: buffer,
                    channels: infos.channels as u16,
                    rate: infos.rate as u64,
                    bitrate_upper: infos.bitrate_upper as u64,
                    bitrate_nominal: infos.bitrate_nominal as u64,
                    bitrate_lower: infos.bitrate_lower as u64,
                    bitrate_window: infos.bitrate_window as u64,
                }))
            }
        }
    }
}

impl<R> Drop for Decoder<R> where R: Read + Seek {
    fn drop(&mut self) {
        unsafe {
            vorbisfile_sys::ov_clear(&mut self.data.vorbis);
        }
    }
}

fn check_errors(code: libc::c_int) -> Result<(), VorbisError> {
    match code {
        0 => Ok(()),

        vorbis_sys::OV_ENOTVORBIS => Err(VorbisError::NotVorbis),
        vorbis_sys::OV_EVERSION => Err(VorbisError::VersionMismatch),
        vorbis_sys::OV_EBADHEADER => Err(VorbisError::BadHeader),
        vorbis_sys::OV_EINVAL => Err(VorbisError::InitialFileHeadersCorrupt),
        vorbis_sys::OV_HOLE => Err(VorbisError::Hole),

        vorbis_sys::OV_EREAD => unimplemented!(),

        // indicates a bug or heap/stack corruption
        vorbis_sys::OV_EFAULT => panic!("Internal libvorbis error"),
        _ => panic!("Unknown vorbis error")
    }
}
<|endoftext|>


<commit_before>// use variable names from paper, namely registers M
#![allow(non_snake_case)]

#![crate_name = "basichll"]
#![crate_type = "lib"]

/* -------------------- std libs ------------------- */
use std::cmp;
use std::fmt;
use std::hash::{ Hash, Hasher, SipHasher };
use std::iter::{ repeat, Iterator };
/* ------------------------------------------------- */

/* -------------------- helpers -------------------- */

fn alpha (m: usize) -> f64 {
    match m {
        16 => 0.673,
        32 => 0.697,
        64 => 0.709,
        _  => 0.7213/(1f64 + 1.079/(m as f64))
    }
}

fn leftmost_one_bit (v: u64) -> usize {
    let mut counter: usize = 0;
    let mut shiftable = v;

    while shiftable > 0 {
        shiftable >>= 1;
        counter += 1;
    }

    64 - counter
}

/* ------------------------------------------------- */

/* --------------- hyper log log ------------------- */

pub struct HLL {
    alpha: f64,
    b: u32,
    m: usize,
    M: Vec<u8>,
    // [!] this is pretty much a hack until I can think of something
    //     better to do for the monoid instance. Basically we need the
    //     zero value to always satisfy the left and right identity laws
    //     but because you need to have the number of registers be
    //     equivalent to do addition, it implies you need a distinct
    //     monoid instance per HLL configuration (i.e. an HLL of 4
    //     registers has a distinct zero from a HLL of 16).
    //
    //     Because I can't really do dependent types in rust, we instead
    //     have a distinguished zero element, that is allowed to bypass
    //     the assertions on the equivalent sizes...
    //
    //     For reference, Ed Kmett's haskell implementation actually does
    //     use higher kinded types and some tricky reflection to make the
    //     monoid instance be parameterised by a config type that is itself
    //     typed to a Peano natural encoded type. Twitter's algebird instance
    //     declares a separate class that encapsulates the notion of
    //     a "HyperLogLogMonoid" instance, and instances of that class are
    //     instantiated with the register size (i.e. the 'instance' for monoid
    //     is just an 'instance' of the class, for two interpretations of
    //     'instance').
    isZero: bool
}

impl HLL {
    pub fn one_hundred_twenty_eight () -> HLL {
        HLL::new(0.09192)
    }

    pub fn new(error: f64) -> HLL {
        assert!(error > 0.0 && error < 1.0);
        // error = 1.04 / sqrt(m)
        let m = ((1.04/error) * (1.04/error)).floor() as usize;
        let b = (m as f64).log2() as u32;

        HLL {
            alpha: alpha(m),
            b: b,
            m: m,
            M: repeat(0u8).take(m).collect(),
            isZero: false
        }
    }

    pub fn insert<T: Hash>(&mut self, val: &T) {
        let mut hasher = SipHasher::new();
        val.hash(&mut hasher);
        let hash = hasher.finish();

        // j is the first b many bits
        let j = (hash >> (64 - self.b)) as usize;
        // w is the remaining bits (i.e. b -> 64)
        let w = hash & (2u64.pow(64 - self.b) - 1) as u64;
        let rho = leftmost_one_bit(w) as u8;

        self.M[j] = cmp::max(self.M[j], rho);
    }

    pub fn count(&self) -> f64 {
        self.range_correction(self.raw_estimate())
    }

    fn raw_estimate(&self) -> f64 {
        let sum: f64 = self.M.iter().fold (0.0, |p, &r| p + 2.0f64.powi(-(r as i32)));

        self.alpha as f64 * ((self.m  * self.m) as f64) * (1.0 / sum)
    }

    fn empty_registers (&self) -> usize {
        self.M.iter().filter(|&r| *r == 0).count()
    }

    fn range_correction(&self, e: f64) -> f64 {
        let twoTo32: f64 = 2.0f64.powi(32) as f64;

        // small range correction
        if e <= (5.0*(self.m as f64))/2.0 {
            let v  = self.empty_registers() as f64;
            let fm = self.m as f64;

            return match v {
                0.0 => e,
                _   => fm * (fm / v).ln()
            }
        }

        // medium range (no) correction
        if e <= twoTo32/30.0 {
            return e;
        }

        -twoTo32 * (1.0 - e/twoTo32).ln()
    }

    pub fn registers(&self) -> Vec<u8> {
        self.M.clone()
    }

    pub fn clone (&self) -> HLL {
        HLL {
            alpha: self.alpha,
            b: self.b,
            m: self.m,
            M: self.M.clone(),
            isZero: self.isZero
        }
    }

    pub fn empty () -> HLL {
        HLL {
            alpha: 0.0,
            m: 0,
            b: 0,
            M: Vec::new(),
            isZero: true
        }
    }

}

/* ------------------------------------------------- */

/* --------------- trait instances ----------------- */

impl std::fmt::Display for HLL {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "α: {}, b: {}, m: {}", self.alpha, self.b, self.m)
    }
}

impl std::fmt::Debug for HLL {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "α: {}, b: {}, m: {}", self.alpha, self.b, self.m)
    }
}

impl std::cmp::Eq for HLL {}
impl std::cmp::PartialEq for HLL {
    fn eq(&self, other: &HLL) -> bool {
           self.alpha  == other.alpha
        && self.m      == other.m
        && self.b      == other.b
        && self.M      == other.M
        && self.isZero == other.isZero
    }
}

fn zipWith<R, U: Iterator, C: Fn(U::Item, U::Item) -> R> (combo: C, left: U, right: U)
   -> Vec<R> {
    left.zip(right).map(| (l, r) | combo(l, r)).collect()
}

fn mergeRegisters (first: &Vec<u8>, second: &Vec<u8>) -> Vec<u8> {
    zipWith(|&l, &r| std::cmp::max(l, r), first.iter(), second.iter())
}

impl<'a> std::ops::Add<&'a HLL> for &'a HLL {
    type Output = HLL;

    fn add(self, other: &'a HLL) -> HLL {
        // [!] gross...
        if self.isZero { return other.clone(); }
        if other.isZero { return self.clone(); }

        assert!(self.alpha == other.alpha);
        assert!(self.b == other.b);
        assert!(self.m == other.m);

        HLL {
            alpha: self.alpha,
            b: self.b,
            m: self.m,
            M: mergeRegisters(&self.M, &other.M),
            isZero: false
        }
    }
}

/* ------------------------------------------------- */
<commit_msg>:pencil: add rustdocs<commit_after>// use variable names from paper, namely registers M
#![allow(non_snake_case)]

#![crate_name = "basichll"]
#![crate_type = "lib"]

/* -------------------- std libs ------------------- */
use std::cmp;
use std::fmt;
use std::hash::{ Hash, Hasher, SipHasher };
use std::iter::{ repeat, Iterator };
/* ------------------------------------------------- */

/* -------------------- helpers -------------------- */

fn alpha (m: usize) -> f64 {
    match m {
        16 => 0.673,
        32 => 0.697,
        64 => 0.709,
        _  => 0.7213/(1f64 + 1.079/(m as f64))
    }
}

fn leftmost_one_bit (v: u64) -> usize {
    let mut counter: usize = 0;
    let mut shiftable = v;

    while shiftable > 0 {
        shiftable >>= 1;
        counter += 1;
    }

    64 - counter
}

/* ------------------------------------------------- */

/* --------------- hyper log log ------------------- */

/// The `HLL` struct stores the underlying registers
/// of the HyperLogLog, with `m` many registers.
///
/// The value for `m` is derived from the desired error
/// of the estimation. The error is considered to be
/// 1.04 / sqrt(2 ^ bits). So, given a desired 1% error
/// rate, we result in around 12 bits per register,
/// producing an underlying M of 2^12 bits (i.e. 4kb).
pub struct HLL {
    alpha: f64,
    b: u32,
    m: usize,
    M: Vec<u8>,
    // [!] this is pretty much a hack until I can think of something
    //     better to do for the monoid instance. Basically we need the
    //     zero value to always satisfy the left and right identity laws
    //     but because you need to have the number of registers be
    //     equivalent to do addition, it implies you need a distinct
    //     monoid instance per HLL configuration (i.e. an HLL of 4
    //     registers has a distinct zero from a HLL of 16).
    //
    //     Because I can't really do dependent types in rust, we instead
    //     have a distinguished zero element, that is allowed to bypass
    //     the assertions on the equivalent sizes...
    //
    //     For reference, Ed Kmett's haskell implementation actually does
    //     use higher kinded types and some tricky reflection to make the
    //     monoid instance be parameterised by a config type that is itself
    //     typed to a Peano natural encoded type. Twitter's algebird instance
    //     declares a separate class that encapsulates the notion of
    //     a "HyperLogLogMonoid" instance, and instances of that class are
    //     instantiated with the register size (i.e. the 'instance' for monoid
    //     is just an 'instance' of the class, for two interpretations of
    //     'instance').
    isZero: bool
}

impl HLL {
    /// Convenience function to produce a HLL with
    /// one hundred and twenty eight registers.
    pub fn one_hundred_twenty_eight () -> HLL {
        HLL::new(0.09192)
    }

    /// Create a new HLL with the desired standard error.
    /// Some examples might be:
    ///
    ///     bits    size    error
    ///     12      4096    0.0163
    ///     13      8192    0.0115
    ///     14      16384   0.0081
    ///
    /// The error must be between 0.0 and 1.0. Beware using a stupidly
    /// small error size will grow beyond e.g. isize at less than 0.03
    /// (if you need something that isn't an estimate probably don't use
    /// a hyperloglog).
    pub fn new(error: f64) -> HLL {
        assert!(error > 0.0 && error < 1.0);
        // error = 1.04 / sqrt(m)
        let m = ((1.04/error) * (1.04/error)).floor() as usize;
        let b = (m as f64).log2() as u32;

        HLL {
            alpha: alpha(m),
            b: b,
            m: m,
            M: repeat(0u8).take(m).collect(),
            isZero: false
        }
    }

    /// Add an element into the hyperloglog estimate.
    /// We require the type of value to be able to be hashed.
    pub fn insert<T: Hash>(&mut self, val: &T) {
        let mut hasher = SipHasher::new();
        val.hash(&mut hasher);
        let hash = hasher.finish();

        // j is the first b many bits
        let j = (hash >> (64 - self.b)) as usize;
        // w is the remaining bits (i.e. b -> 64)
        let w = hash & (2u64.pow(64 - self.b) - 1) as u64;
        let rho = leftmost_one_bit(w) as u8;

        self.M[j] = cmp::max(self.M[j], rho);
    }

    /// Return the estimated cardinality of the observed set
    /// of elements.
    pub fn count(&self) -> f64 {
        self.range_correction(self.raw_estimate())
    }

    fn raw_estimate(&self) -> f64 {
        let sum: f64 = self.M.iter().fold (0.0, |p, &r| p + 2.0f64.powi(-(r as i32)));

        self.alpha as f64 * ((self.m  * self.m) as f64) * (1.0 / sum)
    }

    fn empty_registers (&self) -> usize {
        self.M.iter().filter(|&r| *r == 0).count()
    }

    fn range_correction(&self, e: f64) -> f64 {
        let twoTo32: f64 = 2.0f64.powi(32) as f64;

        // small range correction
        if e <= (5.0*(self.m as f64))/2.0 {
            let v  = self.empty_registers() as f64;
            let fm = self.m as f64;

            return match v {
                0.0 => e,
                _   => fm * (fm / v).ln()
            }
        }

        // medium range (no) correction
        if e <= twoTo32/30.0 {
            return e;
        }

        -twoTo32 * (1.0 - e/twoTo32).ln()
    }

    /// Access a copy of the underlying registers (this is mainly
    /// here just for debugging/testing... its unlikely you'll need
    /// this access typically).
    pub fn registers(&self) -> Vec<u8> {
        self.M.clone()
    }

    /// Copies this instance into a new HLL.
    /// Doesn't do anything tricky (i.e. this will entirely
    /// re-allocate the underlying registers).
    pub fn clone (&self) -> HLL {
        HLL {
            alpha: self.alpha,
            b: self.b,
            m: self.m,
            M: self.M.clone(),
            isZero: self.isZero
        }
    }

    /// A completely zeroed HLL. Not particularly useful
    /// except as an identity element in `Add`.
    pub fn empty () -> HLL {
        HLL {
            alpha: 0.0,
            m: 0,
            b: 0,
            M: Vec::new(),
            isZero: true
        }
    }

}

/* ------------------------------------------------- */

/* --------------- trait instances ----------------- */

impl std::fmt::Display for HLL {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "α: {}, b: {}, m: {}", self.alpha, self.b, self.m)
    }
}

impl std::fmt::Debug for HLL {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "α: {}, b: {}, m: {}", self.alpha, self.b, self.m)
    }
}

/// A HLL is considered equal to another HLL when its
/// configuration and registers are exactly identical.
impl std::cmp::Eq for HLL {}
impl std::cmp::PartialEq for HLL {
    fn eq(&self, other: &HLL) -> bool {
           self.alpha  == other.alpha
        && self.m      == other.m
        && self.b      == other.b
        && self.M      == other.M
        && self.isZero == other.isZero
    }
}

fn zipWith<R, U: Iterator, C: Fn(U::Item, U::Item) -> R> (combo: C, left: U, right: U)
   -> Vec<R> {
    left.zip(right).map(| (l, r) | combo(l, r)).collect()
}

fn mergeRegisters (first: &Vec<u8>, second: &Vec<u8>) -> Vec<u8> {
    zipWith(|&l, &r| std::cmp::max(l, r), first.iter(), second.iter())
}

/// Adding together two HLLs produces a new HLL where
/// the larger value of each register has been selected.
impl<'a> std::ops::Add<&'a HLL> for &'a HLL {
    type Output = HLL;

    fn add(self, other: &'a HLL) -> HLL {
        // [!] gross...
        if self.isZero { return other.clone(); }
        if other.isZero { return self.clone(); }

        assert!(self.alpha == other.alpha);
        assert!(self.b == other.b);
        assert!(self.m == other.m);

        HLL {
            alpha: self.alpha,
            b: self.b,
            m: self.m,
            M: mergeRegisters(&self.M, &other.M),
            isZero: false
        }
    }
}

/* ------------------------------------------------- */
<|endoftext|>


<commit_before>//   Copyright 2015 Colin Sherratt
//
//   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.

#![feature(core)]

extern crate atom;

use std::sync::atomic::{AtomicUsize, Ordering};
use std::thread;
use std::mem;
use std::ops::Deref;
use atom::{Atom, GetNextMut};

use std::boxed::FnBox;

pub use select::Select;
pub use barrier::Barrier;
mod select;
mod barrier;

/// Drop rules
/// This may be freed iff state is Pulsed | Dropped
/// and Waiting is Dropped
struct Inner {
    state: AtomicUsize,
    waiting: Atom<Waiting, Box<Waiting>>
}

// TODO 64bit sized, probably does not matter now
const PULSED: usize = 0x8000_0000;
const TX_DROP: usize = 0x4000_0000;
const TX_FLAGS: usize = PULSED | TX_DROP;
const REF_COUNT: usize = !TX_FLAGS;

struct Waiting {
    next: Option<Box<Waiting>>,
    wake: Wake
}

impl GetNextMut for Box<Waiting> {
    type NextPtr = Option<Box<Waiting>>;

    fn get_next(&mut self) -> &mut Option<Box<Waiting>> {
        &mut self.next
    }
}

enum Wake {
    Thread(thread::Thread),
    Select(select::Handle),
    Barrier(barrier::Handle),
    Callback(Box<FnBox() + Send>)
}

impl Waiting {
    fn wake(s: Box<Self>, id: usize) {
        let mut next = Some(s);
        while let Some(s) = next {
            // There must be a better way to do this...
            let s = *s;
            let Waiting { next: n, wake } = s;
            next = n;
            match wake {
                Wake::Thread(thread) => thread.unpark(),
                Wake::Select(select) => {
                    let trigger = {
                        let mut guard = select.0.lock().unwrap();
                        guard.ready.push(id);
                        guard.trigger.take()
                    };
                    trigger.map(|x| x.trigger());
                }
                Wake::Barrier(barrier) => {
                    let count = barrier.0.count.fetch_sub(1, Ordering::Relaxed);
                    if count == 1 {
                        let mut guard = barrier.0.trigger.lock().unwrap();
                        if let Some(t) = guard.take() {
                            t.trigger();
                        }
                    }
                }
                Wake::Callback(cb) => cb()
            }
        }
    }

    fn id(&self) -> usize {
        unsafe { mem::transmute(self) }
    }

    fn thread() -> Box<Waiting> {
        Box::new(Waiting {
            next: None,
            wake: Wake::Thread(thread::current())
        })
    }

    fn select(handle: select::Handle) ->Box<Waiting> {
        Box::new(Waiting{
            next: None,
            wake: Wake::Select(handle)
        })
    }

    fn barrier(handle: barrier::Handle) ->Box<Waiting> {
        Box::new(Waiting{
            next: None,
            wake: Wake::Barrier(handle)
        })
    }

    fn callback(f: Box<FnBox() + Send>) ->Box<Waiting> {
        Box::new(Waiting{
            next: None,
            wake: Wake::Callback(f)
        })
    }
}

unsafe impl Send for Trigger {}

pub struct Trigger {
    inner: *mut Inner,
    pulsed: bool
}

fn delete_inner(state: usize, inner: *mut Inner) {
    if state & REF_COUNT == 1 {
        let inner: Box<Inner> = unsafe {
            mem::transmute(inner)
        };
        drop(inner);
    }
}

impl Drop for Trigger {
    fn drop(&mut self) {
        if !self.pulsed {
            self.set(TX_DROP);
            self.wake();
        }
        let state = self.inner().state.fetch_sub(1, Ordering::Relaxed);
        delete_inner(state, self.inner)
    }
}

impl Trigger {
    /// Create a Trigger from a usize. This is natrually
    /// unsafe.
    pub unsafe fn cast_from_usize(ptr: usize) -> Trigger {
        Trigger {
            inner: mem::transmute(ptr),
            pulsed: false
        }
    }

    /// Convert a trigger to a usize, This is unsafe
    /// and it will kill your kittens if you are not carful
    /// This is used for cases rare cases
    pub unsafe fn cast_to_usize(self) -> usize {
        let us = mem::transmute(self.inner);
        mem::forget(self);
        us
    }

    fn inner(&self) -> &Inner {
        unsafe { mem::transmute(self.inner) }
    }

    fn set(&self, state: usize) -> usize {
        self.inner().state.fetch_or(state, Ordering::Relaxed)
    }

    fn wake(&self) {
        let id = unsafe { mem::transmute(self.inner) };
        match self.inner().waiting.take(Ordering::Acquire) {
            None => (),
            Some(v) => Waiting::wake(v, id)
        }
    }

    /// Trigger an pulse, this can only occure once
    /// Returns true if this triggering triggered the pulse
    pub fn trigger(mut self) {
        self.pulsed = true;
        self.set(PULSED);
        self.wake();

        let state = self.inner().state.fetch_sub(1, Ordering::Relaxed);
        delete_inner(state, self.inner);
        unsafe { mem::forget(self) }
    }
}

unsafe impl Send for Pulse {}

pub struct Pulse {
    inner: *mut Inner
}

impl Clone for Pulse {
    fn clone(&self) -> Pulse {
        self.inner().state.fetch_add(1, Ordering::Relaxed);
        Pulse { inner: self.inner }
    }
}

impl Drop for Pulse {
    fn drop(&mut self) {
        let flag = self.inner().state.fetch_sub(1, Ordering::Relaxed);
        delete_inner(flag, self.inner);
    }
}

impl Pulse {
    pub fn new() -> (Pulse, Trigger) {
        let inner = Box::new(Inner {
            state: AtomicUsize::new(2),
            waiting: Atom::empty()
        });

        let inner = unsafe {mem::transmute(inner)};

        (Pulse {
            inner: inner
         },
         Trigger {
            inner: inner,
            pulsed: false
        })
    }

    fn inner(&self) -> &Inner {
        unsafe { mem::transmute(self.inner) }
    }

    // Read out the state of the Pulse
    fn state(&self) -> usize {
        self.inner().state.load(Ordering::Relaxed)
    }

    /// Check to see if the pulse is pending or not
    pub fn is_pending(&self) -> bool {
        self.state() & TX_FLAGS == 0
    }

    // Check to see if the pulse is pending or not
    fn in_use(&self) -> bool {
        let state = self.state();
        (state & REF_COUNT) != 1 || (state & TX_FLAGS) == 0
    }

    /// Add a waiter to a waitlist
    fn add_to_waitlist(&self, waiter: Box<Waiting>) -> usize {
        let id = waiter.id();

        self.inner().waiting.replace_and_set_next(
            waiter,
            Ordering::AcqRel
        );

        // if armed fire now
        if !self.is_pending() {
            if let Some(t) = self.inner().waiting.take(Ordering::Acquire) {
                Waiting::wake(t, self.id());
            }
        }
        id
    }

    /// Remove Waiter with `id` from the waitlist
    fn remove_from_waitlist(&self, id: usize) {
        let mut wl = self.inner().waiting.take(Ordering::Acquire);
        while let Some(mut w) = wl {
            let next = w.next.take();
            if w.id() != id {
                self.add_to_waitlist(w);
            }
            wl = next;
        }
    }

    /// Arm a pulse to wake
    fn arm(self, waiter: Box<Waiting>) -> ArmedPulse {
        let id = self.add_to_waitlist(waiter);
        ArmedPulse {
            id: id,
            pulse: self
        }
    }

    /// Arm a pulse that is only armed for
    fn arm_ref<'a>(&'a self, waiter: Box<Waiting>) -> ArmedPulseRef<'a> {
        let id = self.add_to_waitlist(waiter);
        ArmedPulseRef {
            pulse: self,
            id: id
        }
    }

    /// Wait for an pulse to be triggered
    ///
    /// Panics if something else is waiting on this already
    pub fn wait(&self) -> Result<(), WaitError> {
        loop {
            if !self.is_pending() {
                let state = self.state();
                return if (state & PULSED) == PULSED {
                    Ok(())
                } else {
                    Err(WaitError(state))
                };
            }

            let p = self.arm_ref(Waiting::thread());
            if self.is_pending() {
                thread::park();
            }
            drop(p);
        }
    }

    pub fn id(&self) -> usize {
        unsafe { mem::transmute_copy(&self.inner) }
    }

    pub fn recycle(&self) -> Option<Trigger> {
        if self.in_use() {
            None
        } else {
            self.inner().state.store(2, Ordering::Relaxed);
            Some(Trigger{
                inner: self.inner,
                pulsed: false,
            })
        }
    }

    pub fn on_complete<F>(self, f: F) where F: FnOnce() + Send + 'static {
        self.arm(Waiting::callback(Box::new(f)));
    }
}

#[derive(Debug)]
pub struct WaitError(usize);

struct ArmedPulse {
    pulse: Pulse,
    id: usize
}

impl Deref for ArmedPulse {
    type Target = Pulse;

    fn deref(&self) -> &Pulse { &self.pulse }
}

impl ArmedPulse {
    fn disarm(self) -> Pulse {
        self.remove_from_waitlist(self.id);
        self.pulse
    }
}

struct ArmedPulseRef<'a> {
    pulse: &'a Pulse,
    id: usize
}

impl<'a> Deref for ArmedPulseRef<'a> {
    type Target = Pulse;

    fn deref(&self) -> &Pulse { &self.pulse }
}

impl<'a> Drop for ArmedPulseRef<'a> {
    fn drop(&mut self) {
        self.remove_from_waitlist(self.id);
    }
}<commit_msg>Remove ArmRef<commit_after>//   Copyright 2015 Colin Sherratt
//
//   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.

#![feature(core)]

extern crate atom;

use std::sync::atomic::{AtomicUsize, Ordering};
use std::thread;
use std::mem;
use std::ops::Deref;
use atom::{Atom, GetNextMut};

use std::boxed::FnBox;

pub use select::Select;
pub use barrier::Barrier;
mod select;
mod barrier;

/// Drop rules
/// This may be freed iff state is Pulsed | Dropped
/// and Waiting is Dropped
struct Inner {
    state: AtomicUsize,
    waiting: Atom<Waiting, Box<Waiting>>
}

// TODO 64bit sized, probably does not matter now
const PULSED: usize = 0x8000_0000;
const TX_DROP: usize = 0x4000_0000;
const TX_FLAGS: usize = PULSED | TX_DROP;
const REF_COUNT: usize = !TX_FLAGS;

struct Waiting {
    next: Option<Box<Waiting>>,
    wake: Wake
}

impl GetNextMut for Box<Waiting> {
    type NextPtr = Option<Box<Waiting>>;

    fn get_next(&mut self) -> &mut Option<Box<Waiting>> {
        &mut self.next
    }
}

enum Wake {
    Thread(thread::Thread),
    Select(select::Handle),
    Barrier(barrier::Handle),
    Callback(Box<FnBox() + Send>)
}

impl Waiting {
    fn wake(s: Box<Self>, id: usize) {
        let mut next = Some(s);
        while let Some(s) = next {
            // There must be a better way to do this...
            let s = *s;
            let Waiting { next: n, wake } = s;
            next = n;
            match wake {
                Wake::Thread(thread) => thread.unpark(),
                Wake::Select(select) => {
                    let trigger = {
                        let mut guard = select.0.lock().unwrap();
                        guard.ready.push(id);
                        guard.trigger.take()
                    };
                    trigger.map(|x| x.trigger());
                }
                Wake::Barrier(barrier) => {
                    let count = barrier.0.count.fetch_sub(1, Ordering::Relaxed);
                    if count == 1 {
                        let mut guard = barrier.0.trigger.lock().unwrap();
                        if let Some(t) = guard.take() {
                            t.trigger();
                        }
                    }
                }
                Wake::Callback(cb) => cb()
            }
        }
    }

    fn id(&self) -> usize {
        unsafe { mem::transmute(self) }
    }

    fn thread() -> Box<Waiting> {
        Box::new(Waiting {
            next: None,
            wake: Wake::Thread(thread::current())
        })
    }

    fn select(handle: select::Handle) ->Box<Waiting> {
        Box::new(Waiting{
            next: None,
            wake: Wake::Select(handle)
        })
    }

    fn barrier(handle: barrier::Handle) ->Box<Waiting> {
        Box::new(Waiting{
            next: None,
            wake: Wake::Barrier(handle)
        })
    }

    fn callback(f: Box<FnBox() + Send>) ->Box<Waiting> {
        Box::new(Waiting{
            next: None,
            wake: Wake::Callback(f)
        })
    }
}

unsafe impl Send for Trigger {}

pub struct Trigger {
    inner: *mut Inner,
    pulsed: bool
}

fn delete_inner(state: usize, inner: *mut Inner) {
    if state & REF_COUNT == 1 {
        let inner: Box<Inner> = unsafe {
            mem::transmute(inner)
        };
        drop(inner);
    }
}

impl Drop for Trigger {
    fn drop(&mut self) {
        if !self.pulsed {
            self.set(TX_DROP);
            self.wake();
        }
        let state = self.inner().state.fetch_sub(1, Ordering::Relaxed);
        delete_inner(state, self.inner)
    }
}

impl Trigger {
    /// Create a Trigger from a usize. This is natrually
    /// unsafe.
    pub unsafe fn cast_from_usize(ptr: usize) -> Trigger {
        Trigger {
            inner: mem::transmute(ptr),
            pulsed: false
        }
    }

    /// Convert a trigger to a usize, This is unsafe
    /// and it will kill your kittens if you are not carful
    /// This is used for cases rare cases
    pub unsafe fn cast_to_usize(self) -> usize {
        let us = mem::transmute(self.inner);
        mem::forget(self);
        us
    }

    fn inner(&self) -> &Inner {
        unsafe { mem::transmute(self.inner) }
    }

    fn set(&self, state: usize) -> usize {
        self.inner().state.fetch_or(state, Ordering::Relaxed)
    }

    fn wake(&self) {
        let id = unsafe { mem::transmute(self.inner) };
        match self.inner().waiting.take(Ordering::Acquire) {
            None => (),
            Some(v) => Waiting::wake(v, id)
        }
    }

    /// Trigger an pulse, this can only occure once
    /// Returns true if this triggering triggered the pulse
    pub fn trigger(mut self) {
        self.pulsed = true;
        self.set(PULSED);
        self.wake();

        let state = self.inner().state.fetch_sub(1, Ordering::Relaxed);
        delete_inner(state, self.inner);
        unsafe { mem::forget(self) }
    }
}

unsafe impl Send for Pulse {}

pub struct Pulse {
    inner: *mut Inner
}

impl Clone for Pulse {
    fn clone(&self) -> Pulse {
        self.inner().state.fetch_add(1, Ordering::Relaxed);
        Pulse { inner: self.inner }
    }
}

impl Drop for Pulse {
    fn drop(&mut self) {
        let flag = self.inner().state.fetch_sub(1, Ordering::Relaxed);
        delete_inner(flag, self.inner);
    }
}

impl Pulse {
    pub fn new() -> (Pulse, Trigger) {
        let inner = Box::new(Inner {
            state: AtomicUsize::new(2),
            waiting: Atom::empty()
        });

        let inner = unsafe {mem::transmute(inner)};

        (Pulse {
            inner: inner
         },
         Trigger {
            inner: inner,
            pulsed: false
        })
    }

    fn inner(&self) -> &Inner {
        unsafe { mem::transmute(self.inner) }
    }

    // Read out the state of the Pulse
    fn state(&self) -> usize {
        self.inner().state.load(Ordering::Relaxed)
    }

    /// Check to see if the pulse is pending or not
    pub fn is_pending(&self) -> bool {
        self.state() & TX_FLAGS == 0
    }

    // Check to see if the pulse is pending or not
    fn in_use(&self) -> bool {
        let state = self.state();
        (state & REF_COUNT) != 1 || (state & TX_FLAGS) == 0
    }

    /// Add a waiter to a waitlist
    fn add_to_waitlist(&self, waiter: Box<Waiting>) -> usize {
        let id = waiter.id();

        self.inner().waiting.replace_and_set_next(
            waiter,
            Ordering::AcqRel
        );

        // if armed fire now
        if !self.is_pending() {
            if let Some(t) = self.inner().waiting.take(Ordering::Acquire) {
                Waiting::wake(t, self.id());
            }
        }
        id
    }

    /// Remove Waiter with `id` from the waitlist
    fn remove_from_waitlist(&self, id: usize) {
        let mut wl = self.inner().waiting.take(Ordering::Acquire);
        while let Some(mut w) = wl {
            let next = w.next.take();
            if w.id() != id {
                self.add_to_waitlist(w);
            }
            wl = next;
        }
    }

    /// Arm a pulse to wake
    fn arm(self, waiter: Box<Waiting>) -> ArmedPulse {
        let id = self.add_to_waitlist(waiter);
        ArmedPulse {
            id: id,
            pulse: self
        }
    }

    /// Wait for an pulse to be triggered
    ///
    /// Panics if something else is waiting on this already
    pub fn wait(&self) -> Result<(), WaitError> {
        loop {
            if !self.is_pending() {
                let state = self.state();
                return if (state & PULSED) == PULSED {
                    Ok(())
                } else {
                    Err(WaitError(state))
                };
            }

            let p = self.clone().arm(Waiting::thread());
            if self.is_pending() {
                thread::park();
            }
            drop(p);
        }
    }

    pub fn id(&self) -> usize {
        unsafe { mem::transmute_copy(&self.inner) }
    }

    pub fn recycle(&self) -> Option<Trigger> {
        if self.in_use() {
            None
        } else {
            self.inner().state.store(2, Ordering::Relaxed);
            Some(Trigger{
                inner: self.inner,
                pulsed: false,
            })
        }
    }

    pub fn on_complete<F>(self, f: F) where F: FnOnce() + Send + 'static {
        self.arm(Waiting::callback(Box::new(f)));
    }
}

#[derive(Debug)]
pub struct WaitError(usize);

struct ArmedPulse {
    pulse: Pulse,
    id: usize
}

impl Deref for ArmedPulse {
    type Target = Pulse;

    fn deref(&self) -> &Pulse { &self.pulse }
}

impl ArmedPulse {
    fn disarm(self) -> Pulse {
        self.remove_from_waitlist(self.id);
        self.pulse
    }
}
<|endoftext|>


<commit_before>
//! # mruby
//! mruby binding
#[allow(dead_code)]
extern crate libc;
use std::rc::{Rc};
use std::cell::{RefCell};
use mruby::{mrb_open,mrb_close,mrb_state,mrb_value,Struct_RClass};
mod mruby;

pub type MrbState = Rc<RefCell<*mut mrb_state>>;
pub type MrbClass = Rc<RefCell<*mut Struct_RClass>>;

pub struct Mrb {
    mrb : MrbState
}

pub fn new_mrb() -> Mrb {
    let mrb = unsafe {
        mrb_open()
    };
    Mrb{ mrb:Rc::new(RefCell::new(mrb)) }
}

pub struct Class {
    mrb : MrbState,
    clz : MrbClass,
    outer : MrbClass
}

impl Mrb {

    #[inline(always)]
    fn get_mrb(&self) -> *mut mrb_state {
        unsafe { *(self.mrb).borrow_mut() }
    }

    pub fn close(&self) {
        unsafe {
            mrb_close(self.get_mrb());
        }
        std::mem::drop(self);
    }

    pub fn get_class(&self,name:&str) -> Option<Class> {
        let mrb = unsafe { *self.get_mrb() };
        let class =
            match name {
                "object" => { mrb.object_class },
                "class" => { mrb.class_class },
                "string" => { mrb.string_class },
                "array" => { mrb.array_class },
                "hash" => { mrb.hash_class },
                _ => {
                    unsafe { mruby::mrb_class_get(self.get_mrb(),name.as_slice().as_ptr() as *const libc::c_char) }
                }
            };
        if class.is_null() {
            None
        } else {
            Some(Class{mrb:self.clone(),clz:Rc::new(RefCell::new(class)))
        }
    }

    pub fn load(&self,code:&str) -> mrb_value {
        unsafe {
            mruby::mrb_load_string(self.get_mrb(),code.as_slice().as_ptr() as *const libc::c_char)
        }
    }

    pub fn def_class(&self,clzname:&str,outer:Option<Class>) -> Class {
        let super_clz = match outer {
            Some(c) => c,
            None() => {
}

#[test]
fn test_mrb_open() {
    let m = new_mrb();
    m.close();
}

#[test]
fn test_get_class() {
    let m = new_mrb();
    assert!(m.get_class("class").is_some())
    assert!(m.get_class("object").is_some())
    assert!(m.get_class("hash").is_some())
    assert!(m.get_class("array").is_some())
    assert!(m.get_class("string").is_some())
    m.close();
}

#[test]
fn test_load_str() {
    let m = new_mrb();
    let mut v = m.load("1..3.each do |i| puts i end");
    assert!(v.is_nil());
    m.close();
}
<commit_msg>add map<name,class><commit_after>
#![feature(unsafe_destructor)]
#[allow(dead_code)]

extern crate libc;
use std::rc::{Rc};
use std::cell::{RefCell};
use std::collections::{HashMap};
use mruby::{mrb_open,mrb_close,mrb_state,mrb_value,Struct_RClass};
mod mruby;

pub type MrbState = Rc<RefCell<*mut mrb_state>>;
pub type MrbClass = Rc<RefCell<*mut Struct_RClass>>;

pub struct Mrb {
    mrb : MrbState,
    clzs : RefCell<HashMap<String,MrbClass>>
}

pub struct Class {
    mrb : MrbState,
    clz : MrbClass
}

impl Mrb {

    pub fn new() -> Mrb {
        let mrb = unsafe {
            mrb_open()
        };
        let state = unsafe { *mrb };
        let clzs : RefCell<HashMap<String,MrbClass>> = RefCell::new(HashMap::new());
        let m = Mrb{ mrb:Rc::new(RefCell::new(mrb)),clzs:clzs };
        m.clzs.borrow_mut().insert(String::from_str("Object"),Rc::new(RefCell::new(state.object_class)));
        m.clzs.borrow_mut().insert(String::from_str("Class"),Rc::new(RefCell::new(state.class_class)));
        m.clzs.borrow_mut().insert(String::from_str("String"),Rc::new(RefCell::new(state.string_class)));
        m.clzs.borrow_mut().insert(String::from_str("Array"),Rc::new(RefCell::new(state.array_class)));
        m.clzs.borrow_mut().insert(String::from_str("Hash"),Rc::new(RefCell::new(state.hash_class)));
        m
    }

    #[inline(always)]
    fn get_mrb(&self) -> *mut mrb_state {
        *(self.mrb).borrow_mut()
    }

    pub fn get_class(&self,name:&str) -> Option<Class> {
        let mut h = self.clzs.borrow_mut();
        let clzname = String::from_str(name);
        if h.get(&clzname).is_some() {
                return Some(Class{mrb:self.mrb.clone(),clz:h.get(&clzname).unwrap().clone()})
        }
        let mclz = unsafe {
            mruby::mrb_class_get(self.get_mrb(),
                                 name.as_slice().as_ptr() as *const libc::c_char)
        };
        if mclz.is_null() {
            None
        } else {
            let class = Class{mrb:self.mrb.clone(),clz:Rc::new(RefCell::new(mclz))};
            h.insert(clzname,class.clz.clone());
            Some(class)
        }
    }

    pub fn load(&self,code:&str) -> mrb_value {
        unsafe {
            mruby::mrb_load_string(self.get_mrb(),
            code.as_slice().as_ptr() as *const libc::c_char)
        }
    }

}

#[unsafe_destructor]
impl Drop for RefCell<*mut mrb_state> {
    fn drop(&mut self) {
        let mrb = *self.borrow_mut();
        unsafe {
            mrb_close(mrb);
        }
    }
}

#[test]
fn test_mrb_open() {
    let m = Mrb::new();
}

#[test]
fn test_get_class() {
    let m = Mrb::new();
    assert!(m.get_class("Class").is_some());
    assert!(m.get_class("Object").is_some());
    assert!(m.get_class("Hash").is_some());
    assert!(m.get_class("Array").is_some());
    assert!(m.get_class("String").is_some());
}

#[test]
fn test_load_str() {
    let m = Mrb::new();
    let mut v = m.load("1..3.each do |i| puts i end");
    assert!(v.is_nil());
}
<|endoftext|>


<commit_before>#![crate_type = "rlib"]
#![feature(macro_rules,globs)]

#[macro_export]
macro_rules! monad(
    ($m:ident {
        let $p:pat = $e:expr;
        $($rest:tt)*
    } in $y:expr) => ({
        let $p = $e;
        monad!($m { $($rest)* } in $y)
    });
    ($m:ident {
        $p:pat <- $e:expr;
        $($rest:tt)*
    } in $y:expr) => (
        $m::mbind($e,|$p| {
            monad!($m {
                $($rest)*
            } in $y)
        })
    );
    ($m:ident {
        $e:expr;
        $($rest:tt)*
    } in $y:expr) => (
        monad!($m { _ <- $e; $($rest)* } in $y)
    );
    ($m:ident {
        $e:expr
    } in $y:expr) => (
        monad!($m { _ <- $e; } in $y)
    );
    ($m:ident { } in $y:expr) => ($m::mpure($y));
)

pub struct OptionMonad;

impl OptionMonad {
    pub fn mpure<T>(value: T) -> Option<T> { Some(value) }
    pub fn mbind<T,U>(value: Option<T>, func: |T| -> Option<U>) -> Option<U> {
        match value {
            Some(v) => func(v),
            None => None
        }
    }
}

pub struct ResultMonad;

impl ResultMonad {
    pub fn mpure<T,E>(value: T) -> Result<T,E> { Ok(value) }
    pub fn mbind<T,U,E>(value: Result<T,E>, func: |T| -> Result<U,E>) -> Result<U,E> {
        match value {
            Ok(v) => func(v),
            Err(e) => Err(e)
        }
    }
}

pub struct IterMonad;

impl IterMonad {
    pub fn mpure<T>(value: T) -> std::option::Item<T> {
        Some(value).into_iter()
    }
    pub fn mbind<T,U,I:Iterator<T>,J:Iterator<U>>(value: I, func: |T| -> J)
                                                  -> std::vec::MoveItems<U> {
        value.flat_map(func).collect::<Vec<U>>().into_iter()
    }
}

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

    #[test]
    fn option() {
        let result = monad!(OptionMonad {
            (a,x) <- Some((2i,6i));
            (b,y) <- Some((3i,7i));
        } in (a+b,x*y));

        assert_eq!(result, Some((2+3,6*7)));
    }

    #[test]
    fn option_fail() {
        let result = monad!(OptionMonad {
            (a,x) <- None::<(int,int)>;
            (b,y) <- Some((3i,7i));
        } in (a+b,x*y));

        assert_eq!(result, None);
    }

    #[test]
    fn result() {
        let result: Result<(int,int),()> = monad!(ResultMonad {
            (a,x) <- Ok((2i,6i));
            (b,y) <- Ok((3i,7i));
        } in (a+b,x*y));

        assert_eq!(result, Ok((2+3,6*7)));
    }

    #[test]
    fn result_fail() {
        let result: Result<(int,int),()> = monad!(ResultMonad {
            (a,x) <- Err::<(int,int),()>(());
            (b,y) <- Ok((3i,7i));
        } in (a+b,x*y));

        assert_eq!(result, Err(()));
    }

    #[test]
    fn iter() {
        let mut result = monad!(IterMonad {
            a <- vec![1u,2,3].into_iter();
            b <- vec!["hello"].into_iter();
        } in (a,b));

        assert_eq!(result.collect::<Vec<(uint,&'static str)>>(),
                   vec![(1u,"hello"),(2,"hello"),(3,"hello")]);
    }

    #[test]
    fn ordinary_bindings() {
        let result = monad!(OptionMonad {
            let a = Some(5u);
            x <- a;
            let b = Some(4u);
            y <- b;
        } in x*y);
        assert_eq!(result, Some(20));
    }

    #[test]
    fn sequence() {
        let result = monad!(OptionMonad {
            Some(());
            x <- Some(());
            None::<()>
        } in x);
        assert_eq!(result, None);
    }
}
<commit_msg>Update and fix library<commit_after>#![crate_type = "rlib"]
#![feature(macro_rules, globs)]

#[macro_export]
macro_rules! monad {
    ($m:ident {
        let $p:pat = $e:expr;
        $($rest:tt)*
    } in $y:expr) => ({
        let $p = $e;
        monad!($m { $($rest)* } in $y)
    });
    ($m:ident {
        $p:pat <- $e:expr;
        $($rest:tt)*
    } in $y:expr) => (
        $m::mbind($e, move |&mut:$p| {
            monad!($m {
                $($rest)*
            } in $y)
        })
    );
    ($m:ident {
        $e:expr;
        $($rest:tt)*
    } in $y:expr) => (
        monad!($m { _ <- $e; $($rest)* } in $y)
    );
    ($m:ident {
        $e:expr
    } in $y:expr) => (
        monad!($m { _ <- $e; } in $y)
    );
    ($m:ident { } in $y:expr) => ($m::mpure($y));
}

#[allow(missing_copy_implementations)]
pub struct OptionMonad;

impl OptionMonad {
    pub fn mpure<T>(value: T) -> Option<T> { Some(value) }
    pub fn mbind<T,U,F>(value: Option<T>, mut func: F) -> Option<U>
                       where F: FnMut(T) -> Option<U> {
        match value {
            Some(v) => func(v),
            None => None
        }
    }
}

#[allow(missing_copy_implementations)]
pub struct ResultMonad;

impl ResultMonad {
    pub fn mpure<T,E>(value: T) -> Result<T,E> { Ok(value) }
    pub fn mbind<T,U,E,F>(value: Result<T,E>, mut func: F) -> Result<U,E>
                         where F: FnMut(T) -> Result<U,E> {
        match value {
            Ok(v) => func(v),
            Err(e) => Err(e)
        }
    }
}

pub struct IterBind<T,U,I,J,F>
    where I: Iterator<T>,
          J: Iterator<U>,
          F: FnMut(T) -> J {
    input: I,
    output: Option<J>,
    func: F
}

impl<T,U,I,J,F> Iterator<U> for IterBind<T,U,I,J,F>
    where I: Iterator<T>,
          J: Iterator<U>,
          F: FnMut(T) -> J {
    fn next(&mut self) -> Option<U> {
        if let Some(mut o) = self.output.take() {
            if let Some(v) = o.next() {
                self.output = Some(o);
                Some(v)
            } else {
                self.output = self.input.next().map(|v| (self.func)(v));
                self.next()
            }
        } else {
            None
        }
    }
}

#[allow(missing_copy_implementations)]
pub struct IterMonad;

impl IterMonad {
    pub fn mpure<T>(value: T) -> std::option::IntoIter<T> {
        Some(value).into_iter()
    }
    pub fn mbind<T,U,I,J,F>(mut input: I, mut func: F) -> IterBind<T,U,I,J,F>
                           where I: Iterator<T>,
                                 J: Iterator<U>,
                                 F: FnMut(T) -> J {
        let output = input.next().map(|v| func(v));
        IterBind {
            input: input,
            output: output,
            func: func
        }
    }
}

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

    #[test]
    fn option() {
        let result = monad!(OptionMonad {
            (a,x) <- Some((2i,6i));
            (b,y) <- Some((3i,7i));
        } in (a+b,x*y));

        assert_eq!(result, Some((2+3,6*7)));
    }

    #[test]
    fn option_fail() {
        let result = monad!(OptionMonad {
            (a,x) <- None::<(int,int)>;
            (b,y) <- Some((3i,7i));
        } in (a+b,x*y));

        assert_eq!(result, None);
    }

    #[test]
    fn result() {
        let result: Result<(int,int),()> = monad!(ResultMonad {
            (a,x) <- Ok((2i,6i));
            (b,y) <- Ok((3i,7i));
        } in (a+b,x*y));

        assert_eq!(result, Ok((2+3,6*7)));
    }

    #[test]
    fn result_fail() {
        let result: Result<(int,int),()> = monad!(ResultMonad {
            (a,x) <- Err::<(int,int),()>(());
            (b,y) <- Ok((3i,7i));
        } in (a+b,x*y));

        assert_eq!(result, Err(()));
    }

    #[test]
    fn iter() {
        let result = monad!(IterMonad {
            a <- vec![1u, 2, 3].into_iter();
            b <- vec!["hello", "world"].into_iter();
        } in (a,b));

        assert_eq!(result.collect::<Vec<_>>(),
                   vec![(1, "hello"), (1, "world"),
                        (2, "hello"), (2, "world"),
                        (3, "hello"), (3, "world")]);
    }

    #[test]
    fn ordinary_bindings() {
        let result = monad!(OptionMonad {
            let a = Some(5u);
            x <- a;
            let b = Some(4u);
            y <- b;
        } in x*y);
        assert_eq!(result, Some(20));
    }

    #[test]
    fn sequence() {
        let result = monad!(OptionMonad {
            Some(());
            x <- Some(());
            None::<()>
        } in x);
        assert_eq!(result, None);
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2016 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/*
 * TODO: shortcuts to select text in the command line entry.
 * TODO: shortcut to move the cursor at the other end of the selection.
 * TODO: smart selection (select all on first time, select all except the prefix on the second).
 * TODO: remove blocking dialogs?
 * FIXME: can block in input mode.
 * TODO: use MainLoop::new() instead of gtk::main()?
 * FIXME: the commands in the config file are not executed.
 * TODO: take advantage of IntoOption and IntoPair.
 * TODO: automatically connect the AppClose message to Quit if it exists.
 * TODO: thread example (using a oneshot).
 * TODO: change all unneeded &mut self to &self.
 * TODO: set the size of the status bar according to the size of the font.
 * TODO: different event for activate event of special commands.
 * TODO: use the gtk::Statusbar widget?
 * TODO: Associate a color with modes.
 */

//! Minimal UI library based on GTK+.

#![warn(
    trivial_casts,
    trivial_numeric_casts,
    unused_extern_crates,
    unused_import_braces,
    unused_qualifications,
)]

extern crate gdk;
extern crate glib;
extern crate gtk;
#[macro_use]
extern crate log;
#[macro_use]
extern crate mg_settings;
extern crate pango;
#[macro_use]
extern crate relm;
#[macro_use]
extern crate relm_derive;

mod app;
pub mod completion;
mod file;
mod key_converter;

/// List of modes
pub type Modes = &'static [Mode];

/// A mode contains a prefix (i.e. "i") and a name (i.e. "insert").
/// It can only specify whether a count can be shown for it.
#[derive(Clone)]
pub struct Mode {
    pub name: &'static str,
    pub prefix: &'static str,
    pub show_count: bool,
}

pub use app::{Mg, parse_config};
pub use app::Msg::{
    Alert,
    AppClose,
    CloseWin,
    Completers,
    CompletionViewChange,
    CustomCommand,
    CustomDialog,
    DarkTheme,
    DeleteCompletionItem,
    Error,
    Info,
    Message,
    ModeChanged,
    Question,
    SetMode,
    SetSetting,
    SettingChanged,
    StatusBarVisible,
    Title,
    Variables,
    Warning,
};
pub use app::dialog::{
    BlockingInputDialog,
    DialogBuilder,
    DialogResult,
    InputDialog,
    Responder,
    blocking_dialog,
    blocking_input,
    blocking_question,
    blocking_yes_no_question,
    input,
    question,
    yes_no_question,
};
pub use app::settings::{DefaultConfig, NoSettings};
pub use app::status_bar::{StatusBar, StatusBarItem};
pub use app::status_bar::ItemMsg::{Color, Text};

#[macro_export]
macro_rules! hash {
    ($($ident:expr => $value:expr,)*) => {{
        let mut hash_map: ::mg::completion::Completers = ::std::collections::HashMap::new();
        $(hash_map.insert($ident, $value);)*
        hash_map
    }};
}

#[macro_export]
macro_rules! char_slice {
    ($( $val:expr ),*) => {{
        static SLICE: &'static [char] = &[$($val),*];
        SLICE
    }};
}

#[macro_export]
macro_rules! static_slice {
    ($( $val:expr ),* ; $typ:ty) => {{
        static SLICE: &'static [$typ] = &[$($val),*];
        SLICE
    }};
}
<commit_msg>Add comment<commit_after>/*
 * Copyright (c) 2016 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/*
 * FIXME: lowercase letter mapping gets trigger with uppercase letter (`e` vs `Shift-e`).
 * TODO: shortcuts to select text in the command line entry.
 * TODO: shortcut to move the cursor at the other end of the selection.
 * TODO: smart selection (select all on first time, select all except the prefix on the second).
 * TODO: remove blocking dialogs?
 * FIXME: can block in input mode.
 * TODO: use MainLoop::new() instead of gtk::main()?
 * FIXME: the commands in the config file are not executed.
 * TODO: take advantage of IntoOption and IntoPair.
 * TODO: automatically connect the AppClose message to Quit if it exists.
 * TODO: thread example (using a oneshot).
 * TODO: change all unneeded &mut self to &self.
 * TODO: set the size of the status bar according to the size of the font.
 * TODO: different event for activate event of special commands.
 * TODO: use the gtk::Statusbar widget?
 * TODO: Associate a color with modes.
 */

//! Minimal UI library based on GTK+.

#![warn(
    trivial_casts,
    trivial_numeric_casts,
    unused_extern_crates,
    unused_import_braces,
    unused_qualifications,
)]

extern crate gdk;
extern crate glib;
extern crate gtk;
#[macro_use]
extern crate log;
#[macro_use]
extern crate mg_settings;
extern crate pango;
#[macro_use]
extern crate relm;
#[macro_use]
extern crate relm_derive;

mod app;
pub mod completion;
mod file;
mod key_converter;

/// List of modes
pub type Modes = &'static [Mode];

/// A mode contains a prefix (i.e. "i") and a name (i.e. "insert").
/// It can only specify whether a count can be shown for it.
#[derive(Clone)]
pub struct Mode {
    pub name: &'static str,
    pub prefix: &'static str,
    pub show_count: bool,
}

pub use app::{Mg, parse_config};
pub use app::Msg::{
    Alert,
    AppClose,
    CloseWin,
    Completers,
    CompletionViewChange,
    CustomCommand,
    CustomDialog,
    DarkTheme,
    DeleteCompletionItem,
    Error,
    Info,
    Message,
    ModeChanged,
    Question,
    SetMode,
    SetSetting,
    SettingChanged,
    StatusBarVisible,
    Title,
    Variables,
    Warning,
};
pub use app::dialog::{
    BlockingInputDialog,
    DialogBuilder,
    DialogResult,
    InputDialog,
    Responder,
    blocking_dialog,
    blocking_input,
    blocking_question,
    blocking_yes_no_question,
    input,
    question,
    yes_no_question,
};
pub use app::settings::{DefaultConfig, NoSettings};
pub use app::status_bar::{StatusBar, StatusBarItem};
pub use app::status_bar::ItemMsg::{Color, Text};

#[macro_export]
macro_rules! hash {
    ($($ident:expr => $value:expr,)*) => {{
        let mut hash_map: ::mg::completion::Completers = ::std::collections::HashMap::new();
        $(hash_map.insert($ident, $value);)*
        hash_map
    }};
}

#[macro_export]
macro_rules! char_slice {
    ($( $val:expr ),*) => {{
        static SLICE: &'static [char] = &[$($val),*];
        SLICE
    }};
}

#[macro_export]
macro_rules! static_slice {
    ($( $val:expr ),* ; $typ:ty) => {{
        static SLICE: &'static [$typ] = &[$($val),*];
        SLICE
    }};
}
<|endoftext|>


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

#![feature(rustc_private)]

extern crate syntax;

use syntax::ast;
use syntax::codemap::Spanned;
use syntax::ext::base::ExtCtxt;
use syntax::parse::token;
use syntax::parse;
use syntax::print::pprust;
use syntax::ptr::P;

use syntax::ast::{TokenTree, Generics, Expr};

pub use syntax::parse::new_parser_from_tts;
pub use syntax::codemap::{BytePos, Span, dummy_spanned};

pub trait ToTokens {
    fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree>;
}

impl ToTokens for TokenTree {
    fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
        vec!(self.clone())
    }
}

impl<T: ToTokens> ToTokens for Vec<T> {
    fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
        self.iter()
            .flat_map(|t| t.to_tokens(cx).into_iter())
            .collect()
    }
}

impl<T: ToTokens> ToTokens for Spanned<T> {
    fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
        // FIXME: use the span?
        self.node.to_tokens(cx)
    }
}

impl<T: ToTokens> ToTokens for Option<T> {
    fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
        match self {
            &Some(ref t) => t.to_tokens(cx),
            &None => Vec::new(),
        }
    }
}

/* Should be (when bugs in default methods are fixed):

trait ToSource : ToTokens {
    // Takes a thing and generates a string containing rust code for it.
    pub fn to_source() -> String;

    // If you can make source, you can definitely make tokens.
    pub fn to_tokens(cx: &ExtCtxt) -> ~[TokenTree] {
        cx.parse_tts(self.to_source())
    }
}

*/

// FIXME: Move this trait to pprust and get rid of *_to_str?
pub trait ToSource {
    // Takes a thing and generates a string containing rust code for it.
    fn to_source(&self) -> String;
}

// FIXME (Issue #16472): This should go away after ToToken impls
// are revised to go directly to token-trees.
trait ToSourceWithHygiene : ToSource {
    // Takes a thing and generates a string containing rust code
    // for it, encoding Idents as special byte sequences to
    // maintain hygiene across serialization and deserialization.
    fn to_source_with_hygiene(&self) -> String;
}

macro_rules! impl_to_source {
    (P<$t:ty>, $pp:ident) => (
        impl ToSource for P<$t> {
            fn to_source(&self) -> String {
                pprust::$pp(&**self)
            }
        }
        impl ToSourceWithHygiene for P<$t> {
            fn to_source_with_hygiene(&self) -> String {
                pprust::with_hygiene::$pp(&**self)
            }
        }
    );
    ($t:ty, $pp:ident) => (
        impl ToSource for $t {
            fn to_source(&self) -> String {
                pprust::$pp(self)
            }
        }
        impl ToSourceWithHygiene for $t {
            fn to_source_with_hygiene(&self) -> String {
                pprust::with_hygiene::$pp(self)
            }
        }
    );
}

fn slice_to_source<'a, T: ToSource>(sep: &'static str, xs: &'a [T]) -> String {
    xs.iter()
        .map(|i| i.to_source())
        .collect::<Vec<String>>()
        .connect(sep)
        .to_string()
}

fn slice_to_source_with_hygiene<'a, T: ToSourceWithHygiene>(
    sep: &'static str, xs: &'a [T]) -> String {
    xs.iter()
        .map(|i| i.to_source_with_hygiene())
        .collect::<Vec<String>>()
        .connect(sep)
        .to_string()
}

macro_rules! impl_to_source_slice {
    ($t:ty, $sep:expr) => (
        impl ToSource for [$t] {
            fn to_source(&self) -> String {
                slice_to_source($sep, self)
            }
        }

        impl ToSourceWithHygiene for [$t] {
            fn to_source_with_hygiene(&self) -> String {
                slice_to_source_with_hygiene($sep, self)
            }
        }
    )
}

impl ToSource for ast::Ident {
    fn to_source(&self) -> String {
        token::get_ident(*self).to_string()
    }
}

impl ToSourceWithHygiene for ast::Ident {
    fn to_source_with_hygiene(&self) -> String {
        self.encode_with_hygiene()
    }
}

impl_to_source! { ast::Path, path_to_string }
impl_to_source! { ast::Ty, ty_to_string }
impl_to_source! { ast::Block, block_to_string }
impl_to_source! { ast::Arg, arg_to_string }
impl_to_source! { Generics, generics_to_string }
impl_to_source! { P<ast::Item>, item_to_string }
impl_to_source! { P<ast::Stmt>, stmt_to_string }
impl_to_source! { P<ast::Expr>, expr_to_string }
impl_to_source! { P<ast::Pat>, pat_to_string }
impl_to_source! { ast::Arm, arm_to_string }
impl_to_source_slice! { ast::Ty, ", " }
impl_to_source_slice! { P<ast::Item>, "\n\n" }

impl ToSource for ast::Attribute_ {
    fn to_source(&self) -> String {
        pprust::attribute_to_string(&dummy_spanned(self.clone()))
    }
}
impl ToSourceWithHygiene for ast::Attribute_ {
    fn to_source_with_hygiene(&self) -> String {
        self.to_source()
    }
}

impl ToSource for P<ast::ImplItem> {
    fn to_source(&self) -> String {
        pprust::to_string(|s| s.print_impl_item(self))
    }
}

impl ToSourceWithHygiene for P<ast::ImplItem> {
    fn to_source_with_hygiene(&self) -> String {
        pprust::with_hygiene::to_string_hyg(|s| s.print_impl_item(self))
    }
}

impl ToSource for ast::WhereClause {
    fn to_source(&self) -> String {
        pprust::to_string(|s| {
            s.print_where_clause(&self)
        })
    }
}

impl ToSourceWithHygiene for ast::WhereClause {
    fn to_source_with_hygiene(&self) -> String {
        pprust::with_hygiene::to_string_hyg(|s| {
            s.print_where_clause(&self)
        })
    }
}

impl ToSource for str {
    fn to_source(&self) -> String {
        let lit = dummy_spanned(ast::LitStr(
                token::intern_and_get_ident(self), ast::CookedStr));
        pprust::lit_to_string(&lit)
    }
}
impl ToSourceWithHygiene for str {
    fn to_source_with_hygiene(&self) -> String {
        self.to_source()
    }
}

impl ToSource for () {
    fn to_source(&self) -> String {
        "()".to_string()
    }
}
impl ToSourceWithHygiene for () {
    fn to_source_with_hygiene(&self) -> String {
        self.to_source()
    }
}

impl ToSource for bool {
    fn to_source(&self) -> String {
        let lit = dummy_spanned(ast::LitBool(*self));
        pprust::lit_to_string(&lit)
    }
}
impl ToSourceWithHygiene for bool {
    fn to_source_with_hygiene(&self) -> String {
        self.to_source()
    }
}

impl ToSource for char {
    fn to_source(&self) -> String {
        let lit = dummy_spanned(ast::LitChar(*self));
        pprust::lit_to_string(&lit)
    }
}
impl ToSourceWithHygiene for char {
    fn to_source_with_hygiene(&self) -> String {
        self.to_source()
    }
}

macro_rules! impl_to_source_isize {
    (signed, $t:ty, $tag:expr) => (
        impl ToSource for $t {
            fn to_source(&self) -> String {
                let lit = ast::LitInt(*self as u64, ast::SignedIntLit($tag,
                                                                      ast::Sign::new(*self)));
                pprust::lit_to_string(&dummy_spanned(lit))
            }
        }
        impl ToSourceWithHygiene for $t {
            fn to_source_with_hygiene(&self) -> String {
                self.to_source()
            }
        }
    );
    (unsigned, $t:ty, $tag:expr) => (
        impl ToSource for $t {
            fn to_source(&self) -> String {
                let lit = ast::LitInt(*self as u64, ast::UnsignedIntLit($tag));
                pprust::lit_to_string(&dummy_spanned(lit))
            }
        }
        impl ToSourceWithHygiene for $t {
            fn to_source_with_hygiene(&self) -> String {
                self.to_source()
            }
        }
    );
}

impl_to_source_isize! { signed, isize, ast::TyIs }
impl_to_source_isize! { signed, i8,  ast::TyI8 }
impl_to_source_isize! { signed, i16, ast::TyI16 }
impl_to_source_isize! { signed, i32, ast::TyI32 }
impl_to_source_isize! { signed, i64, ast::TyI64 }

impl_to_source_isize! { unsigned, usize, ast::TyUs }
impl_to_source_isize! { unsigned, u8,   ast::TyU8 }
impl_to_source_isize! { unsigned, u16,  ast::TyU16 }
impl_to_source_isize! { unsigned, u32,  ast::TyU32 }
impl_to_source_isize! { unsigned, u64,  ast::TyU64 }

// Alas ... we write these out instead. All redundant.

macro_rules! impl_to_tokens {
    ($t:ty) => (
        impl ToTokens for $t {
            fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
                cx.parse_tts_with_hygiene(self.to_source_with_hygiene())
            }
        }
    )
}

macro_rules! impl_to_tokens_lifetime {
    ($t:ty) => (
        impl<'a> ToTokens for $t {
            fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
                cx.parse_tts_with_hygiene(self.to_source_with_hygiene())
            }
        }
    )
}

impl_to_tokens! { ast::Ident }
impl_to_tokens! { ast::Path }
impl_to_tokens! { P<ast::Item> }
impl_to_tokens! { P<ast::ImplItem> }
impl_to_tokens! { ast::WhereClause }
impl_to_tokens! { P<ast::Pat> }
impl_to_tokens! { ast::Arm }
impl_to_tokens_lifetime! { &'a [P<ast::Item>] }
impl_to_tokens! { ast::Ty }
impl_to_tokens_lifetime! { &'a [ast::Ty] }
impl_to_tokens! { Generics }
impl_to_tokens! { P<ast::Stmt> }
impl_to_tokens! { P<ast::Expr> }
impl_to_tokens! { ast::Block }
impl_to_tokens! { ast::Arg }
impl_to_tokens! { ast::Attribute_ }
impl_to_tokens_lifetime! { &'a str }
impl_to_tokens! { () }
impl_to_tokens! { char }
impl_to_tokens! { bool }
impl_to_tokens! { isize }
impl_to_tokens! { i8 }
impl_to_tokens! { i16 }
impl_to_tokens! { i32 }
impl_to_tokens! { i64 }
impl_to_tokens! { usize }
impl_to_tokens! { u8 }
impl_to_tokens! { u16 }
impl_to_tokens! { u32 }
impl_to_tokens! { u64 }

pub trait ExtParseUtils {
    fn parse_item(&self, s: String) -> P<ast::Item>;
    fn parse_expr(&self, s: String) -> P<ast::Expr>;
    fn parse_stmt(&self, s: String) -> P<ast::Stmt>;
    fn parse_tts(&self, s: String) -> Vec<ast::TokenTree>;
}

trait ExtParseUtilsWithHygiene {
    // FIXME (Issue #16472): This should go away after ToToken impls
    // are revised to go directly to token-trees.
    fn parse_tts_with_hygiene(&self, s: String) -> Vec<ast::TokenTree>;
}

impl<'a> ExtParseUtils for ExtCtxt<'a> {

    fn parse_item(&self, s: String) -> P<ast::Item> {
        parse::parse_item_from_source_str(
            "<quote expansion>".to_string(),
            s,
            self.cfg(),
            self.parse_sess()).expect("parse error")
    }

    fn parse_stmt(&self, s: String) -> P<ast::Stmt> {
        parse::parse_stmt_from_source_str("<quote expansion>".to_string(),
                                          s,
                                          self.cfg(),
                                          self.parse_sess()).expect("parse error")
    }

    fn parse_expr(&self, s: String) -> P<ast::Expr> {
        parse::parse_expr_from_source_str("<quote expansion>".to_string(),
                                          s,
                                          self.cfg(),
                                          self.parse_sess())
    }

    fn parse_tts(&self, s: String) -> Vec<ast::TokenTree> {
        parse::parse_tts_from_source_str("<quote expansion>".to_string(),
                                         s,
                                         self.cfg(),
                                         self.parse_sess())
    }
}

impl<'a> ExtParseUtilsWithHygiene for ExtCtxt<'a> {

    fn parse_tts_with_hygiene(&self, s: String) -> Vec<ast::TokenTree> {
        use syntax::parse::with_hygiene::parse_tts_from_source_str;
        parse_tts_from_source_str("<quote expansion>".to_string(),
                                  s,
                                  self.cfg(),
                                  self.parse_sess())
    }
}
<commit_msg>Allow tokens to be extracted from slices<commit_after>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(rustc_private)]

extern crate syntax;

use syntax::ast;
use syntax::codemap::Spanned;
use syntax::ext::base::ExtCtxt;
use syntax::parse::token;
use syntax::parse;
use syntax::print::pprust;
use syntax::ptr::P;

use syntax::ast::{TokenTree, Generics, Expr};

pub use syntax::parse::new_parser_from_tts;
pub use syntax::codemap::{BytePos, Span, dummy_spanned};

pub trait ToTokens {
    fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree>;
}

impl ToTokens for TokenTree {
    fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
        vec!(self.clone())
    }
}

impl<'a, T: ToTokens> ToTokens for &'a [T] {
    fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
        self.iter()
            .flat_map(|t| t.to_tokens(cx).into_iter())
            .collect()
    }
}

impl<T: ToTokens> ToTokens for Vec<T> {
    fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
        let slice: &[T] = self;
        slice.to_tokens(cx)
    }
}

impl<T: ToTokens> ToTokens for Spanned<T> {
    fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
        // FIXME: use the span?
        self.node.to_tokens(cx)
    }
}

impl<T: ToTokens> ToTokens for Option<T> {
    fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
        match self {
            &Some(ref t) => t.to_tokens(cx),
            &None => Vec::new(),
        }
    }
}

/* Should be (when bugs in default methods are fixed):

trait ToSource : ToTokens {
    // Takes a thing and generates a string containing rust code for it.
    pub fn to_source() -> String;

    // If you can make source, you can definitely make tokens.
    pub fn to_tokens(cx: &ExtCtxt) -> ~[TokenTree] {
        cx.parse_tts(self.to_source())
    }
}

*/

// FIXME: Move this trait to pprust and get rid of *_to_str?
pub trait ToSource {
    // Takes a thing and generates a string containing rust code for it.
    fn to_source(&self) -> String;
}

// FIXME (Issue #16472): This should go away after ToToken impls
// are revised to go directly to token-trees.
trait ToSourceWithHygiene : ToSource {
    // Takes a thing and generates a string containing rust code
    // for it, encoding Idents as special byte sequences to
    // maintain hygiene across serialization and deserialization.
    fn to_source_with_hygiene(&self) -> String;
}

macro_rules! impl_to_source {
    (P<$t:ty>, $pp:ident) => (
        impl ToSource for P<$t> {
            fn to_source(&self) -> String {
                pprust::$pp(&**self)
            }
        }
        impl ToSourceWithHygiene for P<$t> {
            fn to_source_with_hygiene(&self) -> String {
                pprust::with_hygiene::$pp(&**self)
            }
        }
    );
    ($t:ty, $pp:ident) => (
        impl ToSource for $t {
            fn to_source(&self) -> String {
                pprust::$pp(self)
            }
        }
        impl ToSourceWithHygiene for $t {
            fn to_source_with_hygiene(&self) -> String {
                pprust::with_hygiene::$pp(self)
            }
        }
    );
}

fn slice_to_source<'a, T: ToSource>(sep: &'static str, xs: &'a [T]) -> String {
    xs.iter()
        .map(|i| i.to_source())
        .collect::<Vec<String>>()
        .connect(sep)
        .to_string()
}

fn slice_to_source_with_hygiene<'a, T: ToSourceWithHygiene>(
    sep: &'static str, xs: &'a [T]) -> String {
    xs.iter()
        .map(|i| i.to_source_with_hygiene())
        .collect::<Vec<String>>()
        .connect(sep)
        .to_string()
}

macro_rules! impl_to_source_slice {
    ($t:ty, $sep:expr) => (
        impl ToSource for [$t] {
            fn to_source(&self) -> String {
                slice_to_source($sep, self)
            }
        }

        impl ToSourceWithHygiene for [$t] {
            fn to_source_with_hygiene(&self) -> String {
                slice_to_source_with_hygiene($sep, self)
            }
        }
    )
}

impl ToSource for ast::Ident {
    fn to_source(&self) -> String {
        token::get_ident(*self).to_string()
    }
}

impl ToSourceWithHygiene for ast::Ident {
    fn to_source_with_hygiene(&self) -> String {
        self.encode_with_hygiene()
    }
}

impl_to_source! { ast::Path, path_to_string }
impl_to_source! { ast::Ty, ty_to_string }
impl_to_source! { ast::Block, block_to_string }
impl_to_source! { ast::Arg, arg_to_string }
impl_to_source! { Generics, generics_to_string }
impl_to_source! { P<ast::Item>, item_to_string }
impl_to_source! { P<ast::Stmt>, stmt_to_string }
impl_to_source! { P<ast::Expr>, expr_to_string }
impl_to_source! { P<ast::Pat>, pat_to_string }
impl_to_source! { ast::Arm, arm_to_string }
impl_to_source_slice! { ast::Ty, ", " }
impl_to_source_slice! { P<ast::Item>, "\n\n" }

impl ToSource for ast::Attribute_ {
    fn to_source(&self) -> String {
        pprust::attribute_to_string(&dummy_spanned(self.clone()))
    }
}
impl ToSourceWithHygiene for ast::Attribute_ {
    fn to_source_with_hygiene(&self) -> String {
        self.to_source()
    }
}

impl ToSource for P<ast::ImplItem> {
    fn to_source(&self) -> String {
        pprust::to_string(|s| s.print_impl_item(self))
    }
}

impl ToSourceWithHygiene for P<ast::ImplItem> {
    fn to_source_with_hygiene(&self) -> String {
        pprust::with_hygiene::to_string_hyg(|s| s.print_impl_item(self))
    }
}

impl ToSource for ast::WhereClause {
    fn to_source(&self) -> String {
        pprust::to_string(|s| {
            s.print_where_clause(&self)
        })
    }
}

impl ToSourceWithHygiene for ast::WhereClause {
    fn to_source_with_hygiene(&self) -> String {
        pprust::with_hygiene::to_string_hyg(|s| {
            s.print_where_clause(&self)
        })
    }
}

impl ToSource for str {
    fn to_source(&self) -> String {
        let lit = dummy_spanned(ast::LitStr(
                token::intern_and_get_ident(self), ast::CookedStr));
        pprust::lit_to_string(&lit)
    }
}
impl ToSourceWithHygiene for str {
    fn to_source_with_hygiene(&self) -> String {
        self.to_source()
    }
}

impl ToSource for () {
    fn to_source(&self) -> String {
        "()".to_string()
    }
}
impl ToSourceWithHygiene for () {
    fn to_source_with_hygiene(&self) -> String {
        self.to_source()
    }
}

impl ToSource for bool {
    fn to_source(&self) -> String {
        let lit = dummy_spanned(ast::LitBool(*self));
        pprust::lit_to_string(&lit)
    }
}
impl ToSourceWithHygiene for bool {
    fn to_source_with_hygiene(&self) -> String {
        self.to_source()
    }
}

impl ToSource for char {
    fn to_source(&self) -> String {
        let lit = dummy_spanned(ast::LitChar(*self));
        pprust::lit_to_string(&lit)
    }
}
impl ToSourceWithHygiene for char {
    fn to_source_with_hygiene(&self) -> String {
        self.to_source()
    }
}

macro_rules! impl_to_source_isize {
    (signed, $t:ty, $tag:expr) => (
        impl ToSource for $t {
            fn to_source(&self) -> String {
                let lit = ast::LitInt(*self as u64, ast::SignedIntLit($tag,
                                                                      ast::Sign::new(*self)));
                pprust::lit_to_string(&dummy_spanned(lit))
            }
        }
        impl ToSourceWithHygiene for $t {
            fn to_source_with_hygiene(&self) -> String {
                self.to_source()
            }
        }
    );
    (unsigned, $t:ty, $tag:expr) => (
        impl ToSource for $t {
            fn to_source(&self) -> String {
                let lit = ast::LitInt(*self as u64, ast::UnsignedIntLit($tag));
                pprust::lit_to_string(&dummy_spanned(lit))
            }
        }
        impl ToSourceWithHygiene for $t {
            fn to_source_with_hygiene(&self) -> String {
                self.to_source()
            }
        }
    );
}

impl_to_source_isize! { signed, isize, ast::TyIs }
impl_to_source_isize! { signed, i8,  ast::TyI8 }
impl_to_source_isize! { signed, i16, ast::TyI16 }
impl_to_source_isize! { signed, i32, ast::TyI32 }
impl_to_source_isize! { signed, i64, ast::TyI64 }

impl_to_source_isize! { unsigned, usize, ast::TyUs }
impl_to_source_isize! { unsigned, u8,   ast::TyU8 }
impl_to_source_isize! { unsigned, u16,  ast::TyU16 }
impl_to_source_isize! { unsigned, u32,  ast::TyU32 }
impl_to_source_isize! { unsigned, u64,  ast::TyU64 }

// Alas ... we write these out instead. All redundant.

macro_rules! impl_to_tokens {
    ($t:ty) => (
        impl ToTokens for $t {
            fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
                cx.parse_tts_with_hygiene(self.to_source_with_hygiene())
            }
        }
    )
}

macro_rules! impl_to_tokens_lifetime {
    ($t:ty) => (
        impl<'a> ToTokens for $t {
            fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
                cx.parse_tts_with_hygiene(self.to_source_with_hygiene())
            }
        }
    )
}

impl_to_tokens! { ast::Ident }
impl_to_tokens! { ast::Path }
impl_to_tokens! { P<ast::Item> }
impl_to_tokens! { P<ast::ImplItem> }
impl_to_tokens! { ast::WhereClause }
impl_to_tokens! { P<ast::Pat> }
impl_to_tokens! { ast::Arm }
impl_to_tokens! { ast::Ty }
impl_to_tokens! { Generics }
impl_to_tokens! { P<ast::Stmt> }
impl_to_tokens! { P<ast::Expr> }
impl_to_tokens! { ast::Block }
impl_to_tokens! { ast::Arg }
impl_to_tokens! { ast::Attribute_ }
impl_to_tokens_lifetime! { &'a str }
impl_to_tokens! { () }
impl_to_tokens! { char }
impl_to_tokens! { bool }
impl_to_tokens! { isize }
impl_to_tokens! { i8 }
impl_to_tokens! { i16 }
impl_to_tokens! { i32 }
impl_to_tokens! { i64 }
impl_to_tokens! { usize }
impl_to_tokens! { u8 }
impl_to_tokens! { u16 }
impl_to_tokens! { u32 }
impl_to_tokens! { u64 }

pub trait ExtParseUtils {
    fn parse_item(&self, s: String) -> P<ast::Item>;
    fn parse_expr(&self, s: String) -> P<ast::Expr>;
    fn parse_stmt(&self, s: String) -> P<ast::Stmt>;
    fn parse_tts(&self, s: String) -> Vec<ast::TokenTree>;
}

trait ExtParseUtilsWithHygiene {
    // FIXME (Issue #16472): This should go away after ToToken impls
    // are revised to go directly to token-trees.
    fn parse_tts_with_hygiene(&self, s: String) -> Vec<ast::TokenTree>;
}

impl<'a> ExtParseUtils for ExtCtxt<'a> {

    fn parse_item(&self, s: String) -> P<ast::Item> {
        parse::parse_item_from_source_str(
            "<quote expansion>".to_string(),
            s,
            self.cfg(),
            self.parse_sess()).expect("parse error")
    }

    fn parse_stmt(&self, s: String) -> P<ast::Stmt> {
        parse::parse_stmt_from_source_str("<quote expansion>".to_string(),
                                          s,
                                          self.cfg(),
                                          self.parse_sess()).expect("parse error")
    }

    fn parse_expr(&self, s: String) -> P<ast::Expr> {
        parse::parse_expr_from_source_str("<quote expansion>".to_string(),
                                          s,
                                          self.cfg(),
                                          self.parse_sess())
    }

    fn parse_tts(&self, s: String) -> Vec<ast::TokenTree> {
        parse::parse_tts_from_source_str("<quote expansion>".to_string(),
                                         s,
                                         self.cfg(),
                                         self.parse_sess())
    }
}

impl<'a> ExtParseUtilsWithHygiene for ExtCtxt<'a> {

    fn parse_tts_with_hygiene(&self, s: String) -> Vec<ast::TokenTree> {
        use syntax::parse::with_hygiene::parse_tts_from_source_str;
        parse_tts_from_source_str("<quote expansion>".to_string(),
                                  s,
                                  self.cfg(),
                                  self.parse_sess())
    }
}
<|endoftext|>