<commit_before>//! Abstractions for temporarily _rooting_ handles to managed JavaScript memory.

use std::mem;
use std::os::raw::c_void;
use std::marker::PhantomData;
use std::cell::RefCell;
use neon_runtime;
use neon_runtime::raw;
use mem::Handle;
use js::{Value, JsObject};
use vm::internal::Isolate;
use self::internal::ScopeInternal;

pub(crate) mod internal {
    use vm::internal::Isolate;
    use std::cell::RefCell;

    pub trait ScopeInternal: Sized {
        fn isolate(&self) -> Isolate;
        fn active_cell(&self) -> &RefCell<bool>;
    }
}

pub trait Scope<'a>: ScopeInternal {
    fn nested<T, F: for<'inner> FnOnce(&mut NestedScope<'inner>) -> T>(&self, f: F) -> T;
    fn chained<T, F: for<'inner> FnOnce(&mut ChainedScope<'inner, 'a>) -> T>(&self, f: F) -> T;

    fn global(&self) -> Handle<'a, JsObject> {
        JsObject::build(|out| {
            unsafe {
                neon_runtime::scope::get_global(self.isolate().to_raw(), out);
            }
        })
    }
}

fn ensure_active<T: ScopeInternal>(scope: &T) {
    if !*scope.active_cell().borrow() {
        panic!("illegal attempt to nest in inactive scope");
    }
}

pub struct RootScope<'a> {
    isolate: Isolate,
    active: RefCell<bool>,
    phantom: PhantomData<&'a ()>
}

pub struct NestedScope<'a> {
    isolate: Isolate,
    active: RefCell<bool>,
    phantom: PhantomData<&'a ()>
}

pub struct ChainedScope<'a, 'outer> {
    isolate: Isolate,
    active: RefCell<bool>,
    v8: *mut raw::EscapableHandleScope,
    parent: PhantomData<&'outer ()>,
    phantom: PhantomData<&'a ()>
}

impl<'a, 'outer> ChainedScope<'a, 'outer> {
    pub fn escape<T: Value>(&self, local: Handle<'a, T>) -> Handle<'outer, T> {
        unsafe {
            let mut result_local: raw::Local = mem::zeroed();
            neon_runtime::scope::escape(&mut result_local, self.v8, local.to_raw());
            Handle::new_internal(T::from_raw(result_local))
        }
    }
}

impl<'a> RootScope<'a> {
    pub(crate) fn new(isolate: Isolate) -> RootScope<'a> {
        RootScope {
            isolate: isolate,
            active: RefCell::new(true),
            phantom: PhantomData
        }
    }

    pub(crate) fn with<T, F: FnOnce(&'a mut RootScope<'a>) -> T>(&'a mut self, f: F) -> T {
        debug_assert!(unsafe { neon_runtime::scope::size() } <= mem::size_of::<raw::HandleScope>());
        debug_assert!(unsafe { neon_runtime::scope::alignment() } <= mem::align_of::<raw::HandleScope>());

        let mut v8_scope = raw::HandleScope::new();

        unsafe {
            neon_runtime::scope::enter(&mut v8_scope, self.isolate().to_raw());
        }

        let result = f(self);

        unsafe {
            neon_runtime::scope::exit(&mut v8_scope);
        }

        result

    }
}

impl<'a> Scope<'a> for RootScope<'a> {
    fn nested<T, F: for<'inner> FnOnce(&mut NestedScope<'inner>) -> T>(&self, f: F) -> T {
        nest(self, f)
    }

    fn chained<T, F: for<'inner> FnOnce(&mut ChainedScope<'inner, 'a>) -> T>(&self, f: F) -> T {
        chain(self, f)
    }
}

extern "C" fn chained_callback<'a, T, P, F>(out: &mut Box<Option<T>>,
                                            parent: &P,
                                            v8: *mut raw::EscapableHandleScope,
                                            f: Box<F>)
    where P: Scope<'a>,
          F: for<'inner> FnOnce(&mut ChainedScope<'inner, 'a>) -> T
{
    let mut chained = ChainedScope {
        isolate: parent.isolate(),
        active: RefCell::new(true),
        v8: v8,
        parent: PhantomData,
        phantom: PhantomData
    };
    let result = f(&mut chained);
    **out = Some(result);
}

impl<'a> ScopeInternal for RootScope<'a> {
    fn isolate(&self) -> Isolate { self.isolate }

    fn active_cell(&self) -> &RefCell<bool> {
        &self.active
    }
}

fn chain<'a, T, S, F>(outer: &S, f: F) -> T
    where S: Scope<'a>,
          F: for<'inner> FnOnce(&mut ChainedScope<'inner, 'a>) -> T
{
    ensure_active(outer);
    let closure: Box<F> = Box::new(f);
    let callback: extern "C" fn(&mut Box<Option<T>>, &S, *mut raw::EscapableHandleScope, Box<F>) = chained_callback::<T, S, F>;
    let mut result: Box<Option<T>> = Box::new(None);
    {
        let out: &mut Box<Option<T>> = &mut result;
        { *outer.active_cell().borrow_mut() = false; }
        unsafe {
            let out: *mut c_void = mem::transmute(out);
            let closure: *mut c_void = mem::transmute(closure);
            let callback: extern "C" fn(&mut c_void, *mut c_void, *mut c_void, *mut c_void) = mem::transmute(callback);
            let this: *mut c_void = mem::transmute(outer);
            neon_runtime::scope::chained(out, closure, callback, this);
        }
        { *outer.active_cell().borrow_mut() = true; }
    }
    result.unwrap()
}

fn nest<'me, T, S, F>(outer: &'me S, f: F) -> T
    where S: ScopeInternal,
          F: for<'nested> FnOnce(&mut NestedScope<'nested>) -> T
{
    ensure_active(outer);
    let closure: Box<F> = Box::new(f);
    let callback: extern "C" fn(&mut Box<Option<T>>, Isolate, Box<F>) = nested_callback::<T, F>;
    let mut result: Box<Option<T>> = Box::new(None);
    {
        let out: &mut Box<Option<T>> = &mut result;
        { *outer.active_cell().borrow_mut() = false; }
        unsafe {
            let out: *mut c_void = mem::transmute(out);
            let closure: *mut c_void = mem::transmute(closure);
            let callback: extern "C" fn(&mut c_void, *mut c_void, *mut c_void) = mem::transmute(callback);
            let isolate: *mut c_void = mem::transmute(outer.isolate());
            neon_runtime::scope::nested(out, closure, callback, isolate);
        }
        { *outer.active_cell().borrow_mut() = true; }
    }
    result.unwrap()
}

extern "C" fn nested_callback<T, F>(out: &mut Box<Option<T>>,
                                    isolate: Isolate,
                                    f: Box<F>)
    where F: for<'nested> FnOnce(&mut NestedScope<'nested>) -> T
{
    let mut nested = NestedScope {
        isolate: isolate,
        active: RefCell::new(true),
        phantom: PhantomData
    };
    let result = f(&mut nested);
    **out = Some(result);
}

impl<'a> Scope<'a> for NestedScope<'a> {
    fn nested<T, F: for<'inner> FnOnce(&mut NestedScope<'inner>) -> T>(&self, f: F) -> T {
        nest(self, f)
    }

    fn chained<T, F: for<'inner> FnOnce(&mut ChainedScope<'inner, 'a>) -> T>(&self, f: F) -> T {
        chain(self, f)
    }
}

impl<'a> ScopeInternal for NestedScope<'a> {
    fn isolate(&self) -> Isolate { self.isolate }

    fn active_cell(&self) -> &RefCell<bool> {
        &self.active
    }
}

impl<'a, 'outer> Scope<'a> for ChainedScope<'a, 'outer> {
    fn nested<T, F: for<'inner> FnOnce(&mut NestedScope<'inner>) -> T>(&self, f: F) -> T {
        nest(self, f)
    }

    fn chained<T, F: for<'inner> FnOnce(&mut ChainedScope<'inner, 'a>) -> T>(&self, f: F) -> T {
        chain(self, f)
    }
}

impl<'a, 'outer> ScopeInternal for ChainedScope<'a, 'outer> {
    fn isolate(&self) -> Isolate { self.isolate }

    fn active_cell(&self) -> &RefCell<bool> {
        &self.active
    }
}
<commit_msg>Replace RefCell<bool> with Cell<bool><commit_after>//! Abstractions for temporarily _rooting_ handles to managed JavaScript memory.

use std::mem;
use std::os::raw::c_void;
use std::marker::PhantomData;
use std::cell::Cell;
use neon_runtime;
use neon_runtime::raw;
use mem::Handle;
use js::{Value, JsObject};
use vm::internal::Isolate;
use self::internal::ScopeInternal;

pub(crate) mod internal {
    use vm::internal::Isolate;

    pub trait ScopeInternal: Sized {
        fn isolate(&self) -> Isolate;
        fn active(&self) -> bool;
        fn set_active(&self, bool);
    }
}

pub trait Scope<'a>: ScopeInternal {
    fn nested<T, F: for<'inner> FnOnce(&mut NestedScope<'inner>) -> T>(&self, f: F) -> T;
    fn chained<T, F: for<'inner> FnOnce(&mut ChainedScope<'inner, 'a>) -> T>(&self, f: F) -> T;

    fn global(&self) -> Handle<'a, JsObject> {
        JsObject::build(|out| {
            unsafe {
                neon_runtime::scope::get_global(self.isolate().to_raw(), out);
            }
        })
    }
}

fn ensure_active<T: ScopeInternal>(scope: &T) {
    if !scope.active() {
        panic!("illegal attempt to nest in inactive scope");
    }
}

pub struct RootScope<'a> {
    isolate: Isolate,
    active: Cell<bool>,
    phantom: PhantomData<&'a ()>
}

pub struct NestedScope<'a> {
    isolate: Isolate,
    active: Cell<bool>,
    phantom: PhantomData<&'a ()>
}

pub struct ChainedScope<'a, 'outer> {
    isolate: Isolate,
    active: Cell<bool>,
    v8: *mut raw::EscapableHandleScope,
    parent: PhantomData<&'outer ()>,
    phantom: PhantomData<&'a ()>
}

impl<'a, 'outer> ChainedScope<'a, 'outer> {
    pub fn escape<T: Value>(&self, local: Handle<'a, T>) -> Handle<'outer, T> {
        unsafe {
            let mut result_local: raw::Local = mem::zeroed();
            neon_runtime::scope::escape(&mut result_local, self.v8, local.to_raw());
            Handle::new_internal(T::from_raw(result_local))
        }
    }
}

impl<'a> RootScope<'a> {
    pub(crate) fn new(isolate: Isolate) -> RootScope<'a> {
        RootScope {
            isolate: isolate,
            active: Cell::new(true),
            phantom: PhantomData
        }
    }

    pub(crate) fn with<T, F: FnOnce(&'a mut RootScope<'a>) -> T>(&'a mut self, f: F) -> T {
        debug_assert!(unsafe { neon_runtime::scope::size() } <= mem::size_of::<raw::HandleScope>());
        debug_assert!(unsafe { neon_runtime::scope::alignment() } <= mem::align_of::<raw::HandleScope>());

        let mut v8_scope = raw::HandleScope::new();

        unsafe {
            neon_runtime::scope::enter(&mut v8_scope, self.isolate().to_raw());
        }

        let result = f(self);

        unsafe {
            neon_runtime::scope::exit(&mut v8_scope);
        }

        result

    }
}

impl<'a> Scope<'a> for RootScope<'a> {
    fn nested<T, F: for<'inner> FnOnce(&mut NestedScope<'inner>) -> T>(&self, f: F) -> T {
        nest(self, f)
    }

    fn chained<T, F: for<'inner> FnOnce(&mut ChainedScope<'inner, 'a>) -> T>(&self, f: F) -> T {
        chain(self, f)
    }
}

extern "C" fn chained_callback<'a, T, P, F>(out: &mut Box<Option<T>>,
                                            parent: &P,
                                            v8: *mut raw::EscapableHandleScope,
                                            f: Box<F>)
    where P: Scope<'a>,
          F: for<'inner> FnOnce(&mut ChainedScope<'inner, 'a>) -> T
{
    let mut chained = ChainedScope {
        isolate: parent.isolate(),
        active: Cell::new(true),
        v8: v8,
        parent: PhantomData,
        phantom: PhantomData
    };
    let result = f(&mut chained);
    **out = Some(result);
}

impl<'a> ScopeInternal for RootScope<'a> {
    fn isolate(&self) -> Isolate { self.isolate }

    fn active(&self) -> bool {
        self.active.get()
    }

    fn set_active(&self, active: bool) {
        self.active.set(active);
    }
}

fn chain<'a, T, S, F>(outer: &S, f: F) -> T
    where S: Scope<'a>,
          F: for<'inner> FnOnce(&mut ChainedScope<'inner, 'a>) -> T
{
    ensure_active(outer);
    let closure: Box<F> = Box::new(f);
    let callback: extern "C" fn(&mut Box<Option<T>>, &S, *mut raw::EscapableHandleScope, Box<F>) = chained_callback::<T, S, F>;
    let mut result: Box<Option<T>> = Box::new(None);
    {
        let out: &mut Box<Option<T>> = &mut result;
        outer.set_active(false);
        unsafe {
            let out: *mut c_void = mem::transmute(out);
            let closure: *mut c_void = mem::transmute(closure);
            let callback: extern "C" fn(&mut c_void, *mut c_void, *mut c_void, *mut c_void) = mem::transmute(callback);
            let this: *mut c_void = mem::transmute(outer);
            neon_runtime::scope::chained(out, closure, callback, this);
        }
        outer.set_active(true);
    }
    result.unwrap()
}

fn nest<'me, T, S, F>(outer: &'me S, f: F) -> T
    where S: ScopeInternal,
          F: for<'nested> FnOnce(&mut NestedScope<'nested>) -> T
{
    ensure_active(outer);
    let closure: Box<F> = Box::new(f);
    let callback: extern "C" fn(&mut Box<Option<T>>, Isolate, Box<F>) = nested_callback::<T, F>;
    let mut result: Box<Option<T>> = Box::new(None);
    {
        let out: &mut Box<Option<T>> = &mut result;
        outer.set_active(false);
        unsafe {
            let out: *mut c_void = mem::transmute(out);
            let closure: *mut c_void = mem::transmute(closure);
            let callback: extern "C" fn(&mut c_void, *mut c_void, *mut c_void) = mem::transmute(callback);
            let isolate: *mut c_void = mem::transmute(outer.isolate());
            neon_runtime::scope::nested(out, closure, callback, isolate);
        }
        outer.set_active(true);
    }
    result.unwrap()
}

extern "C" fn nested_callback<T, F>(out: &mut Box<Option<T>>,
                                    isolate: Isolate,
                                    f: Box<F>)
    where F: for<'nested> FnOnce(&mut NestedScope<'nested>) -> T
{
    let mut nested = NestedScope {
        isolate: isolate,
        active: Cell::new(true),
        phantom: PhantomData
    };
    let result = f(&mut nested);
    **out = Some(result);
}

impl<'a> Scope<'a> for NestedScope<'a> {
    fn nested<T, F: for<'inner> FnOnce(&mut NestedScope<'inner>) -> T>(&self, f: F) -> T {
        nest(self, f)
    }

    fn chained<T, F: for<'inner> FnOnce(&mut ChainedScope<'inner, 'a>) -> T>(&self, f: F) -> T {
        chain(self, f)
    }
}

impl<'a> ScopeInternal for NestedScope<'a> {
    fn isolate(&self) -> Isolate { self.isolate }

    fn active(&self) -> bool {
        self.active.get()
    }

    fn set_active(&self, active: bool) {
        self.active.set(active);
    }
}

impl<'a, 'outer> Scope<'a> for ChainedScope<'a, 'outer> {
    fn nested<T, F: for<'inner> FnOnce(&mut NestedScope<'inner>) -> T>(&self, f: F) -> T {
        nest(self, f)
    }

    fn chained<T, F: for<'inner> FnOnce(&mut ChainedScope<'inner, 'a>) -> T>(&self, f: F) -> T {
        chain(self, f)
    }
}

impl<'a, 'outer> ScopeInternal for ChainedScope<'a, 'outer> {
    fn isolate(&self) -> Isolate { self.isolate }

    fn active(&self) -> bool {
        self.active.get()
    }

    fn set_active(&self, active: bool) {
        self.active.set(active);
    }
}
<|endoftext|>


<commit_before>//! An enum that represents any state event. A state event is represented by
//! a parameterized struct allowing more flexibility in whats being sent.

use std::{
    convert::TryFrom,
    time::{SystemTime, UNIX_EPOCH},
};

use js_int::UInt;
use ruma_identifiers::{EventId, RoomId, UserId};
use serde::{
    ser::{Error, SerializeStruct},
    Serialize, Serializer,
};

use crate::{RoomEventContent, StateEventContent, TryFromRaw, UnsignedData};
use ruma_events_macros::{event_content_collection, Event};

event_content_collection! {
    /// A state event.
    name: AnyStateEventContent,
    events: ["m.room.aliases", "m.room.avatar"]
}

/// State event.
#[derive(Clone, Debug, Event)]
pub struct StateEvent<C: StateEventContent> {
    /// Data specific to the event type.
    pub content: C,

    /// The globally unique event identifier for the user who sent the event.
    pub event_id: EventId,

    /// Contains the fully-qualified ID of the user who sent this event.
    pub sender: UserId,

    /// Timestamp in milliseconds on originating homeserver when this event was sent.
    pub origin_server_ts: SystemTime,

    /// The ID of the room associated with this event.
    pub room_id: RoomId,

    /// A unique key which defines the overwriting semantics for this piece of room state.
    ///
    /// This is often an empty string, but some events send a `UserId` to show
    /// which user the event affects.
    pub state_key: String,

    /// Optional previous content for this event.
    pub prev_content: Option<C>,

    /// Additional key-value pairs not signed by the homeserver.
    pub unsigned: UnsignedData,
}

#[cfg(test)]
mod tests {
    use std::{
        convert::TryFrom,
        time::{Duration, UNIX_EPOCH},
    };

    use js_int::UInt;
    use matches::assert_matches;
    use ruma_identifiers::{EventId, RoomAliasId, RoomId, UserId};
    use serde_json::{from_value as from_json_value, json, to_value as to_json_value};

    use super::{AnyStateEventContent, StateEvent};
    use crate::{
        room::{
            aliases::AliasesEventContent, avatar::AvatarEventContent, ImageInfo, ThumbnailInfo,
        },
        EventJson, UnsignedData,
    };

    #[test]
    fn serialize_aliases_with_prev_content() {
        let aliases_event = StateEvent {
            content: AnyStateEventContent::RoomAliases(AliasesEventContent {
                aliases: vec![RoomAliasId::try_from("#somewhere:localhost").unwrap()],
            }),
            event_id: EventId::try_from("$h29iv0s8:example.com").unwrap(),
            origin_server_ts: UNIX_EPOCH + Duration::from_millis(1),
            prev_content: Some(AnyStateEventContent::RoomAliases(AliasesEventContent {
                aliases: vec![RoomAliasId::try_from("#somewhere:localhost").unwrap()],
            })),
            room_id: RoomId::try_from("!roomid:room.com").unwrap(),
            sender: UserId::try_from("@carl:example.com").unwrap(),
            state_key: "".to_string(),
            unsigned: UnsignedData::default(),
        };

        let actual = to_json_value(&aliases_event).unwrap();
        let expected = json!({
            "content": {
                "aliases": [ "#somewhere:localhost" ]
            },
            "event_id": "$h29iv0s8:example.com",
            "origin_server_ts": 1,
            "prev_content": {
                "aliases": [ "#somewhere:localhost" ]
            },
            "room_id": "!roomid:room.com",
            "sender": "@carl:example.com",
            "state_key": "",
            "type": "m.room.aliases",
        });

        assert_eq!(actual, expected);
    }

    #[test]
    fn serialize_aliases_without_prev_content() {
        let aliases_event = StateEvent {
            content: AnyStateEventContent::RoomAliases(AliasesEventContent {
                aliases: vec![RoomAliasId::try_from("#somewhere:localhost").unwrap()],
            }),
            event_id: EventId::try_from("$h29iv0s8:example.com").unwrap(),
            origin_server_ts: UNIX_EPOCH + Duration::from_millis(1),
            prev_content: None,
            room_id: RoomId::try_from("!roomid:room.com").unwrap(),
            sender: UserId::try_from("@carl:example.com").unwrap(),
            state_key: "".to_string(),
            unsigned: UnsignedData::default(),
        };

        let actual = to_json_value(&aliases_event).unwrap();
        let expected = json!({
            "content": {
                "aliases": [ "#somewhere:localhost" ]
            },
            "event_id": "$h29iv0s8:example.com",
            "origin_server_ts": 1,
            "room_id": "!roomid:room.com",
            "sender": "@carl:example.com",
            "state_key": "",
            "type": "m.room.aliases",
        });

        assert_eq!(actual, expected);
    }

    #[test]
    fn deserialize_aliases_content() {
        let json_data = json!({
            "aliases": [ "#somewhere:localhost" ]
        });

        assert_matches!(
            from_json_value::<EventJson<AnyStateEventContent>>(json_data)
                .unwrap()
                .deserialize_content("m.room.aliases")
                .unwrap(),
            AnyStateEventContent::RoomAliases(content)
            if content.aliases == vec![RoomAliasId::try_from("#somewhere:localhost").unwrap()]
        );
    }

    #[test]
    fn deserialize_aliases_with_prev_content() {
        let json_data = json!({
            "content": {
                "aliases": [ "#somewhere:localhost" ]
            },
            "event_id": "$h29iv0s8:example.com",
            "origin_server_ts": 1,
            "prev_content": {
                "aliases": [ "#inner:localhost" ]
            },
            "room_id": "!roomid:room.com",
            "sender": "@carl:example.com",
            "state_key": "",
            "type": "m.room.aliases"
        });

        assert_matches!(
            from_json_value::<EventJson<StateEvent<AnyStateEventContent>>>(json_data)
                .unwrap()
                .deserialize()
                .unwrap(),
            StateEvent {
                content: AnyStateEventContent::RoomAliases(content),
                event_id,
                origin_server_ts,
                prev_content: Some(AnyStateEventContent::RoomAliases(prev_content)),
                room_id,
                sender,
                state_key,
                unsigned,
            } if content.aliases == vec![RoomAliasId::try_from("#somewhere:localhost").unwrap()]
                && event_id == EventId::try_from("$h29iv0s8:example.com").unwrap()
                && origin_server_ts == UNIX_EPOCH + Duration::from_millis(1)
                && prev_content.aliases == vec![RoomAliasId::try_from("#inner:localhost").unwrap()]
                && room_id == RoomId::try_from("!roomid:room.com").unwrap()
                && sender == UserId::try_from("@carl:example.com").unwrap()
                && state_key == ""
                && unsigned.is_empty()
        );
    }

    #[test]
    fn deserialize_avatar_without_prev_content() {
        let json_data = json!({
            "content": {
                "info": {
                    "h": 423,
                    "mimetype": "image/png",
                    "size": 84242,
                    "thumbnail_info": {
                      "h": 334,
                      "mimetype": "image/png",
                      "size": 82595,
                      "w": 800
                    },
                    "thumbnail_url": "mxc://matrix.org",
                    "w": 1011
                  },
                "url": "http://www.matrix.org"
            },
            "event_id": "$h29iv0s8:example.com",
            "origin_server_ts": 1,
            "room_id": "!roomid:room.com",
            "sender": "@carl:example.com",
            "state_key": "",
            "type": "m.room.avatar"
        });

        assert_matches!(
            from_json_value::<EventJson<StateEvent<AnyStateEventContent>>>(json_data)
                .unwrap()
                .deserialize()
                .unwrap(),
            StateEvent {
                content: AnyStateEventContent::RoomAvatar(AvatarEventContent {
                    info: Some(info),
                    url,
                }),
                event_id,
                origin_server_ts,
                prev_content: None,
                room_id,
                sender,
                state_key,
                unsigned
            } if event_id == EventId::try_from("$h29iv0s8:example.com").unwrap()
                && origin_server_ts == UNIX_EPOCH + Duration::from_millis(1)
                && room_id == RoomId::try_from("!roomid:room.com").unwrap()
                && sender == UserId::try_from("@carl:example.com").unwrap()
                && state_key == ""
                && matches!(
                    info.as_ref(),
                    ImageInfo {
                        height,
                        width,
                        mimetype: Some(mimetype),
                        size,
                        thumbnail_info: Some(thumbnail_info),
                        thumbnail_url: Some(thumbnail_url),
                        thumbnail_file: None,
                    } if *height == UInt::new(423)
                        && *width == UInt::new(1011)
                        && *mimetype == "image/png"
                        && *size == UInt::new(84242)
                        && matches!(
                            thumbnail_info.as_ref(),
                            ThumbnailInfo {
                                width: thumb_width,
                                height: thumb_height,
                                mimetype: thumb_mimetype,
                                size: thumb_size,
                            } if *thumb_width == UInt::new(800)
                                && *thumb_height == UInt::new(334)
                                && *thumb_mimetype == Some("image/png".to_string())
                                && *thumb_size == UInt::new(82595)
                                && *thumbnail_url == "mxc://matrix.org"
                        )
                )
                && url == "http://www.matrix.org"
                && unsigned.is_empty()
        );
    }
}
<commit_msg>Update list of events in AnyStateEventContent<commit_after>//! An enum that represents any state event. A state event is represented by
//! a parameterized struct allowing more flexibility in whats being sent.

use std::{
    convert::TryFrom,
    time::{SystemTime, UNIX_EPOCH},
};

use js_int::UInt;
use ruma_identifiers::{EventId, RoomId, UserId};
use serde::{
    ser::{Error, SerializeStruct},
    Serialize, Serializer,
};

use crate::{RoomEventContent, StateEventContent, TryFromRaw, UnsignedData};
use ruma_events_macros::{event_content_collection, Event};

event_content_collection! {
    /// A state event.
    name: AnyStateEventContent,
    events: [
        "m.room.aliases",
        "m.room.avatar",
        "m.room.canonical_alias",
        "m.room.create",
        "m.room.encryption",
        "m.room.guest_access",
        "m.room.history_visibility",
        "m.room.join_rules",
        "m.room.member",
        "m.room.name",
        "m.room.pinned_events",
        "m.room.power_levels",
        "m.room.server_acl",
        "m.room.third_party_invite",
        "m.room.tombstone",
        "m.room.topic",
    ]
}

/// State event.
#[derive(Clone, Debug, Event)]
pub struct StateEvent<C: StateEventContent> {
    /// Data specific to the event type.
    pub content: C,

    /// The globally unique event identifier for the user who sent the event.
    pub event_id: EventId,

    /// Contains the fully-qualified ID of the user who sent this event.
    pub sender: UserId,

    /// Timestamp in milliseconds on originating homeserver when this event was sent.
    pub origin_server_ts: SystemTime,

    /// The ID of the room associated with this event.
    pub room_id: RoomId,

    /// A unique key which defines the overwriting semantics for this piece of room state.
    ///
    /// This is often an empty string, but some events send a `UserId` to show
    /// which user the event affects.
    pub state_key: String,

    /// Optional previous content for this event.
    pub prev_content: Option<C>,

    /// Additional key-value pairs not signed by the homeserver.
    pub unsigned: UnsignedData,
}

#[cfg(test)]
mod tests {
    use std::{
        convert::TryFrom,
        time::{Duration, UNIX_EPOCH},
    };

    use js_int::UInt;
    use matches::assert_matches;
    use ruma_identifiers::{EventId, RoomAliasId, RoomId, UserId};
    use serde_json::{from_value as from_json_value, json, to_value as to_json_value};

    use super::{AnyStateEventContent, StateEvent};
    use crate::{
        room::{
            aliases::AliasesEventContent, avatar::AvatarEventContent, ImageInfo, ThumbnailInfo,
        },
        EventJson, UnsignedData,
    };

    #[test]
    fn serialize_aliases_with_prev_content() {
        let aliases_event = StateEvent {
            content: AnyStateEventContent::RoomAliases(AliasesEventContent {
                aliases: vec![RoomAliasId::try_from("#somewhere:localhost").unwrap()],
            }),
            event_id: EventId::try_from("$h29iv0s8:example.com").unwrap(),
            origin_server_ts: UNIX_EPOCH + Duration::from_millis(1),
            prev_content: Some(AnyStateEventContent::RoomAliases(AliasesEventContent {
                aliases: vec![RoomAliasId::try_from("#somewhere:localhost").unwrap()],
            })),
            room_id: RoomId::try_from("!roomid:room.com").unwrap(),
            sender: UserId::try_from("@carl:example.com").unwrap(),
            state_key: "".to_string(),
            unsigned: UnsignedData::default(),
        };

        let actual = to_json_value(&aliases_event).unwrap();
        let expected = json!({
            "content": {
                "aliases": [ "#somewhere:localhost" ]
            },
            "event_id": "$h29iv0s8:example.com",
            "origin_server_ts": 1,
            "prev_content": {
                "aliases": [ "#somewhere:localhost" ]
            },
            "room_id": "!roomid:room.com",
            "sender": "@carl:example.com",
            "state_key": "",
            "type": "m.room.aliases",
        });

        assert_eq!(actual, expected);
    }

    #[test]
    fn serialize_aliases_without_prev_content() {
        let aliases_event = StateEvent {
            content: AnyStateEventContent::RoomAliases(AliasesEventContent {
                aliases: vec![RoomAliasId::try_from("#somewhere:localhost").unwrap()],
            }),
            event_id: EventId::try_from("$h29iv0s8:example.com").unwrap(),
            origin_server_ts: UNIX_EPOCH + Duration::from_millis(1),
            prev_content: None,
            room_id: RoomId::try_from("!roomid:room.com").unwrap(),
            sender: UserId::try_from("@carl:example.com").unwrap(),
            state_key: "".to_string(),
            unsigned: UnsignedData::default(),
        };

        let actual = to_json_value(&aliases_event).unwrap();
        let expected = json!({
            "content": {
                "aliases": [ "#somewhere:localhost" ]
            },
            "event_id": "$h29iv0s8:example.com",
            "origin_server_ts": 1,
            "room_id": "!roomid:room.com",
            "sender": "@carl:example.com",
            "state_key": "",
            "type": "m.room.aliases",
        });

        assert_eq!(actual, expected);
    }

    #[test]
    fn deserialize_aliases_content() {
        let json_data = json!({
            "aliases": [ "#somewhere:localhost" ]
        });

        assert_matches!(
            from_json_value::<EventJson<AnyStateEventContent>>(json_data)
                .unwrap()
                .deserialize_content("m.room.aliases")
                .unwrap(),
            AnyStateEventContent::RoomAliases(content)
            if content.aliases == vec![RoomAliasId::try_from("#somewhere:localhost").unwrap()]
        );
    }

    #[test]
    fn deserialize_aliases_with_prev_content() {
        let json_data = json!({
            "content": {
                "aliases": [ "#somewhere:localhost" ]
            },
            "event_id": "$h29iv0s8:example.com",
            "origin_server_ts": 1,
            "prev_content": {
                "aliases": [ "#inner:localhost" ]
            },
            "room_id": "!roomid:room.com",
            "sender": "@carl:example.com",
            "state_key": "",
            "type": "m.room.aliases"
        });

        assert_matches!(
            from_json_value::<EventJson<StateEvent<AnyStateEventContent>>>(json_data)
                .unwrap()
                .deserialize()
                .unwrap(),
            StateEvent {
                content: AnyStateEventContent::RoomAliases(content),
                event_id,
                origin_server_ts,
                prev_content: Some(AnyStateEventContent::RoomAliases(prev_content)),
                room_id,
                sender,
                state_key,
                unsigned,
            } if content.aliases == vec![RoomAliasId::try_from("#somewhere:localhost").unwrap()]
                && event_id == EventId::try_from("$h29iv0s8:example.com").unwrap()
                && origin_server_ts == UNIX_EPOCH + Duration::from_millis(1)
                && prev_content.aliases == vec![RoomAliasId::try_from("#inner:localhost").unwrap()]
                && room_id == RoomId::try_from("!roomid:room.com").unwrap()
                && sender == UserId::try_from("@carl:example.com").unwrap()
                && state_key == ""
                && unsigned.is_empty()
        );
    }

    #[test]
    fn deserialize_avatar_without_prev_content() {
        let json_data = json!({
            "content": {
                "info": {
                    "h": 423,
                    "mimetype": "image/png",
                    "size": 84242,
                    "thumbnail_info": {
                      "h": 334,
                      "mimetype": "image/png",
                      "size": 82595,
                      "w": 800
                    },
                    "thumbnail_url": "mxc://matrix.org",
                    "w": 1011
                  },
                "url": "http://www.matrix.org"
            },
            "event_id": "$h29iv0s8:example.com",
            "origin_server_ts": 1,
            "room_id": "!roomid:room.com",
            "sender": "@carl:example.com",
            "state_key": "",
            "type": "m.room.avatar"
        });

        assert_matches!(
            from_json_value::<EventJson<StateEvent<AnyStateEventContent>>>(json_data)
                .unwrap()
                .deserialize()
                .unwrap(),
            StateEvent {
                content: AnyStateEventContent::RoomAvatar(AvatarEventContent {
                    info: Some(info),
                    url,
                }),
                event_id,
                origin_server_ts,
                prev_content: None,
                room_id,
                sender,
                state_key,
                unsigned
            } if event_id == EventId::try_from("$h29iv0s8:example.com").unwrap()
                && origin_server_ts == UNIX_EPOCH + Duration::from_millis(1)
                && room_id == RoomId::try_from("!roomid:room.com").unwrap()
                && sender == UserId::try_from("@carl:example.com").unwrap()
                && state_key == ""
                && matches!(
                    info.as_ref(),
                    ImageInfo {
                        height,
                        width,
                        mimetype: Some(mimetype),
                        size,
                        thumbnail_info: Some(thumbnail_info),
                        thumbnail_url: Some(thumbnail_url),
                        thumbnail_file: None,
                    } if *height == UInt::new(423)
                        && *width == UInt::new(1011)
                        && *mimetype == "image/png"
                        && *size == UInt::new(84242)
                        && matches!(
                            thumbnail_info.as_ref(),
                            ThumbnailInfo {
                                width: thumb_width,
                                height: thumb_height,
                                mimetype: thumb_mimetype,
                                size: thumb_size,
                            } if *thumb_width == UInt::new(800)
                                && *thumb_height == UInt::new(334)
                                && *thumb_mimetype == Some("image/png".to_string())
                                && *thumb_size == UInt::new(82595)
                                && *thumbnail_url == "mxc://matrix.org"
                        )
                )
                && url == "http://www.matrix.org"
                && unsigned.is_empty()
        );
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::fs::File;
use std::io::Read;
use std::path::{Path, PathBuf};
use std::sync::Arc;
use page::Page;
use toctree::TocTree;
use handlebars::{self, Handlebars};
use serde_json;
use toml;

struct TocTreeHelper {
    toctree: Arc<TocTree>,
}

impl handlebars::HelperDef for TocTreeHelper {
    fn call(&self,
            h: &handlebars::Helper,
            _: &Handlebars,
            rc: &mut handlebars::RenderContext)
            -> Result<(), handlebars::RenderError> {
        let slug = h.param(0).unwrap().value().as_str().unwrap();
        let html = self.toctree
            .generate_html(slug)
            .or_else(|msg| Err(handlebars::RenderError::new(msg)))?
            .concat();
        rc.writer.write_all(html.as_bytes())?;
        Ok(())
    }
}

#[derive(Deserialize)]
struct RawConfig {
    constants: Option<serde_json::map::Map<String, serde_json::Value>>,
    templates: HashMap<String, PathBuf>,
}

pub struct Theme {
    path: PathBuf,
    constants: serde_json::map::Map<String, serde_json::Value>,
    templates: HashMap<String, PathBuf>,
}

impl Theme {
    pub fn load(path: &Path) -> Result<Self, ()> {
        let mut file = File::open(path).or(Err(()))?;
        let mut data = String::new();
        file.read_to_string(&mut data).or(Err(()))?;
        let config: RawConfig = toml::from_str(&data).or(Err(()))?;

        let constants = config.constants.unwrap_or_else(serde_json::map::Map::new);
        Ok(Theme {
               path: path.to_owned(),
               constants: constants,
               templates: config.templates,
           })
    }
}

pub struct Renderer<'a> {
    handlebars: Handlebars,
    constants: &'a serde_json::map::Map<String, serde_json::Value>,
}

impl<'a> Renderer<'a> {
    pub fn new(theme: &'a Theme,
               toctree: TocTree)
               -> Result<Renderer<'a>, handlebars::TemplateFileError> {
        let mut handlebars = Handlebars::new();
        let theme_dir_path = theme.path.parent().unwrap_or_else(|| Path::new(""));

        for (template_name, template_path) in &theme.templates {
            let template_path = theme_dir_path.join(template_path);
            handlebars
                .register_template_file(template_name, template_path)?;
        }

        handlebars.register_helper("toctree",
                                   Box::new(TocTreeHelper { toctree: Arc::new(toctree) }));

        Ok(Renderer {
               handlebars,
               constants: &theme.constants,
           })
    }

    pub fn render(&self,
                  template_name: &str,
                  project_args: &serde_json::map::Map<String, serde_json::Value>,
                  page: &Page)
                  -> Result<String, handlebars::RenderError> {
        let ctx = json!({
            "page": &page.theme_config,
            "project": project_args,
            "theme": self.constants,
            "body": &page.body,
        });

        self.handlebars.render(template_name, &ctx)
    }
}
<commit_msg>Add striptags template helper<commit_after>use std::collections::HashMap;
use std::fs::File;
use std::io::Read;
use std::path::{Path, PathBuf};
use std::sync::Arc;
use page::Page;
use toctree::TocTree;
use handlebars::{self, Handlebars};
use regex::Regex;
use serde_json;
use toml;

lazy_static! {
    static ref PAT_TAGS: Regex = Regex::new("<[^>]+>").expect("Failed to compile striptags regex");
}

struct TocTreeHelper {
    toctree: Arc<TocTree>,
}

impl handlebars::HelperDef for TocTreeHelper {
    fn call(&self,
            h: &handlebars::Helper,
            _: &Handlebars,
            rc: &mut handlebars::RenderContext)
            -> Result<(), handlebars::RenderError> {
        let slug = h.param(0).unwrap().value().as_str().unwrap();
        let html = self.toctree
            .generate_html(slug)
            .or_else(|msg| Err(handlebars::RenderError::new(msg)))?
            .concat();
        rc.writer.write_all(html.as_bytes())?;
        Ok(())
    }
}

struct StripTags;

impl handlebars::HelperDef for StripTags {
    fn call(&self,
            h: &handlebars::Helper,
            _: &Handlebars,
            rc: &mut handlebars::RenderContext)
            -> Result<(), handlebars::RenderError> {
        let arg = h.param(0).unwrap().value().as_str().unwrap();
        let stripped = PAT_TAGS.replace_all(arg, "");
        rc.writer.write_all(stripped.as_bytes())?;
        Ok(())
    }
}

#[derive(Deserialize)]
struct RawConfig {
    constants: Option<serde_json::map::Map<String, serde_json::Value>>,
    templates: HashMap<String, PathBuf>,
}

pub struct Theme {
    path: PathBuf,
    constants: serde_json::map::Map<String, serde_json::Value>,
    templates: HashMap<String, PathBuf>,
}

impl Theme {
    pub fn load(path: &Path) -> Result<Self, ()> {
        let mut file = File::open(path).or(Err(()))?;
        let mut data = String::new();
        file.read_to_string(&mut data).or(Err(()))?;
        let config: RawConfig = toml::from_str(&data).or(Err(()))?;

        let constants = config.constants.unwrap_or_else(serde_json::map::Map::new);
        Ok(Theme {
               path: path.to_owned(),
               constants: constants,
               templates: config.templates,
           })
    }
}

pub struct Renderer<'a> {
    handlebars: Handlebars,
    constants: &'a serde_json::map::Map<String, serde_json::Value>,
}

impl<'a> Renderer<'a> {
    pub fn new(theme: &'a Theme,
               toctree: TocTree)
               -> Result<Renderer<'a>, handlebars::TemplateFileError> {
        let mut handlebars = Handlebars::new();
        let theme_dir_path = theme.path.parent().unwrap_or_else(|| Path::new(""));

        for (template_name, template_path) in &theme.templates {
            let template_path = theme_dir_path.join(template_path);
            handlebars
                .register_template_file(template_name, template_path)?;
        }

        handlebars.register_helper("toctree",
                                   Box::new(TocTreeHelper { toctree: Arc::new(toctree) }));

        handlebars.register_helper("striptags", Box::new(StripTags));

        Ok(Renderer {
               handlebars,
               constants: &theme.constants,
           })
    }

    pub fn render(&self,
                  template_name: &str,
                  project_args: &serde_json::map::Map<String, serde_json::Value>,
                  page: &Page)
                  -> Result<String, handlebars::RenderError> {
        let ctx = json!({
            "page": &page.theme_config,
            "project": project_args,
            "theme": self.constants,
            "body": &page.body,
        });

        self.handlebars.render(template_name, &ctx)
    }
}
<|endoftext|>


<commit_before>
use color::Color;
use rustc_serialize::{
    json,
    Encodable,
    Decodable,
};
use std::error::Error;
use std::io::File;
use std::str;
use std::borrow::ToOwned;
use ui_context::UiContext;

/// A data holder for style-related data.
#[derive(Show, Clone, RustcEncodable, RustcDecodable)]
pub struct Theme {
    pub name: String,
    pub background_color: Color,
    pub shape_color: Color,
    pub frame_color: Color,
    pub frame_width: f64,
    pub label_color: Color,
    pub font_size_large: u32,
    pub font_size_medium: u32,
    pub font_size_small: u32,
    //TODO: Add unique theme-ing for each widget.
    //i.e. maybe_slider: Option<SliderTheme>, etc
}

impl Theme {

    /// The default theme if not loading from file.
    pub fn default() -> Theme {
        Theme {
            name: "Demo Theme".to_string(),
            background_color: Color::new(0.0, 0.0, 0.0, 1.0),
            shape_color: Color::new(1.0, 1.0, 1.0, 1.0),
            frame_color: Color::new(0.0, 0.0, 0.0, 1.0),
            frame_width: 1.0,
            label_color: Color::new(0.0, 0.0, 0.0, 1.0),
            font_size_large: 32,
            font_size_medium: 24,
            font_size_small: 18,
        }
    }

    /// Load a theme from file.
    pub fn load(path: &str) -> Result<Theme, String> {
        let contents = match File::open(&Path::new(path)).read_to_end() {
            Ok(buf) => Ok(buf),
            Err(e) => Err(format!("Failed to load Theme correctly: {}", e)),
        };
        let contents_str = contents.ok();
        let json_object = contents_str.and_then(|s| json::Json::from_str(str::from_utf8(s.as_slice()).unwrap()).ok());
        let mut decoder = json_object.map(|j| json::Decoder::new(j));
        let theme = match decoder {
            Some(ref mut d) => match Decodable::decode(d) {
                Ok(lib) => Ok(lib),
                Err(e) => Err(format!("Failed to load Theme correctly: {}", e.description())),
            },
            None => Err(String::from_str("Failed to load Theme correctly")),
        };
        theme
    }

    /// Save a theme to file.
    pub fn save(&self, path: &str) -> Result<(), String> {
        let json_string = match json::encode(self) {
                Ok(x) => x,
                Err(e) => return Err(e.description().to_owned())
            };
        let mut file = File::create(&Path::new(path));
        match file.write(json_string.as_bytes()) {
            Ok(()) => Ok(()),
            Err(e) => Err(format!("Theme failed to save correctly: {}", e)),
        }
    }

}

/// A trait to make it easier to generically access the UIC on different widget contexts.
pub trait Themeable {
    /// Return a reference to the UiContext.
    fn get_theme(&self) -> &UiContext;
    /// Return a reference to the UiContext.
    fn get_theme_mut(&mut self) -> &mut UiContext;
}

<commit_msg>std::io -> std::old_id<commit_after>
use color::Color;
use rustc_serialize::{
    json,
    Encodable,
    Decodable,
};
use std::error::Error;
use std::old_io::File;
use std::str;
use std::borrow::ToOwned;
use ui_context::UiContext;

/// A data holder for style-related data.
#[derive(Show, Clone, RustcEncodable, RustcDecodable)]
pub struct Theme {
    pub name: String,
    pub background_color: Color,
    pub shape_color: Color,
    pub frame_color: Color,
    pub frame_width: f64,
    pub label_color: Color,
    pub font_size_large: u32,
    pub font_size_medium: u32,
    pub font_size_small: u32,
    //TODO: Add unique theme-ing for each widget.
    //i.e. maybe_slider: Option<SliderTheme>, etc
}

impl Theme {

    /// The default theme if not loading from file.
    pub fn default() -> Theme {
        Theme {
            name: "Demo Theme".to_string(),
            background_color: Color::new(0.0, 0.0, 0.0, 1.0),
            shape_color: Color::new(1.0, 1.0, 1.0, 1.0),
            frame_color: Color::new(0.0, 0.0, 0.0, 1.0),
            frame_width: 1.0,
            label_color: Color::new(0.0, 0.0, 0.0, 1.0),
            font_size_large: 32,
            font_size_medium: 24,
            font_size_small: 18,
        }
    }

    /// Load a theme from file.
    pub fn load(path: &str) -> Result<Theme, String> {
        let contents = match File::open(&Path::new(path)).read_to_end() {
            Ok(buf) => Ok(buf),
            Err(e) => Err(format!("Failed to load Theme correctly: {}", e)),
        };
        let contents_str = contents.ok();
        let json_object = contents_str.and_then(|s| json::Json::from_str(str::from_utf8(s.as_slice()).unwrap()).ok());
        let mut decoder = json_object.map(|j| json::Decoder::new(j));
        let theme = match decoder {
            Some(ref mut d) => match Decodable::decode(d) {
                Ok(lib) => Ok(lib),
                Err(e) => Err(format!("Failed to load Theme correctly: {}", e.description())),
            },
            None => Err(String::from_str("Failed to load Theme correctly")),
        };
        theme
    }

    /// Save a theme to file.
    pub fn save(&self, path: &str) -> Result<(), String> {
        let json_string = match json::encode(self) {
                Ok(x) => x,
                Err(e) => return Err(e.description().to_owned())
            };
        let mut file = File::create(&Path::new(path));
        match file.write_all(json_string.as_bytes()) {
            Ok(()) => Ok(()),
            Err(e) => Err(format!("Theme failed to save correctly: {}", e)),
        }
    }

}

/// A trait to make it easier to generically access the UIC on different widget contexts.
pub trait Themeable {
    /// Return a reference to the UiContext.
    fn get_theme(&self) -> &UiContext;
    /// Return a reference to the UiContext.
    fn get_theme_mut(&mut self) -> &mut UiContext;
}
<|endoftext|>


<commit_before>//! Lexed pieces of source files.

use std::fmt;
use std::mem;

use clang_sys::*;

use utility;
use super::{TranslationUnit};
use super::source::{SourceLocation, SourceRange};

//================================================
// Enums
//================================================

// TokenKind _____________________________________

/// Indicates the categorization of a token.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[repr(C)]
pub enum TokenKind {
    /// A comment token.
    Comment = 4,
    /// An identifier token.
    Identifier = 2,
    /// A keyword token.
    Keyword = 1,
    /// A literal token.
    Literal = 3,
    /// A puncuation token.
    Punctuation = 0,
}

//================================================
// Structs
//================================================

// Token _________________________________________

/// A lexed piece of a source file.
#[derive(Copy, Clone)]
pub struct Token<'tu> {
    raw: CXToken,
    tu: &'tu TranslationUnit<'tu>,
}

impl<'tu> Token<'tu> {
    //- Constructors -----------------------------

    #[doc(hidden)]
    pub fn from_raw(raw: CXToken, tu: &'tu TranslationUnit<'tu>) -> Token<'tu> {
        Token{ raw: raw, tu: tu }
    }

    //- Accessors --------------------------------

    /// Returns the categorization of this token.
    pub fn get_kind(&self) -> TokenKind {
        unsafe { mem::transmute(clang_getTokenKind(self.raw)) }
    }

    /// Returns the textual representation of this token.
    pub fn get_spelling(&self) -> String {
        unsafe { utility::to_string(clang_getTokenSpelling(self.tu.ptr, self.raw)) }
    }

    /// Returns the source location of this token.
    pub fn get_location(&self) -> SourceLocation<'tu> {
        unsafe { SourceLocation::from_raw(clang_getTokenLocation(self.tu.ptr, self.raw), self.tu) }
    }

    /// Returns the source range of this token.
    pub fn get_range(&self) -> SourceRange<'tu> {
        unsafe { SourceRange::from_raw(clang_getTokenExtent(self.tu.ptr, self.raw), self.tu) }
    }
}

impl<'tu> fmt::Debug for Token<'tu> {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.debug_struct("Token")
            .field("kind", &self.get_kind())
            .field("spelling", &self.get_spelling())
            .field("range", &self.get_range())
            .finish()
    }
}
<commit_msg>Add missing license headers<commit_after>// Copyright 2016 Kyle Mayes
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Lexed pieces of source files.

use std::fmt;
use std::mem;

use clang_sys::*;

use utility;
use super::{TranslationUnit};
use super::source::{SourceLocation, SourceRange};

//================================================
// Enums
//================================================

// TokenKind _____________________________________

/// Indicates the categorization of a token.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[repr(C)]
pub enum TokenKind {
    /// A comment token.
    Comment = 4,
    /// An identifier token.
    Identifier = 2,
    /// A keyword token.
    Keyword = 1,
    /// A literal token.
    Literal = 3,
    /// A puncuation token.
    Punctuation = 0,
}

//================================================
// Structs
//================================================

// Token _________________________________________

/// A lexed piece of a source file.
#[derive(Copy, Clone)]
pub struct Token<'tu> {
    raw: CXToken,
    tu: &'tu TranslationUnit<'tu>,
}

impl<'tu> Token<'tu> {
    //- Constructors -----------------------------

    #[doc(hidden)]
    pub fn from_raw(raw: CXToken, tu: &'tu TranslationUnit<'tu>) -> Token<'tu> {
        Token{ raw: raw, tu: tu }
    }

    //- Accessors --------------------------------

    /// Returns the categorization of this token.
    pub fn get_kind(&self) -> TokenKind {
        unsafe { mem::transmute(clang_getTokenKind(self.raw)) }
    }

    /// Returns the textual representation of this token.
    pub fn get_spelling(&self) -> String {
        unsafe { utility::to_string(clang_getTokenSpelling(self.tu.ptr, self.raw)) }
    }

    /// Returns the source location of this token.
    pub fn get_location(&self) -> SourceLocation<'tu> {
        unsafe { SourceLocation::from_raw(clang_getTokenLocation(self.tu.ptr, self.raw), self.tu) }
    }

    /// Returns the source range of this token.
    pub fn get_range(&self) -> SourceRange<'tu> {
        unsafe { SourceRange::from_raw(clang_getTokenExtent(self.tu.ptr, self.raw), self.tu) }
    }
}

impl<'tu> fmt::Debug for Token<'tu> {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.debug_struct("Token")
            .field("kind", &self.get_kind())
            .field("spelling", &self.get_spelling())
            .field("range", &self.get_range())
            .finish()
    }
}
<|endoftext|>


<commit_before>use std::collections::{ HashSet, HashMap };
use std::sync::RwLock;
use super::blake2::blake2b::blake2b;
use super::COLUMNS;
use super::{
    ClientDB,
    DBValue,
    DBError
};

type DBHashMap = HashMap<Vec<u8>, Vec<u8>>;
type ColumnHashSet = HashSet<String>;

/// An in-memory database implementing the ClientDB trait.
///
/// It is not particularily optimized, it exists for ease and speed of testing. It's not expected
/// this DB would be used outside of tests.
pub struct MemoryDB {
    db: RwLock<DBHashMap>,
    known_columns: RwLock<ColumnHashSet>
}

impl MemoryDB {
    /// Open the in-memory database.
    ///
    /// All columns must be supplied initially, you will get an error if you try to access a column
    /// that was not declared here. This condition is enforced artificially to simulate RocksDB.
    pub fn open() -> Self {
        let db: DBHashMap = HashMap::new();
        let mut known_columns: ColumnHashSet = HashSet::new();
        for col in COLUMNS.iter() {
            known_columns.insert(col.to_string());
        }
        Self {
            db: RwLock::new(db),
            known_columns: RwLock::new(known_columns),
        }
    }

    /// Hashes a key and a column name in order to get a unique key for the supplied column.
    fn get_key_for_col(col: &str, key: &[u8]) -> Vec<u8> {
        blake2b(32, col.as_bytes(), key).as_bytes().to_vec()
    }
}

impl ClientDB for MemoryDB {
    /// Get the value of some key from the database. Returns `None` if the key does not exist.
    fn get(&self, col: &str, key: &[u8])
        -> Result<Option<DBValue>, DBError>
    {
        // Panic if the DB locks are poisoned.
        let db = self.db.read().unwrap();
        let known_columns = self.known_columns.read().unwrap();

        if known_columns.contains(&col.to_string()) {
            let column_key = MemoryDB::get_key_for_col(col, key);
            Ok(db.get(&column_key).and_then(|val| Some(val.clone())))
        } else {
            Err(DBError{ message: "Unknown column".to_string() })
        }
    }

    /// Puts a key in the database.
    fn put(&self, col: &str, key: &[u8], val: &[u8])
        -> Result<(), DBError>
    {
        // Panic if the DB locks are poisoned.
        let mut db = self.db.write().unwrap();
        let known_columns = self.known_columns.read().unwrap();

        if known_columns.contains(&col.to_string()) {
            let column_key = MemoryDB::get_key_for_col(col, key);
            db.insert(column_key, val.to_vec());
            Ok(())
        } else {
            Err(DBError{ message: "Unknown column".to_string() })
        }
    }

    /// Return true if some key exists in some column.
    fn exists(&self, col: &str, key: &[u8])
        -> Result<bool, DBError>
    {
        // Panic if the DB locks are poisoned.
        let db = self.db.read().unwrap();
        let known_columns = self.known_columns.read().unwrap();

        if known_columns.contains(&col.to_string()) {
            let column_key = MemoryDB::get_key_for_col(col, key);
            Ok(db.contains_key(&column_key))
        } else {
            Err(DBError{ message: "Unknown column".to_string() })

        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use super::super::ClientDB;
    use std::thread;
    use std::sync::Arc;
    use super::super::stores::{
        BLOCKS_DB_COLUMN,
        VALIDATOR_DB_COLUMN,
    };

    #[test]
    fn test_memorydb_column_access() {
        let col_a: &str = BLOCKS_DB_COLUMN;
        let col_b: &str = VALIDATOR_DB_COLUMN;

        let column_families = vec![
            col_a,
            col_b,
        ];

        let db = MemoryDB::open();

        /*
         * Testing that if we write to the same key in different columns that
         * there is not an overlap.
         */
        db.put(col_a, "same".as_bytes(), "cat".as_bytes()).unwrap();
        db.put(col_b, "same".as_bytes(), "dog".as_bytes()).unwrap();

        assert_eq!(db.get(col_a, "same".as_bytes()).unwrap().unwrap(), "cat".as_bytes());
        assert_eq!(db.get(col_b, "same".as_bytes()).unwrap().unwrap(), "dog".as_bytes());

    }

    #[test]
    fn test_memorydb_unknown_column_access() {
        let col_a: &str = BLOCKS_DB_COLUMN;
        let col_x: &str = "ColumnX";

        let column_families = vec![
            col_a,
            // col_x is excluded on purpose
        ];

        let db = MemoryDB::open();

        /*
         * Test that we get errors when using undeclared columns
         */
        assert!(db.put(col_a, "cats".as_bytes(), "lol".as_bytes()).is_ok());
        assert!(db.put(col_x, "cats".as_bytes(), "lol".as_bytes()).is_err());

        assert!(db.get(col_a, "cats".as_bytes()).is_ok());
        assert!(db.get(col_x, "cats".as_bytes()).is_err());
    }

    #[test]
    fn test_memorydb_exists() {
        let col_a: &str = BLOCKS_DB_COLUMN;
        let col_b: &str = VALIDATOR_DB_COLUMN;

        let column_families = vec![
            col_a,
            col_b,
        ];

        let db = MemoryDB::open();

        /*
         * Testing that if we write to the same key in different columns that
         * there is not an overlap.
         */
        db.put(col_a, "cats".as_bytes(), "lol".as_bytes()).unwrap();

        assert_eq!(true, db.exists(col_a, "cats".as_bytes()).unwrap());
        assert_eq!(false, db.exists(col_b, "cats".as_bytes()).unwrap());

        assert_eq!(false, db.exists(col_a, "dogs".as_bytes()).unwrap());
        assert_eq!(false, db.exists(col_b, "dogs".as_bytes()).unwrap());
    }

    #[test]
    fn test_memorydb_threading() {
        let col_name: &str = BLOCKS_DB_COLUMN;

        let db = Arc::new(MemoryDB::open());

        let thread_count = 10;
        let write_count = 10;

        // We're execting the product of these numbers to fit in one byte.
        assert!(thread_count * write_count <= 255);

        let mut handles = vec![];
        for t in 0..thread_count {
            let wc = write_count;
            let db = db.clone();
            let col = col_name.clone();
            let handle = thread::spawn(move || {
                for w in 0..wc {
                    let key = (t * w) as u8;
                    let val = 42;
                    db.put(&col, &vec![key], &vec![val]).unwrap();
                }
            });
            handles.push(handle);
        }

        for handle in handles {
            handle.join().unwrap();
        }

        for t in 0..thread_count {
            for w in 0..write_count {
                let key = (t * w) as u8;
                let val = db.get(&col_name, &vec![key]).unwrap().unwrap();
                assert_eq!(vec![42], val);
            }
        }
    }
}
<commit_msg>Fix warnings<commit_after>use std::collections::{ HashSet, HashMap };
use std::sync::RwLock;
use super::blake2::blake2b::blake2b;
use super::COLUMNS;
use super::{
    ClientDB,
    DBValue,
    DBError
};

type DBHashMap = HashMap<Vec<u8>, Vec<u8>>;
type ColumnHashSet = HashSet<String>;

/// An in-memory database implementing the ClientDB trait.
///
/// It is not particularily optimized, it exists for ease and speed of testing. It's not expected
/// this DB would be used outside of tests.
pub struct MemoryDB {
    db: RwLock<DBHashMap>,
    known_columns: RwLock<ColumnHashSet>
}

impl MemoryDB {
    /// Open the in-memory database.
    ///
    /// All columns must be supplied initially, you will get an error if you try to access a column
    /// that was not declared here. This condition is enforced artificially to simulate RocksDB.
    pub fn open() -> Self {
        let db: DBHashMap = HashMap::new();
        let mut known_columns: ColumnHashSet = HashSet::new();
        for col in COLUMNS.iter() {
            known_columns.insert(col.to_string());
        }
        Self {
            db: RwLock::new(db),
            known_columns: RwLock::new(known_columns),
        }
    }

    /// Hashes a key and a column name in order to get a unique key for the supplied column.
    fn get_key_for_col(col: &str, key: &[u8]) -> Vec<u8> {
        blake2b(32, col.as_bytes(), key).as_bytes().to_vec()
    }
}

impl ClientDB for MemoryDB {
    /// Get the value of some key from the database. Returns `None` if the key does not exist.
    fn get(&self, col: &str, key: &[u8])
        -> Result<Option<DBValue>, DBError>
    {
        // Panic if the DB locks are poisoned.
        let db = self.db.read().unwrap();
        let known_columns = self.known_columns.read().unwrap();

        if known_columns.contains(&col.to_string()) {
            let column_key = MemoryDB::get_key_for_col(col, key);
            Ok(db.get(&column_key).and_then(|val| Some(val.clone())))
        } else {
            Err(DBError{ message: "Unknown column".to_string() })
        }
    }

    /// Puts a key in the database.
    fn put(&self, col: &str, key: &[u8], val: &[u8])
        -> Result<(), DBError>
    {
        // Panic if the DB locks are poisoned.
        let mut db = self.db.write().unwrap();
        let known_columns = self.known_columns.read().unwrap();

        if known_columns.contains(&col.to_string()) {
            let column_key = MemoryDB::get_key_for_col(col, key);
            db.insert(column_key, val.to_vec());
            Ok(())
        } else {
            Err(DBError{ message: "Unknown column".to_string() })
        }
    }

    /// Return true if some key exists in some column.
    fn exists(&self, col: &str, key: &[u8])
        -> Result<bool, DBError>
    {
        // Panic if the DB locks are poisoned.
        let db = self.db.read().unwrap();
        let known_columns = self.known_columns.read().unwrap();

        if known_columns.contains(&col.to_string()) {
            let column_key = MemoryDB::get_key_for_col(col, key);
            Ok(db.contains_key(&column_key))
        } else {
            Err(DBError{ message: "Unknown column".to_string() })

        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use super::super::ClientDB;
    use std::thread;
    use std::sync::Arc;
    use super::super::stores::{
        BLOCKS_DB_COLUMN,
        VALIDATOR_DB_COLUMN,
    };

    #[test]
    fn test_memorydb_column_access() {
        let col_a: &str = BLOCKS_DB_COLUMN;
        let col_b: &str = VALIDATOR_DB_COLUMN;

        let db = MemoryDB::open();

        /*
         * Testing that if we write to the same key in different columns that
         * there is not an overlap.
         */
        db.put(col_a, "same".as_bytes(), "cat".as_bytes()).unwrap();
        db.put(col_b, "same".as_bytes(), "dog".as_bytes()).unwrap();

        assert_eq!(db.get(col_a, "same".as_bytes()).unwrap().unwrap(), "cat".as_bytes());
        assert_eq!(db.get(col_b, "same".as_bytes()).unwrap().unwrap(), "dog".as_bytes());

    }

    #[test]
    fn test_memorydb_unknown_column_access() {
        let col_a: &str = BLOCKS_DB_COLUMN;
        let col_x: &str = "ColumnX";

        let db = MemoryDB::open();

        /*
         * Test that we get errors when using undeclared columns
         */
        assert!(db.put(col_a, "cats".as_bytes(), "lol".as_bytes()).is_ok());
        assert!(db.put(col_x, "cats".as_bytes(), "lol".as_bytes()).is_err());

        assert!(db.get(col_a, "cats".as_bytes()).is_ok());
        assert!(db.get(col_x, "cats".as_bytes()).is_err());
    }

    #[test]
    fn test_memorydb_exists() {
        let col_a: &str = BLOCKS_DB_COLUMN;
        let col_b: &str = VALIDATOR_DB_COLUMN;

        let db = MemoryDB::open();

        /*
         * Testing that if we write to the same key in different columns that
         * there is not an overlap.
         */
        db.put(col_a, "cats".as_bytes(), "lol".as_bytes()).unwrap();

        assert_eq!(true, db.exists(col_a, "cats".as_bytes()).unwrap());
        assert_eq!(false, db.exists(col_b, "cats".as_bytes()).unwrap());

        assert_eq!(false, db.exists(col_a, "dogs".as_bytes()).unwrap());
        assert_eq!(false, db.exists(col_b, "dogs".as_bytes()).unwrap());
    }

    #[test]
    fn test_memorydb_threading() {
        let col_name: &str = BLOCKS_DB_COLUMN;

        let db = Arc::new(MemoryDB::open());

        let thread_count = 10;
        let write_count = 10;

        // We're execting the product of these numbers to fit in one byte.
        assert!(thread_count * write_count <= 255);

        let mut handles = vec![];
        for t in 0..thread_count {
            let wc = write_count;
            let db = db.clone();
            let col = col_name.clone();
            let handle = thread::spawn(move || {
                for w in 0..wc {
                    let key = (t * w) as u8;
                    let val = 42;
                    db.put(&col, &vec![key], &vec![val]).unwrap();
                }
            });
            handles.push(handle);
        }

        for handle in handles {
            handle.join().unwrap();
        }

        for t in 0..thread_count {
            for w in 0..write_count {
                let key = (t * w) as u8;
                let val = db.get(&col_name, &vec![key]).unwrap().unwrap();
                assert_eq!(vec![42], val);
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::ascii::AsciiExt;
use std::collections::HashMap;

use error::{Error, Result};

/// `ALPHA =  %x41-5A / %x61-7A ; A-Z / a-z`
pub fn alpha(c: char) -> bool {
    c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z'
}

/// `DIGIT = %x30-39 ; 0-9`
pub fn digit(c: char) -> bool {
    c >= '0' && c <= '9'
}

/// `tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*"
/// / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~"
/// / DIGIT / ALPHA ; any VCHAR, except delimiters`
pub fn tchar(c: char) -> bool {
    c == '!' || c == '#' || c == '$' || c == '%' || c == '&' || c == '\'' || c == '*' ||
    c == '+' || c == '-' || c == '.' || c == '^' ||
    c == '_' || c == '`' || c == '|' || c == '~' || digit(c) || alpha(c)
}

/// `bcharsnospace := DIGIT / ALPHA / "'" / "(" / ")" /
/// "+" / "_" / "," / "-" / "." /
/// "/" / ":" / "=" / "?"`
pub fn bcharsnospace(c: char) -> bool {
    digit(c) || alpha(c) || c == '\'' || c == '(' || c == ')' || c == '+' ||
    c == '_' || c == ',' || c == '-' || c == '.' || c == '/' || c == ':' || c == '=' || c == '?'
}

/// `bchars := bcharsnospace / " "`
pub fn bchars(c: char) -> bool {
    bcharsnospace(c) || c == ' '
}

/// `token = 1*tchar`
pub fn token(s: &str) -> bool {
    !s.is_empty() && s.chars().all(tchar)
}

/// boundary := 0*69<bchars> bcharsnospace
pub fn boundary(s: &str) -> bool {
    !s.is_empty() && s.len() <= 70 && s.chars().all(bchars) &&
    bcharsnospace(s.chars().last().unwrap())
}

fn is_whitespace(c: u8) -> bool {
    c == b' ' || c == b'\n' || c == b'\r' || c == b'\t'
}

fn is_undefined(sequence: &[u8], s: usize) -> bool {
    sequence.len() <= s
}

pub type Bytes = Vec<u8>;

pub fn parse_media_type(sequence: &[u8]) -> Result<(Bytes, Bytes, HashMap<Bytes, Bytes>)> {
    // https://mimesniff.spec.whatwg.org/#parsing-a-mime-type
    if sequence.is_empty() {
        return Err(Error::Invalid);
    }
    let mut s: usize = 0;
    let mut type_ = Vec::new();
    let mut subtype = Vec::new();
    let mut parameters = HashMap::new();
    while is_whitespace(sequence[s]) {
        s += 1;
    }
    let mut t: u8 = 0;
    loop {
        if t > 127 {
            return Err(Error::Invalid);
        }
        if is_undefined(sequence, s) {
            return Err(Error::Invalid);
        }
        if sequence[s] == b'/' {
            break;
        }
        type_.push(sequence[s].to_ascii_lowercase());
        s += 1;
        t += 1;
    }
    s += 1;
    let mut u: u8 = 0;
    loop {
        if u > 127 {
            return Err(Error::Invalid);
        }
        if is_undefined(sequence, s) {
            return Ok((type_, subtype, parameters));
        }
        if is_whitespace(sequence[s]) || sequence[s] == b';' {
            break;
        }
        subtype.push(sequence[s].to_ascii_lowercase());
        s += 1;
        u += 1;
    }
    'L: loop {
        'M: loop {
            if is_undefined(sequence, s) || sequence[s] == b';' {
                break 'M;
            }
            if is_whitespace(sequence[s]) {
                s += 1;
                continue;
            }
            if sequence[s] == b'"' {
                s += 1;
                'N: loop {
                    if (is_undefined(sequence, s) || sequence[s] == b'"') && sequence[s] == b'"' {
                        s += 1;
                        break 'N;
                    }
                    if sequence[s] == b'\\' && !is_undefined(sequence, s + 1) {
                        s += 1
                    }
                    s += 1;
                }
            } else {
                'N2: loop {
                    if is_undefined(sequence, s) || is_whitespace(sequence[s]) ||
                       sequence[s] == b';' {
                        break 'N2;
                    }
                    s += 1;
                }
            }
        }
        if is_undefined(sequence, s) {
            return Ok((type_, subtype, parameters));
        }
        s += 1;
        while is_whitespace(sequence[s]) {
            s += 1;
        }
        let mut name = Vec::new();
        let mut extra = Vec::new();
        let mut p = 0;
        'M2: loop {
            name.append(&mut extra);
            loop {
                if !(is_whitespace(sequence[s]) || sequence[s] == b'=') {
                    if p > 127 {
                        return Err(Error::Invalid);
                    }
                    if is_undefined(sequence, s) {
                        if name != b"" && parameters.get(&name).is_none() {
                            parameters.insert(name, Vec::new());
                        }
                        return Ok((type_, subtype, parameters));
                    }
                    name.push(sequence[s].to_ascii_lowercase());
                    s += 1;
                    p += 1;
                } else {
                    break;
                }
            }
            loop {
                if is_whitespace(sequence[s]) {
                    extra.push(sequence[s]);
                    s += 1;
                    p += 1;
                } else {
                    break;
                }
            }
            if sequence[s] == b'=' {
                break 'M2;
            }
        }
        s += 1;
        loop {
            if !is_whitespace(sequence[s]) {
                break;
            }
            s += 1;
        }
        let mut value = Vec::new();
        if is_undefined(sequence, s) {
            parameters.insert(name, value);
            return Ok((type_, subtype, parameters));
        }
        if sequence[s] == b'"' {
            s += 1;
            'M3: loop {
                if is_undefined(sequence, s) || sequence[s] == b'"' {
                    parameters.insert(name, value);
                    if sequence[s] == b'"' {
                        s += 1
                    }
                    break 'M3;
                }
                if sequence[s] == b'\\' && !is_undefined(sequence, s + 1) {
                    s += 1;
                }
                value.push(sequence[s]);
                s += 1;
            }
        } else {
            'M4: loop {
                if is_undefined(sequence, s) || is_whitespace(sequence[s]) || sequence[s] == b';' {
                    parameters.insert(name, value);
                    break 'M4;
                }
                value.push(sequence[s]);
                s += 1;
            }
        }
    }
}
<commit_msg>fix(parsing): remove unstable feature append<commit_after>use std::ascii::AsciiExt;
use std::collections::HashMap;

use error::{Error, Result};

/// `ALPHA =  %x41-5A / %x61-7A ; A-Z / a-z`
pub fn alpha(c: char) -> bool {
    c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z'
}

/// `DIGIT = %x30-39 ; 0-9`
pub fn digit(c: char) -> bool {
    c >= '0' && c <= '9'
}

/// `tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*"
/// / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~"
/// / DIGIT / ALPHA ; any VCHAR, except delimiters`
pub fn tchar(c: char) -> bool {
    c == '!' || c == '#' || c == '$' || c == '%' || c == '&' || c == '\'' || c == '*' ||
    c == '+' || c == '-' || c == '.' || c == '^' ||
    c == '_' || c == '`' || c == '|' || c == '~' || digit(c) || alpha(c)
}

/// `bcharsnospace := DIGIT / ALPHA / "'" / "(" / ")" /
/// "+" / "_" / "," / "-" / "." /
/// "/" / ":" / "=" / "?"`
pub fn bcharsnospace(c: char) -> bool {
    digit(c) || alpha(c) || c == '\'' || c == '(' || c == ')' || c == '+' ||
    c == '_' || c == ',' || c == '-' || c == '.' || c == '/' || c == ':' || c == '=' || c == '?'
}

/// `bchars := bcharsnospace / " "`
pub fn bchars(c: char) -> bool {
    bcharsnospace(c) || c == ' '
}

/// `token = 1*tchar`
pub fn token(s: &str) -> bool {
    !s.is_empty() && s.chars().all(tchar)
}

/// boundary := 0*69<bchars> bcharsnospace
pub fn boundary(s: &str) -> bool {
    !s.is_empty() && s.len() <= 70 && s.chars().all(bchars) &&
    bcharsnospace(s.chars().last().unwrap())
}

fn is_whitespace(c: u8) -> bool {
    c == b' ' || c == b'\n' || c == b'\r' || c == b'\t'
}

fn is_undefined(sequence: &[u8], s: usize) -> bool {
    sequence.len() <= s
}

pub type Bytes = Vec<u8>;

pub fn parse_media_type(sequence: &[u8]) -> Result<(Bytes, Bytes, HashMap<Bytes, Bytes>)> {
    // https://mimesniff.spec.whatwg.org/#parsing-a-mime-type
    if sequence.is_empty() {
        return Err(Error::Invalid);
    }
    let mut s: usize = 0;
    let mut type_ = Vec::new();
    let mut subtype = Vec::new();
    let mut parameters = HashMap::new();
    while is_whitespace(sequence[s]) {
        s += 1;
    }
    let mut t: u8 = 0;
    loop {
        if t > 127 {
            return Err(Error::Invalid);
        }
        if is_undefined(sequence, s) {
            return Err(Error::Invalid);
        }
        if sequence[s] == b'/' {
            break;
        }
        type_.push(sequence[s].to_ascii_lowercase());
        s += 1;
        t += 1;
    }
    s += 1;
    let mut u: u8 = 0;
    loop {
        if u > 127 {
            return Err(Error::Invalid);
        }
        if is_undefined(sequence, s) {
            return Ok((type_, subtype, parameters));
        }
        if is_whitespace(sequence[s]) || sequence[s] == b';' {
            break;
        }
        subtype.push(sequence[s].to_ascii_lowercase());
        s += 1;
        u += 1;
    }
    'L: loop {
        'M: loop {
            if is_undefined(sequence, s) || sequence[s] == b';' {
                break 'M;
            }
            if is_whitespace(sequence[s]) {
                s += 1;
                continue;
            }
            if sequence[s] == b'"' {
                s += 1;
                'N: loop {
                    if (is_undefined(sequence, s) || sequence[s] == b'"') && sequence[s] == b'"' {
                        s += 1;
                        break 'N;
                    }
                    if sequence[s] == b'\\' && !is_undefined(sequence, s + 1) {
                        s += 1
                    }
                    s += 1;
                }
            } else {
                'N2: loop {
                    if is_undefined(sequence, s) || is_whitespace(sequence[s]) ||
                       sequence[s] == b';' {
                        break 'N2;
                    }
                    s += 1;
                }
            }
        }
        if is_undefined(sequence, s) {
            return Ok((type_, subtype, parameters));
        }
        s += 1;
        while is_whitespace(sequence[s]) {
            s += 1;
        }
        let mut name = Vec::new();
        let mut extra = Vec::new();
        let mut p = 0;
        'M2: loop {
            name.extend(extra.iter());
            loop {
                if !(is_whitespace(sequence[s]) || sequence[s] == b'=') {
                    if p > 127 {
                        return Err(Error::Invalid);
                    }
                    if is_undefined(sequence, s) {
                        if name != b"" && parameters.get(&name).is_none() {
                            parameters.insert(name, Vec::new());
                        }
                        return Ok((type_, subtype, parameters));
                    }
                    name.push(sequence[s].to_ascii_lowercase());
                    s += 1;
                    p += 1;
                } else {
                    break;
                }
            }
            loop {
                if is_whitespace(sequence[s]) {
                    extra.push(sequence[s]);
                    s += 1;
                    p += 1;
                } else {
                    break;
                }
            }
            if sequence[s] == b'=' {
                break 'M2;
            }
        }
        s += 1;
        loop {
            if !is_whitespace(sequence[s]) {
                break;
            }
            s += 1;
        }
        let mut value = Vec::new();
        if is_undefined(sequence, s) {
            parameters.insert(name, value);
            return Ok((type_, subtype, parameters));
        }
        if sequence[s] == b'"' {
            s += 1;
            'M3: loop {
                if is_undefined(sequence, s) || sequence[s] == b'"' {
                    parameters.insert(name, value);
                    if sequence[s] == b'"' {
                        s += 1
                    }
                    break 'M3;
                }
                if sequence[s] == b'\\' && !is_undefined(sequence, s + 1) {
                    s += 1;
                }
                value.push(sequence[s]);
                s += 1;
            }
        } else {
            'M4: loop {
                if is_undefined(sequence, s) || is_whitespace(sequence[s]) || sequence[s] == b';' {
                    parameters.insert(name, value);
                    break 'M4;
                }
                value.push(sequence[s]);
                s += 1;
            }
        }
    }
}
<|endoftext|>


<commit_before>use utils::bigint::M256;
use std::cmp::{min};
use super::{Result, Error};
use super::opcode::Opcode;

pub trait PC {
    fn peek_opcode(&self) -> Result<Opcode>;
    fn read_opcode(&mut self) -> Result<Opcode>;
    fn stop(&mut self);
    fn stopped(&self) -> bool;
    fn read(&mut self, byte_count: usize) -> Result<M256>;
    fn position(&self) -> usize;
    fn jump(&mut self, position: usize);
    fn code(&self) -> &[u8];
}

pub struct VectorPC {
    position: usize,
    code: Vec<u8>,
    stopped: bool
}

impl VectorPC {
    pub fn new(code: &[u8]) -> Self {
        VectorPC {
            position: 0,
            code: code.into(),
            stopped: false,
        }
    }
}

impl PC for VectorPC {
    fn code(&self) -> &[u8] {
        self.code.as_ref()
    }

    fn jump(&mut self, position: usize) {
        self.position = position;
    }

    fn position(&self) -> usize {
        self.position
    }

    fn peek_opcode(&self) -> Result<Opcode> {
        let position = self.position;
        if position >= self.code.len() {
            return Err(Error::PCOverflow);
        }
        let opcode: Opcode = self.code[position].into();
        Ok(opcode)
    }

    fn read_opcode(&mut self) -> Result<Opcode> {
        let position = self.position;
        if position.checked_add(1).is_none() {
            return Err(Error::PCTooLarge);
        }
        if position >= self.code.len() {
            return Err(Error::PCOverflow);
        }
        let opcode: Opcode = self.code[position].into();
        self.position += 1;
        Ok(opcode)
    }

    fn stop(&mut self) {
        self.stopped = true;
    }

    fn stopped(&self) -> bool {
        self.stopped || self.position >= self.code.len()
    }

    fn read(&mut self, byte_count: usize) -> Result<M256> {
        let position = self.position;
        if position.checked_add(byte_count).is_none() || position.checked_add(byte_count).unwrap() >= self.code.len() {
            return Err(Error::PCOverflow);
        }
        self.position += byte_count;
        let max = min(position + byte_count, self.code.len());
        Ok(M256::from(&self.code[position..max]))
    }
}
<commit_msg>Problem: reading more byte_count than code.len() is okay Solution: do not throw PCOverflow<commit_after>use utils::bigint::M256;
use std::cmp::{min};
use super::{Result, Error};
use super::opcode::Opcode;

pub trait PC {
    fn peek_opcode(&self) -> Result<Opcode>;
    fn read_opcode(&mut self) -> Result<Opcode>;
    fn stop(&mut self);
    fn stopped(&self) -> bool;
    fn read(&mut self, byte_count: usize) -> Result<M256>;
    fn position(&self) -> usize;
    fn jump(&mut self, position: usize);
    fn code(&self) -> &[u8];
}

pub struct VectorPC {
    position: usize,
    code: Vec<u8>,
    stopped: bool
}

impl VectorPC {
    pub fn new(code: &[u8]) -> Self {
        VectorPC {
            position: 0,
            code: code.into(),
            stopped: false,
        }
    }
}

impl PC for VectorPC {
    fn code(&self) -> &[u8] {
        self.code.as_ref()
    }

    fn jump(&mut self, position: usize) {
        self.position = position;
    }

    fn position(&self) -> usize {
        self.position
    }

    fn peek_opcode(&self) -> Result<Opcode> {
        let position = self.position;
        if position >= self.code.len() {
            return Err(Error::PCOverflow);
        }
        let opcode: Opcode = self.code[position].into();
        Ok(opcode)
    }

    fn read_opcode(&mut self) -> Result<Opcode> {
        let position = self.position;
        if position.checked_add(1).is_none() {
            return Err(Error::PCTooLarge);
        }
        if position >= self.code.len() {
            return Err(Error::PCOverflow);
        }
        let opcode: Opcode = self.code[position].into();
        self.position += 1;
        Ok(opcode)
    }

    fn stop(&mut self) {
        self.stopped = true;
    }

    fn stopped(&self) -> bool {
        self.stopped || self.position >= self.code.len()
    }

    fn read(&mut self, byte_count: usize) -> Result<M256> {
        let position = self.position;
        if position.checked_add(byte_count).is_none() {
            return Err(Error::PCTooLarge);
        }
        self.position += byte_count;
        let max = min(position + byte_count, self.code.len());
        Ok(M256::from(&self.code[position..max]))
    }
}
<|endoftext|>


<commit_before>pub mod cpu;
pub mod ioapic;
pub mod local_apic;
pub mod pic;
pub mod pit;
pub mod rtc;
pub mod serial;
#[cfg(feature = "acpi")]
pub mod hpet;
#[cfg(feature = "system76_ec_debug")]
pub mod system76_ec;

use crate::paging::KernelMapper;

pub unsafe fn init() {
    pic::init();
    local_apic::init(&mut KernelMapper::lock());
}
pub unsafe fn init_after_acpi()  {
    // this will disable the IOAPIC if needed.
    //ioapic::init(mapper);
}

#[cfg(feature = "acpi")]
unsafe fn init_hpet() -> bool {
    use crate::acpi::ACPI_TABLE;
    if let Some(ref mut hpet) = *ACPI_TABLE.hpet.write() {
        hpet::init(hpet)
    } else {
        false
    }
}

#[cfg(not(feature = "acpi"))]
unsafe fn init_hpet() -> bool {
    false
}

pub unsafe fn init_noncore() {
    if init_hpet() {
        log::info!("HPET used as system timer");
    } else {
        pit::init();
        log::info!("PIT used as system timer");
    }

    rtc::init();
    serial::init();
}

pub unsafe fn init_ap() {
    local_apic::init_ap();
}
<commit_msg>Disable HPET use on x86<commit_after>pub mod cpu;
pub mod ioapic;
pub mod local_apic;
pub mod pic;
pub mod pit;
pub mod rtc;
pub mod serial;
#[cfg(feature = "acpi")]
pub mod hpet;
#[cfg(feature = "system76_ec_debug")]
pub mod system76_ec;

use crate::paging::KernelMapper;

pub unsafe fn init() {
    pic::init();
    local_apic::init(&mut KernelMapper::lock());
}
pub unsafe fn init_after_acpi()  {
    // this will disable the IOAPIC if needed.
    //ioapic::init(mapper);
}

#[cfg(feature = "acpi")]
unsafe fn init_hpet() -> bool {
    use crate::acpi::ACPI_TABLE;
    if let Some(ref mut hpet) = *ACPI_TABLE.hpet.write() {
        hpet::init(hpet)
    } else {
        false
    }
}

#[cfg(not(feature = "acpi"))]
unsafe fn init_hpet() -> bool {
    false
}

pub unsafe fn init_noncore() {
    if false /*TODO: init_hpet()*/ {
        log::info!("HPET used as system timer");
    } else {
        pit::init();
        log::info!("PIT used as system timer");
    }

    rtc::init();
    serial::init();
}

pub unsafe fn init_ap() {
    local_apic::init_ap();
}
<|endoftext|>