<commit_before>//! [GET /_matrix/client/r0/notifications](https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-notifications)

use std::time::SystemTime;

use js_int::UInt;
use ruma_api::ruma_api;
use ruma_common::{push::Action, Raw};
use ruma_events::AnyEvent;
use ruma_identifiers::RoomId;
use serde::{Deserialize, Serialize};

ruma_api! {
    metadata: {
        description: "Paginate through the list of events that the user has been, or would have been notified about.",
        method: GET,
        name: "get_notifications",
        path: "/_matrix/client/r0/notifications",
        rate_limited: false,
        requires_authentication: true,
    }

    #[derive(Default)]
    request: {
        /// Pagination token given to retrieve the next set of events.
        #[ruma_api(query)]
        #[serde(skip_serializing_if = "Option::is_none")]
        pub from: Option<&'a str>,

        /// Limit on the number of events to return in this request.
        #[ruma_api(query)]
        #[serde(skip_serializing_if = "Option::is_none")]
        pub limit: Option<UInt>,

        /// Allows basic filtering of events returned. Supply "highlight" to return only events
        /// where the notification had the 'highlight' tweak set.
        #[ruma_api(query)]
        #[serde(skip_serializing_if = "Option::is_none")]
        pub only: Option<&'a str>
    }

    response: {
        /// The token to supply in the from param of the next /notifications request in order
        /// to request more events. If this is absent, there are no more results.
        #[serde(skip_serializing_if = "Option::is_none")]
        pub next_token: Option<String>,

        /// The list of events that triggered notifications.
        pub notifications: Vec<Raw<Notification>>,
    }

    error: crate::Error
}

impl<'a> Request<'a> {
    /// Creates an empty `Request`.
    pub fn new() -> Self {
        Default::default()
    }
}

impl Response {
    /// Creates a new `Response` with the given notifications.
    pub fn new(notifications: Vec<Raw<Notification>>) -> Self {
        Self { next_token: None, notifications }
    }
}

/// Represents a notification.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct Notification {
    /// The actions to perform when the conditions for this rule are met.
    pub actions: Vec<Action>,

    /// The event that triggered the notification.
    pub event: Raw<AnyEvent>,

    /// The profile tag of the rule that matched this event.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub profile_tag: Option<String>,

    /// Indicates whether the user has sent a read receipt indicating that they have read this
    /// message.
    pub read: bool,

    /// The ID of the room in which the event was posted.
    pub room_id: RoomId,

    /// The time at which the event notification was sent.
    #[serde(with = "ruma_serde::time::ms_since_unix_epoch")]
    pub ts: SystemTime,
}

impl Notification {
    /// Creates a new `Notification` with the given actions, event, read flag, room ID and
    /// timestamp.
    pub fn new(
        actions: Vec<Action>,
        event: Raw<AnyEvent>,
        read: bool,
        room_id: RoomId,
        ts: SystemTime,
    ) -> Self {
        Self { actions, event, profile_tag: None, read, room_id, ts }
    }
}
<commit_msg>Remove questionable use of Raw<commit_after>//! [GET /_matrix/client/r0/notifications](https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-notifications)

use std::time::SystemTime;

use js_int::UInt;
use ruma_api::ruma_api;
use ruma_common::{push::Action, Raw};
use ruma_events::AnyEvent;
use ruma_identifiers::RoomId;
use serde::{Deserialize, Serialize};

ruma_api! {
    metadata: {
        description: "Paginate through the list of events that the user has been, or would have been notified about.",
        method: GET,
        name: "get_notifications",
        path: "/_matrix/client/r0/notifications",
        rate_limited: false,
        requires_authentication: true,
    }

    #[derive(Default)]
    request: {
        /// Pagination token given to retrieve the next set of events.
        #[ruma_api(query)]
        #[serde(skip_serializing_if = "Option::is_none")]
        pub from: Option<&'a str>,

        /// Limit on the number of events to return in this request.
        #[ruma_api(query)]
        #[serde(skip_serializing_if = "Option::is_none")]
        pub limit: Option<UInt>,

        /// Allows basic filtering of events returned. Supply "highlight" to return only events
        /// where the notification had the 'highlight' tweak set.
        #[ruma_api(query)]
        #[serde(skip_serializing_if = "Option::is_none")]
        pub only: Option<&'a str>
    }

    response: {
        /// The token to supply in the from param of the next /notifications request in order
        /// to request more events. If this is absent, there are no more results.
        #[serde(skip_serializing_if = "Option::is_none")]
        pub next_token: Option<String>,

        /// The list of events that triggered notifications.
        pub notifications: Vec<Notification>,
    }

    error: crate::Error
}

impl<'a> Request<'a> {
    /// Creates an empty `Request`.
    pub fn new() -> Self {
        Default::default()
    }
}

impl Response {
    /// Creates a new `Response` with the given notifications.
    pub fn new(notifications: Vec<Notification>) -> Self {
        Self { next_token: None, notifications }
    }
}

/// Represents a notification.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct Notification {
    /// The actions to perform when the conditions for this rule are met.
    pub actions: Vec<Action>,

    /// The event that triggered the notification.
    pub event: Raw<AnyEvent>,

    /// The profile tag of the rule that matched this event.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub profile_tag: Option<String>,

    /// Indicates whether the user has sent a read receipt indicating that they have read this
    /// message.
    pub read: bool,

    /// The ID of the room in which the event was posted.
    pub room_id: RoomId,

    /// The time at which the event notification was sent.
    #[serde(with = "ruma_serde::time::ms_since_unix_epoch")]
    pub ts: SystemTime,
}

impl Notification {
    /// Creates a new `Notification` with the given actions, event, read flag, room ID and
    /// timestamp.
    pub fn new(
        actions: Vec<Action>,
        event: Raw<AnyEvent>,
        read: bool,
        room_id: RoomId,
        ts: SystemTime,
    ) -> Self {
        Self { actions, event, profile_tag: None, read, room_id, ts }
    }
}
<|endoftext|>


<commit_before>//! Implementation of intrusive doubly linked list

use core::mem;

use core::ptr::Unique;
use core::marker::PhantomData;

use link::Link;

pub trait Node: Sized {
    fn prev(&self) -> &Link<Self>;
    fn next(&self) -> &Link<Self>;

    fn prev_mut(&mut self) -> &mut Link<Self>;
    fn next_mut(&mut self) -> &mut Link<Self>;
}

pub trait Owner<T> where T: Node {
    fn get(&self) -> &T;
    fn get_mut(&mut self) -> &mut T;

    fn take(self);

    unsafe fn from_raw_ptr(ptr: *mut T) -> Self;
}

pub struct List<T, U> where T: Owner<U>, U: Node {
    head: Link<U>,
    tail: Link<U>,
    _phantom1: PhantomData<T>,
}

impl<T, U> List<T, U> where T: Owner<U>, U: Node {
    pub fn new() -> Self {
        List {
            head: Link::none(),
            tail: Link::none(),
            _phantom1: PhantomData,
        }
    }

    pub fn front(&self) -> Option<&U> {
        self.head.as_ref()
    }

    pub fn back(&self) -> Option<&U> {
        self.tail.as_ref()
    }

    pub fn front_mut(&mut self) -> Option<&mut U> {
        self.head.as_mut()
    }

    pub fn back_mut(&mut self) -> Option<&mut U> {
        self.tail.as_mut()
    }

    pub fn is_empty(&self) -> bool {
        self.head == Link::none()
    }

    pub fn push_front(&mut self, mut elem: T) {
        match self.head.as_mut() {
            None => {
                *elem.get_mut().prev_mut() = Link::none();
                *elem.get_mut().next_mut() = Link::none();

                self.tail = Link::some(elem.get_mut());
            }
            Some(h) => {
                *elem.get_mut().prev_mut() = Link::none();
                *elem.get_mut().next_mut() = Link::some(h);

                *h.prev_mut() = Link::some(elem.get_mut());
            },
        }

        self.head = Link::some(elem.get_mut());

        elem.take();
    }

    pub fn push_back(&mut self, mut elem: T) {
        match self.tail.as_mut() {
            None => {
                *elem.get_mut().prev_mut() = Link::none();
                *elem.get_mut().next_mut() = Link::none();

                self.head = Link::some(elem.get_mut());
            }
            Some(t) => {
                *elem.get_mut().prev_mut() = Link::some(t);
                *elem.get_mut().next_mut() = Link::none();

                *t.next_mut() = Link::some(elem.get_mut());
            }
        }

        self.tail = Link::some(elem.get_mut());

        elem.take();
    }

    pub fn pop_front(&mut self) -> Option<T> {
        self.head.take().as_mut().and_then(|h| {
            match h.next_mut().as_mut() {
                None => self.tail = Link::none(),
                Some(n) => {
                    *n.prev_mut() = Link::none();

                    self.head = Link::some(n);
                }
            }

            Some(unsafe { T::from_raw_ptr(h) })
        })
    }

    pub fn pop_back(&mut self) -> Option<T> {
        self.tail.take().as_mut().and_then(|t| {
            match t.prev_mut().as_mut() {
                None => self.head = Link::none(),
                Some(p) => {
                    *p.next_mut() = Link::none();

                    self.tail = Link::some(p);
                }
            }

            Some(unsafe { T::from_raw_ptr(t) })
        })
    }

    pub fn cursor<'a>(&'a mut self) -> Cursor<'a, T, U> {
        Cursor {
            list: self,
            pos: Link::none(),
        }
    }
}

pub struct Cursor<'a, T, U> where T: Owner<U> + 'a, U: Node + 'a {
    list: &'a mut List<T, U>,
    pos: Link<U>,
}

impl<'a, T, U> Cursor<'a, T, U> where T: Owner<U> + 'a, U: Node + 'a {
    pub fn prev(&mut self) -> Option<&mut U> {
        match self.pos.take().as_mut() {
            None => {
                self.pos = self.list.tail.clone();
                None
            }
            Some(p) => {
                self.pos = p.prev().clone();
                Some(unsafe { mem::transmute(p) })
            }
        }
    }

    pub fn next(&mut self) -> Option<&mut U> {
        match self.pos.take().as_mut() {
            None => match self.list.head.as_mut() {
                // Empty list
                None => None,
                // We are at the head of the list
                Some(h) => {
                    self.pos = Link::some(h);
                    self.pos.as_mut()
                }
            },
            Some (p) => match p.next_mut().as_mut() {
                // End of the list
                None => {
                    self.pos = Link::none();
                    None
                }
                Some(n) => {
                    self.pos = Link::some(n);
                    self.pos.as_mut()
                }
            },
        }
    }

    pub fn prev_peek(&mut self) -> Option<&mut U> {
        self.pos.as_mut()
    }

    pub fn next_peek(&mut self) -> Option<&mut U> {
        match self.pos.as_mut() {
            None => self.list.front_mut(),
            Some(p) => p.next_mut().as_mut(),
        }
    }
}

impl<T> Owner<T> for Unique<T> where T: Node {
    #[inline]
    fn get(&self) -> &T {
        unsafe { self.get() }
    }

    #[inline]
    fn get_mut(&mut self) -> &mut T {
        unsafe { self.get_mut() }
    }

    #[inline]
    fn take(self) {}

    unsafe fn from_raw_ptr(ptr: *mut T) -> Self {
        Unique::new(ptr)
    }
}

#[cfg(test)]
impl<T> Owner<T> for ::std::boxed::Box<T> where T: Node {
    #[inline]
    fn get(&self) -> &T {
        &**self
    }

    #[inline]
    fn get_mut(&mut self) -> &mut T {
        &mut **self
    }

    #[inline]
    fn take(self) {
        ::std::boxed::Box::into_raw(self);
    }

    unsafe fn from_raw_ptr(ptr: *mut T) -> Self {
        ::std::boxed::Box::from_raw(ptr)
    }
}

#[cfg(test)]
mod test {
    use core::ptr::Unique;

    use std::boxed::Box;

    use list::{List, Node};
    use link::Link;

    #[derive(Debug)]
    struct UsizeNode {
        pub data: usize,
        prev: Link<UsizeNode>,
        next: Link<UsizeNode>,
    }

    impl UsizeNode {
        pub fn new(data: usize) -> Self {
            UsizeNode {
                data: data,
                prev: Link::none(),
                next: Link::none(),
            }
        }
    }

    impl Node for UsizeNode {
        fn prev(&self) -> &Link<Self> {
            &self.prev
        }

        fn next(&self) -> &Link<Self> {
            &self.next
        }

        fn prev_mut(&mut self) -> &mut Link<Self> {
            &mut self.prev
        }

        fn next_mut(&mut self) -> &mut Link<Self> {
            &mut self.next
        }
    }

    impl PartialEq for UsizeNode {
        fn eq(&self, rhs: &Self) -> bool { self.data == rhs.data }
    }

    #[test]
    fn test_unique() {
        let one = Box::new(UsizeNode::new(1));
        let two = Box::new(UsizeNode::new(2));
        let three = Box::new(UsizeNode::new(3));

        let one_ptr = Box::into_raw(one);
        let two_ptr = Box::into_raw(two);
        let three_ptr = Box::into_raw(three);

        let one_unique = unsafe { Unique::new(one_ptr) };
        let two_unique = unsafe { Unique::new(two_ptr) };
        let three_unique = unsafe { Unique::new(three_ptr) };

        let mut list = List::<Unique<UsizeNode>, UsizeNode>::new();

        list.push_front(three_unique);
        list.push_front(two_unique);
        list.push_front(one_unique);

        unsafe {
            assert_eq!(list.pop_back().unwrap().get_mut().data, 3);
            assert_eq!(list.pop_back().unwrap().get_mut().data, 2);
            assert_eq!(list.pop_back().unwrap().get_mut().data, 1);
            assert!(list.pop_back().is_none());
        }

        // Cleanup
        unsafe {
            Box::from_raw(one_ptr);
            Box::from_raw(two_ptr);
            Box::from_raw(three_ptr);
        }
    }

    #[test]
    fn test_basic() {
        let mut list = List::<Box<UsizeNode>, UsizeNode>::new();

        assert_eq!(list.front(), None);
        assert_eq!(list.back(), None);

        assert!(list.is_empty());

        list.push_front(Box::new(UsizeNode::new(2)));

        assert!(!list.is_empty());
        assert_eq!(list.front(), list.back());

        list.push_front(Box::new(UsizeNode::new(1)));
        list.push_front(Box::new(UsizeNode::new(0)));

        assert_eq!(list.front().unwrap().data, 0);
        assert_eq!(list.back().unwrap().data, 2);

        list.push_back(Box::new(UsizeNode::new(3)));
        assert_eq!(list.back().unwrap().data, 3);

        list.push_back(Box::new(UsizeNode::new(4)));
        assert_eq!(list.back().unwrap().data, 4);

        assert!(!list.is_empty());

        assert_eq!(list.pop_front().unwrap().data, 0);
        assert_eq!(list.pop_front().unwrap().data, 1);
        assert_eq!(list.pop_front().unwrap().data, 2);
        assert_eq!(list.pop_back().unwrap().data, 4);
        assert_eq!(list.pop_back().unwrap().data, 3);
        assert_eq!(list.pop_back(), None);

        assert!(list.is_empty());

        list.push_back(Box::new(UsizeNode::new(5)));
        assert_eq!(list.pop_front().unwrap().data, 5);
        assert_eq!(list.pop_front(), None);

        assert!(list.is_empty());

        list.push_back(Box::new(UsizeNode::new(6)));
        list.push_back(Box::new(UsizeNode::new(7)));

        assert!(!list.is_empty());

        list.front_mut().unwrap().data = 6;
        list.back_mut().unwrap().data = 7;

        assert_eq!(list.front().unwrap().data, 6);
        assert_eq!(list.back().unwrap().data, 7);

        assert_eq!(list.pop_back().unwrap().data, 7);

        assert!(!list.is_empty());

        assert_eq!(list.pop_front().unwrap().data, 6);
        assert!(list.pop_front().is_none());
        assert!(list.pop_back().is_none());

        assert!(list.is_empty());
    }

    #[test]
    fn test_basic_cursor() {
        let mut list = List::<Box<UsizeNode>, UsizeNode>::new();

        {
            let mut cursor = list.cursor();

            assert!(cursor.next().is_none());
            assert!(cursor.prev().is_none());
            assert!(cursor.prev().is_none());
            assert!(cursor.next().is_none());
        }

        list.push_back(Box::new(UsizeNode::new(0)));
        list.push_back(Box::new(UsizeNode::new(1)));
        list.push_back(Box::new(UsizeNode::new(2)));
        list.push_back(Box::new(UsizeNode::new(3)));

        assert_eq!(list.front().unwrap().data, 0);
        assert_eq!(list.back().unwrap().data, 3);

        let mut cursor = list.cursor();

        assert!(cursor.prev_peek().is_none());
        assert_eq!(cursor.next_peek().unwrap().data, 0);

        assert_eq!(cursor.next().unwrap().data, 0);
        assert_eq!(cursor.next().unwrap().data, 1);
        assert_eq!(cursor.next().unwrap().data, 2);
        assert_eq!(cursor.next().unwrap().data, 3);
        assert!(cursor.next().is_none());
        assert_eq!(cursor.next().unwrap().data, 0);

        assert_eq!(cursor.prev().unwrap().data, 0);
        assert!(cursor.prev().is_none());
        assert_eq!(cursor.prev().unwrap().data, 3);
        assert_eq!(cursor.prev().unwrap().data, 2);
        assert_eq!(cursor.prev().unwrap().data, 1);
        assert_eq!(cursor.prev().unwrap().data, 0);
        assert!(cursor.prev().is_none());
    }
}
<commit_msg>libintrusive: Add Cursor::remove() + test<commit_after>//! Implementation of intrusive doubly linked list

use core::mem;

use core::ptr::Unique;
use core::marker::PhantomData;

use link::Link;

pub trait Node: Sized {
    fn prev(&self) -> &Link<Self>;
    fn next(&self) -> &Link<Self>;

    fn prev_mut(&mut self) -> &mut Link<Self>;
    fn next_mut(&mut self) -> &mut Link<Self>;
}

pub trait Owner<T> where T: Node {
    fn get(&self) -> &T;
    fn get_mut(&mut self) -> &mut T;

    fn take(self);

    unsafe fn from_raw_ptr(ptr: *mut T) -> Self;
}

pub struct List<T, U> where T: Owner<U>, U: Node {
    head: Link<U>,
    tail: Link<U>,
    _phantom1: PhantomData<T>,
}

impl<T, U> List<T, U> where T: Owner<U>, U: Node {
    pub fn new() -> Self {
        List {
            head: Link::none(),
            tail: Link::none(),
            _phantom1: PhantomData,
        }
    }

    pub fn front(&self) -> Option<&U> {
        self.head.as_ref()
    }

    pub fn back(&self) -> Option<&U> {
        self.tail.as_ref()
    }

    pub fn front_mut(&mut self) -> Option<&mut U> {
        self.head.as_mut()
    }

    pub fn back_mut(&mut self) -> Option<&mut U> {
        self.tail.as_mut()
    }

    pub fn is_empty(&self) -> bool {
        self.head == Link::none()
    }

    pub fn push_front(&mut self, mut elem: T) {
        match self.head.as_mut() {
            None => {
                *elem.get_mut().prev_mut() = Link::none();
                *elem.get_mut().next_mut() = Link::none();

                self.tail = Link::some(elem.get_mut());
            }
            Some(h) => {
                *elem.get_mut().prev_mut() = Link::none();
                *elem.get_mut().next_mut() = Link::some(h);

                *h.prev_mut() = Link::some(elem.get_mut());
            },
        }

        self.head = Link::some(elem.get_mut());

        elem.take();
    }

    pub fn push_back(&mut self, mut elem: T) {
        match self.tail.as_mut() {
            None => {
                *elem.get_mut().prev_mut() = Link::none();
                *elem.get_mut().next_mut() = Link::none();

                self.head = Link::some(elem.get_mut());
            }
            Some(t) => {
                *elem.get_mut().prev_mut() = Link::some(t);
                *elem.get_mut().next_mut() = Link::none();

                *t.next_mut() = Link::some(elem.get_mut());
            }
        }

        self.tail = Link::some(elem.get_mut());

        elem.take();
    }

    pub fn pop_front(&mut self) -> Option<T> {
        self.head.take().as_mut().and_then(|h| {
            match h.next_mut().as_mut() {
                None => self.tail = Link::none(),
                Some(n) => {
                    *n.prev_mut() = Link::none();

                    self.head = Link::some(n);
                }
            }

            Some(unsafe { T::from_raw_ptr(h) })
        })
    }

    pub fn pop_back(&mut self) -> Option<T> {
        self.tail.take().as_mut().and_then(|t| {
            match t.prev_mut().as_mut() {
                None => self.head = Link::none(),
                Some(p) => {
                    *p.next_mut() = Link::none();

                    self.tail = Link::some(p);
                }
            }

            Some(unsafe { T::from_raw_ptr(t) })
        })
    }

    pub fn cursor<'a>(&'a mut self) -> Cursor<'a, T, U> {
        Cursor {
            list: self,
            pos: Link::none(),
        }
    }
}

pub struct Cursor<'a, T, U> where T: Owner<U> + 'a, U: Node + 'a {
    list: &'a mut List<T, U>,
    pos: Link<U>,
}

impl<'a, T, U> Cursor<'a, T, U> where T: Owner<U> + 'a, U: Node + 'a {
    pub fn prev(&mut self) -> Option<&mut U> {
        match self.pos.take().as_mut() {
            None => {
                self.pos = self.list.tail.clone();
                None
            }
            Some(p) => {
                self.pos = p.prev().clone();
                Some(unsafe { mem::transmute(p) })
            }
        }
    }

    pub fn next(&mut self) -> Option<&mut U> {
        match self.pos.take().as_mut() {
            None => match self.list.head.as_mut() {
                // Empty list
                None => None,
                // We are at the head of the list
                Some(h) => {
                    self.pos = Link::some(h);
                    self.pos.as_mut()
                }
            },
            Some (p) => match p.next_mut().as_mut() {
                // End of the list
                None => {
                    self.pos = Link::none();
                    None
                }
                Some(n) => {
                    self.pos = Link::some(n);
                    self.pos.as_mut()
                }
            },
        }
    }

    pub fn prev_peek(&mut self) -> Option<&mut U> {
        self.pos.as_mut()
    }

    pub fn next_peek(&mut self) -> Option<&mut U> {
        match self.pos.as_mut() {
            None => self.list.front_mut(),
            Some(p) => p.next_mut().as_mut(),
        }
    }

    pub fn remove(&mut self) -> Option<T> {
        match self.pos.as_mut() {
            // Start of the list or empty
            None => self.list.pop_front(),
            Some(p) => match p.next_mut().take().as_mut() {
                // End of the list
                None => None,
                Some(n) => {
                    match n.next_mut().as_mut() {
                        None => self.list.tail = Link::some(p),
                        Some(next) => {
                            *next.prev_mut() = Link::some(p);
                            *p.next_mut() = Link::some(next);
                        }
                    }

                    Some(unsafe { T::from_raw_ptr(n) })
                }
            }
        }
    }
}

impl<T> Owner<T> for Unique<T> where T: Node {
    #[inline]
    fn get(&self) -> &T {
        unsafe { self.get() }
    }

    #[inline]
    fn get_mut(&mut self) -> &mut T {
        unsafe { self.get_mut() }
    }

    #[inline]
    fn take(self) {}

    unsafe fn from_raw_ptr(ptr: *mut T) -> Self {
        Unique::new(ptr)
    }
}

#[cfg(test)]
impl<T> Owner<T> for ::std::boxed::Box<T> where T: Node {
    #[inline]
    fn get(&self) -> &T {
        &**self
    }

    #[inline]
    fn get_mut(&mut self) -> &mut T {
        &mut **self
    }

    #[inline]
    fn take(self) {
        ::std::boxed::Box::into_raw(self);
    }

    unsafe fn from_raw_ptr(ptr: *mut T) -> Self {
        ::std::boxed::Box::from_raw(ptr)
    }
}

#[cfg(test)]
mod test {
    use core::ptr::Unique;

    use std::boxed::Box;

    use list::{List, Node};
    use link::Link;

    #[derive(Debug)]
    struct UsizeNode {
        pub data: usize,
        prev: Link<UsizeNode>,
        next: Link<UsizeNode>,
    }

    impl UsizeNode {
        pub fn new(data: usize) -> Self {
            UsizeNode {
                data: data,
                prev: Link::none(),
                next: Link::none(),
            }
        }
    }

    impl Node for UsizeNode {
        fn prev(&self) -> &Link<Self> {
            &self.prev
        }

        fn next(&self) -> &Link<Self> {
            &self.next
        }

        fn prev_mut(&mut self) -> &mut Link<Self> {
            &mut self.prev
        }

        fn next_mut(&mut self) -> &mut Link<Self> {
            &mut self.next
        }
    }

    impl PartialEq for UsizeNode {
        fn eq(&self, rhs: &Self) -> bool { self.data == rhs.data }
    }

    #[test]
    fn test_unique() {
        let one = Box::new(UsizeNode::new(1));
        let two = Box::new(UsizeNode::new(2));
        let three = Box::new(UsizeNode::new(3));

        let one_ptr = Box::into_raw(one);
        let two_ptr = Box::into_raw(two);
        let three_ptr = Box::into_raw(three);

        let one_unique = unsafe { Unique::new(one_ptr) };
        let two_unique = unsafe { Unique::new(two_ptr) };
        let three_unique = unsafe { Unique::new(three_ptr) };

        let mut list = List::<Unique<UsizeNode>, UsizeNode>::new();

        list.push_front(three_unique);
        list.push_front(two_unique);
        list.push_front(one_unique);

        unsafe {
            assert_eq!(list.pop_back().unwrap().get_mut().data, 3);
            assert_eq!(list.pop_back().unwrap().get_mut().data, 2);
            assert_eq!(list.pop_back().unwrap().get_mut().data, 1);
            assert!(list.pop_back().is_none());
        }

        // Cleanup
        unsafe {
            Box::from_raw(one_ptr);
            Box::from_raw(two_ptr);
            Box::from_raw(three_ptr);
        }
    }

    #[test]
    fn test_basic() {
        let mut list = List::<Box<UsizeNode>, UsizeNode>::new();

        assert_eq!(list.front(), None);
        assert_eq!(list.back(), None);

        assert!(list.is_empty());

        list.push_front(Box::new(UsizeNode::new(2)));

        assert!(!list.is_empty());
        assert_eq!(list.front(), list.back());

        list.push_front(Box::new(UsizeNode::new(1)));
        list.push_front(Box::new(UsizeNode::new(0)));

        assert_eq!(list.front().unwrap().data, 0);
        assert_eq!(list.back().unwrap().data, 2);

        list.push_back(Box::new(UsizeNode::new(3)));
        assert_eq!(list.back().unwrap().data, 3);

        list.push_back(Box::new(UsizeNode::new(4)));
        assert_eq!(list.back().unwrap().data, 4);

        assert!(!list.is_empty());

        assert_eq!(list.pop_front().unwrap().data, 0);
        assert_eq!(list.pop_front().unwrap().data, 1);
        assert_eq!(list.pop_front().unwrap().data, 2);
        assert_eq!(list.pop_back().unwrap().data, 4);
        assert_eq!(list.pop_back().unwrap().data, 3);
        assert_eq!(list.pop_back(), None);

        assert!(list.is_empty());

        list.push_back(Box::new(UsizeNode::new(5)));
        assert_eq!(list.pop_front().unwrap().data, 5);
        assert_eq!(list.pop_front(), None);

        assert!(list.is_empty());

        list.push_back(Box::new(UsizeNode::new(6)));
        list.push_back(Box::new(UsizeNode::new(7)));

        assert!(!list.is_empty());

        list.front_mut().unwrap().data = 6;
        list.back_mut().unwrap().data = 7;

        assert_eq!(list.front().unwrap().data, 6);
        assert_eq!(list.back().unwrap().data, 7);

        assert_eq!(list.pop_back().unwrap().data, 7);

        assert!(!list.is_empty());

        assert_eq!(list.pop_front().unwrap().data, 6);
        assert!(list.pop_front().is_none());
        assert!(list.pop_back().is_none());

        assert!(list.is_empty());
    }

    #[test]
    fn test_basic_cursor() {
        let mut list = List::<Box<UsizeNode>, UsizeNode>::new();

        {
            let mut cursor = list.cursor();

            assert!(cursor.next().is_none());
            assert!(cursor.prev().is_none());
            assert!(cursor.prev().is_none());
            assert!(cursor.next().is_none());
        }

        list.push_back(Box::new(UsizeNode::new(0)));
        list.push_back(Box::new(UsizeNode::new(1)));
        list.push_back(Box::new(UsizeNode::new(2)));
        list.push_back(Box::new(UsizeNode::new(3)));

        assert_eq!(list.front().unwrap().data, 0);
        assert_eq!(list.back().unwrap().data, 3);

        let mut cursor = list.cursor();

        assert!(cursor.prev_peek().is_none());
        assert_eq!(cursor.next_peek().unwrap().data, 0);

        assert_eq!(cursor.next().unwrap().data, 0);
        assert_eq!(cursor.next().unwrap().data, 1);
        assert_eq!(cursor.next().unwrap().data, 2);
        assert_eq!(cursor.next().unwrap().data, 3);
        assert!(cursor.next().is_none());
        assert_eq!(cursor.next().unwrap().data, 0);

        assert_eq!(cursor.prev().unwrap().data, 0);
        assert!(cursor.prev().is_none());
        assert_eq!(cursor.prev().unwrap().data, 3);
        assert_eq!(cursor.prev().unwrap().data, 2);
        assert_eq!(cursor.prev().unwrap().data, 1);
        assert_eq!(cursor.prev().unwrap().data, 0);
        assert!(cursor.prev().is_none());
    }

    #[test]
    fn test_cursor_remove() {
        let mut list = List::<Box<UsizeNode>, UsizeNode>::new();

        list.push_back(Box::new(UsizeNode::new(0)));
        list.push_back(Box::new(UsizeNode::new(1)));
        list.push_back(Box::new(UsizeNode::new(2)));
        list.push_back(Box::new(UsizeNode::new(3)));

        {
            let mut cursor = list.cursor();

            assert_eq!(cursor.remove().unwrap().data, 0);
            assert_eq!(cursor.next().unwrap().data, 1);
            assert_eq!(cursor.remove().unwrap().data, 2);
            assert_eq!(cursor.remove().unwrap().data, 3);
            assert!(cursor.remove().is_none());
        }

        assert_eq!(list.front().unwrap().data, list.back().unwrap().data);
        assert_eq!(list.cursor().remove().unwrap().data, 1);
        assert!(list.is_empty());
    }
}
<|endoftext|>


<commit_before>//! This file contains code for parsing SSR rules, which look something like `foo($a) ==>> bar($b)`.
//! We first split everything before and after the separator `==>>`. Next, both the search pattern
//! and the replacement template get tokenized by the Rust tokenizer. Tokens are then searched for
//! placeholders, which start with `$`. For replacement templates, this is the final form. For
//! search patterns, we go further and parse the pattern as each kind of thing that we can match.
//! e.g. expressions, type references etc.

use crate::{SsrError, SsrPattern, SsrRule};
use ra_syntax::{ast, AstNode, SmolStr, SyntaxKind};
use rustc_hash::{FxHashMap, FxHashSet};
use std::str::FromStr;

/// Returns from the current function with an error, supplied by arguments as for format!
macro_rules! bail {
    ($e:expr) => {return Err($crate::SsrError::new($e))};
    ($fmt:expr, $($arg:tt)+) => {return Err($crate::SsrError::new(format!($fmt, $($arg)+)))}
}

#[derive(Clone, Debug)]
pub(crate) struct SsrTemplate {
    pub(crate) tokens: Vec<PatternElement>,
}

#[derive(Debug)]
pub(crate) struct RawSearchPattern {
    tokens: Vec<PatternElement>,
}

// Part of a search or replace pattern.
#[derive(Clone, Debug, PartialEq, Eq)]
pub(crate) enum PatternElement {
    Token(Token),
    Placeholder(Placeholder),
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub(crate) struct Placeholder {
    /// The name of this placeholder. e.g. for "$a", this would be "a"
    pub(crate) ident: SmolStr,
    /// A unique name used in place of this placeholder when we parse the pattern as Rust code.
    stand_in_name: String,
    pub(crate) constraints: Vec<Constraint>,
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub(crate) enum Constraint {
    Kind(NodeKind),
    Not(Box<Constraint>),
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub(crate) enum NodeKind {
    Literal,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct Token {
    kind: SyntaxKind,
    pub(crate) text: SmolStr,
}

impl FromStr for SsrRule {
    type Err = SsrError;

    fn from_str(query: &str) -> Result<SsrRule, SsrError> {
        let mut it = query.split("==>>");
        let pattern = it.next().expect("at least empty string").trim();
        let template = it
            .next()
            .ok_or_else(|| SsrError("Cannot find delimiter `==>>`".into()))?
            .trim()
            .to_string();
        if it.next().is_some() {
            return Err(SsrError("More than one delimiter found".into()));
        }
        let rule = SsrRule { pattern: pattern.parse()?, template: template.parse()? };
        validate_rule(&rule)?;
        Ok(rule)
    }
}

impl FromStr for RawSearchPattern {
    type Err = SsrError;

    fn from_str(pattern_str: &str) -> Result<RawSearchPattern, SsrError> {
        Ok(RawSearchPattern { tokens: parse_pattern(pattern_str)? })
    }
}

impl RawSearchPattern {
    /// Returns this search pattern as Rust source code that we can feed to the Rust parser.
    fn as_rust_code(&self) -> String {
        let mut res = String::new();
        for t in &self.tokens {
            res.push_str(match t {
                PatternElement::Token(token) => token.text.as_str(),
                PatternElement::Placeholder(placeholder) => placeholder.stand_in_name.as_str(),
            });
        }
        res
    }

    fn placeholders_by_stand_in(&self) -> FxHashMap<SmolStr, Placeholder> {
        let mut res = FxHashMap::default();
        for t in &self.tokens {
            if let PatternElement::Placeholder(placeholder) = t {
                res.insert(SmolStr::new(placeholder.stand_in_name.clone()), placeholder.clone());
            }
        }
        res
    }
}

impl FromStr for SsrPattern {
    type Err = SsrError;

    fn from_str(pattern_str: &str) -> Result<SsrPattern, SsrError> {
        let raw: RawSearchPattern = pattern_str.parse()?;
        let raw_str = raw.as_rust_code();
        let res = SsrPattern {
            expr: ast::Expr::parse(&raw_str).ok().map(|n| n.syntax().clone()),
            type_ref: ast::TypeRef::parse(&raw_str).ok().map(|n| n.syntax().clone()),
            item: ast::ModuleItem::parse(&raw_str).ok().map(|n| n.syntax().clone()),
            path: ast::Path::parse(&raw_str).ok().map(|n| n.syntax().clone()),
            pattern: ast::Pat::parse(&raw_str).ok().map(|n| n.syntax().clone()),
            placeholders_by_stand_in: raw.placeholders_by_stand_in(),
            raw,
        };
        if res.expr.is_none()
            && res.type_ref.is_none()
            && res.item.is_none()
            && res.path.is_none()
            && res.pattern.is_none()
        {
            bail!("Pattern is not a valid Rust expression, type, item, path or pattern");
        }
        Ok(res)
    }
}

impl FromStr for SsrTemplate {
    type Err = SsrError;

    fn from_str(pattern_str: &str) -> Result<SsrTemplate, SsrError> {
        let tokens = parse_pattern(pattern_str)?;
        // Validate that the template is a valid fragment of Rust code. We reuse the validation
        // logic for search patterns since the only thing that differs is the error message.
        if SsrPattern::from_str(pattern_str).is_err() {
            bail!("Replacement is not a valid Rust expression, type, item, path or pattern");
        }
        // Our actual template needs to preserve whitespace, so we can't reuse `tokens`.
        Ok(SsrTemplate { tokens })
    }
}

/// Returns `pattern_str`, parsed as a search or replace pattern. If `remove_whitespace` is true,
/// then any whitespace tokens will be removed, which we do for the search pattern, but not for the
/// replace pattern.
fn parse_pattern(pattern_str: &str) -> Result<Vec<PatternElement>, SsrError> {
    let mut res = Vec::new();
    let mut placeholder_names = FxHashSet::default();
    let mut tokens = tokenize(pattern_str)?.into_iter();
    while let Some(token) = tokens.next() {
        if token.kind == SyntaxKind::DOLLAR {
            let placeholder = parse_placeholder(&mut tokens)?;
            if !placeholder_names.insert(placeholder.ident.clone()) {
                bail!("Name `{}` repeats more than once", placeholder.ident);
            }
            res.push(PatternElement::Placeholder(placeholder));
        } else {
            res.push(PatternElement::Token(token));
        }
    }
    Ok(res)
}

/// Checks for errors in a rule. e.g. the replace pattern referencing placeholders that the search
/// pattern didn't define.
fn validate_rule(rule: &SsrRule) -> Result<(), SsrError> {
    let mut defined_placeholders = FxHashSet::default();
    for p in &rule.pattern.raw.tokens {
        if let PatternElement::Placeholder(placeholder) = p {
            defined_placeholders.insert(&placeholder.ident);
        }
    }
    let mut undefined = Vec::new();
    for p in &rule.template.tokens {
        if let PatternElement::Placeholder(placeholder) = p {
            if !defined_placeholders.contains(&placeholder.ident) {
                undefined.push(format!("${}", placeholder.ident));
            }
            if !placeholder.constraints.is_empty() {
                bail!("Replacement placeholders cannot have constraints");
            }
        }
    }
    if !undefined.is_empty() {
        bail!("Replacement contains undefined placeholders: {}", undefined.join(", "));
    }
    Ok(())
}

fn tokenize(source: &str) -> Result<Vec<Token>, SsrError> {
    let mut start = 0;
    let (raw_tokens, errors) = ra_syntax::tokenize(source);
    if let Some(first_error) = errors.first() {
        bail!("Failed to parse pattern: {}", first_error);
    }
    let mut tokens: Vec<Token> = Vec::new();
    for raw_token in raw_tokens {
        let token_len = usize::from(raw_token.len);
        tokens.push(Token {
            kind: raw_token.kind,
            text: SmolStr::new(&source[start..start + token_len]),
        });
        start += token_len;
    }
    Ok(tokens)
}

fn parse_placeholder(tokens: &mut std::vec::IntoIter<Token>) -> Result<Placeholder, SsrError> {
    let mut name = None;
    let mut constraints = Vec::new();
    if let Some(token) = tokens.next() {
        match token.kind {
            SyntaxKind::IDENT => {
                name = Some(token.text);
            }
            SyntaxKind::L_CURLY => {
                let token =
                    tokens.next().ok_or_else(|| SsrError::new("Unexpected end of placeholder"))?;
                if token.kind == SyntaxKind::IDENT {
                    name = Some(token.text);
                }
                loop {
                    let token = tokens
                        .next()
                        .ok_or_else(|| SsrError::new("Placeholder is missing closing brace '}'"))?;
                    match token.kind {
                        SyntaxKind::COLON => {
                            constraints.push(parse_constraint(tokens)?);
                        }
                        SyntaxKind::R_CURLY => break,
                        _ => bail!("Unexpected token while parsing placeholder: '{}'", token.text),
                    }
                }
            }
            _ => {
                bail!("Placeholders should either be $name or ${name:constraints}");
            }
        }
    }
    let name = name.ok_or_else(|| SsrError::new("Placeholder ($) with no name"))?;
    Ok(Placeholder::new(name, constraints))
}

fn parse_constraint(tokens: &mut std::vec::IntoIter<Token>) -> Result<Constraint, SsrError> {
    let constraint_type = tokens
        .next()
        .ok_or_else(|| SsrError::new("Found end of placeholder while looking for a constraint"))?
        .text
        .to_string();
    match constraint_type.as_str() {
        "kind" => {
            expect_token(tokens, "(")?;
            let t = tokens.next().ok_or_else(|| {
                SsrError::new("Unexpected end of constraint while looking for kind")
            })?;
            if t.kind != SyntaxKind::IDENT {
                bail!("Expected ident, found {:?} while parsing kind constraint", t.kind);
            }
            expect_token(tokens, ")")?;
            Ok(Constraint::Kind(NodeKind::from(&t.text)?))
        }
        "not" => {
            expect_token(tokens, "(")?;
            let sub = parse_constraint(tokens)?;
            expect_token(tokens, ")")?;
            Ok(Constraint::Not(Box::new(sub)))
        }
        x => bail!("Unsupported constraint type '{}'", x),
    }
}

fn expect_token(tokens: &mut std::vec::IntoIter<Token>, expected: &str) -> Result<(), SsrError> {
    if let Some(t) = tokens.next() {
        if t.text == expected {
            return Ok(());
        }
        bail!("Expected {} found {}", expected, t.text);
    }
    bail!("Expected {} found end of stream");
}

impl NodeKind {
    fn from(name: &SmolStr) -> Result<NodeKind, SsrError> {
        Ok(match name.as_str() {
            "literal" => NodeKind::Literal,
            _ => bail!("Unknown node kind '{}'", name),
        })
    }
}

impl Placeholder {
    fn new(name: SmolStr, constraints: Vec<Constraint>) -> Self {
        Self { stand_in_name: format!("__placeholder_{}", name), constraints, ident: name }
    }
}

impl SsrError {
    fn new(message: impl Into<String>) -> SsrError {
        SsrError(message.into())
    }
}

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

    #[test]
    fn parser_happy_case() {
        fn token(kind: SyntaxKind, text: &str) -> PatternElement {
            PatternElement::Token(Token { kind, text: SmolStr::new(text) })
        }
        fn placeholder(name: &str) -> PatternElement {
            PatternElement::Placeholder(Placeholder::new(SmolStr::new(name), Vec::new()))
        }
        let result: SsrRule = "foo($a, $b) ==>> bar($b, $a)".parse().unwrap();
        assert_eq!(
            result.pattern.raw.tokens,
            vec![
                token(SyntaxKind::IDENT, "foo"),
                token(SyntaxKind::L_PAREN, "("),
                placeholder("a"),
                token(SyntaxKind::COMMA, ","),
                token(SyntaxKind::WHITESPACE, " "),
                placeholder("b"),
                token(SyntaxKind::R_PAREN, ")"),
            ]
        );
        assert_eq!(
            result.template.tokens,
            vec![
                token(SyntaxKind::IDENT, "bar"),
                token(SyntaxKind::L_PAREN, "("),
                placeholder("b"),
                token(SyntaxKind::COMMA, ","),
                token(SyntaxKind::WHITESPACE, " "),
                placeholder("a"),
                token(SyntaxKind::R_PAREN, ")"),
            ]
        );
    }
}
<commit_msg>SSR: Use T! instead of SyntaxKind::* where possible<commit_after>//! This file contains code for parsing SSR rules, which look something like `foo($a) ==>> bar($b)`.
//! We first split everything before and after the separator `==>>`. Next, both the search pattern
//! and the replacement template get tokenized by the Rust tokenizer. Tokens are then searched for
//! placeholders, which start with `$`. For replacement templates, this is the final form. For
//! search patterns, we go further and parse the pattern as each kind of thing that we can match.
//! e.g. expressions, type references etc.

use crate::{SsrError, SsrPattern, SsrRule};
use ra_syntax::{ast, AstNode, SmolStr, SyntaxKind, T};
use rustc_hash::{FxHashMap, FxHashSet};
use std::str::FromStr;

/// Returns from the current function with an error, supplied by arguments as for format!
macro_rules! bail {
    ($e:expr) => {return Err($crate::SsrError::new($e))};
    ($fmt:expr, $($arg:tt)+) => {return Err($crate::SsrError::new(format!($fmt, $($arg)+)))}
}

#[derive(Clone, Debug)]
pub(crate) struct SsrTemplate {
    pub(crate) tokens: Vec<PatternElement>,
}

#[derive(Debug)]
pub(crate) struct RawSearchPattern {
    tokens: Vec<PatternElement>,
}

// Part of a search or replace pattern.
#[derive(Clone, Debug, PartialEq, Eq)]
pub(crate) enum PatternElement {
    Token(Token),
    Placeholder(Placeholder),
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub(crate) struct Placeholder {
    /// The name of this placeholder. e.g. for "$a", this would be "a"
    pub(crate) ident: SmolStr,
    /// A unique name used in place of this placeholder when we parse the pattern as Rust code.
    stand_in_name: String,
    pub(crate) constraints: Vec<Constraint>,
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub(crate) enum Constraint {
    Kind(NodeKind),
    Not(Box<Constraint>),
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub(crate) enum NodeKind {
    Literal,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct Token {
    kind: SyntaxKind,
    pub(crate) text: SmolStr,
}

impl FromStr for SsrRule {
    type Err = SsrError;

    fn from_str(query: &str) -> Result<SsrRule, SsrError> {
        let mut it = query.split("==>>");
        let pattern = it.next().expect("at least empty string").trim();
        let template = it
            .next()
            .ok_or_else(|| SsrError("Cannot find delimiter `==>>`".into()))?
            .trim()
            .to_string();
        if it.next().is_some() {
            return Err(SsrError("More than one delimiter found".into()));
        }
        let rule = SsrRule { pattern: pattern.parse()?, template: template.parse()? };
        validate_rule(&rule)?;
        Ok(rule)
    }
}

impl FromStr for RawSearchPattern {
    type Err = SsrError;

    fn from_str(pattern_str: &str) -> Result<RawSearchPattern, SsrError> {
        Ok(RawSearchPattern { tokens: parse_pattern(pattern_str)? })
    }
}

impl RawSearchPattern {
    /// Returns this search pattern as Rust source code that we can feed to the Rust parser.
    fn as_rust_code(&self) -> String {
        let mut res = String::new();
        for t in &self.tokens {
            res.push_str(match t {
                PatternElement::Token(token) => token.text.as_str(),
                PatternElement::Placeholder(placeholder) => placeholder.stand_in_name.as_str(),
            });
        }
        res
    }

    fn placeholders_by_stand_in(&self) -> FxHashMap<SmolStr, Placeholder> {
        let mut res = FxHashMap::default();
        for t in &self.tokens {
            if let PatternElement::Placeholder(placeholder) = t {
                res.insert(SmolStr::new(placeholder.stand_in_name.clone()), placeholder.clone());
            }
        }
        res
    }
}

impl FromStr for SsrPattern {
    type Err = SsrError;

    fn from_str(pattern_str: &str) -> Result<SsrPattern, SsrError> {
        let raw: RawSearchPattern = pattern_str.parse()?;
        let raw_str = raw.as_rust_code();
        let res = SsrPattern {
            expr: ast::Expr::parse(&raw_str).ok().map(|n| n.syntax().clone()),
            type_ref: ast::TypeRef::parse(&raw_str).ok().map(|n| n.syntax().clone()),
            item: ast::ModuleItem::parse(&raw_str).ok().map(|n| n.syntax().clone()),
            path: ast::Path::parse(&raw_str).ok().map(|n| n.syntax().clone()),
            pattern: ast::Pat::parse(&raw_str).ok().map(|n| n.syntax().clone()),
            placeholders_by_stand_in: raw.placeholders_by_stand_in(),
            raw,
        };
        if res.expr.is_none()
            && res.type_ref.is_none()
            && res.item.is_none()
            && res.path.is_none()
            && res.pattern.is_none()
        {
            bail!("Pattern is not a valid Rust expression, type, item, path or pattern");
        }
        Ok(res)
    }
}

impl FromStr for SsrTemplate {
    type Err = SsrError;

    fn from_str(pattern_str: &str) -> Result<SsrTemplate, SsrError> {
        let tokens = parse_pattern(pattern_str)?;
        // Validate that the template is a valid fragment of Rust code. We reuse the validation
        // logic for search patterns since the only thing that differs is the error message.
        if SsrPattern::from_str(pattern_str).is_err() {
            bail!("Replacement is not a valid Rust expression, type, item, path or pattern");
        }
        // Our actual template needs to preserve whitespace, so we can't reuse `tokens`.
        Ok(SsrTemplate { tokens })
    }
}

/// Returns `pattern_str`, parsed as a search or replace pattern. If `remove_whitespace` is true,
/// then any whitespace tokens will be removed, which we do for the search pattern, but not for the
/// replace pattern.
fn parse_pattern(pattern_str: &str) -> Result<Vec<PatternElement>, SsrError> {
    let mut res = Vec::new();
    let mut placeholder_names = FxHashSet::default();
    let mut tokens = tokenize(pattern_str)?.into_iter();
    while let Some(token) = tokens.next() {
        if token.kind == T![$] {
            let placeholder = parse_placeholder(&mut tokens)?;
            if !placeholder_names.insert(placeholder.ident.clone()) {
                bail!("Name `{}` repeats more than once", placeholder.ident);
            }
            res.push(PatternElement::Placeholder(placeholder));
        } else {
            res.push(PatternElement::Token(token));
        }
    }
    Ok(res)
}

/// Checks for errors in a rule. e.g. the replace pattern referencing placeholders that the search
/// pattern didn't define.
fn validate_rule(rule: &SsrRule) -> Result<(), SsrError> {
    let mut defined_placeholders = FxHashSet::default();
    for p in &rule.pattern.raw.tokens {
        if let PatternElement::Placeholder(placeholder) = p {
            defined_placeholders.insert(&placeholder.ident);
        }
    }
    let mut undefined = Vec::new();
    for p in &rule.template.tokens {
        if let PatternElement::Placeholder(placeholder) = p {
            if !defined_placeholders.contains(&placeholder.ident) {
                undefined.push(format!("${}", placeholder.ident));
            }
            if !placeholder.constraints.is_empty() {
                bail!("Replacement placeholders cannot have constraints");
            }
        }
    }
    if !undefined.is_empty() {
        bail!("Replacement contains undefined placeholders: {}", undefined.join(", "));
    }
    Ok(())
}

fn tokenize(source: &str) -> Result<Vec<Token>, SsrError> {
    let mut start = 0;
    let (raw_tokens, errors) = ra_syntax::tokenize(source);
    if let Some(first_error) = errors.first() {
        bail!("Failed to parse pattern: {}", first_error);
    }
    let mut tokens: Vec<Token> = Vec::new();
    for raw_token in raw_tokens {
        let token_len = usize::from(raw_token.len);
        tokens.push(Token {
            kind: raw_token.kind,
            text: SmolStr::new(&source[start..start + token_len]),
        });
        start += token_len;
    }
    Ok(tokens)
}

fn parse_placeholder(tokens: &mut std::vec::IntoIter<Token>) -> Result<Placeholder, SsrError> {
    let mut name = None;
    let mut constraints = Vec::new();
    if let Some(token) = tokens.next() {
        match token.kind {
            SyntaxKind::IDENT => {
                name = Some(token.text);
            }
            T!['{'] => {
                let token =
                    tokens.next().ok_or_else(|| SsrError::new("Unexpected end of placeholder"))?;
                if token.kind == SyntaxKind::IDENT {
                    name = Some(token.text);
                }
                loop {
                    let token = tokens
                        .next()
                        .ok_or_else(|| SsrError::new("Placeholder is missing closing brace '}'"))?;
                    match token.kind {
                        T![:] => {
                            constraints.push(parse_constraint(tokens)?);
                        }
                        T!['}'] => break,
                        _ => bail!("Unexpected token while parsing placeholder: '{}'", token.text),
                    }
                }
            }
            _ => {
                bail!("Placeholders should either be $name or ${name:constraints}");
            }
        }
    }
    let name = name.ok_or_else(|| SsrError::new("Placeholder ($) with no name"))?;
    Ok(Placeholder::new(name, constraints))
}

fn parse_constraint(tokens: &mut std::vec::IntoIter<Token>) -> Result<Constraint, SsrError> {
    let constraint_type = tokens
        .next()
        .ok_or_else(|| SsrError::new("Found end of placeholder while looking for a constraint"))?
        .text
        .to_string();
    match constraint_type.as_str() {
        "kind" => {
            expect_token(tokens, "(")?;
            let t = tokens.next().ok_or_else(|| {
                SsrError::new("Unexpected end of constraint while looking for kind")
            })?;
            if t.kind != SyntaxKind::IDENT {
                bail!("Expected ident, found {:?} while parsing kind constraint", t.kind);
            }
            expect_token(tokens, ")")?;
            Ok(Constraint::Kind(NodeKind::from(&t.text)?))
        }
        "not" => {
            expect_token(tokens, "(")?;
            let sub = parse_constraint(tokens)?;
            expect_token(tokens, ")")?;
            Ok(Constraint::Not(Box::new(sub)))
        }
        x => bail!("Unsupported constraint type '{}'", x),
    }
}

fn expect_token(tokens: &mut std::vec::IntoIter<Token>, expected: &str) -> Result<(), SsrError> {
    if let Some(t) = tokens.next() {
        if t.text == expected {
            return Ok(());
        }
        bail!("Expected {} found {}", expected, t.text);
    }
    bail!("Expected {} found end of stream");
}

impl NodeKind {
    fn from(name: &SmolStr) -> Result<NodeKind, SsrError> {
        Ok(match name.as_str() {
            "literal" => NodeKind::Literal,
            _ => bail!("Unknown node kind '{}'", name),
        })
    }
}

impl Placeholder {
    fn new(name: SmolStr, constraints: Vec<Constraint>) -> Self {
        Self { stand_in_name: format!("__placeholder_{}", name), constraints, ident: name }
    }
}

impl SsrError {
    fn new(message: impl Into<String>) -> SsrError {
        SsrError(message.into())
    }
}

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

    #[test]
    fn parser_happy_case() {
        fn token(kind: SyntaxKind, text: &str) -> PatternElement {
            PatternElement::Token(Token { kind, text: SmolStr::new(text) })
        }
        fn placeholder(name: &str) -> PatternElement {
            PatternElement::Placeholder(Placeholder::new(SmolStr::new(name), Vec::new()))
        }
        let result: SsrRule = "foo($a, $b) ==>> bar($b, $a)".parse().unwrap();
        assert_eq!(
            result.pattern.raw.tokens,
            vec![
                token(SyntaxKind::IDENT, "foo"),
                token(T!['('], "("),
                placeholder("a"),
                token(T![,], ","),
                token(SyntaxKind::WHITESPACE, " "),
                placeholder("b"),
                token(T![')'], ")"),
            ]
        );
        assert_eq!(
            result.template.tokens,
            vec![
                token(SyntaxKind::IDENT, "bar"),
                token(T!['('], "("),
                placeholder("b"),
                token(T![,], ","),
                token(SyntaxKind::WHITESPACE, " "),
                placeholder("a"),
                token(T![')'], ")"),
            ]
        );
    }
}
<|endoftext|>


<commit_before>use std::path::Path;
use std::slice::Iter;
use std::ops::{Index, IndexMut};
use time::now_utc;
use xi_rope::Rope;

use super::Buffer;

/// Creates, manages and deletes all the buffers in Qork, maintaining the various invariants that
/// we expect from the buffers. Firstly, if a buffer is backed by a file, a second buffer on that
/// file cannot be created. Secondly, all buffers have unique identity.
///
/// Note that a Buffer is very different from a BufferView.
pub struct BufferCollection {
    next_buffer_id: i64,
    buffers: Vec<Buffer>
}

impl BufferCollection {
    fn next_buffer_id(&mut self) -> i64 {
        // No point being clever. No practical scenario in which these will need to be reused.
        self.next_buffer_id += 1;
        self.next_buffer_id
    }

    pub fn new() -> BufferCollection {
        BufferCollection {
            next_buffer_id: -1,
            buffers: Vec::new()
        }
    }

    /// Creates and returns a new empty buffer.
    pub fn new_empty_buffer(&mut self) -> &mut Buffer {
        let now = now_utc();

        let b = Buffer {
            id: self.next_buffer_id(),
            filename: None,
            title: String::default(),
            data: Rope::from(""),
            is_changed: false,
            created_time_utc: now,
            last_accessed_time_utc: now,
            last_changed_time_utc: now
        };

        let i = self.buffers.len();
        self.buffers.push(b);
        &mut self.buffers[i]
    }

    /*
    /// Creates a buffer from a filename. If there is already a Buffer for the file it is returned,
    /// else the file is opened and loaded if it exists, else if the file does not exist then a
    /// new buffer is created with that filename, but no loading is done (the Buffer is considered
    /// to be backed by a file that does not exist yet, it will be created when you save it.)
    pub fn open_file(&mut self) -> Buffer {
        Buffer::new()
    }
    */

    pub fn len(&mut self) -> usize {
        self.buffers.len()
    }

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

    pub fn iter(&self) -> Iter<Buffer> {
        self.buffers.iter()
    }

    pub fn add(&mut self, buffer: Buffer) {
        self.buffers.push(buffer)
    }

    pub fn find_by_filename<P : AsRef<Path>>(&mut self, filename: P) -> Option<&mut Buffer> {
        self.buffers.iter_mut().find(|b| b.filename.as_ref().map_or(false, |f| f == filename.as_ref()))
    }
}

impl Index<usize> for BufferCollection {
    type Output = Buffer;

    fn index(&self, index: usize) -> &Buffer {
        &self.buffers[index]
    }
}

impl IndexMut<usize> for BufferCollection {
    fn index_mut<'a>(&'a mut self, index: usize) -> &'a mut Buffer {
        &mut self.buffers[index]
    }
}

#[cfg(test)]
mod buffer_collection_tests {
    use super::*;
    use std::path::PathBuf;

    /*
    #[test]
    fn add_works() {
        let mut bc = BufferCollection::new();
        let mut b = Buffer::new();
        b.filename = Some(PathBuf::from("a"));
        bc.add(b);

        let b2 = &bc[0];
        assert_eq!(b2.filename, Some(PathBuf::from("a")));
    }
    */

    #[test]
    fn new_empty_buffer_adds_and_returns_buffer() {
        let now = now_utc();
        let mut bc = BufferCollection::new();
        let b1 = Buffer::new();
        let b2 = Buffer::new();
        bc.add(b1);
        bc.add(b2);

        // let b1 = bc.new_empty_buffer();
        // let b2 = bc.new_empty_buffer();
        // let i = bc.len();
        // assert_eq!(0, b1.id);
        // assert_eq!(1, i);

        // let b1 = Buffer {
        //     id: 2,
        //     filename: None,
        //     title: String::default(),
        //     data: Rope::from(""),
        //     is_changed: false,
        //     created_time_utc: now,
        //     last_accessed_time_utc: now,
        //     last_changed_time_utc: now
        // };

        // let b2 = Buffer {
        //     id: 2,
        //     filename: None,
        //     title: String::default(),
        //     data: Rope::from(""),
        //     is_changed: false,
        //     created_time_utc: now,
        //     last_accessed_time_utc: now,
        //     last_changed_time_utc: now
        // };

        //let b2 = &bc[0];
        //assert_eq!(b1, b2);
    }
}
<commit_msg>Buffers: improve variable name.<commit_after>use std::path::Path;
use std::slice::Iter;
use std::ops::{Index, IndexMut};
use time::now_utc;
use xi_rope::Rope;

use super::Buffer;

/// Creates, manages and deletes all the buffers in Qork, maintaining the various invariants that
/// we expect from the buffers. Firstly, if a buffer is backed by a file, a second buffer on that
/// file cannot be created. Secondly, all buffers have unique identity.
///
/// Note that a Buffer is very different from a BufferView.
pub struct BufferCollection {
    last_buffer_id: i64,
    buffers: Vec<Buffer>
}

impl BufferCollection {
    fn new_buffer_id(&mut self) -> i64 {
        // No point being clever. No practical scenario in which these will need to be reused.
        self.last_buffer_id += 1;
        self.last_buffer_id
    }

    pub fn new() -> BufferCollection {
        BufferCollection {
            last_buffer_id: -1,
            buffers: Vec::new()
        }
    }

    /// Creates and returns a new empty buffer.
    pub fn new_empty_buffer(&mut self) -> &mut Buffer {
        let now = now_utc();

        let b = Buffer {
            id: self.new_buffer_id(),
            filename: None,
            title: String::default(),
            data: Rope::from(""),
            is_changed: false,
            created_time_utc: now,
            last_accessed_time_utc: now,
            last_changed_time_utc: now
        };

        let i = self.buffers.len();
        self.buffers.push(b);
        &mut self.buffers[i]
    }

    /*
    /// Creates a buffer from a filename. If there is already a Buffer for the file it is returned,
    /// else the file is opened and loaded if it exists, else if the file does not exist then a
    /// new buffer is created with that filename, but no loading is done (the Buffer is considered
    /// to be backed by a file that does not exist yet, it will be created when you save it.)
    pub fn open_file(&mut self) -> Buffer {
        Buffer::new()
    }
    */

    pub fn len(&mut self) -> usize {
        self.buffers.len()
    }

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

    pub fn iter(&self) -> Iter<Buffer> {
        self.buffers.iter()
    }

    pub fn add(&mut self, buffer: Buffer) {
        self.buffers.push(buffer)
    }

    pub fn find_by_filename<P : AsRef<Path>>(&mut self, filename: P) -> Option<&mut Buffer> {
        self.buffers.iter_mut().find(|b| b.filename.as_ref().map_or(false, |f| f == filename.as_ref()))
    }
}

impl Index<usize> for BufferCollection {
    type Output = Buffer;

    fn index(&self, index: usize) -> &Buffer {
        &self.buffers[index]
    }
}

impl IndexMut<usize> for BufferCollection {
    fn index_mut<'a>(&'a mut self, index: usize) -> &'a mut Buffer {
        &mut self.buffers[index]
    }
}

#[cfg(test)]
mod buffer_collection_tests {
    use super::*;
    use std::path::PathBuf;

    /*
    #[test]
    fn add_works() {
        let mut bc = BufferCollection::new();
        let mut b = Buffer::new();
        b.filename = Some(PathBuf::from("a"));
        bc.add(b);

        let b2 = &bc[0];
        assert_eq!(b2.filename, Some(PathBuf::from("a")));
    }
    */

    #[test]
    fn new_empty_buffer_adds_and_returns_buffer() {
        let now = now_utc();
        let mut bc = BufferCollection::new();
        let b1 = Buffer::new();
        let b2 = Buffer::new();
        bc.add(b1);
        bc.add(b2);

        // let b1 = bc.new_empty_buffer();
        // let b2 = bc.new_empty_buffer();
        // let i = bc.len();
        // assert_eq!(0, b1.id);
        // assert_eq!(1, i);

        // let b1 = Buffer {
        //     id: 2,
        //     filename: None,
        //     title: String::default(),
        //     data: Rope::from(""),
        //     is_changed: false,
        //     created_time_utc: now,
        //     last_accessed_time_utc: now,
        //     last_changed_time_utc: now
        // };

        // let b2 = Buffer {
        //     id: 2,
        //     filename: None,
        //     title: String::default(),
        //     data: Rope::from(""),
        //     is_changed: false,
        //     created_time_utc: now,
        //     last_accessed_time_utc: now,
        //     last_changed_time_utc: now
        // };

        //let b2 = &bc[0];
        //assert_eq!(b1, b2);
    }
}
<|endoftext|>


<commit_before>use quick_error::quick_error;

/// Type alias for a result from this crate.
pub type Result<T> = ::std::result::Result<T, Error>;

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        Io(err: std::io::Error) {
            from()
        }
        FromUtf8(err: std::string::FromUtf8Error) {
            from()
        }
        NoPduAvailable {

        }
        InvalidMaxPdu {

        }
        PduTooLarge {

        }
        InvalidPduVariable {

        }
        MultipleTransferSyntaxesProposed {

        }
        InvalidRejectResult {

        }
        InvalidRejectServiceUserReason {

        }
        InvalidRejectServiceProviderASCEReason {

        }
        InvalidRejectServiceProviderPresentationReason {

        }
        InvalidRejectSource {

        }
        InvalidAbortServiceProviderReason {

        }
        InvalidAbortSource {

        }
        InvalidPresentationContextResultReason {

        }
        InvalidTransferSyntaxSubItem {

        }
        UnknownPresentationContextSubItem {

        }
        EncodingError(err: dicom_encoding::error::Error) {
            from()
        }
        MissingApplicationContextName {

        }
        MissingAbstractSyntax {

        }
        MissingTransferSyntax {

        }
    }
}
<commit_msg>Suggestions.<commit_after>use quick_error::quick_error;

/// Type alias for a result from this crate.
pub type Result<T> = std::result::Result<T, Error>;

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        Io(err: std::io::Error) {
            from()
        }
        FromUtf8(err: std::string::FromUtf8Error) {
            from()
        }
        NoPduAvailable {

        }
        InvalidMaxPdu {

        }
        PduTooLarge {

        }
        InvalidPduVariable {

        }
        MultipleTransferSyntaxesProposed {

        }
        InvalidRejectResult {

        }
        InvalidRejectServiceUserReason {

        }
        InvalidRejectServiceProviderASCEReason {

        }
        InvalidRejectServiceProviderPresentationReason {

        }
        InvalidRejectSource {

        }
        InvalidAbortServiceProviderReason {

        }
        InvalidAbortSource {

        }
        InvalidPresentationContextResultReason {

        }
        InvalidTransferSyntaxSubItem {

        }
        UnknownPresentationContextSubItem {

        }
        EncodingError(err: dicom_encoding::error::Error) {
            from()
        }
        MissingApplicationContextName {

        }
        MissingAbstractSyntax {

        }
        MissingTransferSyntax {

        }
    }
}
<|endoftext|>


<commit_before>use modular_flow::graph::*;
use modular_flow::context::*;
use jack::prelude::*;
use std::thread;
pub fn run_audio_io(ctx: NodeContext) {
    let n_inputs = ctx.node().in_ports().len();
    let n_outputs = ctx.node().out_ports().len();
    thread::spawn(move || {
        // create client
        let (client, _status) = Client::new("flow-synth", client_options::NO_START_SERVER).unwrap();

        // create ports
        let inputs: Vec<_> = (0..n_inputs)
            .map(|i| client.register_port(&format!("in-{}", i), AudioInSpec::default()).unwrap())
            .collect();
        let mut outputs: Vec<_> = (0..n_outputs)
            .map(|i| client.register_port(&format!("out-{}", i), AudioOutSpec::default()).unwrap())
            .collect();

        let unowned_inputs: Vec<_> = inputs.iter().map(|x| x.clone_unowned()).collect();
        let unowned_outputs: Vec<_> = outputs.iter().map(|x| x.clone_unowned()).collect();

        let processor = ClosureProcessHandler::new(move |_: &Client, ps: &ProcessScope| -> JackControl {
            // get port buffers
            let input_ports: Vec<_> = inputs.iter().map(|input| AudioInPort::new(input, ps)).collect();
            let mut output_ports: Vec<_> =
                outputs.iter_mut().map(|output| AudioOutPort::new(output, ps)).collect();

            // shuffle data
            let lock = ctx.lock();
            for (idx, input) in input_ports.iter().enumerate() {
                lock.write(OutPortID(idx), input).unwrap();
            }
            for (idx, output) in output_ports.iter_mut().enumerate() {
                // to avoid xruns, don't block, just skip instead.
                if lock.available::<f32>(InPortID(idx)) >= output.len() {
                    let read = lock.read_n(InPortID(idx), output.len()).unwrap();
                    output.copy_from_slice(&read);
                }
            }

            // do it forever
            JackControl::Continue
        });

        // activate the client
        let active_client = AsyncClient::new(client, (), processor).unwrap();

        // connect ports
        // TODO not sure what to do with this long term,
        // might just leave it disconnected, or connect to sys in/out
        // connect our outputs to physical playback
        let physical_playback =
            active_client.ports(None, None, port_flags::IS_INPUT | port_flags::IS_PHYSICAL);
        for (physical, ours) in physical_playback
            .iter()
            .map(|name| active_client.port_by_name(name).unwrap())
            .zip(unowned_outputs.iter())
        {
            active_client.connect_ports(ours, &physical).unwrap();
        }
        // connect our inputs to the pulse sink
        let pulse_sink = active_client.ports(Some("PulseAudio"), None, port_flags::IS_OUTPUT);
        for (pulse, ours) in pulse_sink
            .iter()
            .map(|name| active_client.port_by_name(name).unwrap())
            .zip(unowned_inputs.iter())
        {
            active_client.connect_ports(&pulse, ours).unwrap();
        }
        thread::park();
    });
}
<commit_msg>ensure audio channels stay in sync<commit_after>use modular_flow::graph::Port;
use modular_flow::context::*;
use jack::prelude::*;
use std::thread;
pub fn run_audio_io(ctx: NodeContext) {
    let n_inputs = ctx.node().in_ports().len();
    let n_outputs = ctx.node().out_ports().len();
    thread::spawn(move || {
        // create client
        let (client, _status) = Client::new("flow-synth", client_options::NO_START_SERVER).unwrap();

        // create ports
        let inputs: Vec<_> = (0..n_inputs)
            .map(|i| client.register_port(&format!("in-{}", i), AudioInSpec::default()).unwrap())
            .collect();
        let mut outputs: Vec<_> = (0..n_outputs)
            .map(|i| client.register_port(&format!("out-{}", i), AudioOutSpec::default()).unwrap())
            .collect();

        let unowned_inputs: Vec<_> = inputs.iter().map(|x| x.clone_unowned()).collect();
        let unowned_outputs: Vec<_> = outputs.iter().map(|x| x.clone_unowned()).collect();

        let processor =
            ClosureProcessHandler::new(move |client: &Client, ps: &ProcessScope| -> JackControl {
                // get port buffers
                let input_ports: Vec<_> = inputs.iter().map(|input| AudioInPort::new(input, ps)).collect();
                let mut output_ports: Vec<_> =
                    outputs.iter_mut().map(|output| AudioOutPort::new(output, ps)).collect();

                // shuffle data
                let lock = ctx.lock();
                for (input, out_port) in input_ports.iter().zip(lock.node().out_ports()) {
                    lock.write(out_port.id(), input).unwrap();
                }
                // to avoid xruns, don't block, just skip instead.
                if lock.node()
                    .in_ports()
                    .iter()
                    .all(|in_port| lock.available::<f32>(in_port.id()) >= client.buffer_size() as usize)
                {
                    for (output, in_port) in output_ports.iter_mut().zip(lock.node().in_ports()) {
                        let read = lock.read_n(in_port.id(), client.buffer_size() as usize).unwrap();
                        output.copy_from_slice(&read);
                    }
                }

                // do it forever
                JackControl::Continue
            });

        // activate the client
        let active_client = AsyncClient::new(client, (), processor).unwrap();

        // connect ports
        // TODO not sure what to do with this long term,
        // might just leave it disconnected, or connect to sys in/out
        // connect our outputs to physical playback
        let physical_playback =
            active_client.ports(None, None, port_flags::IS_INPUT | port_flags::IS_PHYSICAL);
        for (physical, ours) in physical_playback
            .iter()
            .map(|name| active_client.port_by_name(name).unwrap())
            .zip(unowned_outputs.iter())
        {
            active_client.connect_ports(ours, &physical).unwrap();
        }
        // connect our inputs to the pulse sink
        let pulse_sink = active_client.ports(Some("PulseAudio"), None, port_flags::IS_OUTPUT);
        for (pulse, ours) in pulse_sink
            .iter()
            .map(|name| active_client.port_by_name(name).unwrap())
            .zip(unowned_inputs.iter())
        {
            active_client.connect_ports(&pulse, ours).unwrap();
        }
        thread::park();
    });
}
<|endoftext|>


<commit_before>//! OpenGL back-end for Piston-Graphics.

// External crates.
use std::ffi::CString;
use shader_version::{ OpenGL, Shaders };
use shader_version::glsl::GLSL;
use graphics::{ Context, DrawState, Graphics, Viewport };
use graphics::color::gamma_srgb_to_linear;
use gl;
use gl::types::{
    GLint,
    GLsizei,
    GLuint,
};

// Local crate.
use draw_state;
use Texture;
use shader_utils::{
    compile_shader,
    DynamicAttribute,
};

struct Colored {
    vao: GLuint,
    vertex_shader: GLuint,
    fragment_shader: GLuint,
    program: GLuint,
    pos: DynamicAttribute,
    color: GLint,
}

impl Drop for Colored {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteVertexArrays(1, &self.vao);
            gl::DeleteProgram(self.program);
            gl::DeleteShader(self.vertex_shader);
            gl::DeleteShader(self.fragment_shader);
        }
    }
}

impl Colored {
    fn new(glsl: GLSL) -> Self {
        use shaders::colored;

        let src = |bytes| unsafe { ::std::str::from_utf8_unchecked(bytes) };

        let vertex_shader = match compile_shader(
            gl::VERTEX_SHADER,                  // shader type
            Shaders::new().set(GLSL::V1_20, src(colored::VERTEX_GLSL_120))
                          .set(GLSL::V1_50, src(colored::VERTEX_GLSL_150_CORE))
                          .get(glsl).unwrap()
        ) {
            Ok(id) => id,
            Err(s) => panic!("compile_shader: {}", s)
        };
        let fragment_shader = match compile_shader(
            gl::FRAGMENT_SHADER,                // shader type
            Shaders::new().set(GLSL::V1_20, src(colored::FRAGMENT_GLSL_120))
                          .set(GLSL::V1_50, src(colored::FRAGMENT_GLSL_150_CORE))
                          .get(glsl).unwrap()
        ) {
            Ok(id) => id,
            Err(s) => panic!("compile_shader: {}", s)
        };

        let program;
        unsafe {
            program = gl::CreateProgram();
            gl::AttachShader(program, vertex_shader);
            gl::AttachShader(program, fragment_shader);

            let c_o_color = CString::new("o_Color").unwrap();
            gl::BindFragDataLocation(program, 0, c_o_color.as_ptr());
            drop(c_o_color);
        }

        let mut vao = 0;
        unsafe {
            gl::GenVertexArrays(1, &mut vao);
            gl::LinkProgram(program);
        }
        let pos = DynamicAttribute::xy(
                program,
                "pos",
                vao
            ).unwrap();
        let c_color = CString::new("color").unwrap();
        let color = unsafe {
                gl::GetUniformLocation(program, c_color.as_ptr())
            };
        drop(c_color);
        if color == -1 {
            panic!("Could not find uniform `color`");
        }
        Colored {
            vao: vao,
            vertex_shader: vertex_shader,
            fragment_shader: fragment_shader,
            program: program,
            pos: pos,
            color: color,
        }
    }
}

struct Textured {
    vertex_shader: GLuint,
    fragment_shader: GLuint,
    program: GLuint,
    vao: GLuint,
    color: GLint,
    pos: DynamicAttribute,
    uv: DynamicAttribute,
}

impl Drop for Textured {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteVertexArrays(1, &self.vao);
            gl::DeleteProgram(self.program);
            gl::DeleteShader(self.vertex_shader);
            gl::DeleteShader(self.fragment_shader);
        }
    }
}

impl Textured {
    fn new(glsl: GLSL) -> Self {
        use shaders::textured;

        let src = |bytes| unsafe { ::std::str::from_utf8_unchecked(bytes) };

        let vertex_shader = match compile_shader(
            gl::VERTEX_SHADER,                  // shader type
            Shaders::new().set(GLSL::V1_20, src(textured::VERTEX_GLSL_120))
                          .set(GLSL::V1_50, src(textured::VERTEX_GLSL_150_CORE))
                          .get(glsl).unwrap()
        ) {
            Ok(id) => id,
            Err(s) => panic!("compile_shader: {}", s)
        };
        let fragment_shader = match compile_shader(
            gl::FRAGMENT_SHADER,                // shader type
            Shaders::new().set(GLSL::V1_20, src(textured::FRAGMENT_GLSL_120))
                          .set(GLSL::V1_50, src(textured::FRAGMENT_GLSL_150_CORE))
                          .get(glsl).unwrap()
        ) {
            Ok(id) => id,
            Err(s) => panic!("compile_shader: {}", s)
        };

        let program;
        unsafe {
            program = gl::CreateProgram();
            gl::AttachShader(program, vertex_shader);
            gl::AttachShader(program, fragment_shader);

            let c_o_color = CString::new("o_Color").unwrap();
            gl::BindFragDataLocation(program, 0, c_o_color.as_ptr());
            drop(c_o_color);
        }

        let mut vao = 0;
        unsafe {
            gl::GenVertexArrays(1, &mut vao);
            gl::LinkProgram(program);
        }
        let pos = DynamicAttribute::xy(
                program,
                "pos",
                vao
            ).unwrap();
        let c_color = CString::new("color").unwrap();
        let color = unsafe {
                gl::GetUniformLocation(program, c_color.as_ptr())
            };
        drop(c_color);
        if color == -1 {
            panic!("Could not find uniform `color`");
        }
        let uv = DynamicAttribute::uv(
                program,
                "uv",
                vao
            ).unwrap();
        Textured {
            vao: vao,
            vertex_shader: vertex_shader,
            fragment_shader: fragment_shader,
            program: program,
            pos: pos,
            color: color,
            uv: uv,
        }
    }
}

// Newlines and indents for cleaner panic message.
const GL_FUNC_NOT_LOADED: &'static str = "
    OpenGL function pointers must be loaded before creating the `Gl` backend!
    For more info, see the following issue on GitHub:
    https://github.com/PistonDevelopers/opengl_graphics/issues/103
";

/// Contains OpenGL data.
pub struct GlGraphics {
    colored: Colored,
    textured: Textured,
    // Keeps track of the current shader program.
    current_program: Option<GLuint>,
    // Keeps track of the current draw state.
    current_draw_state: Option<DrawState>,
}

impl<'a> GlGraphics {
    /// Creates a new OpenGL back-end.
    ///
    /// # Panics
    /// If the OpenGL function pointers have not been loaded yet.
    /// See https://github.com/PistonDevelopers/opengl_graphics/issues/103 for more info.
    pub fn new(opengl: OpenGL) -> Self {
        assert!(gl::Enable::is_loaded(), GL_FUNC_NOT_LOADED);

        let glsl = opengl.to_glsl();
        // Load the vertices, color and texture coord buffers.
        GlGraphics {
            colored: Colored::new(glsl),
            textured: Textured::new(glsl),
            current_program: None,
            current_draw_state: None,
       }
    }

    /// Sets viewport with normalized coordinates and center as origin.
    pub fn viewport(
        &mut self,
        x: i32,
        y: i32,
        w: i32,
        h: i32
    ) {
        unsafe {
            gl::Viewport(x as GLint, y as GLint, w as GLsizei, h as GLsizei);
        }
    }

    /// Sets the current program only if the program is not in use.
    pub fn use_program(&mut self, program: GLuint) {
        match self.current_program {
            None => {},
            Some(current_program) => {
                if program == current_program { return }
            },
        }

        unsafe {
            gl::UseProgram(program);
        }
        self.current_program = Some(program);
    }

    /// Unset the current program.
    ///
    /// This forces the current program to be set on next drawing call.
    pub fn clear_program(&mut self) {
        self.current_program = None
    }

    /// Sets the current draw state, by detecting changes.
    pub fn use_draw_state(&mut self, draw_state: &DrawState) {
        match self.current_draw_state {
            None => {
                draw_state::bind_scissor(draw_state.scissor);
                draw_state::bind_stencil(draw_state.stencil);
                draw_state::bind_blend(draw_state.blend);
            }
            Some(ref old_state) => {
                draw_state::bind_state(old_state, draw_state);
            }
        }
        self.current_draw_state = Some(*draw_state);
    }

    /// Unsets the current draw state.
    ///
    /// This forces the current draw state to be set on next drawing call.
    pub fn clear_draw_state(&mut self) {
        self.current_draw_state = None;
    }

    /// Draws graphics.
    pub fn draw<F, U>(&mut self, viewport: Viewport, f: F) -> U
        where
            F: FnOnce(Context, &mut Self) -> U
    {
        let rect = viewport.rect;
        let (x, y, w, h) = (rect[0], rect[1], rect[2], rect[3]);
        self.viewport(x, y, w, h);
        self.clear_program();
        unsafe { gl::Enable(gl::FRAMEBUFFER_SRGB); }
        let c = Context::new_viewport(viewport);
        f(c, self)
    }

    /// Assume all textures has alpha channel for now.
    pub fn has_texture_alpha(&self, _texture: &Texture) -> bool { true }
}

impl Graphics for GlGraphics {
    type Texture = Texture;

    fn clear_color(&mut self, color: [f32; 4]) {
        let color = gamma_srgb_to_linear(color);
        unsafe {
            let (r, g, b, a) = (color[0], color[1], color[2], color[3]);
            gl::ClearColor(r, g, b, a);
            gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
        }
    }

    fn clear_stencil(&mut self, value: u8) {
        unsafe {
            gl::ClearStencil(value as i32);
        }
    }

    fn tri_list<F>(
        &mut self,
        draw_state: &DrawState,
        color: &[f32; 4],
        mut f: F
    )
        where F: FnMut(&mut FnMut(&[f32]))
    {
        let color = gamma_srgb_to_linear(*color);
        {
            // Set shader program and draw state.
            let shader_program = self.colored.program;
            self.use_program(shader_program);
            self.use_draw_state(draw_state);
        }
        let ref mut shader = self.colored;

        unsafe {
            gl::BindVertexArray(shader.vao);
            gl::Uniform4f(shader.color, color[0], color[1], color[2], color[3]);
            // Render triangles whether they are facing
            // clockwise or counter clockwise.
            gl::Disable(gl::CULL_FACE);
        }

        f(&mut |vertices: &[f32]| {
            // xy makes two floats.
            let size_vertices: i32 = 2;
            let items: i32 = vertices.len() as i32 / size_vertices;

            unsafe {
                shader.pos.set(vertices);
                gl::DrawArrays(gl::TRIANGLES, 0, items);
            }
        });

        unsafe {
            gl::BindVertexArray(0);
        }
    }

    fn tri_list_uv<F>(
        &mut self,
        draw_state: &DrawState,
        color: &[f32; 4],
        texture: &Texture,
        mut f: F
    )
        where F: FnMut(&mut FnMut(&[f32], &[f32]))
    {
        let color = gamma_srgb_to_linear(*color);
        {
            // Set shader program and draw state.
            let shader_program = self.textured.program;
            self.use_program(shader_program);
            self.use_draw_state(draw_state);
        }
        let ref mut shader = self.textured;

        let texture = texture.get_id();
        unsafe {
            gl::BindTexture(gl::TEXTURE_2D, texture);
            // Render triangles whether they are facing
            // clockwise or counter clockwise.
            gl::Disable(gl::CULL_FACE);
            gl::BindVertexArray(shader.vao);
            gl::Uniform4f(shader.color, color[0], color[1], color[2], color[3]);
        }

        f(&mut |vertices: &[f32], texture_coords: &[f32]| {
            let size_vertices: i32 = 2;
            let items: i32 = vertices.len() as i32 / size_vertices;

            unsafe {
                shader.pos.set(vertices);
                shader.uv.set(texture_coords);
                gl::DrawArrays(gl::TRIANGLES, 0, items);
            }
        });

        unsafe {
            gl::BindVertexArray(0);
        }
    }
}

// Might not fail if previous tests loaded functions.
#[test]
#[should_panic]
fn test_gl_loaded() {
    GlGraphics::new(OpenGL::V3_2);
}
<commit_msg>Support emscripten<commit_after>//! OpenGL back-end for Piston-Graphics.

// External crates.
use std::ffi::CString;
use shader_version::{ OpenGL, Shaders };
use shader_version::glsl::GLSL;
use graphics::{ Context, DrawState, Graphics, Viewport };
use graphics::color::gamma_srgb_to_linear;
use gl;
use gl::types::{
    GLint,
    GLsizei,
    GLuint,
};

// Local crate.
use draw_state;
use Texture;
use shader_utils::{
    compile_shader,
    DynamicAttribute,
};

struct Colored {
    vao: GLuint,
    vertex_shader: GLuint,
    fragment_shader: GLuint,
    program: GLuint,
    pos: DynamicAttribute,
    color: GLint,
}

impl Drop for Colored {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteVertexArrays(1, &self.vao);
            gl::DeleteProgram(self.program);
            gl::DeleteShader(self.vertex_shader);
            gl::DeleteShader(self.fragment_shader);
        }
    }
}

impl Colored {
    fn new(glsl: GLSL) -> Self {
        use shaders::colored;

        let src = |bytes| unsafe { ::std::str::from_utf8_unchecked(bytes) };

        let vertex_shader = match compile_shader(
            gl::VERTEX_SHADER,                  // shader type
            Shaders::new().set(GLSL::V1_20, src(colored::VERTEX_GLSL_120))
                          .set(GLSL::V1_50, src(colored::VERTEX_GLSL_150_CORE))
                          .get(glsl).unwrap()
        ) {
            Ok(id) => id,
            Err(s) => panic!("compile_shader: {}", s)
        };
        let fragment_shader = match compile_shader(
            gl::FRAGMENT_SHADER,                // shader type
            Shaders::new().set(GLSL::V1_20, src(colored::FRAGMENT_GLSL_120))
                          .set(GLSL::V1_50, src(colored::FRAGMENT_GLSL_150_CORE))
                          .get(glsl).unwrap()
        ) {
            Ok(id) => id,
            Err(s) => panic!("compile_shader: {}", s)
        };

        let program;
        unsafe {
            program = gl::CreateProgram();
            gl::AttachShader(program, vertex_shader);
            gl::AttachShader(program, fragment_shader);

            let c_o_color = CString::new("o_Color").unwrap();
            if cfg!(not(target_os = "emscripten")) {
                gl::BindFragDataLocation(program, 0, c_o_color.as_ptr());
            }
            drop(c_o_color);
        }

        let mut vao = 0;
        unsafe {
            gl::GenVertexArrays(1, &mut vao);
            gl::LinkProgram(program);
        }
        let pos = DynamicAttribute::xy(
                program,
                "pos",
                vao
            ).unwrap();
        let c_color = CString::new("color").unwrap();
        let color = unsafe {
                gl::GetUniformLocation(program, c_color.as_ptr())
            };
        drop(c_color);
        if color == -1 {
            panic!("Could not find uniform `color`");
        }
        Colored {
            vao: vao,
            vertex_shader: vertex_shader,
            fragment_shader: fragment_shader,
            program: program,
            pos: pos,
            color: color,
        }
    }
}

struct Textured {
    vertex_shader: GLuint,
    fragment_shader: GLuint,
    program: GLuint,
    vao: GLuint,
    color: GLint,
    pos: DynamicAttribute,
    uv: DynamicAttribute,
}

impl Drop for Textured {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteVertexArrays(1, &self.vao);
            gl::DeleteProgram(self.program);
            gl::DeleteShader(self.vertex_shader);
            gl::DeleteShader(self.fragment_shader);
        }
    }
}

impl Textured {
    fn new(glsl: GLSL) -> Self {
        use shaders::textured;

        let src = |bytes| unsafe { ::std::str::from_utf8_unchecked(bytes) };

        let vertex_shader = match compile_shader(
            gl::VERTEX_SHADER,                  // shader type
            Shaders::new().set(GLSL::V1_20, src(textured::VERTEX_GLSL_120))
                          .set(GLSL::V1_50, src(textured::VERTEX_GLSL_150_CORE))
                          .get(glsl).unwrap()
        ) {
            Ok(id) => id,
            Err(s) => panic!("compile_shader: {}", s)
        };
        let fragment_shader = match compile_shader(
            gl::FRAGMENT_SHADER,                // shader type
            Shaders::new().set(GLSL::V1_20, src(textured::FRAGMENT_GLSL_120))
                          .set(GLSL::V1_50, src(textured::FRAGMENT_GLSL_150_CORE))
                          .get(glsl).unwrap()
        ) {
            Ok(id) => id,
            Err(s) => panic!("compile_shader: {}", s)
        };

        let program;
        unsafe {
            program = gl::CreateProgram();
            gl::AttachShader(program, vertex_shader);
            gl::AttachShader(program, fragment_shader);

            let c_o_color = CString::new("o_Color").unwrap();
            if cfg!(not(target_os = "emscripten")) {
                gl::BindFragDataLocation(program, 0, c_o_color.as_ptr());
            }
            drop(c_o_color);
        }

        let mut vao = 0;
        unsafe {
            gl::GenVertexArrays(1, &mut vao);
            gl::LinkProgram(program);
        }
        let pos = DynamicAttribute::xy(
                program,
                "pos",
                vao
            ).unwrap();
        let c_color = CString::new("color").unwrap();
        let color = unsafe {
                gl::GetUniformLocation(program, c_color.as_ptr())
            };
        drop(c_color);
        if color == -1 {
            panic!("Could not find uniform `color`");
        }
        let uv = DynamicAttribute::uv(
                program,
                "uv",
                vao
            ).unwrap();
        Textured {
            vao: vao,
            vertex_shader: vertex_shader,
            fragment_shader: fragment_shader,
            program: program,
            pos: pos,
            color: color,
            uv: uv,
        }
    }
}

// Newlines and indents for cleaner panic message.
const GL_FUNC_NOT_LOADED: &'static str = "
    OpenGL function pointers must be loaded before creating the `Gl` backend!
    For more info, see the following issue on GitHub:
    https://github.com/PistonDevelopers/opengl_graphics/issues/103
";

/// Contains OpenGL data.
pub struct GlGraphics {
    colored: Colored,
    textured: Textured,
    // Keeps track of the current shader program.
    current_program: Option<GLuint>,
    // Keeps track of the current draw state.
    current_draw_state: Option<DrawState>,
}

impl<'a> GlGraphics {
    /// Creates a new OpenGL back-end.
    ///
    /// # Panics
    /// If the OpenGL function pointers have not been loaded yet.
    /// See https://github.com/PistonDevelopers/opengl_graphics/issues/103 for more info.
    pub fn new(opengl: OpenGL) -> Self {
        assert!(gl::Enable::is_loaded(), GL_FUNC_NOT_LOADED);

        let glsl = opengl.to_glsl();
        // Load the vertices, color and texture coord buffers.
        GlGraphics {
            colored: Colored::new(glsl),
            textured: Textured::new(glsl),
            current_program: None,
            current_draw_state: None,
       }
    }

    /// Sets viewport with normalized coordinates and center as origin.
    pub fn viewport(
        &mut self,
        x: i32,
        y: i32,
        w: i32,
        h: i32
    ) {
        unsafe {
            gl::Viewport(x as GLint, y as GLint, w as GLsizei, h as GLsizei);
        }
    }

    /// Sets the current program only if the program is not in use.
    pub fn use_program(&mut self, program: GLuint) {
        match self.current_program {
            None => {},
            Some(current_program) => {
                if program == current_program { return }
            },
        }

        unsafe {
            gl::UseProgram(program);
        }
        self.current_program = Some(program);
    }

    /// Unset the current program.
    ///
    /// This forces the current program to be set on next drawing call.
    pub fn clear_program(&mut self) {
        self.current_program = None
    }

    /// Sets the current draw state, by detecting changes.
    pub fn use_draw_state(&mut self, draw_state: &DrawState) {
        match self.current_draw_state {
            None => {
                draw_state::bind_scissor(draw_state.scissor);
                draw_state::bind_stencil(draw_state.stencil);
                draw_state::bind_blend(draw_state.blend);
            }
            Some(ref old_state) => {
                draw_state::bind_state(old_state, draw_state);
            }
        }
        self.current_draw_state = Some(*draw_state);
    }

    /// Unsets the current draw state.
    ///
    /// This forces the current draw state to be set on next drawing call.
    pub fn clear_draw_state(&mut self) {
        self.current_draw_state = None;
    }

    /// Draws graphics.
    pub fn draw<F, U>(&mut self, viewport: Viewport, f: F) -> U
        where
            F: FnOnce(Context, &mut Self) -> U
    {
        let rect = viewport.rect;
        let (x, y, w, h) = (rect[0], rect[1], rect[2], rect[3]);
        self.viewport(x, y, w, h);
        self.clear_program();
        unsafe { gl::Enable(gl::FRAMEBUFFER_SRGB); }
        let c = Context::new_viewport(viewport);
        f(c, self)
    }

    /// Assume all textures has alpha channel for now.
    pub fn has_texture_alpha(&self, _texture: &Texture) -> bool { true }
}

impl Graphics for GlGraphics {
    type Texture = Texture;

    fn clear_color(&mut self, color: [f32; 4]) {
        let color = gamma_srgb_to_linear(color);
        unsafe {
            let (r, g, b, a) = (color[0], color[1], color[2], color[3]);
            gl::ClearColor(r, g, b, a);
            gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
        }
    }

    fn clear_stencil(&mut self, value: u8) {
        unsafe {
            gl::ClearStencil(value as i32);
        }
    }

    fn tri_list<F>(
        &mut self,
        draw_state: &DrawState,
        color: &[f32; 4],
        mut f: F
    )
        where F: FnMut(&mut FnMut(&[f32]))
    {
        let color = gamma_srgb_to_linear(*color);
        {
            // Set shader program and draw state.
            let shader_program = self.colored.program;
            self.use_program(shader_program);
            self.use_draw_state(draw_state);
        }
        let ref mut shader = self.colored;

        unsafe {
            gl::BindVertexArray(shader.vao);
            gl::Uniform4f(shader.color, color[0], color[1], color[2], color[3]);
            // Render triangles whether they are facing
            // clockwise or counter clockwise.
            gl::Disable(gl::CULL_FACE);
        }

        f(&mut |vertices: &[f32]| {
            // xy makes two floats.
            let size_vertices: i32 = 2;
            let items: i32 = vertices.len() as i32 / size_vertices;

            unsafe {
                shader.pos.set(vertices);
                gl::DrawArrays(gl::TRIANGLES, 0, items);
            }
        });

        unsafe {
            gl::BindVertexArray(0);
        }
    }

    fn tri_list_uv<F>(
        &mut self,
        draw_state: &DrawState,
        color: &[f32; 4],
        texture: &Texture,
        mut f: F
    )
        where F: FnMut(&mut FnMut(&[f32], &[f32]))
    {
        let color = gamma_srgb_to_linear(*color);
        {
            // Set shader program and draw state.
            let shader_program = self.textured.program;
            self.use_program(shader_program);
            self.use_draw_state(draw_state);
        }
        let ref mut shader = self.textured;

        let texture = texture.get_id();
        unsafe {
            gl::BindTexture(gl::TEXTURE_2D, texture);
            // Render triangles whether they are facing
            // clockwise or counter clockwise.
            gl::Disable(gl::CULL_FACE);
            gl::BindVertexArray(shader.vao);
            gl::Uniform4f(shader.color, color[0], color[1], color[2], color[3]);
        }

        f(&mut |vertices: &[f32], texture_coords: &[f32]| {
            let size_vertices: i32 = 2;
            let items: i32 = vertices.len() as i32 / size_vertices;

            unsafe {
                shader.pos.set(vertices);
                shader.uv.set(texture_coords);
                gl::DrawArrays(gl::TRIANGLES, 0, items);
            }
        });

        unsafe {
            gl::BindVertexArray(0);
        }
    }
}

// Might not fail if previous tests loaded functions.
#[test]
#[should_panic]
fn test_gl_loaded() {
    GlGraphics::new(OpenGL::V3_2);
}
<|endoftext|>