<commit_before>//! Many kinds of items or constructs can have generic parameters: functions,
//! structs, impls, traits, etc. This module provides a common HIR for these
//! generic parameters. See also the `Generics` type and the `generics_of` query
//! in rustc.

use std::sync::Arc;

use ra_syntax::ast::{self, NameOwner, TypeParamsOwner, TypeBoundsOwner};

use crate::{
    db::{ HirDatabase, DefDatabase},
    Name, AsName, Function, Struct, Enum, Trait, TypeAlias, ImplBlock, Container, path::Path, type_ref::TypeRef, AdtDef
};

/// Data about a generic parameter (to a function, struct, impl, ...).
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct GenericParam {
    // FIXME: give generic params proper IDs
    pub(crate) idx: u32,
    pub(crate) name: Name,
}

/// Data about the generic parameters of a function, struct, impl, etc.
#[derive(Clone, PartialEq, Eq, Debug, Default)]
pub struct GenericParams {
    pub(crate) parent_params: Option<Arc<GenericParams>>,
    pub(crate) params: Vec<GenericParam>,
    pub(crate) where_predicates: Vec<WherePredicate>,
}

/// A single predicate from a where clause, i.e. `where Type: Trait`. Combined
/// where clauses like `where T: Foo + Bar` are turned into multiple of these.
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct WherePredicate {
    pub(crate) type_ref: TypeRef,
    pub(crate) trait_ref: Path,
}

// FIXME: consts can have type parameters from their parents (i.e. associated consts of traits)
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
pub enum GenericDef {
    Function(Function),
    Struct(Struct),
    Enum(Enum),
    Trait(Trait),
    TypeAlias(TypeAlias),
    ImplBlock(ImplBlock),
}
impl_froms!(GenericDef: Function, Struct, Enum, Trait, TypeAlias, ImplBlock);

impl GenericParams {
    pub(crate) fn generic_params_query(
        db: &impl DefDatabase,
        def: GenericDef,
    ) -> Arc<GenericParams> {
        let mut generics = GenericParams::default();
        let parent = match def {
            GenericDef::Function(it) => it.container(db).map(GenericDef::from),
            GenericDef::TypeAlias(it) => it.container(db).map(GenericDef::from),
            GenericDef::Struct(_) | GenericDef::Enum(_) | GenericDef::Trait(_) => None,
            GenericDef::ImplBlock(_) => None,
        };
        generics.parent_params = parent.map(|p| db.generic_params(p));
        let start = generics.parent_params.as_ref().map(|p| p.params.len()).unwrap_or(0) as u32;
        match def {
            GenericDef::Function(it) => generics.fill(&*it.source(db).1, start),
            GenericDef::Struct(it) => generics.fill(&*it.source(db).1, start),
            GenericDef::Enum(it) => generics.fill(&*it.source(db).1, start),
            GenericDef::Trait(it) => {
                // traits get the Self type as an implicit first type parameter
                generics.params.push(GenericParam { idx: start, name: Name::self_type() });
                generics.fill(&*it.source(db).1, start + 1);
            }
            GenericDef::TypeAlias(it) => generics.fill(&*it.source(db).1, start),
            GenericDef::ImplBlock(it) => generics.fill(&*it.source(db).1, start),
        }

        Arc::new(generics)
    }

    fn fill(&mut self, node: &impl TypeParamsOwner, start: u32) {
        if let Some(params) = node.type_param_list() {
            self.fill_params(params, start)
        }
        if let Some(where_clause) = node.where_clause() {
            self.fill_where_predicates(where_clause);
        }
    }

    fn fill_params(&mut self, params: &ast::TypeParamList, start: u32) {
        for (idx, type_param) in params.type_params().enumerate() {
            let name = type_param.name().map(AsName::as_name).unwrap_or_else(Name::missing);
            let param = GenericParam { idx: idx as u32 + start, name: name.clone() };
            self.params.push(param);

            let type_ref = TypeRef::Path(name.into());
            for bound in type_param
                .type_bound_list()
                .iter()
                .flat_map(|type_bound_list| type_bound_list.bounds())
            {
                self.add_where_predicate_from_bound(bound, type_ref.clone());
            }
        }
    }

    fn fill_where_predicates(&mut self, where_clause: &ast::WhereClause) {
        for pred in where_clause.predicates() {
            let type_ref = match pred.type_ref() {
                Some(type_ref) => type_ref,
                None => continue,
            };
            let type_ref = TypeRef::from_ast(type_ref);
            for bound in pred.type_bound_list().iter().flat_map(|l| l.bounds()) {
                self.add_where_predicate_from_bound(bound, type_ref.clone());
            }
        }
    }

    fn add_where_predicate_from_bound(&mut self, bound: &ast::TypeBound, type_ref: TypeRef) {
        let path = bound
            .type_ref()
            .and_then(|tr| match tr.kind() {
                ast::TypeRefKind::PathType(path) => path.path(),
                _ => None,
            })
            .and_then(Path::from_ast);
        let path = match path {
            Some(p) => p,
            None => return,
        };
        self.where_predicates.push(WherePredicate { type_ref, trait_ref: path });
    }

    pub(crate) fn find_by_name(&self, name: &Name) -> Option<&GenericParam> {
        self.params.iter().find(|p| &p.name == name)
    }

    pub fn count_parent_params(&self) -> usize {
        self.parent_params.as_ref().map(|p| p.count_params_including_parent()).unwrap_or(0)
    }

    pub fn count_params_including_parent(&self) -> usize {
        let parent_count = self.count_parent_params();
        parent_count + self.params.len()
    }

    fn for_each_param<'a>(&'a self, f: &mut impl FnMut(&'a GenericParam)) {
        if let Some(parent) = &self.parent_params {
            parent.for_each_param(f);
        }
        self.params.iter().for_each(f);
    }

    pub fn params_including_parent(&self) -> Vec<&GenericParam> {
        let mut vec = Vec::with_capacity(self.count_params_including_parent());
        self.for_each_param(&mut |p| vec.push(p));
        vec
    }
}

impl GenericDef {
    pub(crate) fn resolver(&self, db: &impl HirDatabase) -> crate::Resolver {
        match self {
            GenericDef::Function(inner) => inner.resolver(db),
            GenericDef::Struct(inner) => inner.resolver(db),
            GenericDef::Enum(inner) => inner.resolver(db),
            GenericDef::Trait(inner) => inner.resolver(db),
            GenericDef::TypeAlias(inner) => inner.resolver(db),
            GenericDef::ImplBlock(inner) => inner.resolver(db),
        }
    }
}

impl From<Container> for GenericDef {
    fn from(c: Container) -> Self {
        match c {
            Container::Trait(trait_) => trait_.into(),
            Container::ImplBlock(impl_block) => impl_block.into(),
        }
    }
}

impl From<crate::adt::AdtDef> for GenericDef {
    fn from(adt: crate::adt::AdtDef) -> Self {
        match adt {
            AdtDef::Struct(s) => s.into(),
            AdtDef::Enum(e) => e.into(),
        }
    }
}

pub trait HasGenericParams {
    fn generic_params(self, db: &impl DefDatabase) -> Arc<GenericParams>;
}

impl<T> HasGenericParams for T
where
    T: Into<GenericDef>,
{
    fn generic_params(self, db: &impl DefDatabase) -> Arc<GenericParams> {
        db.generic_params(self.into())
    }
}
<commit_msg>Add default type to GenericParam<commit_after>//! Many kinds of items or constructs can have generic parameters: functions,
//! structs, impls, traits, etc. This module provides a common HIR for these
//! generic parameters. See also the `Generics` type and the `generics_of` query
//! in rustc.

use std::sync::Arc;

use ra_syntax::ast::{self, NameOwner, TypeParamsOwner, TypeBoundsOwner, DefaultTypeParamOwner};

use crate::{
    db::{ HirDatabase, DefDatabase},
    Name, AsName, Function, Struct, Enum, Trait, TypeAlias, ImplBlock, Container, path::Path, type_ref::TypeRef, AdtDef
};

/// Data about a generic parameter (to a function, struct, impl, ...).
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct GenericParam {
    // FIXME: give generic params proper IDs
    pub(crate) idx: u32,
    pub(crate) name: Name,
    pub(crate) default: Option<Path>,
}

/// Data about the generic parameters of a function, struct, impl, etc.
#[derive(Clone, PartialEq, Eq, Debug, Default)]
pub struct GenericParams {
    pub(crate) parent_params: Option<Arc<GenericParams>>,
    pub(crate) params: Vec<GenericParam>,
    pub(crate) where_predicates: Vec<WherePredicate>,
}

/// A single predicate from a where clause, i.e. `where Type: Trait`. Combined
/// where clauses like `where T: Foo + Bar` are turned into multiple of these.
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct WherePredicate {
    pub(crate) type_ref: TypeRef,
    pub(crate) trait_ref: Path,
}

// FIXME: consts can have type parameters from their parents (i.e. associated consts of traits)
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
pub enum GenericDef {
    Function(Function),
    Struct(Struct),
    Enum(Enum),
    Trait(Trait),
    TypeAlias(TypeAlias),
    ImplBlock(ImplBlock),
}
impl_froms!(GenericDef: Function, Struct, Enum, Trait, TypeAlias, ImplBlock);

impl GenericParams {
    pub(crate) fn generic_params_query(
        db: &impl DefDatabase,
        def: GenericDef,
    ) -> Arc<GenericParams> {
        let mut generics = GenericParams::default();
        let parent = match def {
            GenericDef::Function(it) => it.container(db).map(GenericDef::from),
            GenericDef::TypeAlias(it) => it.container(db).map(GenericDef::from),
            GenericDef::Struct(_) | GenericDef::Enum(_) | GenericDef::Trait(_) => None,
            GenericDef::ImplBlock(_) => None,
        };
        generics.parent_params = parent.map(|p| db.generic_params(p));
        let start = generics.parent_params.as_ref().map(|p| p.params.len()).unwrap_or(0) as u32;
        match def {
            GenericDef::Function(it) => generics.fill(&*it.source(db).1, start),
            GenericDef::Struct(it) => generics.fill(&*it.source(db).1, start),
            GenericDef::Enum(it) => generics.fill(&*it.source(db).1, start),
            GenericDef::Trait(it) => {
                // traits get the Self type as an implicit first type parameter
                generics.params.push(GenericParam {
                    idx: start,
                    name: Name::self_type(),
                    default: None,
                });
                generics.fill(&*it.source(db).1, start + 1);
            }
            GenericDef::TypeAlias(it) => generics.fill(&*it.source(db).1, start),
            GenericDef::ImplBlock(it) => generics.fill(&*it.source(db).1, start),
        }

        Arc::new(generics)
    }

    fn fill(&mut self, node: &impl TypeParamsOwner, start: u32) {
        if let Some(params) = node.type_param_list() {
            self.fill_params(params, start)
        }
        if let Some(where_clause) = node.where_clause() {
            self.fill_where_predicates(where_clause);
        }
    }

    fn fill_params(&mut self, params: &ast::TypeParamList, start: u32) {
        for (idx, type_param) in params.type_params().enumerate() {
            let name = type_param.name().map(AsName::as_name).unwrap_or_else(Name::missing);
            let default = type_param.default_type().and_then(|t| t.path()).and_then(Path::from_ast);

            let param = GenericParam { idx: idx as u32 + start, name: name.clone(), default };
            self.params.push(param);

            let type_ref = TypeRef::Path(name.into());
            for bound in type_param
                .type_bound_list()
                .iter()
                .flat_map(|type_bound_list| type_bound_list.bounds())
            {
                self.add_where_predicate_from_bound(bound, type_ref.clone());
            }
        }
    }

    fn fill_where_predicates(&mut self, where_clause: &ast::WhereClause) {
        for pred in where_clause.predicates() {
            let type_ref = match pred.type_ref() {
                Some(type_ref) => type_ref,
                None => continue,
            };
            let type_ref = TypeRef::from_ast(type_ref);
            for bound in pred.type_bound_list().iter().flat_map(|l| l.bounds()) {
                self.add_where_predicate_from_bound(bound, type_ref.clone());
            }
        }
    }

    fn add_where_predicate_from_bound(&mut self, bound: &ast::TypeBound, type_ref: TypeRef) {
        let path = bound
            .type_ref()
            .and_then(|tr| match tr.kind() {
                ast::TypeRefKind::PathType(path) => path.path(),
                _ => None,
            })
            .and_then(Path::from_ast);
        let path = match path {
            Some(p) => p,
            None => return,
        };
        self.where_predicates.push(WherePredicate { type_ref, trait_ref: path });
    }

    pub(crate) fn find_by_name(&self, name: &Name) -> Option<&GenericParam> {
        self.params.iter().find(|p| &p.name == name)
    }

    pub fn count_parent_params(&self) -> usize {
        self.parent_params.as_ref().map(|p| p.count_params_including_parent()).unwrap_or(0)
    }

    pub fn count_params_including_parent(&self) -> usize {
        let parent_count = self.count_parent_params();
        parent_count + self.params.len()
    }

    fn for_each_param<'a>(&'a self, f: &mut impl FnMut(&'a GenericParam)) {
        if let Some(parent) = &self.parent_params {
            parent.for_each_param(f);
        }
        self.params.iter().for_each(f);
    }

    pub fn params_including_parent(&self) -> Vec<&GenericParam> {
        let mut vec = Vec::with_capacity(self.count_params_including_parent());
        self.for_each_param(&mut |p| vec.push(p));
        vec
    }
}

impl GenericDef {
    pub(crate) fn resolver(&self, db: &impl HirDatabase) -> crate::Resolver {
        match self {
            GenericDef::Function(inner) => inner.resolver(db),
            GenericDef::Struct(inner) => inner.resolver(db),
            GenericDef::Enum(inner) => inner.resolver(db),
            GenericDef::Trait(inner) => inner.resolver(db),
            GenericDef::TypeAlias(inner) => inner.resolver(db),
            GenericDef::ImplBlock(inner) => inner.resolver(db),
        }
    }
}

impl From<Container> for GenericDef {
    fn from(c: Container) -> Self {
        match c {
            Container::Trait(trait_) => trait_.into(),
            Container::ImplBlock(impl_block) => impl_block.into(),
        }
    }
}

impl From<crate::adt::AdtDef> for GenericDef {
    fn from(adt: crate::adt::AdtDef) -> Self {
        match adt {
            AdtDef::Struct(s) => s.into(),
            AdtDef::Enum(e) => e.into(),
        }
    }
}

pub trait HasGenericParams {
    fn generic_params(self, db: &impl DefDatabase) -> Arc<GenericParams>;
}

impl<T> HasGenericParams for T
where
    T: Into<GenericDef>,
{
    fn generic_params(self, db: &impl DefDatabase) -> Arc<GenericParams> {
        db.generic_params(self.into())
    }
}
<|endoftext|>


<commit_before>//! Types for persistent data unit schemas
//!
//! The differences between the `RoomV1Pdu` schema and the `RoomV3Pdu` schema are
//! that the `RoomV1Pdu` takes an `event_id` field (`RoomV3Pdu` does not), and
//! `auth_events` and `prev_events` take `Vec<(EventId, EventHash)> rather than
//! `Vec<EventId>` in `RoomV3Pdu`.
//!
//! The stubbed versions of each PDU type remove the `event_id` field (if any)
//! and the `room_id` field for use in PDU templates.

use std::collections::BTreeMap;

use js_int::UInt;
use ruma_common::MilliSecondsSinceUnixEpoch;
use ruma_events::EventType;
use ruma_identifiers::{EventId, RoomId, ServerNameBox, ServerSigningKeyId, UserId};
use serde::{Deserialize, Serialize};
use serde_json::Value as JsonValue;

/// Enum for PDU schemas
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(untagged)]
pub enum Pdu {
    /// PDU for room versions 1 and 2.
    RoomV1Pdu(RoomV1Pdu),

    /// PDU for room versions 3 and above.
    RoomV3Pdu(RoomV3Pdu),
}

/// A 'persistent data unit' (event) for room versions 1 and 2.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct RoomV1Pdu {
    /// Event ID for the PDU.
    pub event_id: EventId,

    /// The room this event belongs to.
    pub room_id: RoomId,

    /// The user id of the user who sent this event.
    pub sender: UserId,

    #[cfg(not(feature = "unstable-pre-spec"))]
    #[cfg_attr(docsrs, doc(cfg(not(feature = "unstable-pre-spec"))))]
    /// The `server_name` of the homeserver that created this event.
    pub origin: String,

    /// Timestamp (milliseconds since the UNIX epoch) on originating homeserver
    /// of when this event was created.
    pub origin_server_ts: MilliSecondsSinceUnixEpoch,

    // TODO: Encode event type as content enum variant, like event enums do
    /// The event's type.
    #[serde(rename = "type")]
    pub kind: EventType,

    /// The event's content.
    pub content: JsonValue,

    /// A key that determines which piece of room state the event represents.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub state_key: Option<String>,

    /// Event IDs for the most recent events in the room that the homeserver was
    /// aware of when it created this event.
    #[serde(skip_serializing_if = "Vec::is_empty")]
    pub prev_events: Vec<(EventId, EventHash)>,

    /// The maximum depth of the `prev_events`, plus one.
    pub depth: UInt,

    /// Event IDs for the authorization events that would allow this event to be
    /// in the room.
    #[serde(skip_serializing_if = "Vec::is_empty")]
    pub auth_events: Vec<(EventId, EventHash)>,

    /// For redaction events, the ID of the event being redacted.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub redacts: Option<EventId>,

    /// Additional data added by the origin server but not covered by the
    /// signatures.
    #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
    pub unsigned: BTreeMap<String, JsonValue>,

    /// Content hashes of the PDU.
    pub hashes: EventHash,

    /// Signatures for the PDU.
    pub signatures: BTreeMap<ServerNameBox, BTreeMap<ServerSigningKeyId, String>>,
}

/// A 'persistent data unit' (event) for room versions 3 and beyond.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct RoomV3Pdu {
    /// The room this event belongs to.
    pub room_id: RoomId,

    /// The user id of the user who sent this event.
    pub sender: UserId,

    #[cfg(not(feature = "unstable-pre-spec"))]
    #[cfg_attr(docsrs, doc(cfg(not(feature = "unstable-pre-spec"))))]
    /// The `server_name` of the homeserver that created this event.
    pub origin: String,

    /// Timestamp (milliseconds since the UNIX epoch) on originating homeserver
    /// of when this event was created.
    pub origin_server_ts: MilliSecondsSinceUnixEpoch,

    // TODO: Encode event type as content enum variant, like event enums do
    /// The event's type.
    #[serde(rename = "type")]
    pub kind: EventType,

    /// The event's content.
    pub content: JsonValue,

    /// A key that determines which piece of room state the event represents.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub state_key: Option<String>,

    /// Event IDs for the most recent events in the room that the homeserver was
    /// aware of when it created this event.
    pub prev_events: Vec<EventId>,

    /// The maximum depth of the `prev_events`, plus one.
    pub depth: UInt,

    /// Event IDs for the authorization events that would allow this event to be
    /// in the room.
    pub auth_events: Vec<EventId>,

    /// For redaction events, the ID of the event being redacted.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub redacts: Option<EventId>,

    /// Additional data added by the origin server but not covered by the
    /// signatures.
    #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
    pub unsigned: BTreeMap<String, JsonValue>,

    /// Content hashes of the PDU.
    pub hashes: EventHash,

    /// Signatures for the PDU.
    pub signatures: BTreeMap<ServerNameBox, BTreeMap<ServerSigningKeyId, String>>,
}

/// Content hashes of a PDU.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct EventHash {
    /// The SHA-256 hash.
    pub sha256: String,
}
<commit_msg>events: Fix import<commit_after>//! Types for persistent data unit schemas
//!
//! The differences between the `RoomV1Pdu` schema and the `RoomV3Pdu` schema are
//! that the `RoomV1Pdu` takes an `event_id` field (`RoomV3Pdu` does not), and
//! `auth_events` and `prev_events` take `Vec<(EventId, EventHash)> rather than
//! `Vec<EventId>` in `RoomV3Pdu`.
//!
//! The stubbed versions of each PDU type remove the `event_id` field (if any)
//! and the `room_id` field for use in PDU templates.

use std::collections::BTreeMap;

use js_int::UInt;
use ruma_common::MilliSecondsSinceUnixEpoch;
use ruma_identifiers::{EventId, RoomId, ServerNameBox, ServerSigningKeyId, UserId};
use serde::{Deserialize, Serialize};
use serde_json::Value as JsonValue;

use crate::EventType;

/// Enum for PDU schemas
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(untagged)]
pub enum Pdu {
    /// PDU for room versions 1 and 2.
    RoomV1Pdu(RoomV1Pdu),

    /// PDU for room versions 3 and above.
    RoomV3Pdu(RoomV3Pdu),
}

/// A 'persistent data unit' (event) for room versions 1 and 2.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct RoomV1Pdu {
    /// Event ID for the PDU.
    pub event_id: EventId,

    /// The room this event belongs to.
    pub room_id: RoomId,

    /// The user id of the user who sent this event.
    pub sender: UserId,

    #[cfg(not(feature = "unstable-pre-spec"))]
    #[cfg_attr(docsrs, doc(cfg(not(feature = "unstable-pre-spec"))))]
    /// The `server_name` of the homeserver that created this event.
    pub origin: String,

    /// Timestamp (milliseconds since the UNIX epoch) on originating homeserver
    /// of when this event was created.
    pub origin_server_ts: MilliSecondsSinceUnixEpoch,

    // TODO: Encode event type as content enum variant, like event enums do
    /// The event's type.
    #[serde(rename = "type")]
    pub kind: EventType,

    /// The event's content.
    pub content: JsonValue,

    /// A key that determines which piece of room state the event represents.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub state_key: Option<String>,

    /// Event IDs for the most recent events in the room that the homeserver was
    /// aware of when it created this event.
    #[serde(skip_serializing_if = "Vec::is_empty")]
    pub prev_events: Vec<(EventId, EventHash)>,

    /// The maximum depth of the `prev_events`, plus one.
    pub depth: UInt,

    /// Event IDs for the authorization events that would allow this event to be
    /// in the room.
    #[serde(skip_serializing_if = "Vec::is_empty")]
    pub auth_events: Vec<(EventId, EventHash)>,

    /// For redaction events, the ID of the event being redacted.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub redacts: Option<EventId>,

    /// Additional data added by the origin server but not covered by the
    /// signatures.
    #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
    pub unsigned: BTreeMap<String, JsonValue>,

    /// Content hashes of the PDU.
    pub hashes: EventHash,

    /// Signatures for the PDU.
    pub signatures: BTreeMap<ServerNameBox, BTreeMap<ServerSigningKeyId, String>>,
}

/// A 'persistent data unit' (event) for room versions 3 and beyond.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct RoomV3Pdu {
    /// The room this event belongs to.
    pub room_id: RoomId,

    /// The user id of the user who sent this event.
    pub sender: UserId,

    #[cfg(not(feature = "unstable-pre-spec"))]
    #[cfg_attr(docsrs, doc(cfg(not(feature = "unstable-pre-spec"))))]
    /// The `server_name` of the homeserver that created this event.
    pub origin: String,

    /// Timestamp (milliseconds since the UNIX epoch) on originating homeserver
    /// of when this event was created.
    pub origin_server_ts: MilliSecondsSinceUnixEpoch,

    // TODO: Encode event type as content enum variant, like event enums do
    /// The event's type.
    #[serde(rename = "type")]
    pub kind: EventType,

    /// The event's content.
    pub content: JsonValue,

    /// A key that determines which piece of room state the event represents.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub state_key: Option<String>,

    /// Event IDs for the most recent events in the room that the homeserver was
    /// aware of when it created this event.
    pub prev_events: Vec<EventId>,

    /// The maximum depth of the `prev_events`, plus one.
    pub depth: UInt,

    /// Event IDs for the authorization events that would allow this event to be
    /// in the room.
    pub auth_events: Vec<EventId>,

    /// For redaction events, the ID of the event being redacted.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub redacts: Option<EventId>,

    /// Additional data added by the origin server but not covered by the
    /// signatures.
    #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
    pub unsigned: BTreeMap<String, JsonValue>,

    /// Content hashes of the PDU.
    pub hashes: EventHash,

    /// Signatures for the PDU.
    pub signatures: BTreeMap<ServerNameBox, BTreeMap<ServerSigningKeyId, String>>,
}

/// Content hashes of a PDU.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct EventHash {
    /// The SHA-256 hash.
    pub sha256: String,
}
<|endoftext|>


<commit_before>use clap::App;

fn main() {
    // This example shows how to create an application with several arguments using usage strings, which can be
    // far less verbose that shown in 01b_QuickExample.rs, but is more readable. The downside is you cannot set
    // the more advanced configuration options using this method (well...actually you can, you'll see ;) )
    //
    // The example below is functionally identical to the 01b_quick_example.rs and 01c_quick_example.rs
    //
    // Create an application with 5 possible arguments (2 auto generated) and 2 subcommands (1 auto generated)
    //    - A config file
    //        + Uses "-c filename" or "--config filename"
    //    - An output file
    //        + A positional argument (i.e. "$ myapp output_filename")
    //    - A debug flag
    //        + Uses "-d" or "--debug"
    //        + Allows multiple occurrences of such as "-dd" (for vary levels of debugging, as an example)
    //    - A help flag (automatically generated by clap)
    //        + Uses "-h" or "--help" (Only autogenerated if you do NOT specify your own "-h" or "--help")
    //    - A version flag (automatically generated by clap)
    //        + Uses "-V" or "--version" (Only autogenerated if you do NOT specify your own "-V" or "--version")
    //    - A subcommand "test" (subcommands behave like their own apps, with their own arguments
    //        + Used by "$ myapp test" with the following arguments
    //            > A list flag
    //                = Uses "-l" (usage is "$ myapp test -l"
    //            > A help flag (automatically generated by clap
    //                = Uses "-h" or "--help" (full usage "$ myapp test -h" or "$ myapp test --help")
    //            > A version flag (automatically generated by clap
    //                = Uses "-V" or "--version" (full usage "$ myapp test -V" or "$ myapp test --version")
    //    - A subcommand "help" (automatically generated by clap because we specified a subcommand of our own)
    //        + Used by "$ myapp help" (same functionality as "-h" or "--help")
    let matches = App::new("MyApp")
        .version("1.0")
        .author("Kevin K. <kbknapp@gmail.com>")
        .about("Does awesome things")
        .arg("-c, --config=[FILE] 'Sets a custom config file'")
        .arg("<output> 'Sets an optional output file'")
        .arg("-d... 'Turn debugging information on'")
        .subcommand(
            App::new("test")
                .about("does testing things")
                .arg("-l, --list 'lists test values'"),
        )
        .get_matches();

    // You can check the value provided by positional arguments, or option arguments
    if let Some(o) = matches.value_of("output") {
        println!("Value for output: {}", o);
    }

    if let Some(c) = matches.value_of("config") {
        println!("Value for config: {}", c);
    }

    // You can see how many times a particular flag or argument occurred
    // Note, only flags can have multiple occurrences
    match matches.occurrences_of("d") {
        0 => println!("Debug mode is off"),
        1 => println!("Debug mode is kind of on"),
        2 => println!("Debug mode is on"),
        _ => println!("Don't be crazy"),
    }

    // You can check for the existence of subcommands, and if found use their
    // matches just as you would the top level app
    if let Some(ref matches) = matches.subcommand_matches("test") {
        // "$ myapp test" was run
        if matches.is_present("list") {
            // "$ myapp test -l" was run
            println!("Printing testing lists...");
        } else {
            println!("Not printing testing lists...");
        }
    }

    // Continued program logic goes here...
}
<commit_msg>Make debug option in example 01a_quick_example follow specification.<commit_after>use clap::App;

fn main() {
    // This example shows how to create an application with several arguments using usage strings, which can be
    // far less verbose that shown in 01b_QuickExample.rs, but is more readable. The downside is you cannot set
    // the more advanced configuration options using this method (well...actually you can, you'll see ;) )
    //
    // The example below is functionally identical to the 01b_quick_example.rs and 01c_quick_example.rs
    //
    // Create an application with 5 possible arguments (2 auto generated) and 2 subcommands (1 auto generated)
    //    - A config file
    //        + Uses "-c filename" or "--config filename"
    //    - An output file
    //        + A positional argument (i.e. "$ myapp output_filename")
    //    - A debug flag
    //        + Uses "-d" or "--debug"
    //        + Allows multiple occurrences of such as "-dd" (for vary levels of debugging, as an example)
    //    - A help flag (automatically generated by clap)
    //        + Uses "-h" or "--help" (Only autogenerated if you do NOT specify your own "-h" or "--help")
    //    - A version flag (automatically generated by clap)
    //        + Uses "-V" or "--version" (Only autogenerated if you do NOT specify your own "-V" or "--version")
    //    - A subcommand "test" (subcommands behave like their own apps, with their own arguments
    //        + Used by "$ myapp test" with the following arguments
    //            > A list flag
    //                = Uses "-l" (usage is "$ myapp test -l"
    //            > A help flag (automatically generated by clap
    //                = Uses "-h" or "--help" (full usage "$ myapp test -h" or "$ myapp test --help")
    //            > A version flag (automatically generated by clap
    //                = Uses "-V" or "--version" (full usage "$ myapp test -V" or "$ myapp test --version")
    //    - A subcommand "help" (automatically generated by clap because we specified a subcommand of our own)
    //        + Used by "$ myapp help" (same functionality as "-h" or "--help")
    let matches = App::new("MyApp")
        .version("1.0")
        .author("Kevin K. <kbknapp@gmail.com>")
        .about("Does awesome things")
        .arg("-c, --config=[FILE] 'Sets a custom config file'")
        .arg("<output> 'Sets an optional output file'")
        .arg("-d..., --debug... 'Turn debugging information on'")
        .subcommand(
            App::new("test")
                .about("does testing things")
                .arg("-l, --list 'lists test values'"),
        )
        .get_matches();

    // You can check the value provided by positional arguments, or option arguments
    if let Some(o) = matches.value_of("output") {
        println!("Value for output: {}", o);
    }

    if let Some(c) = matches.value_of("config") {
        println!("Value for config: {}", c);
    }

    // You can see how many times a particular flag or argument occurred
    // Note, only flags can have multiple occurrences
    match matches.occurrences_of("debug") {
        0 => println!("Debug mode is off"),
        1 => println!("Debug mode is kind of on"),
        2 => println!("Debug mode is on"),
        _ => println!("Don't be crazy"),
    }

    // You can check for the existence of subcommands, and if found use their
    // matches just as you would the top level app
    if let Some(ref matches) = matches.subcommand_matches("test") {
        // "$ myapp test" was run
        if matches.is_present("list") {
            // "$ myapp test -l" was run
            println!("Printing testing lists...");
        } else {
            println!("Not printing testing lists...");
        }
    }

    // Continued program logic goes here...
}
<|endoftext|>


<commit_before>
use std::io::*;
use std::fs::File;
use byteorder::{BigEndian, WriteBytesExt, ReadBytesExt};
use std::fs::OpenOptions;
use std::cmp::Ord;
use std::cmp::Ordering;

#[derive(Debug)]
pub struct Bstar {
    pub root: u64,
    pub order: u64,
    src: File,
}

impl Bstar {

    pub fn load(path: &str) -> Result<Bstar>{

        let mut _file = OpenOptions::new().read(true).write(true).append(true).open(path);

        let mut file = match _file {
            Ok(f) => f,
            Err(err) => return Err(err),
        };

        try!(file.seek(SeekFrom::Start(0)));

        let root = try!(file.read_u64::<BigEndian>());
        let order = try!(file.read_u64::<BigEndian>());
        Ok(Bstar { root: root, order: order, src: file } )

    }

    pub fn create(path: &str, order: u64) -> Result<Bstar> {
        let mut _file = OpenOptions::new().read(true).write(true).append(true).create(true).open(path);

        let mut file = match _file {
            Ok(f) => f,
            Err(err) => return Err(err),
        };

        try!(file.seek(SeekFrom::Start(0)));

        // IMPORTANT: Update the root start when changing B-tree fields!
        try!(file.write_u64::<BigEndian>(16));
        try!(file.write_u64::<BigEndian>(order));

        Ok(Bstar { root: 16, order: order ,src: file } )
    }

    pub fn get_root(&mut self) -> Result<Bnode> {
        Ok(try!(Bnode::read(&mut self.src, self.order, self.root)))
    }

    pub fn insert(&mut self, key: u64, addr: u64 ) -> Result<Bnode> {
        try!(self.src.seek(SeekFrom::Start(self.root)));
        let mut list = SortedList::with_capacity((self.order * 2) as usize);
        list.insert(KeyAddr::new(key, addr));
        list.insert(KeyAddr::new(key, addr));
        list.insert(KeyAddr::new(key, addr));
        let node = Bnode { node_list: list, father: 0, is_leaf: 1 };
        try!(node.write(&mut self.src, self.order, self.root));
        Ok(node)
    }
}

#[derive(Debug,RustcDecodable, RustcEncodable)]
pub struct Bnode {
    pub node_list: SortedList<KeyAddr>,
    pub father: u64,
    // 0 = no leaf, else leaf
    pub is_leaf: u8,

}

impl Bnode {

    pub fn read(file: &mut File,order: u64, index: u64) -> Result<Bnode> {
        file.seek(SeekFrom::Start(index));
        let father = try!(file.read_u64::<BigEndian>());
        let is_leaf = try!(file.read_u8());
        let elementcount = try!(file.read_u64::<BigEndian>());

        let mut list = SortedList::with_capacity((order * 2) as usize);
        for i in 0..elementcount {
            let key = try!(file.read_u64::<BigEndian>());
            let addr = try!(file.read_u64::<BigEndian>());
            list.insert(KeyAddr::new(key, addr));
        }

        Ok(Bnode { node_list: list, father: father, is_leaf: is_leaf } )
    }

    pub fn write(&self, file: &mut File,order: u64, index: u64) -> Result<()> {
        file.seek(SeekFrom::Start(index));
        try!(file.write_u64::<BigEndian>(self.father));
        try!(file.write_u8(self.is_leaf));
        try!(file.write_u64::<BigEndian>(self.node_list.elementcount));
        for i in 0..order * 2 {
            if self.node_list.get(i as usize).is_some() {
                let keyaddr = self.node_list.get(i as usize).unwrap();
                println!("{:?}", keyaddr );
                try!(file.write_u64::<BigEndian>(keyaddr.key));
                try!(file.write_u64::<BigEndian>(keyaddr.addr));
            }
            try!(file.write_u64::<BigEndian>(0));
            try!(file.write_u64::<BigEndian>(0));
        }

        Ok(())
    }

}

#[derive(Debug,RustcDecodable, RustcEncodable)]
pub struct SortedList<T: Comparable> {
    pub list: Vec<T>,
    pub elementcount: u64,

}

impl<T: Comparable> SortedList<T> {
    pub fn new() -> SortedList<T> {
        SortedList { list: Vec::new(), elementcount: 0}
    }

    pub fn with_capacity(size: usize) -> SortedList<T> {
        SortedList { list: Vec::with_capacity(size), elementcount: 0 }
    }

    pub fn insert(&mut self, value: T) -> bool {
        self.list.push(value);
        self.elementcount +=1;
        true
    }

    pub fn get(&self, index: usize) -> Option<&T> {

        if index >= 0 && index <= ( self.elementcount -1 ) as usize {
            Some(&self.list[index])
        } else {
            None
        }
    }

}

#[derive(Debug,RustcDecodable, RustcEncodable, Clone)]
pub struct KeyAddr {
    pub key: u64,
    pub addr: u64,
}

impl KeyAddr {
    pub fn new(key: u64, addr: u64) -> KeyAddr {
        KeyAddr { key: key, addr: addr}
    }
}

impl Comparable for KeyAddr {
    fn cmp(&self, other:&Self) -> CompRes {
        CompRes::Sthan
    }
}

pub enum CompRes {
    Equ,
    Gthan,
    Sthan
}

pub trait Comparable {
    fn cmp(&self, &Self) -> CompRes;
}
<commit_msg>Changed LinkedList implementation to accept all PartialOrd types<commit_after>
use std::io::*;
use std::fs::File;
use byteorder::{BigEndian, WriteBytesExt, ReadBytesExt};
use std::fs::OpenOptions;
use std::cmp::Ord;
use std::cmp::Ordering;

#[derive(Debug)]
pub struct Bstar {
    pub root: u64,
    pub order: u64,
    src: File,
}

impl Bstar {

    pub fn load(path: &str) -> Result<Bstar>{

        let mut _file = OpenOptions::new().read(true).write(true).append(true).open(path);

        let mut file = match _file {
            Ok(f) => f,
            Err(err) => return Err(err),
        };

        try!(file.seek(SeekFrom::Start(0)));

        let root = try!(file.read_u64::<BigEndian>());
        let order = try!(file.read_u64::<BigEndian>());
        Ok(Bstar { root: root, order: order, src: file } )

    }

    pub fn create(path: &str, order: u64) -> Result<Bstar> {
        let mut _file = OpenOptions::new().read(true).write(true).append(true).create(true).open(path);

        let mut file = match _file {
            Ok(f) => f,
            Err(err) => return Err(err),
        };

        try!(file.seek(SeekFrom::Start(0)));

        // IMPORTANT: Update the root start when changing B-tree fields!
        try!(file.write_u64::<BigEndian>(16));
        try!(file.write_u64::<BigEndian>(order));

        Ok(Bstar { root: 16, order: order ,src: file } )
    }

    pub fn get_root(&mut self) -> Result<Bnode> {
        Ok(try!(Bnode::read(&mut self.src, self.order, self.root)))
    }

    pub fn insert(&mut self, key: u64, addr: u64 ) -> Result<Bnode> {
        try!(self.src.seek(SeekFrom::Start(self.root)));
        let mut list = SortedList::with_capacity((self.order * 2) as usize);
        list.insert(KeyAddr::new(key, addr));
        let node = Bnode { node_list: list, father: 0, is_leaf: 1 };
        try!(node.write(&mut self.src, self.order, self.root));
        Ok(node)
    }
}

#[derive(Debug,RustcDecodable, RustcEncodable)]
pub struct Bnode {
    pub node_list: SortedList<KeyAddr<u64>>,
    pub father: u64,
    // 0 = no leaf, else leaf
    pub is_leaf: u8,

}

impl Bnode {

    pub fn read(file: &mut File,order: u64, index: u64) -> Result<Bnode> {
        file.seek(SeekFrom::Start(index));
        let father = try!(file.read_u64::<BigEndian>());
        let is_leaf = try!(file.read_u8());
        let elementcount = try!(file.read_u64::<BigEndian>());

        let mut list = SortedList::with_capacity((order * 2) as usize);
        for i in 0..elementcount {
            let key = try!(file.read_u64::<BigEndian>());
            let addr = try!(file.read_u64::<BigEndian>());
            list.insert(KeyAddr::new(key, addr));
        }

        Ok(Bnode { node_list: list, father: father, is_leaf: is_leaf } )
    }

    pub fn write(&self, file: &mut File,order: u64, index: u64) -> Result<()> {
        file.seek(SeekFrom::Start(index));
        try!(file.write_u64::<BigEndian>(self.father));
        try!(file.write_u8(self.is_leaf));
        try!(file.write_u64::<BigEndian>(self.node_list.elementcount));
        for i in 0..order * 2 {
            if self.node_list.get(i as usize).is_some() {
                let keyaddr = self.node_list.get(i as usize).unwrap();
                println!("{:?}", keyaddr );
                try!(file.write_u64::<BigEndian>(keyaddr.key));
                try!(file.write_u64::<BigEndian>(keyaddr.addr));
            }
            try!(file.write_u64::<BigEndian>(0));
            try!(file.write_u64::<BigEndian>(0));
        }

        Ok(())
    }

}

#[derive(Debug,RustcDecodable, RustcEncodable)]
pub struct SortedList<T: PartialOrd> {
    pub list: Vec<T>,
    pub elementcount: u64,

}

impl<T: PartialOrd> SortedList<T> {
    pub fn new() -> SortedList<T> {
        SortedList { list: Vec::new(), elementcount: 0}
    }

    pub fn with_capacity(size: usize) -> SortedList<T> {
        SortedList { list: Vec::with_capacity(size), elementcount: 0 }
    }

    pub fn insert(&mut self, value: T) -> bool {
        self.list.push(value);
        self.elementcount +=1;
        true
    }

    pub fn get(&self, index: usize) -> Option<&T> {

        if index >= 0 && index <= ( self.elementcount -1 ) as usize {
            Some(&self.list[index])
        } else {
            None
        }
    }

}

#[derive(Debug,RustcDecodable, RustcEncodable, Clone)]
pub struct KeyAddr<T: PartialOrd> {
    pub key: T,
    pub addr: u64,
}

impl<T: PartialOrd> KeyAddr<T> {
    pub fn new(key: T, addr: u64) -> KeyAddr<T> {
        KeyAddr { key: key, addr: addr}
    }
}

impl<T: PartialOrd> PartialOrd for KeyAddr<T> {
    fn partial_cmp(&self, other:&Self) -> Option<Ordering> {
        self.key.partial_cmp(&other.key)
    }
}

impl<T: PartialOrd> PartialEq for KeyAddr<T> {
    fn eq(&self, other: &Self) -> bool {
        self.key.eq(&other.key)
    }
}
<|endoftext|>


<commit_before>// P_2_1_1_01
//
// Generative Gestaltung – Creative Coding im Web
// ISBN: 978-3-87439-902-9, First Edition, Hermann Schmidt, Mainz, 2018
// Benedikt Groß, Hartmut Bohnacker, Julia Laub, Claudius Lazzeroni
// with contributions by Joey Lee and Niels Poldervaart
// Copyright 2018
//
// http://www.generative-gestaltung.de
//
// 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.

/**
 * changing strokeweight and strokecaps on diagonals in a grid
 *
 * MOUSE
 * position x          : left diagonal strokeweight
 * position y          : right diagonal strokeweight
 * left click          : new random layout
 *
 * KEYS
 * 1                   : round strokecap
 * 2                   : square strokecap
 * 3                   : butt strokecap
 * s                   : save png
 */
use nannou::lyon::tessellation::LineCap;
use nannou::prelude::*;
use nannou::rand::rngs::StdRng;
use nannou::rand::{Rng, SeedableRng};

fn main() {
    nannou::app(model).run();
}

struct Model {
    tile_count: u32,
    act_random_seed: u64,
    act_stroke_cap: LineCap,
}

fn model(app: &App) -> Model {
    let _window = app
        .new_window()
        .size(600, 600)
        .view(view)
        .mouse_pressed(mouse_pressed)
        .key_released(key_released)
        .key_pressed(key_pressed)
        .build()
        .unwrap();

    Model {
        tile_count: 20,
        act_random_seed: 0,
        act_stroke_cap: LineCap::Round,
    }
}

fn view(app: &App, model: &Model, frame: Frame) {
    // Prepare to draw.
    let draw = app.draw();
    draw.background().color(BLACK);
    let win = app.window_rect();

    let mut rng = StdRng::seed_from_u64(model.act_random_seed);

    for grid_y in 0..model.tile_count {
        for grid_x in 0..model.tile_count {
            let tile_w = win.w() / model.tile_count as f32;
            let tile_h = win.h() / model.tile_count as f32;
            let pos_x = win.left() + tile_w * grid_x as f32;
            let pos_y = (win.top() - tile_h) - tile_h * grid_y as f32;
            let mx = clamp(win.right() + app.mouse.x, 0.0, win.w());
            let my = clamp(win.top() - app.mouse.y, 0.0, win.h());

            let toggle = rng.gen::<bool>();

            if toggle == false {
                draw.line()
                    .weight(mx / 20.0)
                    .caps(model.act_stroke_cap)
                    .points(
                        pt2(pos_x, pos_y),
                        pt2(
                            pos_x + win.w() / model.tile_count as f32,
                            pos_y + win.h() / model.tile_count as f32,
                        ),
                    );
            }
            if toggle == true {
                draw.line()
                    .weight(my / 20.0)
                    .caps(model.act_stroke_cap)
                    .points(
                        pt2(pos_x, pos_y + win.w() / model.tile_count as f32),
                        pt2(pos_x + win.h() / model.tile_count as f32, pos_y),
                    );
            }
        }
    }

    // Write to the window frame.
    draw.to_frame(app, &frame).unwrap();
}

fn mouse_pressed(_app: &App, model: &mut Model, _button: MouseButton) {
    model.act_random_seed = (random_f32() * 100000.0) as u64;
}
fn key_released(_app: &App, model: &mut Model, key: Key) {
    if key == Key::Key1 {
        model.act_stroke_cap = LineCap::Round;
    }
    if key == Key::Key2 {
        model.act_stroke_cap = LineCap::Square;
    }
    if key == Key::Key3 {
        model.act_stroke_cap = LineCap::Butt;
    }
}
fn key_pressed(app: &App, _model: &mut Model, key: Key) {
    if key == Key::S {
        app.main_window()
            .capture_frame(app.exe_name().unwrap() + ".png");
    }
}
<commit_msg>Fix p_2_1_1_01.rs drawing black lines on black background<commit_after>// P_2_1_1_01
//
// Generative Gestaltung – Creative Coding im Web
// ISBN: 978-3-87439-902-9, First Edition, Hermann Schmidt, Mainz, 2018
// Benedikt Groß, Hartmut Bohnacker, Julia Laub, Claudius Lazzeroni
// with contributions by Joey Lee and Niels Poldervaart
// Copyright 2018
//
// http://www.generative-gestaltung.de
//
// 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.

/**
 * changing strokeweight and strokecaps on diagonals in a grid
 *
 * MOUSE
 * position x          : left diagonal strokeweight
 * position y          : right diagonal strokeweight
 * left click          : new random layout
 *
 * KEYS
 * 1                   : round strokecap
 * 2                   : square strokecap
 * 3                   : butt strokecap
 * s                   : save png
 */
use nannou::lyon::tessellation::LineCap;
use nannou::prelude::*;
use nannou::rand::rngs::StdRng;
use nannou::rand::{Rng, SeedableRng};

fn main() {
    nannou::app(model).run();
}

struct Model {
    tile_count: u32,
    act_random_seed: u64,
    act_stroke_cap: LineCap,
}

fn model(app: &App) -> Model {
    let _window = app
        .new_window()
        .size(600, 600)
        .view(view)
        .mouse_pressed(mouse_pressed)
        .key_released(key_released)
        .key_pressed(key_pressed)
        .build()
        .unwrap();

    Model {
        tile_count: 20,
        act_random_seed: 0,
        act_stroke_cap: LineCap::Round,
    }
}

fn view(app: &App, model: &Model, frame: Frame) {
    // Prepare to draw.
    let draw = app.draw();
    draw.background().color(WHITE);
    let win = app.window_rect();

    let mut rng = StdRng::seed_from_u64(model.act_random_seed);

    for grid_y in 0..model.tile_count {
        for grid_x in 0..model.tile_count {
            let tile_w = win.w() / model.tile_count as f32;
            let tile_h = win.h() / model.tile_count as f32;
            let pos_x = win.left() + tile_w * grid_x as f32;
            let pos_y = (win.top() - tile_h) - tile_h * grid_y as f32;
            let mx = clamp(win.right() + app.mouse.x, 0.0, win.w());
            let my = clamp(win.top() - app.mouse.y, 0.0, win.h());

            let toggle = rng.gen::<bool>();

            if toggle == false {
                draw.line()
                    .weight(mx / 20.0)
                    .caps(model.act_stroke_cap)
                    .points(
                        pt2(pos_x, pos_y),
                        pt2(
                            pos_x + win.w() / model.tile_count as f32,
                            pos_y + win.h() / model.tile_count as f32,
                        ),
                    );
            }
            if toggle == true {
                draw.line()
                    .weight(my / 20.0)
                    .caps(model.act_stroke_cap)
                    .points(
                        pt2(pos_x, pos_y + win.w() / model.tile_count as f32),
                        pt2(pos_x + win.h() / model.tile_count as f32, pos_y),
                    );
            }
        }
    }

    // Write to the window frame.
    draw.to_frame(app, &frame).unwrap();
}

fn mouse_pressed(_app: &App, model: &mut Model, _button: MouseButton) {
    model.act_random_seed = (random_f32() * 100000.0) as u64;
}
fn key_released(_app: &App, model: &mut Model, key: Key) {
    if key == Key::Key1 {
        model.act_stroke_cap = LineCap::Round;
    }
    if key == Key::Key2 {
        model.act_stroke_cap = LineCap::Square;
    }
    if key == Key::Key3 {
        model.act_stroke_cap = LineCap::Butt;
    }
}
fn key_pressed(app: &App, _model: &mut Model, key: Key) {
    if key == Key::S {
        app.main_window()
            .capture_frame(app.exe_name().unwrap() + ".png");
    }
}
<|endoftext|>


<commit_before>use syn::{self, Token, TokenTree, Ident, BinOpToken, DelimToken};
use quote::{Tokens, ToTokens};
use std::collections::HashMap;

#[derive(Debug)]
pub struct Args<'a> {
    input: &'a str,
    pub tokens: Tokens,
}

#[derive(Debug, Clone, Copy, PartialEq)]
enum Type {
    Expr,
    Closure,
    List,
    Object,
}

#[derive(Debug, Clone)]
enum Group {
    Expr(Vec<TokenTree>),
    Closure(Vec<TokenTree>),
    List(Vec<Group>),
    Object(HashMap<String, Group>),
}

impl<'a> Args<'a> {
    pub fn new(input: &str) -> Args {
        Args {
            input: input.trim(),
            tokens: Tokens::new(),
        }
    }

    pub fn process(&mut self) -> &mut Self {
        if self.input.is_empty() {
            self.tokens = quote!(reql::Term::new());
            return self;
        }

        let args = format!("args!({})", self.input);
        let body = self.body();

        self.tokens = quote!({
            #[allow(unused_imports)]
            use reql::{IntoArg, Arg, Term};

            let mut args = Arg::new();
            args.set_string(#args);
            #body
            args
        });

        self
    }

    fn body(&mut self) -> Tokens {
        let tt = syn::parse_token_trees(self.input).expect("failed to parse token tree");
        let mut tokens = Tokens::new();
        let args = self.group_by_comma(tt);
        let last = args.len()-1;
        for (i, arg) in args.into_iter().enumerate() {
            arg.tokenise("args", i == last).to_tokens(&mut tokens);
        }
        tokens
    }

    fn finalise_arg(&self, args: &mut Vec<Group>, tokens: &mut Vec<TokenTree>, typ: &mut Type) {
        let group = match *typ {
            Type::Expr => Group::Expr(tokens.clone()),
            Type::Closure => Group::Closure(tokens.clone()),
            Type::List => Group::List(self.group_by_comma(tokens.clone())),
            Type::Object => Group::Object(self.hash_from_tokens(tokens.clone())),
        };
        args.push(group);
        *tokens = Vec::new();
        *typ = Type::Expr;
    }

    fn hash_from_tokens(&self, tt: Vec<TokenTree>) -> HashMap<String, Group> {
        let mut hash = HashMap::new();

        let mut is_key = true;
        let mut key = String::new();
        let mut val = Vec::new();
        let last = tt.len()-1;

        for (i, tree) in tt.into_iter().enumerate() {
            if let TokenTree::Token(Token::Colon) = tree {
                if key.is_empty() {
                    panic!("A key of an object cannot be empty.");
                }
                is_key = false;
                continue;
            }
            if is_key {
                key = match tree {
                    TokenTree::Token(Token::Literal(syn::Lit::Str(key, _))) => key,
                    tree => {
                        let mut tokens = Tokens::new();
                        tree.to_tokens(&mut tokens);
                        tokens.to_string()
                    }
                };
                continue;
            }
            let token_is_comma = if let TokenTree::Token(Token::Comma) = tree { true } else { false };
            let on_last_token = if i == last { true } else { false };
            let val_end = token_is_comma || on_last_token;
            if !token_is_comma {
                val.push(tree);
            }
            if val_end {
                let arg = self.group_by_comma(val.clone());
                let len = arg.len();
                if len == 0 {
                    panic!("An object key cannot have no value.");
                } else if len == 1 {
                    hash.insert(key.clone(), arg.into_iter().next().unwrap());
                } else {
                    panic!("An object key cannot have more than 1 values.");
                }
                is_key = true;
                val = Vec::new();
            }
        }

        hash
    }

    fn group_by_comma(&self, tt: Vec<TokenTree>) -> Vec<Group> {
        let mut args = Vec::new();
        let mut tokens = Vec::new();
        let mut typ = Type::Expr;
        let last = tt.len()-1;

        for (i, tree) in tt.into_iter().enumerate() {
            let token_is_comma = if let TokenTree::Token(Token::Comma) = tree { true } else { false };
            let on_last_token = if i == last { true } else { false };
            let arg_end = token_is_comma || on_last_token;

            match Type::new(&tokens, &tree, &mut typ) {
                Type::Expr => {
                    if !token_is_comma {
                        tokens.push(tree);
                    }
                    if arg_end {
                        self.finalise_arg(&mut args, &mut tokens, &mut typ);
                    }
                }
                Type::Closure => {
                    if !token_is_comma {
                        tokens.push(tree);
                    }
                    if arg_end {
                        self.finalise_arg(&mut args, &mut tokens, &mut typ);
                    }
                }
                Type::List => {
                    if !token_is_comma {
                        if let TokenTree::Delimited(d) = tree {
                            tokens = d.tts;
                        }
                    }
                    if arg_end {
                        self.finalise_arg(&mut args, &mut tokens, &mut typ);
                    }
                }
                Type::Object => {
                    if !token_is_comma {
                        if let TokenTree::Delimited(d) = tree {
                            tokens = d.tts;
                        }
                    }
                    if arg_end {
                        self.finalise_arg(&mut args, &mut tokens, &mut typ);
                    }
                }
            }
        }
        args
    }
}

impl Group {
    fn tokenise(self, var: &str, last: bool) -> Tokens {
        let mut tokens = Tokens::new();
        let var = Ident::from(var);
        match self {
            Group::Expr(tt) => {
                let mut expr = Tokens::new();
                for token in tt {
                    token.to_tokens(&mut expr);
                }
                quote!(#var.add_arg(#expr.into_arg());)
                    .to_tokens(&mut tokens);
            }
            Group::Closure(_closure) => {
                unimplemented!();
            }
            Group::List(tt) => {
                let mut list = quote!(let mut list_arg = Arg::new(););
                for group in tt {
                    quote!(let mut list_val = Arg::new();)
                        .to_tokens(&mut list);
                    group.tokenise("list_val", false)
                        .to_tokens(&mut list);
                    quote!(list_arg.add_arg(list_val);)
                        .to_tokens(&mut list);
                }
                quote!(#var.add_arg(list_arg);)
                        .to_tokens(&mut list);
                list.to_tokens(&mut tokens);
            }
            Group::Object(tt) => {
                let mut obj = Tokens::new();
                if !last {
                    quote!(let mut obj_arg = Arg::new();)
                        .to_tokens(&mut obj);
                }
                for (key, group) in tt {
                    quote!(let mut obj_val = Arg::new();)
                        .to_tokens(&mut obj);
                    group.tokenise("obj_val", false)
                        .to_tokens(&mut obj);
                    if last {
                        quote!(
                            match Arg::create_term_pair(#key, obj_val) {
                                Ok(temp_pair) => #var.add_opt(temp_pair),
                                Err(error) => #var.set_term(Err(error)),
                            })
                        .to_tokens(&mut obj);
                    } else {
                        quote!(
                            match Arg::create_term_pair(#key, obj_val) {
                                Ok(temp_pair) => obj_arg.add_opt(temp_pair),
                                Err(error) => obj_arg.set_term(Err(error)),
                            })
                        .to_tokens(&mut obj);
                    }
                }
                if !last {
                    quote!(#var.add_arg(obj_arg);)
                        .to_tokens(&mut obj);
                }
                obj.to_tokens(&mut tokens);
            }
        }
        tokens
    }
}

impl Type {
    fn new(tokens: &Vec<TokenTree>, tree: &TokenTree, typ: &mut Type) -> Type {
        if tokens.is_empty() {
            if let TokenTree::Delimited(ref d) = *tree {
                if d.delim == DelimToken::Bracket { *typ = Type::List; }
                else if d.delim == DelimToken::Brace { *typ = Type::Object; }
            }
            else if let TokenTree::Token(Token::BinOp(BinOpToken::Or)) = *tree {
                *typ = Type::Closure;
            }
        } else if tokens.len() == 1 {
            if let TokenTree::Token(Token::BinOp(BinOpToken::Or)) = *tree {
                if let TokenTree::Token(Token::Ident(ref i)) = tokens[0] {
                    if i == "move" {
                        *typ = Type::Closure;
                    }
                }
            }
        }
        *typ
    }
}
<commit_msg>Support closures with no params<commit_after>use syn::{self, Token, TokenTree, Ident, BinOpToken, DelimToken};
use quote::{Tokens, ToTokens};
use std::collections::HashMap;

#[derive(Debug)]
pub struct Args<'a> {
    input: &'a str,
    pub tokens: Tokens,
}

#[derive(Debug, Clone, Copy, PartialEq)]
enum Type {
    Expr,
    Closure,
    List,
    Object,
}

#[derive(Debug, Clone)]
enum Group {
    Expr(Vec<TokenTree>),
    Closure(Vec<TokenTree>),
    List(Vec<Group>),
    Object(HashMap<String, Group>),
}

impl<'a> Args<'a> {
    pub fn new(input: &str) -> Args {
        Args {
            input: input.trim(),
            tokens: Tokens::new(),
        }
    }

    pub fn process(&mut self) -> &mut Self {
        if self.input.is_empty() {
            self.tokens = quote!(reql::Term::new());
            return self;
        }

        let args = format!("args!({})", self.input);
        let body = self.body();

        self.tokens = quote!({
            #[allow(unused_imports)]
            use reql::{IntoArg, Arg, Term};

            let mut args = Arg::new();
            args.set_string(#args);
            #body
            args
        });

        self
    }

    fn body(&mut self) -> Tokens {
        let tt = syn::parse_token_trees(self.input).expect("failed to parse token tree");
        let mut tokens = Tokens::new();
        let args = self.group_by_comma(tt);
        let last = args.len()-1;
        for (i, arg) in args.into_iter().enumerate() {
            arg.tokenise("args", i == last).to_tokens(&mut tokens);
        }
        tokens
    }

    fn finalise_arg(&self, args: &mut Vec<Group>, tokens: &mut Vec<TokenTree>, typ: &mut Type) {
        let group = match *typ {
            Type::Expr => Group::Expr(tokens.clone()),
            Type::Closure => Group::Closure(tokens.clone()),
            Type::List => Group::List(self.group_by_comma(tokens.clone())),
            Type::Object => Group::Object(self.hash_from_tokens(tokens.clone())),
        };
        args.push(group);
        *tokens = Vec::new();
        *typ = Type::Expr;
    }

    fn hash_from_tokens(&self, tt: Vec<TokenTree>) -> HashMap<String, Group> {
        let mut hash = HashMap::new();

        let mut is_key = true;
        let mut key = String::new();
        let mut val = Vec::new();
        let last = tt.len()-1;

        for (i, tree) in tt.into_iter().enumerate() {
            if let TokenTree::Token(Token::Colon) = tree {
                if key.is_empty() {
                    panic!("A key of an object cannot be empty.");
                }
                is_key = false;
                continue;
            }
            if is_key {
                key = match tree {
                    TokenTree::Token(Token::Literal(syn::Lit::Str(key, _))) => key,
                    tree => {
                        let mut tokens = Tokens::new();
                        tree.to_tokens(&mut tokens);
                        tokens.to_string()
                    }
                };
                continue;
            }
            let token_is_comma = if let TokenTree::Token(Token::Comma) = tree { true } else { false };
            let on_last_token = if i == last { true } else { false };
            let val_end = token_is_comma || on_last_token;
            if !token_is_comma {
                val.push(tree);
            }
            if val_end {
                let arg = self.group_by_comma(val.clone());
                let len = arg.len();
                if len == 0 {
                    panic!("An object key cannot have no value.");
                } else if len == 1 {
                    hash.insert(key.clone(), arg.into_iter().next().unwrap());
                } else {
                    panic!("An object key cannot have more than 1 values.");
                }
                is_key = true;
                val = Vec::new();
            }
        }

        hash
    }

    fn group_by_comma(&self, tt: Vec<TokenTree>) -> Vec<Group> {
        let mut args = Vec::new();
        let mut tokens = Vec::new();
        let mut typ = Type::Expr;
        let last = tt.len()-1;

        for (i, tree) in tt.into_iter().enumerate() {
            let token_is_comma = if let TokenTree::Token(Token::Comma) = tree { true } else { false };
            let on_last_token = if i == last { true } else { false };
            let arg_end = token_is_comma || on_last_token;

            match Type::new(&tokens, &tree, &mut typ) {
                Type::Expr => {
                    if !token_is_comma {
                        tokens.push(tree);
                    }
                    if arg_end {
                        self.finalise_arg(&mut args, &mut tokens, &mut typ);
                    }
                }
                Type::Closure => {
                    if !token_is_comma {
                        tokens.push(tree);
                    }
                    if arg_end {
                        self.finalise_arg(&mut args, &mut tokens, &mut typ);
                    }
                }
                Type::List => {
                    if !token_is_comma {
                        if let TokenTree::Delimited(d) = tree {
                            tokens = d.tts;
                        }
                    }
                    if arg_end {
                        self.finalise_arg(&mut args, &mut tokens, &mut typ);
                    }
                }
                Type::Object => {
                    if !token_is_comma {
                        if let TokenTree::Delimited(d) = tree {
                            tokens = d.tts;
                        }
                    }
                    if arg_end {
                        self.finalise_arg(&mut args, &mut tokens, &mut typ);
                    }
                }
            }
        }
        args
    }
}

impl Group {
    fn tokenise(self, var: &str, last: bool) -> Tokens {
        let mut tokens = Tokens::new();
        let var = Ident::from(var);
        match self {
            Group::Expr(tt) => {
                let mut expr = Tokens::new();
                for token in tt {
                    token.to_tokens(&mut expr);
                }
                quote!(#var.add_arg(#expr.into_arg());)
                    .to_tokens(&mut tokens);
            }
            Group::Closure(_closure) => {
                unimplemented!();
            }
            Group::List(tt) => {
                let mut list = quote!(let mut list_arg = Arg::new(););
                for group in tt {
                    quote!(let mut list_val = Arg::new();)
                        .to_tokens(&mut list);
                    group.tokenise("list_val", false)
                        .to_tokens(&mut list);
                    quote!(list_arg.add_arg(list_val);)
                        .to_tokens(&mut list);
                }
                quote!(#var.add_arg(list_arg);)
                        .to_tokens(&mut list);
                list.to_tokens(&mut tokens);
            }
            Group::Object(tt) => {
                let mut obj = Tokens::new();
                if !last {
                    quote!(let mut obj_arg = Arg::new();)
                        .to_tokens(&mut obj);
                }
                for (key, group) in tt {
                    quote!(let mut obj_val = Arg::new();)
                        .to_tokens(&mut obj);
                    group.tokenise("obj_val", false)
                        .to_tokens(&mut obj);
                    if last {
                        quote!(
                            match Arg::create_term_pair(#key, obj_val) {
                                Ok(temp_pair) => #var.add_opt(temp_pair),
                                Err(error) => #var.set_term(Err(error)),
                            })
                        .to_tokens(&mut obj);
                    } else {
                        quote!(
                            match Arg::create_term_pair(#key, obj_val) {
                                Ok(temp_pair) => obj_arg.add_opt(temp_pair),
                                Err(error) => obj_arg.set_term(Err(error)),
                            })
                        .to_tokens(&mut obj);
                    }
                }
                if !last {
                    quote!(#var.add_arg(obj_arg);)
                        .to_tokens(&mut obj);
                }
                obj.to_tokens(&mut tokens);
            }
        }
        tokens
    }
}

impl Type {
    fn new(tokens: &Vec<TokenTree>, tree: &TokenTree, typ: &mut Type) -> Type {
        if tokens.is_empty() {
            if let TokenTree::Delimited(ref d) = *tree {
                if d.delim == DelimToken::Bracket { *typ = Type::List; }
                else if d.delim == DelimToken::Brace { *typ = Type::Object; }
            }
            else if let TokenTree::Token(Token::BinOp(BinOpToken::Or)) = *tree {
                *typ = Type::Closure;
            }
            else if let TokenTree::Token(Token::OrOr) = *tree {
                *typ = Type::Closure;
            }
        } else if tokens.len() == 1 {
            if let TokenTree::Token(Token::BinOp(BinOpToken::Or)) = *tree {
                if let TokenTree::Token(Token::Ident(ref i)) = tokens[0] {
                    if i == "move" {
                        *typ = Type::Closure;
                    }
                }
            }
        }
        *typ
    }
}
<|endoftext|>


<commit_before>//
// Copyright 2018 The Project Oak Authors
//
// 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.
//

//! Functionality to help Oak Nodes interact with gRPC.

pub use crate::proto::code::Code;
use crate::{proto, OakError};
use log::{error, warn};
pub use proto::grpc_encap::{GrpcRequest, GrpcResponse};
use protobuf::ProtobufEnum;

pub mod client;
mod invocation;
pub use invocation::Invocation;

/// Result type that uses a [`proto::status::Status`] type for error values.
pub type Result<T> = std::result::Result<T, proto::status::Status>;

/// Helper to create a gRPC status object.
pub fn build_status(code: Code, msg: &str) -> proto::status::Status {
    let mut status = proto::status::Status::new();
    status.set_code(code.value());
    status.set_message(msg.to_string());
    status
}

/// Channel-holding object that encapsulates response messages into
/// `GrpcResponse` wrapper messages and writes serialized versions to a send
/// channel.
pub struct ChannelResponseWriter {
    sender: crate::io::Sender<GrpcResponse>,
}

/// Indicate whether a write method should leave the current gRPC method
/// invocation open or close it.
#[derive(PartialEq, Clone, Debug)]
pub enum WriteMode {
    KeepOpen,
    Close,
}

impl ChannelResponseWriter {
    pub fn new(sender: crate::io::Sender<GrpcResponse>) -> Self {
        ChannelResponseWriter { sender }
    }

    /// Retrieve the Oak handle underlying the writer object.
    pub fn handle(self) -> crate::WriteHandle {
        self.sender.handle
    }

    /// Write out a gRPC response and optionally close out the method
    /// invocation.  Any errors from the channel are silently dropped.
    pub fn write<T: protobuf::Message>(
        &mut self,
        rsp: &T,
        mode: WriteMode,
    ) -> std::result::Result<(), OakError> {
        // Put the serialized response into a GrpcResponse message wrapper and
        // serialize it into the channel.
        let mut grpc_rsp = GrpcResponse::new();
        let mut any = protobuf::well_known_types::Any::new();
        rsp.write_to_writer(&mut any.value)?;
        grpc_rsp.set_rsp_msg(any);
        grpc_rsp.set_last(match mode {
            WriteMode::KeepOpen => false,
            WriteMode::Close => true,
        });
        self.sender.send(&grpc_rsp)?;
        if mode == WriteMode::Close {
            self.sender.close()?;
        }
        Ok(())
    }

    /// Write an empty gRPC response and optionally close out the method
    /// invocation. Any errors from the channel are silently dropped.
    pub fn write_empty(&mut self, mode: WriteMode) -> std::result::Result<(), OakError> {
        let mut grpc_rsp = GrpcResponse::new();
        grpc_rsp.set_rsp_msg(protobuf::well_known_types::Any::new());
        grpc_rsp.set_last(match mode {
            WriteMode::KeepOpen => false,
            WriteMode::Close => true,
        });
        self.sender.send(&grpc_rsp)?;
        if mode == WriteMode::Close {
            self.sender.close()?;
        }
        Ok(())
    }

    /// Close out the gRPC method invocation with the given final result.
    pub fn close(&mut self, result: Result<()>) -> std::result::Result<(), OakError> {
        // Build a final GrpcResponse message wrapper and serialize it into the
        // channel.
        let mut grpc_rsp = GrpcResponse::new();
        grpc_rsp.set_last(true);
        if let Err(status) = result {
            grpc_rsp.set_status(status);
        }
        self.sender.send(&grpc_rsp)?;
        self.sender.close()?;
        Ok(())
    }
}

/// Trait for Oak Nodes that act as a gRPC services.
///
/// An `OakNode` instance is normally passed to [`oak::run_event_loop`], to
/// allow repeated invocation of its `invoke()` method.
pub trait OakNode {
    /// Process a single gRPC method invocation.
    ///
    /// The method name is provided by `method` and the incoming serialized gRPC
    /// request is held in `req`.  Response messages should be written using
    /// `writer.write`, followed by `writer.close`.
    fn invoke(&mut self, method: &str, req: &[u8], writer: ChannelResponseWriter);
}

impl<T: OakNode> crate::Node<Invocation> for T {
    /// Handle incoming gRPC events for an [`OakNode`].
    ///
    /// Invoking the given `node`'s [`invoke`] method for each incoming request that
    /// arrives on the inbound channel as a serialized [`Invocation`] object,
    /// giving the [`invoke`] method the outbound channel for encapsulated responses
    /// to be written to.
    ///
    /// [`invoke`]: OakNode::invoke
    fn handle_command(
        &mut self,
        invocation: Invocation,
    ) -> std::result::Result<(), crate::OakError> {
        // Read a single encapsulated request message from the read half.
        let req: GrpcRequest = invocation.request_receiver.receive()?;
        // Since we are expecting a single message, close the channel immediately.
        // This will change when we implement client streaming (#97).
        invocation.request_receiver.close()?;
        if !req.last {
            // TODO(#97): Implement client streaming.
            panic!("Support for streaming requests not yet implemented");
        }
        self.invoke(
            &req.method_name,
            req.get_req_msg().value.as_slice(),
            ChannelResponseWriter::new(invocation.response_sender),
        );
        Ok(())
    }
}

/// Encapsulate a protocol buffer message in a GrpcRequest wrapper using the
/// given method name.
pub fn encap_request<T: protobuf::Message>(req: T, method_name: &str) -> Option<GrpcRequest> {
    // Put the request in a GrpcRequest wrapper and serialize it.
    let mut grpc_req = GrpcRequest::new();
    grpc_req.set_method_name(method_name.to_string());
    let mut any = protobuf::well_known_types::Any::new();
    if let Err(e) = req.write_to_writer(&mut any.value) {
        warn!("failed to serialize gRPC request: {}", e);
        return None;
    };
    grpc_req.set_req_msg(any);
    grpc_req.set_last(true);
    Some(grpc_req)
}

/// Extract a protocol buffer message from a GrpcResponse wrapper.
/// Returns the message together with an indicator of whether this is the last
/// response.
pub fn decap_response<T: protobuf::Message>(mut grpc_rsp: GrpcResponse) -> Result<(T, bool)> {
    if grpc_rsp.get_status().get_code() != Code::OK.value() {
        return Err(grpc_rsp.take_status());
    }
    let rsp = protobuf::parse_from_bytes(&grpc_rsp.get_rsp_msg().value).map_err(|proto_err| {
        build_status(
            Code::INVALID_ARGUMENT,
            &format!("message parsing failed: {}", proto_err),
        )
    })?;
    Ok((rsp, grpc_rsp.get_last()))
}

/// Helper to inject a (single) gRPC request message via a notification channel,
/// in the same manner as the gRPC pseudo-Node does, and return a channel for
/// reading responses from.
pub fn invoke_grpc_method_stream<R>(
    method_name: &str,
    req: R,
    invocation_channel: &crate::io::Sender<Invocation>,
) -> Result<crate::io::Receiver<GrpcResponse>>
where
    R: protobuf::Message,
{
    // Create a new channel for request message delivery.
    let (req_sender, req_receiver) =
        crate::io::channel_create::<GrpcRequest>().expect("failed to create channel");

    // Put the request in a GrpcRequest wrapper and send it into the request
    // message channel.
    let req = encap_request(req, method_name).expect("failed to serialize GrpcRequest");
    req_sender.send(&req).expect("failed to write to channel");
    req_sender.close().expect("failed to close channel");

    // Create a new channel for responses to arrive on.
    let (rsp_sender, rsp_receiver) =
        crate::io::channel_create::<GrpcResponse>().expect("failed to create channel");

    // Build an Invocation holding the two channels and send it down the
    // specified channel.
    let invocation = Invocation {
        request_receiver: req_receiver.clone(),
        response_sender: rsp_sender.clone(),
    };
    invocation_channel
        .send(&invocation)
        .expect("failed to write invocation to channel");
    req_receiver.close().expect("failed to close channel");
    rsp_sender.close().expect("failed to close channel");

    Ok(rsp_receiver)
}

/// Helper to inject a (single) gRPC request message via a notification channel,
/// in the same manner as the gRPC pseudo-Node does, and collect a (single)
/// response.
pub fn invoke_grpc_method<R, Q>(
    method_name: &str,
    req: R,
    invocation_channel: &crate::io::Sender<Invocation>,
) -> Result<Q>
where
    R: protobuf::Message,
    Q: protobuf::Message,
{
    let rsp_receiver = invoke_grpc_method_stream(method_name, req, invocation_channel)?;
    // Read a single encapsulated response.
    let grpc_rsp = rsp_receiver.receive().map_err(|status| {
        error!("failed to receive response: {:?}", status);
        build_status(
            Code::INTERNAL,
            &format!("failed to receive gRPC response: {:?}", status),
        )
    })?;
    rsp_receiver.close().expect("failed to close channel");
    let (rsp, last) = decap_response(grpc_rsp)?;
    if !last {
        panic!("Expected single final response");
    }

    Ok(rsp)
}

/// Generic function that handles request deserialization and response
/// serialization (and sending down a channel) for a function that handles a
/// request/response pair.
///
/// Panics if [de-]serialization or channel operations fail.
pub fn handle_req_rsp<C, R, Q>(mut node_fn: C, req: &[u8], mut writer: ChannelResponseWriter)
where
    C: FnMut(R) -> Result<Q>,
    R: protobuf::Message,
    Q: protobuf::Message,
{
    let r: R = protobuf::parse_from_bytes(&req).expect("Failed to parse request protobuf message");
    let result = match node_fn(r) {
        Ok(rsp) => writer.write(&rsp, WriteMode::Close),
        Err(status) => writer.close(Err(status)),
    };
    if let Err(e) = result {
        panic!("Failed to process response: {:?}", e)
    }
}

/// Generic function that handles request deserialization and response
/// serialization (and sending down a channel) for a function that handles a
/// request and streams responses.
///
/// Panics if [de-]serialization or channel operations fail.
pub fn handle_req_stream<C, R>(mut node_fn: C, req: &[u8], writer: ChannelResponseWriter)
where
    C: FnMut(R, ChannelResponseWriter),
    R: protobuf::Message,
{
    let r: R = protobuf::parse_from_bytes(&req).expect("Failed to parse request protobuf message");
    node_fn(r, writer)
}

/// Generic function that handles request deserialization and response
/// serialization (and sending down a channel) for a function that handles a
/// stream of requests to produce a response.
///
/// Panics if [de-]serialization or channel operations fail.
pub fn handle_stream_rsp<C, R, Q>(mut node_fn: C, req: &[u8], mut writer: ChannelResponseWriter)
where
    C: FnMut(Vec<R>) -> Result<Q>,
    R: protobuf::Message,
    Q: protobuf::Message,
{
    // TODO(#97): better client-side streaming
    let rr: Vec<R> =
        vec![protobuf::parse_from_bytes(&req).expect("Failed to parse request protobuf message")];
    let result = match node_fn(rr) {
        Ok(rsp) => writer.write(&rsp, WriteMode::Close),
        Err(status) => writer.close(Err(status)),
    };
    if let Err(e) = result {
        panic!("Failed to process response: {:?}", e)
    }
}

/// Generic function that handles request deserialization and response
/// serialization (and sending down a channel) for a function that handles a
/// stream of requests to produce a stream of responses.
///
/// Panics if [de-]serialization or channel operations fail.
pub fn handle_stream_stream<C, R>(mut node_fn: C, req: &[u8], writer: ChannelResponseWriter)
where
    C: FnMut(Vec<R>, ChannelResponseWriter),
    R: protobuf::Message,
{
    // TODO(#97): better client-side streaming
    let rr: Vec<R> =
        vec![protobuf::parse_from_bytes(&req).expect("Failed to parse request protobuf message")];
    node_fn(rr, writer)
}
<commit_msg>sdk: add missing link destination<commit_after>//
// Copyright 2018 The Project Oak Authors
//
// 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.
//

//! Functionality to help Oak Nodes interact with gRPC.

pub use crate::proto::code::Code;
use crate::{proto, OakError};
use log::{error, warn};
pub use proto::grpc_encap::{GrpcRequest, GrpcResponse};
use protobuf::ProtobufEnum;

pub mod client;
mod invocation;
pub use invocation::Invocation;

/// Result type that uses a [`proto::status::Status`] type for error values.
pub type Result<T> = std::result::Result<T, proto::status::Status>;

/// Helper to create a gRPC status object.
pub fn build_status(code: Code, msg: &str) -> proto::status::Status {
    let mut status = proto::status::Status::new();
    status.set_code(code.value());
    status.set_message(msg.to_string());
    status
}

/// Channel-holding object that encapsulates response messages into
/// `GrpcResponse` wrapper messages and writes serialized versions to a send
/// channel.
pub struct ChannelResponseWriter {
    sender: crate::io::Sender<GrpcResponse>,
}

/// Indicate whether a write method should leave the current gRPC method
/// invocation open or close it.
#[derive(PartialEq, Clone, Debug)]
pub enum WriteMode {
    KeepOpen,
    Close,
}

impl ChannelResponseWriter {
    pub fn new(sender: crate::io::Sender<GrpcResponse>) -> Self {
        ChannelResponseWriter { sender }
    }

    /// Retrieve the Oak handle underlying the writer object.
    pub fn handle(self) -> crate::WriteHandle {
        self.sender.handle
    }

    /// Write out a gRPC response and optionally close out the method
    /// invocation.  Any errors from the channel are silently dropped.
    pub fn write<T: protobuf::Message>(
        &mut self,
        rsp: &T,
        mode: WriteMode,
    ) -> std::result::Result<(), OakError> {
        // Put the serialized response into a GrpcResponse message wrapper and
        // serialize it into the channel.
        let mut grpc_rsp = GrpcResponse::new();
        let mut any = protobuf::well_known_types::Any::new();
        rsp.write_to_writer(&mut any.value)?;
        grpc_rsp.set_rsp_msg(any);
        grpc_rsp.set_last(match mode {
            WriteMode::KeepOpen => false,
            WriteMode::Close => true,
        });
        self.sender.send(&grpc_rsp)?;
        if mode == WriteMode::Close {
            self.sender.close()?;
        }
        Ok(())
    }

    /// Write an empty gRPC response and optionally close out the method
    /// invocation. Any errors from the channel are silently dropped.
    pub fn write_empty(&mut self, mode: WriteMode) -> std::result::Result<(), OakError> {
        let mut grpc_rsp = GrpcResponse::new();
        grpc_rsp.set_rsp_msg(protobuf::well_known_types::Any::new());
        grpc_rsp.set_last(match mode {
            WriteMode::KeepOpen => false,
            WriteMode::Close => true,
        });
        self.sender.send(&grpc_rsp)?;
        if mode == WriteMode::Close {
            self.sender.close()?;
        }
        Ok(())
    }

    /// Close out the gRPC method invocation with the given final result.
    pub fn close(&mut self, result: Result<()>) -> std::result::Result<(), OakError> {
        // Build a final GrpcResponse message wrapper and serialize it into the
        // channel.
        let mut grpc_rsp = GrpcResponse::new();
        grpc_rsp.set_last(true);
        if let Err(status) = result {
            grpc_rsp.set_status(status);
        }
        self.sender.send(&grpc_rsp)?;
        self.sender.close()?;
        Ok(())
    }
}

/// Trait for Oak Nodes that act as a gRPC services.
///
/// An `OakNode` instance is normally passed to [`oak::run_event_loop`], to
/// allow repeated invocation of its `invoke()` method.
///
/// [`oak::run_event_loop`]: ../../oak/fn.run_event_loop.html
pub trait OakNode {
    /// Process a single gRPC method invocation.
    ///
    /// The method name is provided by `method` and the incoming serialized gRPC
    /// request is held in `req`.  Response messages should be written using
    /// `writer.write`, followed by `writer.close`.
    fn invoke(&mut self, method: &str, req: &[u8], writer: ChannelResponseWriter);
}

impl<T: OakNode> crate::Node<Invocation> for T {
    /// Handle incoming gRPC events for an [`OakNode`].
    ///
    /// Invoking the given `node`'s [`invoke`] method for each incoming request that
    /// arrives on the inbound channel as a serialized [`Invocation`] object,
    /// giving the [`invoke`] method the outbound channel for encapsulated responses
    /// to be written to.
    ///
    /// [`invoke`]: OakNode::invoke
    fn handle_command(
        &mut self,
        invocation: Invocation,
    ) -> std::result::Result<(), crate::OakError> {
        // Read a single encapsulated request message from the read half.
        let req: GrpcRequest = invocation.request_receiver.receive()?;
        // Since we are expecting a single message, close the channel immediately.
        // This will change when we implement client streaming (#97).
        invocation.request_receiver.close()?;
        if !req.last {
            // TODO(#97): Implement client streaming.
            panic!("Support for streaming requests not yet implemented");
        }
        self.invoke(
            &req.method_name,
            req.get_req_msg().value.as_slice(),
            ChannelResponseWriter::new(invocation.response_sender),
        );
        Ok(())
    }
}

/// Encapsulate a protocol buffer message in a GrpcRequest wrapper using the
/// given method name.
pub fn encap_request<T: protobuf::Message>(req: T, method_name: &str) -> Option<GrpcRequest> {
    // Put the request in a GrpcRequest wrapper and serialize it.
    let mut grpc_req = GrpcRequest::new();
    grpc_req.set_method_name(method_name.to_string());
    let mut any = protobuf::well_known_types::Any::new();
    if let Err(e) = req.write_to_writer(&mut any.value) {
        warn!("failed to serialize gRPC request: {}", e);
        return None;
    };
    grpc_req.set_req_msg(any);
    grpc_req.set_last(true);
    Some(grpc_req)
}

/// Extract a protocol buffer message from a GrpcResponse wrapper.
/// Returns the message together with an indicator of whether this is the last
/// response.
pub fn decap_response<T: protobuf::Message>(mut grpc_rsp: GrpcResponse) -> Result<(T, bool)> {
    if grpc_rsp.get_status().get_code() != Code::OK.value() {
        return Err(grpc_rsp.take_status());
    }
    let rsp = protobuf::parse_from_bytes(&grpc_rsp.get_rsp_msg().value).map_err(|proto_err| {
        build_status(
            Code::INVALID_ARGUMENT,
            &format!("message parsing failed: {}", proto_err),
        )
    })?;
    Ok((rsp, grpc_rsp.get_last()))
}

/// Helper to inject a (single) gRPC request message via a notification channel,
/// in the same manner as the gRPC pseudo-Node does, and return a channel for
/// reading responses from.
pub fn invoke_grpc_method_stream<R>(
    method_name: &str,
    req: R,
    invocation_channel: &crate::io::Sender<Invocation>,
) -> Result<crate::io::Receiver<GrpcResponse>>
where
    R: protobuf::Message,
{
    // Create a new channel for request message delivery.
    let (req_sender, req_receiver) =
        crate::io::channel_create::<GrpcRequest>().expect("failed to create channel");

    // Put the request in a GrpcRequest wrapper and send it into the request
    // message channel.
    let req = encap_request(req, method_name).expect("failed to serialize GrpcRequest");
    req_sender.send(&req).expect("failed to write to channel");
    req_sender.close().expect("failed to close channel");

    // Create a new channel for responses to arrive on.
    let (rsp_sender, rsp_receiver) =
        crate::io::channel_create::<GrpcResponse>().expect("failed to create channel");

    // Build an Invocation holding the two channels and send it down the
    // specified channel.
    let invocation = Invocation {
        request_receiver: req_receiver.clone(),
        response_sender: rsp_sender.clone(),
    };
    invocation_channel
        .send(&invocation)
        .expect("failed to write invocation to channel");
    req_receiver.close().expect("failed to close channel");
    rsp_sender.close().expect("failed to close channel");

    Ok(rsp_receiver)
}

/// Helper to inject a (single) gRPC request message via a notification channel,
/// in the same manner as the gRPC pseudo-Node does, and collect a (single)
/// response.
pub fn invoke_grpc_method<R, Q>(
    method_name: &str,
    req: R,
    invocation_channel: &crate::io::Sender<Invocation>,
) -> Result<Q>
where
    R: protobuf::Message,
    Q: protobuf::Message,
{
    let rsp_receiver = invoke_grpc_method_stream(method_name, req, invocation_channel)?;
    // Read a single encapsulated response.
    let grpc_rsp = rsp_receiver.receive().map_err(|status| {
        error!("failed to receive response: {:?}", status);
        build_status(
            Code::INTERNAL,
            &format!("failed to receive gRPC response: {:?}", status),
        )
    })?;
    rsp_receiver.close().expect("failed to close channel");
    let (rsp, last) = decap_response(grpc_rsp)?;
    if !last {
        panic!("Expected single final response");
    }

    Ok(rsp)
}

/// Generic function that handles request deserialization and response
/// serialization (and sending down a channel) for a function that handles a
/// request/response pair.
///
/// Panics if [de-]serialization or channel operations fail.
pub fn handle_req_rsp<C, R, Q>(mut node_fn: C, req: &[u8], mut writer: ChannelResponseWriter)
where
    C: FnMut(R) -> Result<Q>,
    R: protobuf::Message,
    Q: protobuf::Message,
{
    let r: R = protobuf::parse_from_bytes(&req).expect("Failed to parse request protobuf message");
    let result = match node_fn(r) {
        Ok(rsp) => writer.write(&rsp, WriteMode::Close),
        Err(status) => writer.close(Err(status)),
    };
    if let Err(e) = result {
        panic!("Failed to process response: {:?}", e)
    }
}

/// Generic function that handles request deserialization and response
/// serialization (and sending down a channel) for a function that handles a
/// request and streams responses.
///
/// Panics if [de-]serialization or channel operations fail.
pub fn handle_req_stream<C, R>(mut node_fn: C, req: &[u8], writer: ChannelResponseWriter)
where
    C: FnMut(R, ChannelResponseWriter),
    R: protobuf::Message,
{
    let r: R = protobuf::parse_from_bytes(&req).expect("Failed to parse request protobuf message");
    node_fn(r, writer)
}

/// Generic function that handles request deserialization and response
/// serialization (and sending down a channel) for a function that handles a
/// stream of requests to produce a response.
///
/// Panics if [de-]serialization or channel operations fail.
pub fn handle_stream_rsp<C, R, Q>(mut node_fn: C, req: &[u8], mut writer: ChannelResponseWriter)
where
    C: FnMut(Vec<R>) -> Result<Q>,
    R: protobuf::Message,
    Q: protobuf::Message,
{
    // TODO(#97): better client-side streaming
    let rr: Vec<R> =
        vec![protobuf::parse_from_bytes(&req).expect("Failed to parse request protobuf message")];
    let result = match node_fn(rr) {
        Ok(rsp) => writer.write(&rsp, WriteMode::Close),
        Err(status) => writer.close(Err(status)),
    };
    if let Err(e) = result {
        panic!("Failed to process response: {:?}", e)
    }
}

/// Generic function that handles request deserialization and response
/// serialization (and sending down a channel) for a function that handles a
/// stream of requests to produce a stream of responses.
///
/// Panics if [de-]serialization or channel operations fail.
pub fn handle_stream_stream<C, R>(mut node_fn: C, req: &[u8], writer: ChannelResponseWriter)
where
    C: FnMut(Vec<R>, ChannelResponseWriter),
    R: protobuf::Message,
{
    // TODO(#97): better client-side streaming
    let rr: Vec<R> =
        vec![protobuf::parse_from_bytes(&req).expect("Failed to parse request protobuf message")];
    node_fn(rr, writer)
}
<|endoftext|>