<commit_before>// Copyright 2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use std::ops::{Deref, DerefMut};
use std::slice;

#[cfg(feature = "use_glib")]
use glib::translate::*;
use ffi;
use ffi::enums::{
    Format,
    SurfaceType,
};

use BorrowError;
use surface::{Surface, SurfaceExt, SurfacePriv};
use Status;

#[derive(Debug)]
pub struct ImageSurface(Surface);

impl ImageSurface {
    pub fn from(surface: Surface) -> Result<ImageSurface, Surface> {
        if surface.get_type() == SurfaceType::Image {
            Ok(ImageSurface(surface))
        }
        else {
            Err(surface)
        }
    }

    pub unsafe fn from_raw_full(ptr: *mut ffi::cairo_surface_t) -> Result<ImageSurface, Status> {
        let surface = Self::from(Surface::from_raw_full(ptr)).unwrap();
        let status = surface.status();
        match status {
            Status::Success => Ok(surface),
            _ => Err(status)
        }
    }

    pub fn create(format: Format, width: i32, height: i32) -> Result<ImageSurface, Status> {
        unsafe { Self::from_raw_full(ffi::cairo_image_surface_create(format, width, height)) }
    }

    pub fn create_for_data<F>(data: Box<[u8]>, free: F, format: Format, width: i32, height: i32,
                              stride: i32) -> Result<ImageSurface, Status>
    where F: FnOnce(Box<[u8]>) + 'static {
        assert!(data.len() >= (height * stride) as usize);
        unsafe {
            let mut data = Box::new(AsyncBorrow::new(data, free));
            let ptr = (*data).as_mut().as_mut_ptr();
            let r = ImageSurface::from_raw_full(
                ffi::cairo_image_surface_create_for_data(ptr, format, width, height, stride));
            match r {
                Ok(surface) => surface.set_user_data(&IMAGE_SURFACE_DATA, data).map (|_| surface),
                Err(status) => Err(status)
            }
        }
    }

    pub fn get_data(&mut self) -> Result<ImageSurfaceData, BorrowError> {
        unsafe {
            if ffi::cairo_surface_get_reference_count(self.to_raw_none()) > 1 {
                return Err(BorrowError::NonExclusive)
            }
            self.flush();
            match self.status() {
                Status::Success => (),
                status => return Err(BorrowError::from(status)),
            }
            if ffi::cairo_image_surface_get_data(self.to_raw_none()).is_null() {
                return Err(BorrowError::from(Status::SurfaceFinished))
            }
            Ok(ImageSurfaceData::new(self))
        }
    }

    pub fn get_format(&self) -> Format {
        unsafe { ffi::cairo_image_surface_get_format(self.to_raw_none()) }
    }

    pub fn get_height(&self) -> i32 {
        unsafe { ffi::cairo_image_surface_get_height(self.to_raw_none()) }
    }

    pub fn get_stride(&self) -> i32 {
        unsafe { ffi::cairo_image_surface_get_stride(self.to_raw_none()) }
    }

    pub fn get_width(&self) -> i32 {
        unsafe { ffi::cairo_image_surface_get_width(self.to_raw_none()) }
    }
}

static IMAGE_SURFACE_DATA: () = ();

#[cfg(feature = "use_glib")]
impl<'a> ToGlibPtr<'a, *mut ffi::cairo_surface_t> for ImageSurface {
    type Storage = &'a Surface;

    #[inline]
    fn to_glib_none(&'a self) -> Stash<'a, *mut ffi::cairo_surface_t, Self> {
        let stash = self.0.to_glib_none();
        Stash(stash.0, stash.1)
    }

    #[inline]
    fn to_glib_full(&self) -> *mut ffi::cairo_surface_t {
        unsafe {
            ffi::cairo_surface_reference(self.0.to_glib_none().0)
        }
    }
}

#[cfg(feature = "use_glib")]
impl FromGlibPtrNone<*mut ffi::cairo_surface_t> for ImageSurface {
    #[inline]
    unsafe fn from_glib_none(ptr: *mut ffi::cairo_surface_t) -> ImageSurface {
        Self::from(from_glib_none(ptr)).unwrap()
    }
}

#[cfg(feature = "use_glib")]
impl FromGlibPtrBorrow<*mut ffi::cairo_surface_t> for ImageSurface {
    #[inline]
    unsafe fn from_glib_borrow(ptr: *mut ffi::cairo_surface_t) -> ImageSurface {
        Self::from(from_glib_borrow(ptr)).unwrap()
    }
}

#[cfg(feature = "use_glib")]
impl FromGlibPtrFull<*mut ffi::cairo_surface_t> for ImageSurface {
    #[inline]
    unsafe fn from_glib_full(ptr: *mut ffi::cairo_surface_t) -> ImageSurface {
        Self::from_raw_full(ptr).unwrap()
    }
}

#[cfg(feature = "use_glib")]
gvalue_impl!(ImageSurface, ffi::cairo_surface_t, ffi::gobject::cairo_gobject_surface_get_type);

impl AsRef<Surface> for ImageSurface {
    fn as_ref(&self) -> &Surface {
        &self.0
    }
}

impl Deref for ImageSurface {
    type Target = Surface;

    fn deref(&self) -> &Surface {
        &self.0
    }
}

impl Clone for ImageSurface {
    fn clone(&self) -> ImageSurface {
        ImageSurface(self.0.clone())
    }
}

unsafe impl Send for ImageSurface {}

pub struct ImageSurfaceData<'a> {
    surface: &'a mut ImageSurface,
    slice: &'a mut [u8],
    dirty: bool,
}

impl<'a> ImageSurfaceData<'a> {
    fn new(surface: &'a mut ImageSurface) -> ImageSurfaceData<'a> {
        unsafe {
            let ptr = ffi::cairo_image_surface_get_data(surface.to_raw_none());
            debug_assert!(!ptr.is_null());
            let len = (surface.get_stride() as usize) * (surface.get_height() as usize);
            ImageSurfaceData {
                surface,
                slice: slice::from_raw_parts_mut(ptr, len),
                dirty: false,
            }
        }
    }
}

impl<'a> Drop for ImageSurfaceData<'a> {
    fn drop(&mut self) {
        if self.dirty {
            unsafe { ffi::cairo_surface_mark_dirty(self.surface.to_raw_none()) }
        }
    }
}

impl<'a> Deref for ImageSurfaceData<'a> {
    type Target = [u8];

    fn deref(&self) -> &[u8] {
        self.slice
    }
}

impl<'a> DerefMut for ImageSurfaceData<'a> {
    fn deref_mut(&mut self) -> &mut [u8] {
        self.dirty = true;
        self.slice
    }
}

struct AsyncBorrow<T, F: FnOnce(T) + 'static> {
    data: Option<T>,
    free: Option<F>,
}

impl<T, F: FnOnce(T) + 'static> AsyncBorrow<T, F> {
    fn new(data: T, free: F) -> Self {
        AsyncBorrow { data: Some(data), free: Some(free) }
    }
}

impl<T, F: FnOnce(T) + 'static> AsMut<T> for AsyncBorrow<T, F> {
    fn as_mut(&mut self) -> &mut T {
        self.data.as_mut().unwrap()
    }
}

impl<T, F: FnOnce(T) + 'static> Drop for AsyncBorrow<T, F> {
    fn drop(&mut self) {
        if let (Some(x), Some(f)) = (self.data.take(), self.free.take()) {
            f(x);
        }
    }
}

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

    #[test]
    fn create_with_invalid_size_yields_error() {
        let result = ImageSurface::create(Format::ARgb32, 50000, 50000);
        assert! (result.is_err());
    }

    #[test]
    fn create_for_data_with_invalid_stride_yields_error() {
        let result = ImageSurface::create_for_data(Box::new([0u8; 10]),
                                                   |_| (),
                                                   Format::ARgb32,
                                                   1, 2,
                                                   5); // unaligned stride
        assert! (result.is_err());
    }

    #[test]
    fn create_with_valid_size() {
        let result = ImageSurface::create(Format::ARgb32, 10, 10);
        assert! (result.is_ok());

        let result = ImageSurface::create_for_data(Box::new([0u8; 40 * 10]),
                                                   |_| (),
                                                   Format::ARgb32,
                                                   10, 10, 40);
        assert! (result.is_ok());
    }
}
<commit_msg>Allow any AsMut<[u8]> + Send + 'static to be used for creating an ImageSurface<commit_after>// Copyright 2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use std::ops::{Deref, DerefMut};
use std::slice;

#[cfg(feature = "use_glib")]
use glib::translate::*;
use ffi;
use ffi::enums::{
    Format,
    SurfaceType,
};

use BorrowError;
use surface::{Surface, SurfaceExt, SurfacePriv};
use Status;

#[derive(Debug)]
pub struct ImageSurface(Surface);

impl ImageSurface {
    pub fn from(surface: Surface) -> Result<ImageSurface, Surface> {
        if surface.get_type() == SurfaceType::Image {
            Ok(ImageSurface(surface))
        }
        else {
            Err(surface)
        }
    }

    pub unsafe fn from_raw_full(ptr: *mut ffi::cairo_surface_t) -> Result<ImageSurface, Status> {
        let surface = Self::from(Surface::from_raw_full(ptr)).unwrap();
        let status = surface.status();
        match status {
            Status::Success => Ok(surface),
            _ => Err(status)
        }
    }

    pub fn create(format: Format, width: i32, height: i32) -> Result<ImageSurface, Status> {
        unsafe { Self::from_raw_full(ffi::cairo_image_surface_create(format, width, height)) }
    }

    pub fn create_for_data<D: AsMut<[u8]> + Send + 'static>(data: D, format: Format, width: i32, height: i32,
                              stride: i32) -> Result<ImageSurface, Status> {
        let mut data: Box<AsMut<[u8]> + Send + 'static> = Box::new(data);

        let (ptr, len) = {
            let mut data = (*data).as_mut();

            (data.as_mut_ptr(), data.len())
        };

        assert!(len >= (height * stride) as usize);
        unsafe {
            let r = ImageSurface::from_raw_full(
                ffi::cairo_image_surface_create_for_data(ptr, format, width, height, stride));
            match r {
                Ok(surface) => surface.set_user_data(&IMAGE_SURFACE_DATA, Box::new(data)).map (|_| surface),
                Err(status) => Err(status)
            }
        }
    }

    pub fn get_data(&mut self) -> Result<ImageSurfaceData, BorrowError> {
        unsafe {
            if ffi::cairo_surface_get_reference_count(self.to_raw_none()) > 1 {
                return Err(BorrowError::NonExclusive)
            }
            self.flush();
            match self.status() {
                Status::Success => (),
                status => return Err(BorrowError::from(status)),
            }
            if ffi::cairo_image_surface_get_data(self.to_raw_none()).is_null() {
                return Err(BorrowError::from(Status::SurfaceFinished))
            }
            Ok(ImageSurfaceData::new(self))
        }
    }

    pub fn get_format(&self) -> Format {
        unsafe { ffi::cairo_image_surface_get_format(self.to_raw_none()) }
    }

    pub fn get_height(&self) -> i32 {
        unsafe { ffi::cairo_image_surface_get_height(self.to_raw_none()) }
    }

    pub fn get_stride(&self) -> i32 {
        unsafe { ffi::cairo_image_surface_get_stride(self.to_raw_none()) }
    }

    pub fn get_width(&self) -> i32 {
        unsafe { ffi::cairo_image_surface_get_width(self.to_raw_none()) }
    }
}

static IMAGE_SURFACE_DATA: () = ();

#[cfg(feature = "use_glib")]
impl<'a> ToGlibPtr<'a, *mut ffi::cairo_surface_t> for ImageSurface {
    type Storage = &'a Surface;

    #[inline]
    fn to_glib_none(&'a self) -> Stash<'a, *mut ffi::cairo_surface_t, Self> {
        let stash = self.0.to_glib_none();
        Stash(stash.0, stash.1)
    }

    #[inline]
    fn to_glib_full(&self) -> *mut ffi::cairo_surface_t {
        unsafe {
            ffi::cairo_surface_reference(self.0.to_glib_none().0)
        }
    }
}

#[cfg(feature = "use_glib")]
impl FromGlibPtrNone<*mut ffi::cairo_surface_t> for ImageSurface {
    #[inline]
    unsafe fn from_glib_none(ptr: *mut ffi::cairo_surface_t) -> ImageSurface {
        Self::from(from_glib_none(ptr)).unwrap()
    }
}

#[cfg(feature = "use_glib")]
impl FromGlibPtrBorrow<*mut ffi::cairo_surface_t> for ImageSurface {
    #[inline]
    unsafe fn from_glib_borrow(ptr: *mut ffi::cairo_surface_t) -> ImageSurface {
        Self::from(from_glib_borrow(ptr)).unwrap()
    }
}

#[cfg(feature = "use_glib")]
impl FromGlibPtrFull<*mut ffi::cairo_surface_t> for ImageSurface {
    #[inline]
    unsafe fn from_glib_full(ptr: *mut ffi::cairo_surface_t) -> ImageSurface {
        Self::from_raw_full(ptr).unwrap()
    }
}

#[cfg(feature = "use_glib")]
gvalue_impl!(ImageSurface, ffi::cairo_surface_t, ffi::gobject::cairo_gobject_surface_get_type);

impl AsRef<Surface> for ImageSurface {
    fn as_ref(&self) -> &Surface {
        &self.0
    }
}

impl Deref for ImageSurface {
    type Target = Surface;

    fn deref(&self) -> &Surface {
        &self.0
    }
}

impl Clone for ImageSurface {
    fn clone(&self) -> ImageSurface {
        ImageSurface(self.0.clone())
    }
}

unsafe impl Send for ImageSurface {}

pub struct ImageSurfaceData<'a> {
    surface: &'a mut ImageSurface,
    slice: &'a mut [u8],
    dirty: bool,
}

impl<'a> ImageSurfaceData<'a> {
    fn new(surface: &'a mut ImageSurface) -> ImageSurfaceData<'a> {
        unsafe {
            let ptr = ffi::cairo_image_surface_get_data(surface.to_raw_none());
            debug_assert!(!ptr.is_null());
            let len = (surface.get_stride() as usize) * (surface.get_height() as usize);
            ImageSurfaceData {
                surface,
                slice: slice::from_raw_parts_mut(ptr, len),
                dirty: false,
            }
        }
    }
}

impl<'a> Drop for ImageSurfaceData<'a> {
    fn drop(&mut self) {
        if self.dirty {
            unsafe { ffi::cairo_surface_mark_dirty(self.surface.to_raw_none()) }
        }
    }
}

impl<'a> Deref for ImageSurfaceData<'a> {
    type Target = [u8];

    fn deref(&self) -> &[u8] {
        self.slice
    }
}

impl<'a> DerefMut for ImageSurfaceData<'a> {
    fn deref_mut(&mut self) -> &mut [u8] {
        self.dirty = true;
        self.slice
    }
}

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

    #[test]
    fn create_with_invalid_size_yields_error() {
        let result = ImageSurface::create(Format::ARgb32, 50000, 50000);
        assert! (result.is_err());
    }

    #[test]
    fn create_for_data_with_invalid_stride_yields_error() {
        let result = ImageSurface::create_for_data(vec![0u8; 10],
                                                   Format::ARgb32,
                                                   1, 2,
                                                   5); // unaligned stride
        assert! (result.is_err());
    }

    #[test]
    fn create_with_valid_size() {
        let result = ImageSurface::create(Format::ARgb32, 10, 10);
        assert! (result.is_ok());

        let result = ImageSurface::create_for_data(vec![0u8; 40 * 10],
                                                   Format::ARgb32,
                                                   10, 10, 40);
        assert! (result.is_ok());
    }
}
<|endoftext|>


<commit_before>use super::ease::Easing;
/// This struct captures Bounce easing functions
pub struct Bounce;

impl Easing for Bounce {
    fn ease_in(t: f32, b: f32, c: f32, d: f32) -> f32 {
        c - Bounce::ease_out(d - t, 0.0, c, d) + b
    }

    fn ease_out(t: f32, b: f32, c: f32, d: f32) -> f32 {
        let mut inner_t = t / d;
        if inner_t < 1.0 / 2.75 {
            c * (7.5625 * inner_t * inner_t) + b
        } else if inner_t < 2.0 / 2.75 {
            inner_t -= 1.5 / 2.75;
            c * (7.5625 * inner_t * inner_t + 0.75) + b
        } else if inner_t < 2.5 / 2.75 {
            inner_t -= 2.25 / 2.75;
            c * (7.5625 * inner_t * inner_t + 0.9375) + b
        } else {
            inner_t -= 2.625 / 2.75;
            c * (7.5625 * inner_t * inner_t + 0.984375) + b
        }
    }

    fn ease_in_out(t: f32, b: f32, c: f32, d: f32) -> f32 {
        if t < (d / 2.0) {
            Bounce::ease_in(t * 2.0, 0.0, c, d) * 0.5 + b
        } else {
            Bounce::ease_out(t * 2.0 - d, 0.0, c, d) * 0.5 + c * 0.5 + b
        }

    }
}

#[cfg(test)]
mod test {
    #[allow(unused_imports)]
    use functions::ease::Easing;
    #[test]
    fn ease_out() {
        assert_relative_eq!(super::Bounce::ease_out(1.0, 2.0, 3.0, 4.0), 3.4179688);
        assert_relative_eq!(super::Bounce::ease_out(1.0, 2.0, 3.0, 2.0), 4.296875);
        assert_relative_eq!(super::Bounce::ease_out(100.0, 1.0, 100.0, 100.0),
                            101.000000);
    }

    #[test]
    fn ease_in() {
        assert_relative_eq!(super::Bounce::ease_in(1.0, 2.0, 3.0, 4.0), 2.082031);
    }

    #[test]
    fn ease_in_out() {
        assert_relative_eq!(super::Bounce::ease_in_out(1.0, 2.0, 3.0, 4.0), 2.3515625);
        assert_relative_eq!(super::Bounce::ease_in_out(51.0, 1.0, 100.0, 100.0),
                            51.151250);
    }
}
<commit_msg>Clear the Bounce easing functions<commit_after>use super::ease::Easing;

/// This struct captures Bounce easing functions
pub struct Bounce;

impl Easing for Bounce {
    fn ease_in(t: f32, b: f32, c: f32, d: f32) -> f32 {
        c - Bounce::ease_out(d - t, 0.0, c, d) + b
    }

    fn ease_out(mut t: f32, b: f32, c: f32, d: f32) -> f32 {
        t = t / d;
        if t < 1.0 / 2.75 {
            c * (7.5625 * t * t) + b
        } else if t < 2.0 / 2.75 {
            t -= 1.5 / 2.75;
            c * (7.5625 * t * t + 0.75) + b
        } else if t < 2.5 / 2.75 {
            t -= 2.25 / 2.75;
            c * (7.5625 * t * t + 0.9375) + b
        } else {
            t -= 2.625 / 2.75;
            c * (7.5625 * t * t + 0.984375) + b
        }
    }

    fn ease_in_out(t: f32, b: f32, c: f32, d: f32) -> f32 {
        if t < (d / 2.0) {
            Bounce::ease_in(t * 2.0, 0.0, c, d) * 0.5 + b
        } else {
            Bounce::ease_out(t * 2.0 - d, 0.0, c, d) * 0.5 + c * 0.5 + b
        }

    }
}

#[cfg(test)]
mod test {
    #[allow(unused_imports)]
    use functions::ease::Easing;
    #[test]
    fn ease_out() {
        assert_relative_eq!(super::Bounce::ease_out(1.0, 2.0, 3.0, 4.0), 3.4179688);
        assert_relative_eq!(super::Bounce::ease_out(1.0, 2.0, 3.0, 2.0), 4.296875);
        assert_relative_eq!(super::Bounce::ease_out(100.0, 1.0, 100.0, 100.0),
                            101.000000);
    }

    #[test]
    fn ease_in() {
        assert_relative_eq!(super::Bounce::ease_in(1.0, 2.0, 3.0, 4.0), 2.082031);
    }

    #[test]
    fn ease_in_out() {
        assert_relative_eq!(super::Bounce::ease_in_out(1.0, 2.0, 3.0, 4.0), 2.3515625);
        assert_relative_eq!(super::Bounce::ease_in_out(51.0, 1.0, 100.0, 100.0),
                            51.151250);
    }
}
<|endoftext|>


<commit_before>pub mod client;
pub mod lsm;
pub mod sm;
mod trees;

#[cfg(test)]
mod tests {
    use super::lsm::btree::storage;
    use super::lsm::btree::Ordering;
    use super::*;
    use crate::client::*;
    use crate::index::ranged::lsm::btree;
    use crate::index::EntryKey;
    use crate::ram::cell::*;
    use crate::ram::schema::*;
    use crate::ram::types::Id;
    use crate::ram::types::*;
    use crate::server::*;
    use futures::stream::FuturesUnordered;
    use itertools::Itertools;
    use rand::seq::SliceRandom;
    use std::sync::Arc;
    use std::time::Duration;
    use tokio_stream::StreamExt;

    // #[ignore]
    #[tokio::test(flavor = "multi_thread")]
    async fn general() {
        let _ = env_logger::try_init();
        let server_group = "ranged_index_test";
        let server_addr = String::from("127.0.0.1:5711");
        let server = NebServer::new_from_opts(
            &ServerOptions {
                chunk_count: 1,
                memory_size: 32 * 1024 * 1024 * 1024, // G
                backup_storage: None,
                wal_storage: None,
                services: vec![Service::Cell, Service::RangedIndexer],
            },
            &server_addr,
            server_group,
        )
        .await;
        let client = Arc::new(
            AsyncClient::new(
                &server.rpc,
                &server.membership,
                &vec![server_addr],
                server_group,
            )
            .await
            .unwrap(),
        );
        let index_client = Arc::new(
            client::RangedQueryClient::new(&server.consh, &server.raft_client, &client).await,
        );
        client.new_schema_with_id(schema()).await.unwrap().unwrap();
        let test_capacity = btree::ideal_capacity_from_node_size(btree::level::LEVEL_1) * 3;
        let mut futs = FuturesUnordered::new();
        info!(
            "Testing ranged indexer preesure test with {} items",
            test_capacity
        );
        info!("Generating test set");
        let mut rng = rand::thread_rng();
        let mut nums = (0..test_capacity).collect_vec();
        let mut nums_2 = nums.clone();
        let mut nums_3 = nums.clone();
        nums.as_mut_slice().shuffle(&mut rng);
        nums_2.as_mut_slice().shuffle(&mut rng);
        nums_3.as_mut_slice().shuffle(&mut rng);
        info!("Adding insertion tasks");
        for i in nums_2 {
            let index_client = index_client.clone();
            let client = client.clone();
            futs.push(tokio::spawn(async move {
                let id = Id::new(1, i as u64);
                let key = EntryKey::from_id(&id);
                let mut data_map = Map::new();
                data_map.insert("data", Value::U64(i as u64));
                let cell = Cell::new_with_id(11, &id, Value::Map(data_map));
                client.write_cell(cell).await.unwrap().unwrap();
                index_client.insert(&key).await
            }));
        }
        info!("All tasks queued, waiting for finish");
        while let Some(result) = futs.next().await {
            assert!(result.unwrap().unwrap(), "Insertion return false");
        }
        info!("Verifiying insertion");
        for i in &nums {
            let id = Id::new(1, *i as u64);
            let cell_res = client.read_cell(id).await.unwrap();
            match cell_res {
                Ok(cell) => {
                    assert_eq!(*cell.data["data"].U64().unwrap(), *i as u64);
                }
                Err(e) => {
                    panic!("Expecting cell, found error {:?}", e);
                }
            }
        }
        info!("All keys inserted. The background task should merging trees. Doing searches.");
        let mut futs = FuturesUnordered::new();
        for (i, num) in nums_3.into_iter().enumerate() {
            let index_client = index_client.clone();
            futs.push(tokio::spawn(async move {
                trace!("Seeking Id at {}, index {}", num, i);
                let id = Id::new(1, num as u64);
                let key = EntryKey::from_id(&id);
                let rt_cursor =
                    client::RangedQueryClient::seek(&index_client, &key, Ordering::Forward)
                        .await
                        .unwrap()
                        .unwrap();
                assert_eq!(id, rt_cursor.current().unwrap().0, "at {}", i);
                trace!("Id at {}, index {} have been checked", num, i);
            }));
        }
        while let Some(_) = futs.next().await {}
        debug!("Selection check pased, waiting for 10 secs");
        tokio::time::sleep(Duration::from_secs(10)).await;
        info!("Waiting tree storage");
        storage::wait_until_updated().await;
        info!(
            "Total cells {}, Tree stat {:?}",
            client.count().await.unwrap(),
            index_client.tree_stats().await.unwrap()
        );
        info!("Verifiying insertion round 2");
        for i in &nums {
            let id = Id::new(1, *i as u64);
            let cell_res = client.read_cell(id).await.unwrap();
            match cell_res {
                Ok(cell) => {
                    assert_eq!(*cell.data["data"].U64().unwrap(), *i as u64);
                }
                Err(e) => {
                    panic!("Expecting cell at round 2, found error {:?}", e);
                }
            }
        }
        info!("Scanning forward...");
        let mut rt_cursor = client::RangedQueryClient::seek(
            &index_client,
            &EntryKey::from_id(&Id::new(1, 0)),
            Ordering::Forward,
        )
        .await
        .unwrap()
        .unwrap();
        for num in &nums {
            let id = Id::new(1, *num as u64);
            let current = rt_cursor.current().unwrap().0;
            assert_eq!(id, current, "Expecting {:?}, key {:?}, got {:?}", id, EntryKey::from_id(&id), current);
            let _ = rt_cursor.next().await.unwrap();
            if num % (test_capacity / 128) == 0 {
                debug!("Scanned {} of {}", num, test_capacity);
            }
        }
        info!("Scan finished");
        let end_of_list = rt_cursor.next().await.unwrap();
        assert!(
            end_of_list.is_none(),
            "End of the list have id {:?}",
            end_of_list.unwrap().0
        );
        assert!(
            end_of_list.is_none(),
            "After end of the list have id {:?}",
            end_of_list.unwrap().0
        );
        info!(
            "Total cells {}, Tree stat {:?}",
            client.count().await.unwrap(),
            index_client.tree_stats().await.unwrap()
        );
        panic!("Explicit panic for error discovery");
    }

    fn schema() -> Schema {
        Schema {
            id: 11,
            name: String::from("test"),
            key_field: None,
            str_key_field: None,
            fields: Field::new(
                "*",
                0,
                false,
                false,
                Some(vec![Field::new("data", 10, false, false, None, vec![])]),
                vec![],
            ),
            is_dynamic: false,
        }
    }
}
<commit_msg>fix test<commit_after>pub mod client;
pub mod lsm;
pub mod sm;
mod trees;

#[cfg(test)]
mod tests {
    use super::lsm::btree::storage;
    use super::lsm::btree::Ordering;
    use super::*;
    use crate::client::*;
    use crate::index::ranged::lsm::btree;
    use crate::index::EntryKey;
    use crate::ram::cell::*;
    use crate::ram::schema::*;
    use crate::ram::types::Id;
    use crate::ram::types::*;
    use crate::server::*;
    use futures::stream::FuturesUnordered;
    use itertools::Itertools;
    use rand::seq::SliceRandom;
    use std::sync::Arc;
    use std::time::Duration;
    use tokio_stream::StreamExt;

    // #[ignore]
    #[tokio::test(flavor = "multi_thread")]
    async fn general() {
        let _ = env_logger::try_init();
        let server_group = "ranged_index_test";
        let server_addr = String::from("127.0.0.1:5711");
        let server = NebServer::new_from_opts(
            &ServerOptions {
                chunk_count: 1,
                memory_size: 32 * 1024 * 1024 * 1024, // G
                backup_storage: None,
                wal_storage: None,
                services: vec![Service::Cell, Service::RangedIndexer],
            },
            &server_addr,
            server_group,
        )
        .await;
        let client = Arc::new(
            AsyncClient::new(
                &server.rpc,
                &server.membership,
                &vec![server_addr],
                server_group,
            )
            .await
            .unwrap(),
        );
        let index_client = Arc::new(
            client::RangedQueryClient::new(&server.consh, &server.raft_client, &client).await,
        );
        client.new_schema_with_id(schema()).await.unwrap().unwrap();
        let test_capacity = btree::ideal_capacity_from_node_size(btree::level::LEVEL_1) * 3;
        let mut futs = FuturesUnordered::new();
        info!(
            "Testing ranged indexer preesure test with {} items",
            test_capacity
        );
        info!("Generating test set");
        let mut rng = rand::thread_rng();
        let mut nums = (0..test_capacity).collect_vec();
        let mut nums_2 = nums.clone();
        let mut nums_3 = nums.clone();
        nums.as_mut_slice().shuffle(&mut rng);
        nums_2.as_mut_slice().shuffle(&mut rng);
        nums_3.as_mut_slice().shuffle(&mut rng);
        info!("Adding insertion tasks");
        for i in nums_2 {
            let index_client = index_client.clone();
            let client = client.clone();
            futs.push(tokio::spawn(async move {
                let id = Id::new(1, i as u64);
                let key = EntryKey::from_id(&id);
                let mut data_map = Map::new();
                data_map.insert("data", Value::U64(i as u64));
                let cell = Cell::new_with_id(11, &id, Value::Map(data_map));
                client.write_cell(cell).await.unwrap().unwrap();
                index_client.insert(&key).await
            }));
        }
        info!("All tasks queued, waiting for finish");
        while let Some(result) = futs.next().await {
            assert!(result.unwrap().unwrap(), "Insertion return false");
        }
        info!("Verifiying insertion");
        for i in &nums {
            let id = Id::new(1, *i as u64);
            let cell_res = client.read_cell(id).await.unwrap();
            match cell_res {
                Ok(cell) => {
                    assert_eq!(*cell.data["data"].U64().unwrap(), *i as u64);
                }
                Err(e) => {
                    panic!("Expecting cell, found error {:?}", e);
                }
            }
        }
        info!("All keys inserted. The background task should merging trees. Doing searches.");
        let mut futs = FuturesUnordered::new();
        for (i, num) in nums_3.into_iter().enumerate() {
            let index_client = index_client.clone();
            futs.push(tokio::spawn(async move {
                trace!("Seeking Id at {}, index {}", num, i);
                let id = Id::new(1, num as u64);
                let key = EntryKey::from_id(&id);
                let rt_cursor =
                    client::RangedQueryClient::seek(&index_client, &key, Ordering::Forward, 1)
                        .await
                        .unwrap()
                        .unwrap();
                assert_eq!(id, rt_cursor.current().unwrap().0, "at {}", i);
                trace!("Id at {}, index {} have been checked", num, i);
            }));
        }
        while let Some(_) = futs.next().await {}
        debug!("Selection check pased, waiting for 10 secs");
        tokio::time::sleep(Duration::from_secs(10)).await;
        info!("Waiting tree storage");
        storage::wait_until_updated().await;
        info!(
            "Total cells {}, Tree stat {:?}",
            client.count().await.unwrap(),
            index_client.tree_stats().await.unwrap()
        );
        info!("Verifiying insertion round 2");
        for i in &nums {
            let id = Id::new(1, *i as u64);
            let cell_res = client.read_cell(id).await.unwrap();
            match cell_res {
                Ok(cell) => {
                    assert_eq!(*cell.data["data"].U64().unwrap(), *i as u64);
                }
                Err(e) => {
                    panic!("Expecting cell at round 2, found error {:?}", e);
                }
            }
        }
        info!("Scanning forward...");
        let mut rt_cursor = client::RangedQueryClient::seek(
            &index_client,
            &EntryKey::from_id(&Id::new(1, 0)),
            Ordering::Forward,
            128
        )
        .await
        .unwrap()
        .unwrap();
        for num in &nums {
            let id = Id::new(1, *num as u64);
            let current = rt_cursor.current().unwrap().0;
            assert_eq!(id, current, "Expecting {:?}, key {:?}, got {:?}", id, EntryKey::from_id(&id), current);
            let _ = rt_cursor.next().await.unwrap();
            if num % (test_capacity / 128) == 0 {
                debug!("Scanned {} of {}", num, test_capacity);
            }
        }
        info!("Scan finished");
        let end_of_list = rt_cursor.next().await.unwrap();
        assert!(
            end_of_list.is_none(),
            "End of the list have id {:?}",
            end_of_list.unwrap().0
        );
        assert!(
            end_of_list.is_none(),
            "After end of the list have id {:?}",
            end_of_list.unwrap().0
        );
        info!(
            "Total cells {}, Tree stat {:?}",
            client.count().await.unwrap(),
            index_client.tree_stats().await.unwrap()
        );
        panic!("Explicit panic for error discovery");
    }

    fn schema() -> Schema {
        Schema {
            id: 11,
            name: String::from("test"),
            key_field: None,
            str_key_field: None,
            fields: Field::new(
                "*",
                0,
                false,
                false,
                Some(vec![Field::new("data", 10, false, false, None, vec![])]),
                vec![],
            ),
            is_dynamic: false,
        }
    }
}
<|endoftext|>


<commit_before>//! This module contains the `EvalContext` methods for executing a single step of the interpreter.
//!
//! The main entry point is the `step` method.

use super::{
    CachedMir,
    ConstantId,
    EvalContext,
    ConstantKind,
    StackPopCleanup,
};
use error::EvalResult;
use rustc::mir::repr as mir;
use rustc::ty::{subst, self};
use rustc::hir::def_id::DefId;
use rustc::hir;
use rustc::mir::visit::{Visitor, LvalueContext};
use syntax::codemap::Span;
use std::rc::Rc;

impl<'a, 'tcx> EvalContext<'a, 'tcx> {
    /// Returns true as long as there are more things to do.
    pub fn step(&mut self) -> EvalResult<'tcx, bool> {
        if self.stack.is_empty() {
            return Ok(false);
        }

        let block = self.frame().block;
        let stmt_id = self.frame().stmt;
        let mir = self.mir();
        let basic_block = &mir.basic_blocks()[block];

        if let Some(stmt) = basic_block.statements.get(stmt_id) {
            let mut new = Ok(0);
            ConstantExtractor {
                span: stmt.source_info.span,
                substs: self.substs(),
                def_id: self.frame().def_id,
                ecx: self,
                mir: &mir,
                new_constants: &mut new,
            }.visit_statement(block, stmt, mir::Location {
                block: block,
                statement_index: stmt_id,
            });
            if new? == 0 {
                self.statement(stmt)?;
            }
            // if ConstantExtractor added new frames, we don't execute anything here
            // but await the next call to step
            return Ok(true);
        }

        let terminator = basic_block.terminator();
        let mut new = Ok(0);
        ConstantExtractor {
            span: terminator.source_info.span,
            substs: self.substs(),
            def_id: self.frame().def_id,
            ecx: self,
            mir: &mir,
            new_constants: &mut new,
        }.visit_terminator(block, terminator, mir::Location {
            block: block,
            statement_index: stmt_id,
        });
        if new? == 0 {
            self.terminator(terminator)?;
        }
        // if ConstantExtractor added new frames, we don't execute anything here
        // but await the next call to step
        Ok(true)
    }

    fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> EvalResult<'tcx, ()> {
        trace!("{:?}", stmt);

        use rustc::mir::repr::StatementKind::*;
        match stmt.kind {
            Assign(ref lvalue, ref rvalue) => self.eval_rvalue_into_lvalue(rvalue, lvalue)?,
            SetDiscriminant { .. } => unimplemented!(),

            // Miri can safely ignore these. Only translation needs them.
            StorageLive(_) | StorageDead(_) => {}
        }

        self.frame_mut().stmt += 1;
        Ok(())
    }

    fn terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> EvalResult<'tcx, ()> {
        trace!("{:?}", terminator.kind);
        self.eval_terminator(terminator)?;
        if !self.stack.is_empty() {
            trace!("// {:?}", self.frame().block);
        }
        Ok(())
    }
}

// WARNING: make sure that any methods implemented on this type don't ever access ecx.stack
// this includes any method that might access the stack
// basically don't call anything other than `load_mir`, `alloc_ret_ptr`, `push_stack_frame`
// The reason for this is, that `push_stack_frame` modifies the stack out of obvious reasons
struct ConstantExtractor<'a, 'b: 'a, 'tcx: 'b> {
    span: Span,
    ecx: &'a mut EvalContext<'b, 'tcx>,
    mir: &'a mir::Mir<'tcx>,
    def_id: DefId,
    substs: &'tcx subst::Substs<'tcx>,
    new_constants: &'a mut EvalResult<'tcx, u64>,
}

impl<'a, 'b, 'tcx> ConstantExtractor<'a, 'b, 'tcx> {
    fn global_item(&mut self, def_id: DefId, substs: &'tcx subst::Substs<'tcx>, span: Span, immutable: bool) {
        let cid = ConstantId {
            def_id: def_id,
            substs: substs,
            kind: ConstantKind::Global,
        };
        if self.ecx.statics.contains_key(&cid) {
            return;
        }
        let mir = self.ecx.load_mir(def_id);
        self.try(|this| {
            let ptr = this.ecx.alloc_ret_ptr(mir.return_ty, substs)?;
            this.ecx.statics.insert(cid.clone(), ptr);
            let cleanup = if immutable && !mir.return_ty.type_contents(this.ecx.tcx).interior_unsafe() {
                StackPopCleanup::Freeze(ptr.alloc_id)
            } else {
                StackPopCleanup::None
            };
            this.ecx.push_stack_frame(def_id, span, mir, substs, Some(ptr), cleanup)
        });
    }
    fn try<F: FnOnce(&mut Self) -> EvalResult<'tcx, ()>>(&mut self, f: F) {
        if let Ok(ref mut n) = *self.new_constants {
            *n += 1;
        } else {
            return;
        }
        if let Err(e) = f(self) {
            *self.new_constants = Err(e);
        }
    }
}

impl<'a, 'b, 'tcx> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'tcx> {
    fn visit_constant(&mut self, constant: &mir::Constant<'tcx>, location: mir::Location) {
        self.super_constant(constant, location);
        match constant.literal {
            // already computed by rustc
            mir::Literal::Value { .. } => {}
            mir::Literal::Item { def_id, substs } => {
                if let ty::TyFnDef(..) = constant.ty.sty {
                    // No need to do anything here,
                    // because the type is the actual function, not the signature of the function.
                    // Thus we can simply create a zero sized allocation in `evaluate_operand`
                } else {
                    self.global_item(def_id, substs, constant.span, true);
                }
            },
            mir::Literal::Promoted { index } => {
                let cid = ConstantId {
                    def_id: self.def_id,
                    substs: self.substs,
                    kind: ConstantKind::Promoted(index),
                };
                if self.ecx.statics.contains_key(&cid) {
                    return;
                }
                let mir = self.mir.promoted[index].clone();
                let return_ty = mir.return_ty;
                self.try(|this| {
                    let return_ptr = this.ecx.alloc_ret_ptr(return_ty, cid.substs)?;
                    let mir = CachedMir::Owned(Rc::new(mir));
                    this.ecx.statics.insert(cid.clone(), return_ptr);
                    this.ecx.push_stack_frame(this.def_id,
                                              constant.span,
                                              mir,
                                              this.substs,
                                              Some(return_ptr),
                                              StackPopCleanup::Freeze(return_ptr.alloc_id))
                });
            }
        }
    }

    fn visit_lvalue(&mut self, lvalue: &mir::Lvalue<'tcx>, context: LvalueContext, location: mir::Location) {
        self.super_lvalue(lvalue, context, location);
        if let mir::Lvalue::Static(def_id) = *lvalue {
            let substs = subst::Substs::empty(self.ecx.tcx);
            let span = self.span;
            if let hir::map::Node::NodeItem(&hir::Item { ref node, .. }) = self.ecx.tcx.map.get_if_local(def_id).expect("static not found") {
                if let hir::ItemStatic(_, m, _) = *node {
                    self.global_item(def_id, substs, span, m == hir::MutImmutable);
                    return;
                } else {
                    bug!("static def id doesn't point to static");
                }
            } else {
                bug!("static def id doesn't point to item");
            }
            self.global_item(def_id, substs, span, false);
        }
    }
}
<commit_msg>Update for changes in rustc.<commit_after>//! This module contains the `EvalContext` methods for executing a single step of the interpreter.
//!
//! The main entry point is the `step` method.

use super::{
    CachedMir,
    ConstantId,
    EvalContext,
    ConstantKind,
    StackPopCleanup,
};
use error::EvalResult;
use rustc::mir::repr as mir;
use rustc::ty::{subst, self};
use rustc::hir::def_id::DefId;
use rustc::hir;
use rustc::mir::visit::{Visitor, LvalueContext};
use syntax::codemap::Span;
use std::rc::Rc;

impl<'a, 'tcx> EvalContext<'a, 'tcx> {
    /// Returns true as long as there are more things to do.
    pub fn step(&mut self) -> EvalResult<'tcx, bool> {
        if self.stack.is_empty() {
            return Ok(false);
        }

        let block = self.frame().block;
        let stmt_id = self.frame().stmt;
        let mir = self.mir();
        let basic_block = &mir.basic_blocks()[block];

        if let Some(stmt) = basic_block.statements.get(stmt_id) {
            let mut new = Ok(0);
            ConstantExtractor {
                span: stmt.source_info.span,
                substs: self.substs(),
                def_id: self.frame().def_id,
                ecx: self,
                mir: &mir,
                new_constants: &mut new,
            }.visit_statement(block, stmt, mir::Location {
                block: block,
                statement_index: stmt_id,
            });
            if new? == 0 {
                self.statement(stmt)?;
            }
            // if ConstantExtractor added new frames, we don't execute anything here
            // but await the next call to step
            return Ok(true);
        }

        let terminator = basic_block.terminator();
        let mut new = Ok(0);
        ConstantExtractor {
            span: terminator.source_info.span,
            substs: self.substs(),
            def_id: self.frame().def_id,
            ecx: self,
            mir: &mir,
            new_constants: &mut new,
        }.visit_terminator(block, terminator, mir::Location {
            block: block,
            statement_index: stmt_id,
        });
        if new? == 0 {
            self.terminator(terminator)?;
        }
        // if ConstantExtractor added new frames, we don't execute anything here
        // but await the next call to step
        Ok(true)
    }

    fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> EvalResult<'tcx, ()> {
        trace!("{:?}", stmt);

        use rustc::mir::repr::StatementKind::*;
        match stmt.kind {
            Assign(ref lvalue, ref rvalue) => self.eval_rvalue_into_lvalue(rvalue, lvalue)?,
            SetDiscriminant { .. } => unimplemented!(),

            // Miri can safely ignore these. Only translation needs them.
            StorageLive(_) | StorageDead(_) => {}

            // Defined to do nothing. These are added by optimization passes, to avoid changing the
            // size of MIR constantly.
            Nop => {}
        }

        self.frame_mut().stmt += 1;
        Ok(())
    }

    fn terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> EvalResult<'tcx, ()> {
        trace!("{:?}", terminator.kind);
        self.eval_terminator(terminator)?;
        if !self.stack.is_empty() {
            trace!("// {:?}", self.frame().block);
        }
        Ok(())
    }
}

// WARNING: make sure that any methods implemented on this type don't ever access ecx.stack
// this includes any method that might access the stack
// basically don't call anything other than `load_mir`, `alloc_ret_ptr`, `push_stack_frame`
// The reason for this is, that `push_stack_frame` modifies the stack out of obvious reasons
struct ConstantExtractor<'a, 'b: 'a, 'tcx: 'b> {
    span: Span,
    ecx: &'a mut EvalContext<'b, 'tcx>,
    mir: &'a mir::Mir<'tcx>,
    def_id: DefId,
    substs: &'tcx subst::Substs<'tcx>,
    new_constants: &'a mut EvalResult<'tcx, u64>,
}

impl<'a, 'b, 'tcx> ConstantExtractor<'a, 'b, 'tcx> {
    fn global_item(&mut self, def_id: DefId, substs: &'tcx subst::Substs<'tcx>, span: Span, immutable: bool) {
        let cid = ConstantId {
            def_id: def_id,
            substs: substs,
            kind: ConstantKind::Global,
        };
        if self.ecx.statics.contains_key(&cid) {
            return;
        }
        let mir = self.ecx.load_mir(def_id);
        self.try(|this| {
            let ptr = this.ecx.alloc_ret_ptr(mir.return_ty, substs)?;
            this.ecx.statics.insert(cid.clone(), ptr);
            let cleanup = if immutable && !mir.return_ty.type_contents(this.ecx.tcx).interior_unsafe() {
                StackPopCleanup::Freeze(ptr.alloc_id)
            } else {
                StackPopCleanup::None
            };
            this.ecx.push_stack_frame(def_id, span, mir, substs, Some(ptr), cleanup)
        });
    }
    fn try<F: FnOnce(&mut Self) -> EvalResult<'tcx, ()>>(&mut self, f: F) {
        if let Ok(ref mut n) = *self.new_constants {
            *n += 1;
        } else {
            return;
        }
        if let Err(e) = f(self) {
            *self.new_constants = Err(e);
        }
    }
}

impl<'a, 'b, 'tcx> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'tcx> {
    fn visit_constant(&mut self, constant: &mir::Constant<'tcx>, location: mir::Location) {
        self.super_constant(constant, location);
        match constant.literal {
            // already computed by rustc
            mir::Literal::Value { .. } => {}
            mir::Literal::Item { def_id, substs } => {
                if let ty::TyFnDef(..) = constant.ty.sty {
                    // No need to do anything here,
                    // because the type is the actual function, not the signature of the function.
                    // Thus we can simply create a zero sized allocation in `evaluate_operand`
                } else {
                    self.global_item(def_id, substs, constant.span, true);
                }
            },
            mir::Literal::Promoted { index } => {
                let cid = ConstantId {
                    def_id: self.def_id,
                    substs: self.substs,
                    kind: ConstantKind::Promoted(index),
                };
                if self.ecx.statics.contains_key(&cid) {
                    return;
                }
                let mir = self.mir.promoted[index].clone();
                let return_ty = mir.return_ty;
                self.try(|this| {
                    let return_ptr = this.ecx.alloc_ret_ptr(return_ty, cid.substs)?;
                    let mir = CachedMir::Owned(Rc::new(mir));
                    this.ecx.statics.insert(cid.clone(), return_ptr);
                    this.ecx.push_stack_frame(this.def_id,
                                              constant.span,
                                              mir,
                                              this.substs,
                                              Some(return_ptr),
                                              StackPopCleanup::Freeze(return_ptr.alloc_id))
                });
            }
        }
    }

    fn visit_lvalue(
        &mut self,
        lvalue: &mir::Lvalue<'tcx>,
        context: LvalueContext<'tcx>,
        location: mir::Location
    ) {
        self.super_lvalue(lvalue, context, location);
        if let mir::Lvalue::Static(def_id) = *lvalue {
            let substs = subst::Substs::empty(self.ecx.tcx);
            let span = self.span;
            let node_item = self.ecx.tcx.map.get_if_local(def_id).expect("static not found");
            if let hir::map::Node::NodeItem(&hir::Item { ref node, .. }) = node_item {
                if let hir::ItemStatic(_, m, _) = *node {
                    self.global_item(def_id, substs, span, m == hir::MutImmutable);
                    return;
                } else {
                    bug!("static def id doesn't point to static");
                }
            } else {
                bug!("static def id doesn't point to item");
            }
            self.global_item(def_id, substs, span, false);
        }
    }
}
<|endoftext|>


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

#[forbid(deprecated_mode)];
#[allow(missing_doc)];

pub mod icu {
    pub type UBool = u8;
    pub type UProperty = int;
    pub type UChar32 = char;

    pub static TRUE : u8 = 1u8;
    pub static FALSE : u8 = 1u8;

    pub static UCHAR_ALPHABETIC : UProperty = 0;
    pub static UCHAR_BINARY_START : UProperty = 0; // = UCHAR_ALPHABETIC
    pub static UCHAR_ASCII_HEX_DIGIT : UProperty = 1;
    pub static UCHAR_BIDI_CONTROL : UProperty = 2;

    pub static UCHAR_BIDI_MIRRORED : UProperty = 3;
    pub static UCHAR_DASH : UProperty = 4;
    pub static UCHAR_DEFAULT_IGNORABLE_CODE_POINT : UProperty = 5;
    pub static UCHAR_DEPRECATED : UProperty = 6;

    pub static UCHAR_DIACRITIC : UProperty = 7;
    pub static UCHAR_EXTENDER : UProperty = 8;
    pub static UCHAR_FULL_COMPOSITION_EXCLUSION : UProperty = 9;
    pub static UCHAR_GRAPHEME_BASE : UProperty = 10;

    pub static UCHAR_GRAPHEME_EXTEND : UProperty = 11;
    pub static UCHAR_GRAPHEME_LINK : UProperty = 12;
    pub static UCHAR_HEX_DIGIT : UProperty = 13;
    pub static UCHAR_HYPHEN : UProperty = 14;

    pub static UCHAR_ID_CONTINUE : UProperty = 15;
    pub static UCHAR_ID_START : UProperty = 16;
    pub static UCHAR_IDEOGRAPHIC : UProperty = 17;
    pub static UCHAR_IDS_BINARY_OPERATOR : UProperty = 18;

    pub static UCHAR_IDS_TRINARY_OPERATOR : UProperty = 19;
    pub static UCHAR_JOIN_CONTROL : UProperty = 20;
    pub static UCHAR_LOGICAL_ORDER_EXCEPTION : UProperty = 21;
    pub static UCHAR_LOWERCASE : UProperty = 22;

    pub static UCHAR_MATH : UProperty = 23;
    pub static UCHAR_NONCHARACTER_CODE_POINT : UProperty = 24;
    pub static UCHAR_QUOTATION_MARK : UProperty = 25;
    pub static UCHAR_RADICAL : UProperty = 26;

    pub static UCHAR_SOFT_DOTTED : UProperty = 27;
    pub static UCHAR_TERMINAL_PUNCTUATION : UProperty = 28;
    pub static UCHAR_UNIFIED_IDEOGRAPH : UProperty = 29;
    pub static UCHAR_UPPERCASE : UProperty = 30;

    pub static UCHAR_WHITE_SPACE : UProperty = 31;
    pub static UCHAR_XID_CONTINUE : UProperty = 32;
    pub static UCHAR_XID_START : UProperty = 33;
    pub static UCHAR_CASE_SENSITIVE : UProperty = 34;

    pub static UCHAR_S_TERM : UProperty = 35;
    pub static UCHAR_VARIATION_SELECTOR : UProperty = 36;
    pub static UCHAR_NFD_INERT : UProperty = 37;
    pub static UCHAR_NFKD_INERT : UProperty = 38;

    pub static UCHAR_NFC_INERT : UProperty = 39;
    pub static UCHAR_NFKC_INERT : UProperty = 40;
    pub static UCHAR_SEGMENT_STARTER : UProperty = 41;
    pub static UCHAR_PATTERN_SYNTAX : UProperty = 42;

    pub static UCHAR_PATTERN_WHITE_SPACE : UProperty = 43;
    pub static UCHAR_POSIX_ALNUM : UProperty = 44;
    pub static UCHAR_POSIX_BLANK : UProperty = 45;
    pub static UCHAR_POSIX_GRAPH : UProperty = 46;

    pub static UCHAR_POSIX_PRINT : UProperty = 47;
    pub static UCHAR_POSIX_XDIGIT : UProperty = 48;
    pub static UCHAR_CASED : UProperty = 49;
    pub static UCHAR_CASE_IGNORABLE : UProperty = 50;

    pub static UCHAR_CHANGES_WHEN_LOWERCASED : UProperty = 51;
    pub static UCHAR_CHANGES_WHEN_UPPERCASED : UProperty = 52;
    pub static UCHAR_CHANGES_WHEN_TITLECASED : UProperty = 53;
    pub static UCHAR_CHANGES_WHEN_CASEFOLDED : UProperty = 54;

    pub static UCHAR_CHANGES_WHEN_CASEMAPPED : UProperty = 55;
    pub static UCHAR_CHANGES_WHEN_NFKC_CASEFOLDED : UProperty = 56;
    pub static UCHAR_BINARY_LIMIT : UProperty = 57;
    pub static UCHAR_BIDI_CLASS : UProperty = 0x1000;

    pub static UCHAR_INT_START : UProperty = 0x1000; // UCHAR_BIDI_CLASS
    pub static UCHAR_BLOCK : UProperty = 0x1001;
    pub static UCHAR_CANONICAL_COMBINING_CLASS : UProperty = 0x1002;
    pub static UCHAR_DECOMPOSITION_TYPE : UProperty = 0x1003;

    pub static UCHAR_EAST_ASIAN_WIDTH : UProperty = 0x1004;
    pub static UCHAR_GENERAL_CATEGORY : UProperty = 0x1005;
    pub static UCHAR_JOINING_GROUP : UProperty = 0x1006;
    pub static UCHAR_JOINING_TYPE : UProperty = 0x1007;

    pub static UCHAR_LINE_BREAK : UProperty = 0x1008;
    pub static UCHAR_NUMERIC_TYPE : UProperty = 0x1009;
    pub static UCHAR_SCRIPT : UProperty = 0x100A;
    pub static UCHAR_HANGUL_SYLLABLE_TYPE : UProperty = 0x100B;

    pub static UCHAR_NFD_QUICK_CHECK : UProperty = 0x100C;
    pub static UCHAR_NFKD_QUICK_CHECK : UProperty = 0x100D;
    pub static UCHAR_NFC_QUICK_CHECK : UProperty = 0x100E;
    pub static UCHAR_NFKC_QUICK_CHECK : UProperty = 0x100F;

    pub static UCHAR_LEAD_CANONICAL_COMBINING_CLASS : UProperty = 0x1010;
    pub static UCHAR_TRAIL_CANONICAL_COMBINING_CLASS : UProperty = 0x1011;
    pub static UCHAR_GRAPHEME_CLUSTER_BREAK : UProperty = 0x1012;
    pub static UCHAR_SENTENCE_BREAK : UProperty = 0x1013;

    pub static UCHAR_WORD_BREAK : UProperty = 0x1014;
    pub static UCHAR_INT_LIMIT : UProperty = 0x1015;

    pub static UCHAR_GENERAL_CATEGORY_MASK : UProperty = 0x2000;
    pub static UCHAR_MASK_START : UProperty = 0x2000;
    // = UCHAR_GENERAL_CATEGORY_MASK
    pub static UCHAR_MASK_LIMIT : UProperty = 0x2001;

    pub static UCHAR_NUMERIC_VALUE : UProperty = 0x3000;
    pub static UCHAR_DOUBLE_START : UProperty = 0x3000;
    // = UCHAR_NUMERIC_VALUE
    pub static UCHAR_DOUBLE_LIMIT : UProperty = 0x3001;

    pub static UCHAR_AGE : UProperty = 0x4000;
    pub static UCHAR_STRING_START : UProperty = 0x4000; // = UCHAR_AGE
    pub static UCHAR_BIDI_MIRRORING_GLYPH : UProperty = 0x4001;
    pub static UCHAR_CASE_FOLDING : UProperty = 0x4002;

    pub static UCHAR_ISO_COMMENT : UProperty = 0x4003;
    pub static UCHAR_LOWERCASE_MAPPING : UProperty = 0x4004;
    pub static UCHAR_NAME : UProperty = 0x4005;
    pub static UCHAR_SIMPLE_CASE_FOLDING : UProperty = 0x4006;

    pub static UCHAR_SIMPLE_LOWERCASE_MAPPING : UProperty = 0x4007;
    pub static UCHAR_SIMPLE_TITLECASE_MAPPING : UProperty = 0x4008;
    pub static UCHAR_SIMPLE_UPPERCASE_MAPPING : UProperty = 0x4009;
    pub static UCHAR_TITLECASE_MAPPING : UProperty = 0x400A;

    pub static UCHAR_UNICODE_1_NAME : UProperty = 0x400B;
    pub static UCHAR_UPPERCASE_MAPPING : UProperty = 0x400C;
    pub static UCHAR_STRING_LIMIT : UProperty = 0x400D;

    pub static UCHAR_SCRIPT_EXTENSIONS : UProperty = 0x7000;
    pub static UCHAR_OTHER_PROPERTY_START : UProperty = 0x7000;
    // = UCHAR_SCRIPT_EXTENSIONS;
    pub static UCHAR_OTHER_PROPERTY_LIMIT : UProperty = 0x7001;

    pub static UCHAR_INVALID_CODE : UProperty = -1;

    pub mod libicu {
        #[link_name = "icuuc"]
        #[abi = "cdecl"]
        extern {
            pub unsafe fn u_hasBinaryProperty(c: UChar32, which: UProperty)
                                              -> UBool;
            pub unsafe fn u_isdigit(c: UChar32) -> UBool;
            pub unsafe fn u_islower(c: UChar32) -> UBool;
            pub unsafe fn u_isspace(c: UChar32) -> UBool;
            pub unsafe fn u_isupper(c: UChar32) -> UBool;
            pub unsafe fn u_tolower(c: UChar32) -> UChar32;
            pub unsafe fn u_toupper(c: UChar32) -> UChar32;
        }
    }
}

pub fn is_XID_start(c: char) -> bool {
    return icu::libicu::u_hasBinaryProperty(c, icu::UCHAR_XID_START)
        == icu::TRUE;
}

pub fn is_XID_continue(c: char) -> bool {
    return icu::libicu::u_hasBinaryProperty(c, icu::UCHAR_XID_START)
        == icu::TRUE;
}

/*
Function: is_digit

Returns true if a character is a digit.
*/
pub fn is_digit(c: char) -> bool {
    return icu::libicu::u_isdigit(c) == icu::TRUE;
}

/*
Function: is_lower

Returns true if a character is a lowercase letter.
*/
pub fn is_lower(c: char) -> bool {
    return icu::libicu::u_islower(c) == icu::TRUE;
}

/*
Function: is_space

Returns true if a character is space.
*/
pub fn is_space(c: char) -> bool {
    return icu::libicu::u_isspace(c) == icu::TRUE;
}

/*
Function: is_upper

Returns true if a character is an uppercase letter.
*/
pub fn is_upper(c: char) -> bool {
    return icu::libicu::u_isupper(c) == icu::TRUE;
}

#[cfg(test)]
mod tests {

    #[test]
    fn test_is_digit() {
        assert!((unicode::icu::is_digit('0')));
        assert!((!unicode::icu::is_digit('m')));
    }

    #[test]
    fn test_is_lower() {
        assert!((unicode::icu::is_lower('m')));
        assert!((!unicode::icu::is_lower('M')));
    }

    #[test]
    fn test_is_space() {
        assert!((unicode::icu::is_space(' ')));
        assert!((!unicode::icu::is_space('m')));
    }

    #[test]
    fn test_is_upper() {
        assert!((unicode::icu::is_upper('M')));
        assert!((!unicode::icu::is_upper('m')));
    }
}
<commit_msg>FALSE is not 1u8 but 0u8, of cource.<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[forbid(deprecated_mode)];
#[allow(missing_doc)];

pub mod icu {
    pub type UBool = u8;
    pub type UProperty = int;
    pub type UChar32 = char;

    pub static TRUE : u8 = 1u8;
    pub static FALSE : u8 = 0u8;

    pub static UCHAR_ALPHABETIC : UProperty = 0;
    pub static UCHAR_BINARY_START : UProperty = 0; // = UCHAR_ALPHABETIC
    pub static UCHAR_ASCII_HEX_DIGIT : UProperty = 1;
    pub static UCHAR_BIDI_CONTROL : UProperty = 2;

    pub static UCHAR_BIDI_MIRRORED : UProperty = 3;
    pub static UCHAR_DASH : UProperty = 4;
    pub static UCHAR_DEFAULT_IGNORABLE_CODE_POINT : UProperty = 5;
    pub static UCHAR_DEPRECATED : UProperty = 6;

    pub static UCHAR_DIACRITIC : UProperty = 7;
    pub static UCHAR_EXTENDER : UProperty = 8;
    pub static UCHAR_FULL_COMPOSITION_EXCLUSION : UProperty = 9;
    pub static UCHAR_GRAPHEME_BASE : UProperty = 10;

    pub static UCHAR_GRAPHEME_EXTEND : UProperty = 11;
    pub static UCHAR_GRAPHEME_LINK : UProperty = 12;
    pub static UCHAR_HEX_DIGIT : UProperty = 13;
    pub static UCHAR_HYPHEN : UProperty = 14;

    pub static UCHAR_ID_CONTINUE : UProperty = 15;
    pub static UCHAR_ID_START : UProperty = 16;
    pub static UCHAR_IDEOGRAPHIC : UProperty = 17;
    pub static UCHAR_IDS_BINARY_OPERATOR : UProperty = 18;

    pub static UCHAR_IDS_TRINARY_OPERATOR : UProperty = 19;
    pub static UCHAR_JOIN_CONTROL : UProperty = 20;
    pub static UCHAR_LOGICAL_ORDER_EXCEPTION : UProperty = 21;
    pub static UCHAR_LOWERCASE : UProperty = 22;

    pub static UCHAR_MATH : UProperty = 23;
    pub static UCHAR_NONCHARACTER_CODE_POINT : UProperty = 24;
    pub static UCHAR_QUOTATION_MARK : UProperty = 25;
    pub static UCHAR_RADICAL : UProperty = 26;

    pub static UCHAR_SOFT_DOTTED : UProperty = 27;
    pub static UCHAR_TERMINAL_PUNCTUATION : UProperty = 28;
    pub static UCHAR_UNIFIED_IDEOGRAPH : UProperty = 29;
    pub static UCHAR_UPPERCASE : UProperty = 30;

    pub static UCHAR_WHITE_SPACE : UProperty = 31;
    pub static UCHAR_XID_CONTINUE : UProperty = 32;
    pub static UCHAR_XID_START : UProperty = 33;
    pub static UCHAR_CASE_SENSITIVE : UProperty = 34;

    pub static UCHAR_S_TERM : UProperty = 35;
    pub static UCHAR_VARIATION_SELECTOR : UProperty = 36;
    pub static UCHAR_NFD_INERT : UProperty = 37;
    pub static UCHAR_NFKD_INERT : UProperty = 38;

    pub static UCHAR_NFC_INERT : UProperty = 39;
    pub static UCHAR_NFKC_INERT : UProperty = 40;
    pub static UCHAR_SEGMENT_STARTER : UProperty = 41;
    pub static UCHAR_PATTERN_SYNTAX : UProperty = 42;

    pub static UCHAR_PATTERN_WHITE_SPACE : UProperty = 43;
    pub static UCHAR_POSIX_ALNUM : UProperty = 44;
    pub static UCHAR_POSIX_BLANK : UProperty = 45;
    pub static UCHAR_POSIX_GRAPH : UProperty = 46;

    pub static UCHAR_POSIX_PRINT : UProperty = 47;
    pub static UCHAR_POSIX_XDIGIT : UProperty = 48;
    pub static UCHAR_CASED : UProperty = 49;
    pub static UCHAR_CASE_IGNORABLE : UProperty = 50;

    pub static UCHAR_CHANGES_WHEN_LOWERCASED : UProperty = 51;
    pub static UCHAR_CHANGES_WHEN_UPPERCASED : UProperty = 52;
    pub static UCHAR_CHANGES_WHEN_TITLECASED : UProperty = 53;
    pub static UCHAR_CHANGES_WHEN_CASEFOLDED : UProperty = 54;

    pub static UCHAR_CHANGES_WHEN_CASEMAPPED : UProperty = 55;
    pub static UCHAR_CHANGES_WHEN_NFKC_CASEFOLDED : UProperty = 56;
    pub static UCHAR_BINARY_LIMIT : UProperty = 57;
    pub static UCHAR_BIDI_CLASS : UProperty = 0x1000;

    pub static UCHAR_INT_START : UProperty = 0x1000; // UCHAR_BIDI_CLASS
    pub static UCHAR_BLOCK : UProperty = 0x1001;
    pub static UCHAR_CANONICAL_COMBINING_CLASS : UProperty = 0x1002;
    pub static UCHAR_DECOMPOSITION_TYPE : UProperty = 0x1003;

    pub static UCHAR_EAST_ASIAN_WIDTH : UProperty = 0x1004;
    pub static UCHAR_GENERAL_CATEGORY : UProperty = 0x1005;
    pub static UCHAR_JOINING_GROUP : UProperty = 0x1006;
    pub static UCHAR_JOINING_TYPE : UProperty = 0x1007;

    pub static UCHAR_LINE_BREAK : UProperty = 0x1008;
    pub static UCHAR_NUMERIC_TYPE : UProperty = 0x1009;
    pub static UCHAR_SCRIPT : UProperty = 0x100A;
    pub static UCHAR_HANGUL_SYLLABLE_TYPE : UProperty = 0x100B;

    pub static UCHAR_NFD_QUICK_CHECK : UProperty = 0x100C;
    pub static UCHAR_NFKD_QUICK_CHECK : UProperty = 0x100D;
    pub static UCHAR_NFC_QUICK_CHECK : UProperty = 0x100E;
    pub static UCHAR_NFKC_QUICK_CHECK : UProperty = 0x100F;

    pub static UCHAR_LEAD_CANONICAL_COMBINING_CLASS : UProperty = 0x1010;
    pub static UCHAR_TRAIL_CANONICAL_COMBINING_CLASS : UProperty = 0x1011;
    pub static UCHAR_GRAPHEME_CLUSTER_BREAK : UProperty = 0x1012;
    pub static UCHAR_SENTENCE_BREAK : UProperty = 0x1013;

    pub static UCHAR_WORD_BREAK : UProperty = 0x1014;
    pub static UCHAR_INT_LIMIT : UProperty = 0x1015;

    pub static UCHAR_GENERAL_CATEGORY_MASK : UProperty = 0x2000;
    pub static UCHAR_MASK_START : UProperty = 0x2000;
    // = UCHAR_GENERAL_CATEGORY_MASK
    pub static UCHAR_MASK_LIMIT : UProperty = 0x2001;

    pub static UCHAR_NUMERIC_VALUE : UProperty = 0x3000;
    pub static UCHAR_DOUBLE_START : UProperty = 0x3000;
    // = UCHAR_NUMERIC_VALUE
    pub static UCHAR_DOUBLE_LIMIT : UProperty = 0x3001;

    pub static UCHAR_AGE : UProperty = 0x4000;
    pub static UCHAR_STRING_START : UProperty = 0x4000; // = UCHAR_AGE
    pub static UCHAR_BIDI_MIRRORING_GLYPH : UProperty = 0x4001;
    pub static UCHAR_CASE_FOLDING : UProperty = 0x4002;

    pub static UCHAR_ISO_COMMENT : UProperty = 0x4003;
    pub static UCHAR_LOWERCASE_MAPPING : UProperty = 0x4004;
    pub static UCHAR_NAME : UProperty = 0x4005;
    pub static UCHAR_SIMPLE_CASE_FOLDING : UProperty = 0x4006;

    pub static UCHAR_SIMPLE_LOWERCASE_MAPPING : UProperty = 0x4007;
    pub static UCHAR_SIMPLE_TITLECASE_MAPPING : UProperty = 0x4008;
    pub static UCHAR_SIMPLE_UPPERCASE_MAPPING : UProperty = 0x4009;
    pub static UCHAR_TITLECASE_MAPPING : UProperty = 0x400A;

    pub static UCHAR_UNICODE_1_NAME : UProperty = 0x400B;
    pub static UCHAR_UPPERCASE_MAPPING : UProperty = 0x400C;
    pub static UCHAR_STRING_LIMIT : UProperty = 0x400D;

    pub static UCHAR_SCRIPT_EXTENSIONS : UProperty = 0x7000;
    pub static UCHAR_OTHER_PROPERTY_START : UProperty = 0x7000;
    // = UCHAR_SCRIPT_EXTENSIONS;
    pub static UCHAR_OTHER_PROPERTY_LIMIT : UProperty = 0x7001;

    pub static UCHAR_INVALID_CODE : UProperty = -1;

    pub mod libicu {
        #[link_name = "icuuc"]
        #[abi = "cdecl"]
        extern {
            pub unsafe fn u_hasBinaryProperty(c: UChar32, which: UProperty)
                                              -> UBool;
            pub unsafe fn u_isdigit(c: UChar32) -> UBool;
            pub unsafe fn u_islower(c: UChar32) -> UBool;
            pub unsafe fn u_isspace(c: UChar32) -> UBool;
            pub unsafe fn u_isupper(c: UChar32) -> UBool;
            pub unsafe fn u_tolower(c: UChar32) -> UChar32;
            pub unsafe fn u_toupper(c: UChar32) -> UChar32;
        }
    }
}

pub fn is_XID_start(c: char) -> bool {
    return icu::libicu::u_hasBinaryProperty(c, icu::UCHAR_XID_START)
        == icu::TRUE;
}

pub fn is_XID_continue(c: char) -> bool {
    return icu::libicu::u_hasBinaryProperty(c, icu::UCHAR_XID_START)
        == icu::TRUE;
}

/*
Function: is_digit

Returns true if a character is a digit.
*/
pub fn is_digit(c: char) -> bool {
    return icu::libicu::u_isdigit(c) == icu::TRUE;
}

/*
Function: is_lower

Returns true if a character is a lowercase letter.
*/
pub fn is_lower(c: char) -> bool {
    return icu::libicu::u_islower(c) == icu::TRUE;
}

/*
Function: is_space

Returns true if a character is space.
*/
pub fn is_space(c: char) -> bool {
    return icu::libicu::u_isspace(c) == icu::TRUE;
}

/*
Function: is_upper

Returns true if a character is an uppercase letter.
*/
pub fn is_upper(c: char) -> bool {
    return icu::libicu::u_isupper(c) == icu::TRUE;
}

#[cfg(test)]
mod tests {

    #[test]
    fn test_is_digit() {
        assert!((unicode::icu::is_digit('0')));
        assert!((!unicode::icu::is_digit('m')));
    }

    #[test]
    fn test_is_lower() {
        assert!((unicode::icu::is_lower('m')));
        assert!((!unicode::icu::is_lower('M')));
    }

    #[test]
    fn test_is_space() {
        assert!((unicode::icu::is_space(' ')));
        assert!((!unicode::icu::is_space('m')));
    }

    #[test]
    fn test_is_upper() {
        assert!((unicode::icu::is_upper('M')));
        assert!((!unicode::icu::is_upper('m')));
    }
}
<|endoftext|>


<commit_before>// pest. The Elegant Parser
// Copyright (c) 2018 Dragoș Tiselice
//
// 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. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

//! # pest. The Elegant Parser
//!
//! pest is a general purpose parser written in Rust with a focus on accessibility, correctness,
//! and performance. It uses parsing expression grammars (or [PEG]) as input, which are similar in
//! spirit to regular expressions, but which offer the enhanced expressivity needed to parse
//! complex languages.
//!
//! [PEG]: https://en.wikipedia.org/wiki/Parsing_expression_grammar
//!
//! ## Getting started
//!
//! The recommended way to start parsing with pest is to read the official [book].
//!
//! Other helpful resources:
//!
//! * API reference on [docs.rs]
//! * play with grammars and share them on our [fiddle]
//! * leave feedback, ask questions, or greet us on [Gitter]
//!
//! [book]: https://pest-parser.github.io/book
//! [docs.rs]: https://docs.rs/pest
//! [fiddle]: https://pest-parser.github.io/#editor
//! [Gitter]: https://gitter.im/dragostis/pest
//!
//! ## `.pest` files
//!
//! Grammar definitions reside in custom `.pest` files located in the `src` directory. Their path is
//! relative to `src` and is specified between the `derive` attribute and empty `struct` that
//! `Parser` will be derived on.
//!
//! ```ignore
//! #[derive(Parser)]
//! #[grammar = "path/to/my_grammar.pest"] // relative to src
//! struct MyParser;
//! ```
//!
//! ## Grammar
//!
//! A grammar is a series of rules separated by whitespace, possibly containing comments.
//!
//! ### Comments
//!
//! Comments start with `//` and end at the end of the line.
//!
//! ```ignore
//! // a comment
//! ```
//!
//! ### Rules
//!
//! Rules have the following form:
//!
//! ```ignore
//! name = optional_modifier { expression }
//! ```
//!
//! The name of the rule is formed from alphanumeric characters or `_` with the condition that the
//! first character is not a digit and is used to create token pairs. When the rule starts being
//! parsed, the starting part of the token is being produced, with the ending part being produced
//! when the rule finishes parsing.
//!
//! The following token pair notation `a(b(), c())` denotes the tokens: start `a`, start `b`, end
//! `b`, start `c`, end `c`, end `a`.
//!
//! #### Modifiers
//!
//! Modifiers are optional and can be one of `_`, `@`, `$`, or `!`. These modifiers change the
//! behavior of the rules.
//!
//! 1. Silent (`_`)
//!
//!     Silent rules do not create token pairs during parsing, nor are they error-reported.
//!
//!     ```ignore
//!     a = _{ "a" }
//!     b =  { a ~ "b" }
//!     ```
//!
//!     Parsing `"ab"` produces the token pair `b()`.
//!
//! 2. Atomic (`@`)
//!
//!     Atomic rules do not accept whitespace or comments within their expressions and have a
//!     cascading effect on any rule they call. I.e. rules that are not atomic but are called by atomic
//!     rules behave atomically.
//!
//!     Any rules called by atomic rules do not generate token pairs.
//!
//!     ```ignore
//!     a =  { "a" }
//!     b = @{ a ~ "b" }
//!
//!     WHITESPACE = _{ " " }
//!     ```
//!
//!     Parsing `"ab"` produces the token pair `b()`, while `"a   b"` produces an error.
//!
//! 3. Compound-atomic (`$`)
//!
//!     Compound-atomic are identical to atomic rules with the exception that rules called by them are
//!     not forbidden from generating token pairs.
//!
//!     ```ignore
//!     a =  { "a" }
//!     b = ${ a ~ "b" }
//!
//!     WHITESPACE = _{ " " }
//!     ```
//!
//!     Parsing `"ab"` produces the token pairs `b(a())`, while `"a   b"` produces an error.
//!
//! 4. Non-atomic (`!`)
//!
//!     Non-atomic are identical to normal rules with the exception that they stop the cascading effect
//!     of atomic and compound-atomic rules.
//!
//!     ```ignore
//!     a =  { "a" }
//!     b = !{ a ~ "b" }
//!     c = @{ b }
//!
//!     WHITESPACE = _{ " " }
//!     ```
//!
//!     Parsing both `"ab"` and `"a   b"` produce the token pairs `c(a())`.
//!
//! #### Expressions
//!
//! Expressions can be either terminals or non-terminals.
//!
//! 1. Terminals
//!
//!     | Terminal   | Usage                                                          |
//!     |------------|----------------------------------------------------------------|
//!     | `"a"`      | matches the exact string `"a"`                                 |
//!     | `^"a"`     | matches the exact string `"a"` case insensitively (ASCII only) |
//!     | `'a'..'z'` | matches one character between `'a'` and `'z'`                  |
//!     | `a`        | matches rule `a`                                               |
//!
//! Strings and characters follow
//! [Rust's escape mechanisms](https://doc.rust-lang.org/reference/tokens.html#byte-escapes), while
//! identifiers can contain alpha-numeric characters and underscores (`_`), as long as they do not
//! start with a digit.
//!
//! 2. Non-terminals
//!
//!     | Non-terminal          | Usage                                                      |
//!     |-----------------------|------------------------------------------------------------|
//!     | `(e)`                 | matches `e`                                                |
//!     | `e1 ~ e2`             | matches the sequence `e1` `e2`                             |
//!     | e1 \| e2 | matches either `e1` or `e2`                                |
//!     | `e*`                  | matches `e` zero or more times                             |
//!     | `e+`                  | matches `e` one or more times                              |
//!     | `e{n}`                | matches `e` exactly `n` times                              |
//!     | `e{, n}`              | matches `e` at most `n` times                              |
//!     | `e{n,} `              | matches `e` at least `n` times                             |
//!     | `e{m, n}`             | matches `e` between `m` and `n` times inclusively          |
//!     | `e?`                  | optionally matches `e`                                     |
//!     | `&e`                  | matches `e` without making progress                        |
//!     | `!e`                  | matches if `e` doesn't match without making progress       |
//!     | `PUSH(e)`             | matches `e` and pushes it's captured string down the stack |
//!
//!     where `e`, `e1`, and `e2` are expressions.
//!
//! Expressions can modify the stack only if they match the input. For example,
//! if `e1` in the compound expression `e1 | e2` does not match the input, then
//! it does not modify the stack, so `e2` sees the stack in the same state as
//! `e1` did. Repetitions and optionals (`e*`, `e+`, `e{, n}`, `e{n,}`,
//! `e{m,n}`, `e?`) can modify the stack each time `e` matches. The `!e` and `&e`
//! expressions are a special case; they never modify the stack.
//!
//! ## Special rules
//!
//! Special rules can be called within the grammar. They are:
//!
//! * `WHITESPACE` - runs between rules and sub-rules
//! * `COMMENT` - runs between rules and sub-rules
//! * `ANY` - matches exactly one `char`
//! * `SOI` - (start-of-input) matches only when a `Parser` is still at the starting position
//! * `EOI` - (end-of-input) matches only when a `Parser` has reached its end
//! * `POP` - pops a string from the stack and matches it
//! * `POP_ALL` - pops the entire state of the stack and matches it
//! * `PEEK` - peeks a string from the stack and matches it
//! * `PEEK[a..b]` - peeks part of the stack and matches it
//! * `PEEK_ALL` - peeks the entire state of the stack and matches it
//! * `DROP` - drops the top of the stack (fails to match if the stack is empty)
//!
//! `WHITESPACE` and `COMMENT` should be defined manually if needed. All other rules cannot be
//! overridden.
//!
//! ## `WHITESPACE` and `COMMENT`
//!
//! When defined, these rules get matched automatically in sequences (`~`) and repetitions
//! (`*`, `+`) between expressions. Atomic rules and those rules called by atomic rules are exempt
//! from this behavior.
//!
//! These rules should be defined so as to match one whitespace character and one comment only since
//! they are run in repetitions.
//!
//! If both `WHITESPACE` and `COMMENT` are defined, this grammar:
//!
//! ```ignore
//! a = { b ~ c }
//! ```
//!
//! is effectively transformed into this one behind the scenes:
//!
//! ```ignore
//! a = { b ~ WHITESPACE* ~ (COMMENT ~ WHITESPACE*)* ~ c }
//! ```
//!
//! ## `PUSH`, `POP`, `DROP`, and `PEEK`
//!
//! `PUSH(e)` simply pushes the captured string of the expression `e` down a stack. This stack can
//! then later be used to match grammar based on its content with `POP` and `PEEK`.
//!
//! `PEEK` always matches the string at the top of stack. So, if the stack contains `["b", "a"]`
//! (`"a"` being on top), this grammar:
//!
//! ```ignore
//! a = { PEEK }
//! ```
//!
//! is effectively transformed into at parse time:
//!
//! ```ignore
//! a = { "a" }
//! ```
//!
//! `POP` works the same way with the exception that it pops the string off of the stack if the
//! match worked. With the stack from above, if `POP` matches `"a"`, the stack will be mutated
//! to `["b"]`.
//!
//! `DROP` makes it possible to remove the string at the top of the stack
//! without matching it. If the stack is nonempty, `DROP` drops the top of the
//! stack. If the stack is empty, then `DROP` fails to match.
//!
//! ### Advanced peeking
//!
//! `PEEK[start..end]` and `PEEK_ALL` allow to peek deeper into the stack. The syntax works exactly
//! like Rust’s exclusive slice syntax. Additionally, negative indices can be used to indicate an
//! offset from the top. If the end lies before or at the start, the expression matches (as does
//! a `PEEK_ALL` on an empty stack). With the stack `["c", "b", "a"]` (`"a"` on top):
//!
//! ```ignore
//! fill = PUSH("c") ~ PUSH("b") ~ PUSH("a")
//! v = { PEEK_ALL } = { "a" ~ "b" ~ "c" }  // top to bottom
//! w = { PEEK[..] } = { "c" ~ "b" ~ "a" }  // bottom to top
//! x = { PEEK[1..2] } = { PEEK[1..-1] } = { "b" }
//! y = { PEEK[..-2] } = { PEEK[0..1] } = { "a" }
//! z = { PEEK[1..] } = { PEEK[-2..3] } = { "b" ~ "c" }
//! n = { PEEK[2..-2] } = { PEEK[2..1] } = { "" }
//! ```
//!
//! For historical reasons, `PEEK_ALL` matches from top to bottom, while `PEEK[start..end]` matches
//! from bottom to top. There is currectly no syntax to match a slice of the stack top to bottom.
//!
//! ## `Rule`
//!
//! All rules defined or used in the grammar populate a generated `enum` called `Rule`. This
//! implements `pest`'s `RuleType` and can be used throughout the API.
//!
//! ## `Built-in rules`
//!
//! Pest also comes with a number of built-in rules for convenience. They are:
//!
//! * `ASCII_DIGIT` - matches a numeric character from 0..9
//! * `ASCII_NONZERO_DIGIT` - matches a numeric character from 1..9
//! * `ASCII_BIN_DIGIT` - matches a numeric character from 0..1
//! * `ASCII_OCT_DIGIT` - matches a numeric character from 0..7
//! * `ASCII_HEX_DIGIT` - matches a numeric character from 0..9 or a..f or A..F
//! * `ASCII_ALPHA_LOWER` - matches a character from a..z
//! * `ASCII_ALPHA_UPPER` - matches a character from A..Z
//! * `ASCII_ALPHA` - matches a character from a..z or A..Z
//! * `ASCII_ALPHANUMERIC` - matches a character from a..z or A..Z or 0..9
//! * `ASCII` - matches a character from \x00..\x7f
//! * `NEWLINE` - matches either "\n" or "\r\n" or "\r"

#![doc(html_root_url = "https://docs.rs/pest_derive")]

extern crate pest_generator;
extern crate proc_macro;

use proc_macro::TokenStream;

#[proc_macro_derive(Parser, attributes(grammar))]
pub fn derive_parser(input: TokenStream) -> TokenStream {
    pest_generator::derive_parser(input.into(), true).into()
}
<commit_msg>fixed docs<commit_after>// pest. The Elegant Parser
// Copyright (c) 2018 Dragoș Tiselice
//
// 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. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

//! # pest. The Elegant Parser
//!
//! pest is a general purpose parser written in Rust with a focus on accessibility, correctness,
//! and performance. It uses parsing expression grammars (or [PEG]) as input, which are similar in
//! spirit to regular expressions, but which offer the enhanced expressivity needed to parse
//! complex languages.
//!
//! [PEG]: https://en.wikipedia.org/wiki/Parsing_expression_grammar
//!
//! ## Getting started
//!
//! The recommended way to start parsing with pest is to read the official [book].
//!
//! Other helpful resources:
//!
//! * API reference on [docs.rs]
//! * play with grammars and share them on our [fiddle]
//! * leave feedback, ask questions, or greet us on [Gitter]
//!
//! [book]: https://pest-parser.github.io/book
//! [docs.rs]: https://docs.rs/pest
//! [fiddle]: https://pest-parser.github.io/#editor
//! [Gitter]: https://gitter.im/dragostis/pest
//!
//! ## `.pest` files
//!
//! Grammar definitions reside in custom `.pest` files located in the `src` directory. Their path is
//! relative to `src` and is specified between the `derive` attribute and empty `struct` that
//! `Parser` will be derived on.
//!
//! ```ignore
//! #[derive(Parser)]
//! #[grammar = "path/to/my_grammar.pest"] // relative to src
//! struct MyParser;
//! ```
//!
//! ## Grammar
//!
//! A grammar is a series of rules separated by whitespace, possibly containing comments.
//!
//! ### Comments
//!
//! Comments start with `//` and end at the end of the line.
//!
//! ```ignore
//! // a comment
//! ```
//!
//! ### Rules
//!
//! Rules have the following form:
//!
//! ```ignore
//! name = optional_modifier { expression }
//! ```
//!
//! The name of the rule is formed from alphanumeric characters or `_` with the condition that the
//! first character is not a digit and is used to create token pairs. When the rule starts being
//! parsed, the starting part of the token is being produced, with the ending part being produced
//! when the rule finishes parsing.
//!
//! The following token pair notation `a(b(), c())` denotes the tokens: start `a`, start `b`, end
//! `b`, start `c`, end `c`, end `a`.
//!
//! #### Modifiers
//!
//! Modifiers are optional and can be one of `_`, `@`, `$`, or `!`. These modifiers change the
//! behavior of the rules.
//!
//! 1. Silent (`_`)
//!
//!     Silent rules do not create token pairs during parsing, nor are they error-reported.
//!
//!     ```ignore
//!     a = _{ "a" }
//!     b =  { a ~ "b" }
//!     ```
//!
//!     Parsing `"ab"` produces the token pair `b()`.
//!
//! 2. Atomic (`@`)
//!
//!     Atomic rules do not accept whitespace or comments within their expressions and have a
//!     cascading effect on any rule they call. I.e. rules that are not atomic but are called by atomic
//!     rules behave atomically.
//!
//!     Any rules called by atomic rules do not generate token pairs.
//!
//!     ```ignore
//!     a =  { "a" }
//!     b = @{ a ~ "b" }
//!
//!     WHITESPACE = _{ " " }
//!     ```
//!
//!     Parsing `"ab"` produces the token pair `b()`, while `"a   b"` produces an error.
//!
//! 3. Compound-atomic (`$`)
//!
//!     Compound-atomic are identical to atomic rules with the exception that rules called by them are
//!     not forbidden from generating token pairs.
//!
//!     ```ignore
//!     a =  { "a" }
//!     b = ${ a ~ "b" }
//!
//!     WHITESPACE = _{ " " }
//!     ```
//!
//!     Parsing `"ab"` produces the token pairs `b(a())`, while `"a   b"` produces an error.
//!
//! 4. Non-atomic (`!`)
//!
//!     Non-atomic are identical to normal rules with the exception that they stop the cascading effect
//!     of atomic and compound-atomic rules.
//!
//!     ```ignore
//!     a =  { "a" }
//!     b = !{ a ~ "b" }
//!     c = @{ b }
//!
//!     WHITESPACE = _{ " " }
//!     ```
//!
//!     Parsing both `"ab"` and `"a   b"` produce the token pairs `c(a())`.
//!
//! #### Expressions
//!
//! Expressions can be either terminals or non-terminals.
//!
//! 1. Terminals
//!
//!     | Terminal   | Usage                                                          |
//!     |------------|----------------------------------------------------------------|
//!     | `"a"`      | matches the exact string `"a"`                                 |
//!     | `^"a"`     | matches the exact string `"a"` case insensitively (ASCII only) |
//!     | `'a'..'z'` | matches one character between `'a'` and `'z'`                  |
//!     | `a`        | matches rule `a`                                               |
//!
//! Strings and characters follow
//! [Rust's escape mechanisms](https://doc.rust-lang.org/reference/tokens.html#byte-escapes), while
//! identifiers can contain alpha-numeric characters and underscores (`_`), as long as they do not
//! start with a digit.
//!
//! 2. Non-terminals
//!
//!     | Non-terminal          | Usage                                                      |
//!     |-----------------------|------------------------------------------------------------|
//!     | `(e)`                 | matches `e`                                                |
//!     | `e1 ~ e2`             | matches the sequence `e1` `e2`                             |
//!     | e1 \| e2 | matches either `e1` or `e2`                                |
//!     | `e*`                  | matches `e` zero or more times                             |
//!     | `e+`                  | matches `e` one or more times                              |
//!     | `e{n}`                | matches `e` exactly `n` times                              |
//!     | `e{, n}`              | matches `e` at most `n` times                              |
//!     | `e{n,} `              | matches `e` at least `n` times                             |
//!     | `e{m, n}`             | matches `e` between `m` and `n` times inclusively          |
//!     | `e?`                  | optionally matches `e`                                     |
//!     | `&e`                  | matches `e` without making progress                        |
//!     | `!e`                  | matches if `e` doesn't match without making progress       |
//!     | `PUSH(e)`             | matches `e` and pushes it's captured string down the stack |
//!
//!     where `e`, `e1`, and `e2` are expressions.
//!
//! Expressions can modify the stack only if they match the input. For example,
//! if `e1` in the compound expression `e1 | e2` does not match the input, then
//! it does not modify the stack, so `e2` sees the stack in the same state as
//! `e1` did. Repetitions and optionals (`e*`, `e+`, `e{, n}`, `e{n,}`,
//! `e{m,n}`, `e?`) can modify the stack each time `e` matches. The `!e` and `&e`
//! expressions are a special case; they never modify the stack.
//!
//! ## Special rules
//!
//! Special rules can be called within the grammar. They are:
//!
//! * `WHITESPACE` - runs between rules and sub-rules
//! * `COMMENT` - runs between rules and sub-rules
//! * `ANY` - matches exactly one `char`
//! * `SOI` - (start-of-input) matches only when a `Parser` is still at the starting position
//! * `EOI` - (end-of-input) matches only when a `Parser` has reached its end
//! * `POP` - pops a string from the stack and matches it
//! * `POP_ALL` - pops the entire state of the stack and matches it
//! * `PEEK` - peeks a string from the stack and matches it
//! * `PEEK[a..b]` - peeks part of the stack and matches it
//! * `PEEK_ALL` - peeks the entire state of the stack and matches it
//! * `DROP` - drops the top of the stack (fails to match if the stack is empty)
//!
//! `WHITESPACE` and `COMMENT` should be defined manually if needed. All other rules cannot be
//! overridden.
//!
//! ## `WHITESPACE` and `COMMENT`
//!
//! When defined, these rules get matched automatically in sequences (`~`) and repetitions
//! (`*`, `+`) between expressions. Atomic rules and those rules called by atomic rules are exempt
//! from this behavior.
//!
//! These rules should be defined so as to match one whitespace character and one comment only since
//! they are run in repetitions.
//!
//! If both `WHITESPACE` and `COMMENT` are defined, this grammar:
//!
//! ```ignore
//! a = { b ~ c }
//! ```
//!
//! is effectively transformed into this one behind the scenes:
//!
//! ```ignore
//! a = { b ~ WHITESPACE* ~ (COMMENT ~ WHITESPACE*)* ~ c }
//! ```
//!
//! ## `PUSH`, `POP`, `DROP`, and `PEEK`
//!
//! `PUSH(e)` simply pushes the captured string of the expression `e` down a stack. This stack can
//! then later be used to match grammar based on its content with `POP` and `PEEK`.
//!
//! `PEEK` always matches the string at the top of stack. So, if the stack contains `["b", "a"]`
//! (`"a"` being on top), this grammar:
//!
//! ```ignore
//! a = { PEEK }
//! ```
//!
//! is effectively transformed into at parse time:
//!
//! ```ignore
//! a = { "a" }
//! ```
//!
//! `POP` works the same way with the exception that it pops the string off of the stack if the
//! match worked. With the stack from above, if `POP` matches `"a"`, the stack will be mutated
//! to `["b"]`.
//!
//! `DROP` makes it possible to remove the string at the top of the stack
//! without matching it. If the stack is nonempty, `DROP` drops the top of the
//! stack. If the stack is empty, then `DROP` fails to match.
//!
//! ### Advanced peeking
//!
//! `PEEK[start..end]` and `PEEK_ALL` allow to peek deeper into the stack. The syntax works exactly
//! like Rust’s exclusive slice syntax. Additionally, negative indices can be used to indicate an
//! offset from the top. If the end lies before or at the start, the expression matches (as does
//! a `PEEK_ALL` on an empty stack). With the stack `["c", "b", "a"]` (`"a"` on top):
//!
//! ```ignore
//! fill = PUSH("c") ~ PUSH("b") ~ PUSH("a")
//! v = { PEEK_ALL } = { "a" ~ "b" ~ "c" }  // top to bottom
//! w = { PEEK[..] } = { "c" ~ "b" ~ "a" }  // bottom to top
//! x = { PEEK[1..2] } = { PEEK[1..-1] } = { "b" }
//! y = { PEEK[..-2] } = { PEEK[0..1] } = { "a" }
//! z = { PEEK[1..] } = { PEEK[-2..3] } = { "c" ~ "b" }
//! n = { PEEK[2..-2] } = { PEEK[2..1] } = { "" }
//! ```
//!
//! For historical reasons, `PEEK_ALL` matches from top to bottom, while `PEEK[start..end]` matches
//! from bottom to top. There is currectly no syntax to match a slice of the stack top to bottom.
//!
//! ## `Rule`
//!
//! All rules defined or used in the grammar populate a generated `enum` called `Rule`. This
//! implements `pest`'s `RuleType` and can be used throughout the API.
//!
//! ## `Built-in rules`
//!
//! Pest also comes with a number of built-in rules for convenience. They are:
//!
//! * `ASCII_DIGIT` - matches a numeric character from 0..9
//! * `ASCII_NONZERO_DIGIT` - matches a numeric character from 1..9
//! * `ASCII_BIN_DIGIT` - matches a numeric character from 0..1
//! * `ASCII_OCT_DIGIT` - matches a numeric character from 0..7
//! * `ASCII_HEX_DIGIT` - matches a numeric character from 0..9 or a..f or A..F
//! * `ASCII_ALPHA_LOWER` - matches a character from a..z
//! * `ASCII_ALPHA_UPPER` - matches a character from A..Z
//! * `ASCII_ALPHA` - matches a character from a..z or A..Z
//! * `ASCII_ALPHANUMERIC` - matches a character from a..z or A..Z or 0..9
//! * `ASCII` - matches a character from \x00..\x7f
//! * `NEWLINE` - matches either "\n" or "\r\n" or "\r"

#![doc(html_root_url = "https://docs.rs/pest_derive")]

extern crate pest_generator;
extern crate proc_macro;

use proc_macro::TokenStream;

#[proc_macro_derive(Parser, attributes(grammar))]
pub fn derive_parser(input: TokenStream) -> TokenStream {
    pest_generator::derive_parser(input.into(), true).into()
}
<|endoftext|>