<commit_before>//! This module defines the metadata on devices and services.
//!
//! Note that all the data structures in this module represent
//! snapshots of subsets of the devices available. None of these data
//! structures are live, so there is always the possibility that
//! devices may have been added or removed from the FoxBox by the time
//! these data structures are read.

use values::*;

use serde::ser::{Serialize, Serializer};
use serde::de::{Deserialize, Deserializer, Error};

/// The unique Id of a node on the network.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Hash, Eq)]
pub struct NodeId(String);
impl NodeId {
    pub fn new(id: String) -> Self {
        NodeId(id)
    }
    pub fn as_string(&self) -> &String {
        &self.0
    }
}

/// Metadata on a node. A node is a device or collection of devices
/// that may offer services. The FoxBox itself a node offering
/// services such as a clock, communication with the user through her
/// smart devices, etc.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Node {
    /// Tags describing the node.
    ///
    /// These tags can be set by the user, adapters or
    /// applications. They are used by applications to find nodes and
    /// services.
    ///
    /// For instance, a user may set tag "entrance" to all nodes
    /// placed in the entrance of his house, or a tag "blue" to a node
    /// controlling blue lights. An adapter may set tags "plugged" or
    /// "battery" to devices that respectively depend on a plugged
    /// power source or on a battery.
    tags: Vec<String>,

    /// An id unique to this node.
    id: NodeId,

    /// Services connected directly to this node.
    inputs: Vec<Service<Input>>,
    outputs: Vec<Service<Output>>,

    /// Make sure that we can't instantiate from another crate.
    #[serde(default, skip_serializing)]
    private: (),
}

/// The unique Id of a service on the network.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Hash, Eq)]
pub struct ServiceId(String);
impl ServiceId {
    pub fn new(id: String) -> Self {
        ServiceId(id)
    }
    pub fn as_string(&self) -> &String {
        &self.0
    }
}

/// The kind of the service, i.e. a strongly-typed description of
/// _what_ the service can do. Used both for locating services
/// (e.g. "I need a clock" or "I need something that can provide
/// pictures") and for determining the data structure that these
/// services can provide or consume.
///
/// A number of service kinds are standardized, and provided as a set
/// of strongly-typed enum constructors. It is clear, however, that
/// many devices will offer services that cannot be described by
/// pre-existing constructors. For this purpose, this enumeration
/// offers a constructor `Extension`, designed to describe novel
/// services.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum ServiceKind {
    ///
    /// # No payload
    ///

    /// The service is ready. Used for instance once a countdown has
    /// reached completion.
    Ready,

    ///
    /// # Boolean
    ///

    /// The service is used to detect or decide whether some device
    /// is on or off.
    OnOff,

    /// The service is used to detect or decide whether some device
    /// is open or closed.
    OpenClosed,

    ///
    /// # Time
    ///

    /// The service is used to read or set the current absolute time.
    /// Used for instance to wait until a specific time and day before
    /// triggering an action, or to set the appropriate time on a new
    /// device.
    CurrentTime,

    /// The service is used to read or set the current time of day.
    /// Used for instance to trigger an action at a specific hour
    /// every day.
    CurrentTimeOfDay,

    /// The service is part of a countdown. This is the time
    /// remaining until the countdown is elapsed.
    RemainingTime,

    ///
    /// # Temperature
    ///

    Thermostat,
    ActualTemperature,

    /// TODO: Add more

    /// An operation of a kind that has not been standardized yet.
    Extension {
        /// The vendor. Used for namespacing purposes, to avoid
        /// confusing two incompatible extensions with similar
        /// names. For instance, "foxlink@mozilla.com".
        vendor: String,

        /// Identification of the adapter introducing this operation.
        /// Designed to aid with tracing and debugging.
        adapter: String,

        /// A string describing the nature of the value, designed to
        /// let applications discover the devices.
        ///
        /// Examples: `"GroundHumidity"`.
        kind: String,

        /// The data type of the value.
        typ: Type
    }
}

impl ServiceKind {
    /// Get the type of values used to communicate with this service.
    pub fn get_type(&self) -> Type {
        use self::ServiceKind::*;
        use values::Type::*;
        match *self {
            Ready => Unit,
            OnOff | OpenClosed => Bool,
            CurrentTime => TimeStamp,
            CurrentTimeOfDay | RemainingTime => Duration,
            Thermostat | ActualTemperature => Temperature,
            Extension { ref typ, ..} => typ.clone(),
        }
    }
}

/// An input operation available on an service.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Input {
    /// The kind of value that can be obtained from this service.
    pub kind: ServiceKind,

    /// If `Some(duration)`, this service can be polled, i.e. it
    /// will respond when the FoxBox requests the latest value.
    /// Parameter `duration` indicates the smallest interval
    /// between two updates.
    ///
    /// Otherwise, the service cannot be polled and will push
    /// data to the FoxBox when it is available.
    ///
    /// # Examples
    ///
    /// - Long-running pollution or humidity sensors typically
    ///   do not accept requests and rather send batches of
    ///   data every 24h.
    #[serde(default)]
    pub poll: Option<ValDuration>,

    /// If `Some(duration)`, this service can send the data to
    /// the FoxBox whenever it is updated. Parameter `duration`
    /// indicates the smallest interval between two updates.
    ///
    /// Otherwise, the service cannot send data to the FoxBox
    /// and needs to be polled.
    #[serde(default)]
    pub trigger: Option<ValDuration>,

    /// Date at which the latest value was received, whether through
    /// polling or through a trigger.
    pub updated: TimeStamp,

    /// Make sure that we can't instantiate from another crate.
    #[serde(default, skip_serializing)]
    private: (),
}
impl IOMechanism for Input {
}

/// An output operation available on an service.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Output {
    /// The kind of value that can be sent to this service.
    pub kind: ServiceKind,

    /// If `Some(duration)`, this service supports pushing,
    /// i.e. the FoxBox can send values.
    #[serde(default)]
    pub push: Option<ValDuration>,

    /// Date at which the latest value was sent to the service.
    pub updated: TimeStamp,

    /// Make sure that we can't instantiate from another crate.
    #[serde(default, skip_serializing)]
    private: (),
}
impl IOMechanism for Output {
}

/// An service represents a single place where data can enter or
/// leave a device. Note that services support either a single kind
/// of input or a single kind of output. Devices that support both
/// inputs or outputs, or several kinds of inputs, or several kinds of
/// outputs, are represented as nodes containing several services.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Service<IO> where IO: IOMechanism {
    /// Tags describing the service.
    ///
    /// These tags can be set by the user, adapters or
    /// applications. They are used to regroup services for rules.
    ///
    /// For instance "entrance".
    #[serde(default)]
    pub tags: Vec<String>,

    /// An id unique to this service.
    pub id: ServiceId,

    /// The node owning this service.
    pub node: NodeId,

    /// The update mechanism for this service.
    pub mechanism: IO,

    /// The last time the device was seen.
    pub last_seen: TimeStamp,

    /// Make sure that we can't instantiate from another crate.
    #[serde(default, skip_serializing)]
    private: (),
}

/// A mechanism used for communicating between the application and the
/// service.
pub trait IOMechanism: Deserialize + Serialize {
}

<commit_msg>[fxbox/taxonomy] Fields of Node are now public<commit_after>//! This module defines the metadata on devices and services.
//!
//! Note that all the data structures in this module represent
//! snapshots of subsets of the devices available. None of these data
//! structures are live, so there is always the possibility that
//! devices may have been added or removed from the FoxBox by the time
//! these data structures are read.

use values::*;

use serde::ser::{Serialize, Serializer};
use serde::de::{Deserialize, Deserializer, Error};

/// The unique Id of a node on the network.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Hash, Eq)]
pub struct NodeId(String);
impl NodeId {
    pub fn new(id: String) -> Self {
        NodeId(id)
    }
    pub fn as_string(&self) -> &String {
        &self.0
    }
}

/// Metadata on a node. A node is a device or collection of devices
/// that may offer services. The FoxBox itself a node offering
/// services such as a clock, communication with the user through her
/// smart devices, etc.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Node {
    /// Tags describing the node.
    ///
    /// These tags can be set by the user, adapters or
    /// applications. They are used by applications to find nodes and
    /// services.
    ///
    /// For instance, a user may set tag "entrance" to all nodes
    /// placed in the entrance of his house, or a tag "blue" to a node
    /// controlling blue lights. An adapter may set tags "plugged" or
    /// "battery" to devices that respectively depend on a plugged
    /// power source or on a battery.
    pub tags: Vec<String>,

    /// An id unique to this node.
    pub id: NodeId,

    /// Services connected directly to this node.
    pub inputs: Vec<Service<Input>>,
    pub outputs: Vec<Service<Output>>,

    /// Make sure that we can't instantiate from another crate.
    #[serde(default, skip_serializing)]
    private: (),
}

/// The unique Id of a service on the network.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Hash, Eq)]
pub struct ServiceId(String);
impl ServiceId {
    pub fn new(id: String) -> Self {
        ServiceId(id)
    }
    pub fn as_string(&self) -> &String {
        &self.0
    }
}

/// The kind of the service, i.e. a strongly-typed description of
/// _what_ the service can do. Used both for locating services
/// (e.g. "I need a clock" or "I need something that can provide
/// pictures") and for determining the data structure that these
/// services can provide or consume.
///
/// A number of service kinds are standardized, and provided as a set
/// of strongly-typed enum constructors. It is clear, however, that
/// many devices will offer services that cannot be described by
/// pre-existing constructors. For this purpose, this enumeration
/// offers a constructor `Extension`, designed to describe novel
/// services.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum ServiceKind {
    ///
    /// # No payload
    ///

    /// The service is ready. Used for instance once a countdown has
    /// reached completion.
    Ready,

    ///
    /// # Boolean
    ///

    /// The service is used to detect or decide whether some device
    /// is on or off.
    OnOff,

    /// The service is used to detect or decide whether some device
    /// is open or closed.
    OpenClosed,

    ///
    /// # Time
    ///

    /// The service is used to read or set the current absolute time.
    /// Used for instance to wait until a specific time and day before
    /// triggering an action, or to set the appropriate time on a new
    /// device.
    CurrentTime,

    /// The service is used to read or set the current time of day.
    /// Used for instance to trigger an action at a specific hour
    /// every day.
    CurrentTimeOfDay,

    /// The service is part of a countdown. This is the time
    /// remaining until the countdown is elapsed.
    RemainingTime,

    ///
    /// # Temperature
    ///

    Thermostat,
    ActualTemperature,

    /// TODO: Add more

    /// An operation of a kind that has not been standardized yet.
    Extension {
        /// The vendor. Used for namespacing purposes, to avoid
        /// confusing two incompatible extensions with similar
        /// names. For instance, "foxlink@mozilla.com".
        vendor: String,

        /// Identification of the adapter introducing this operation.
        /// Designed to aid with tracing and debugging.
        adapter: String,

        /// A string describing the nature of the value, designed to
        /// let applications discover the devices.
        ///
        /// Examples: `"GroundHumidity"`.
        kind: String,

        /// The data type of the value.
        typ: Type
    }
}

impl ServiceKind {
    /// Get the type of values used to communicate with this service.
    pub fn get_type(&self) -> Type {
        use self::ServiceKind::*;
        use values::Type::*;
        match *self {
            Ready => Unit,
            OnOff | OpenClosed => Bool,
            CurrentTime => TimeStamp,
            CurrentTimeOfDay | RemainingTime => Duration,
            Thermostat | ActualTemperature => Temperature,
            Extension { ref typ, ..} => typ.clone(),
        }
    }
}

/// An input operation available on an service.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Input {
    /// The kind of value that can be obtained from this service.
    pub kind: ServiceKind,

    /// If `Some(duration)`, this service can be polled, i.e. it
    /// will respond when the FoxBox requests the latest value.
    /// Parameter `duration` indicates the smallest interval
    /// between two updates.
    ///
    /// Otherwise, the service cannot be polled and will push
    /// data to the FoxBox when it is available.
    ///
    /// # Examples
    ///
    /// - Long-running pollution or humidity sensors typically
    ///   do not accept requests and rather send batches of
    ///   data every 24h.
    #[serde(default)]
    pub poll: Option<ValDuration>,

    /// If `Some(duration)`, this service can send the data to
    /// the FoxBox whenever it is updated. Parameter `duration`
    /// indicates the smallest interval between two updates.
    ///
    /// Otherwise, the service cannot send data to the FoxBox
    /// and needs to be polled.
    #[serde(default)]
    pub trigger: Option<ValDuration>,

    /// Date at which the latest value was received, whether through
    /// polling or through a trigger.
    pub updated: TimeStamp,

    /// Make sure that we can't instantiate from another crate.
    #[serde(default, skip_serializing)]
    private: (),
}
impl IOMechanism for Input {
}

/// An output operation available on an service.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Output {
    /// The kind of value that can be sent to this service.
    pub kind: ServiceKind,

    /// If `Some(duration)`, this service supports pushing,
    /// i.e. the FoxBox can send values.
    #[serde(default)]
    pub push: Option<ValDuration>,

    /// Date at which the latest value was sent to the service.
    pub updated: TimeStamp,

    /// Make sure that we can't instantiate from another crate.
    #[serde(default, skip_serializing)]
    private: (),
}
impl IOMechanism for Output {
}

/// An service represents a single place where data can enter or
/// leave a device. Note that services support either a single kind
/// of input or a single kind of output. Devices that support both
/// inputs or outputs, or several kinds of inputs, or several kinds of
/// outputs, are represented as nodes containing several services.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Service<IO> where IO: IOMechanism {
    /// Tags describing the service.
    ///
    /// These tags can be set by the user, adapters or
    /// applications. They are used to regroup services for rules.
    ///
    /// For instance "entrance".
    #[serde(default)]
    pub tags: Vec<String>,

    /// An id unique to this service.
    pub id: ServiceId,

    /// The node owning this service.
    pub node: NodeId,

    /// The update mechanism for this service.
    pub mechanism: IO,

    /// The last time the device was seen.
    pub last_seen: TimeStamp,

    /// Make sure that we can't instantiate from another crate.
    #[serde(default, skip_serializing)]
    private: (),
}

/// A mechanism used for communicating between the application and the
/// service.
pub trait IOMechanism: Deserialize + Serialize {
}

<|endoftext|>


<commit_before>//
// Copyright 2017 yvt, all rights reserved.
//
// Licensed under the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>. This file may
// not be copied, modified,or distributed except
// according to those terms.
//
#![feature(test)]
extern crate test;
extern crate unreachable;
extern crate xalloc;

use test::Bencher;
use unreachable::UncheckedOptionExt;
use xalloc::*;

struct Xorshift32(u32);

impl Xorshift32 {
    fn next(&mut self) -> u32 {
        self.0 ^= self.0 << 13;
        self.0 ^= self.0 >> 17;
        self.0 ^= self.0 << 5;
        !self.0
    }
}

#[bench]
fn systlsf_random(b: &mut Bencher) {
    let mut v: Vec<_> = (0..512).map(|_| None).collect();
    let mut sa = SysTlsf::with_capacity(512u32, 512);
    b.iter(|| unsafe {
        let mut r = Xorshift32(0x11451419);
        for _ in 0..65536 {
            let i = ((r.next() >> 8) & 511) as usize;
            if v[i].is_some() {
                sa.dealloc_unchecked(v[i].take().unchecked_unwrap());
            } else {
                v[i] = Some(sa.alloc(1u32).unchecked_unwrap().0);
            }
        }
        for x in v.iter_mut() {
            if let Some(x) = x.take() {
                sa.dealloc_unchecked(x);
            }
        }
    });
}

#[bench]
fn sys_random(b: &mut Bencher) {
    let mut v: Vec<_> = (0..512).map(|_| None).collect();
    b.iter(|| {
        let mut r = Xorshift32(0x11451419);
        for _ in 0..65536 {
            let i = ((r.next() >> 8) & 511) as usize;
            if v[i].is_some() {
                v[i].take();
            } else {
                v[i] = Some(Box::new(1u32));
            }
        }
        for x in v.iter_mut() {
            x.take();
        }
    });
}
<commit_msg>Add stack-like allocation benchmarks<commit_after>//
// Copyright 2017 yvt, all rights reserved.
//
// Licensed under the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>. This file may
// not be copied, modified,or distributed except
// according to those terms.
//
#![feature(test)]
extern crate test;
extern crate unreachable;
extern crate xalloc;

use test::Bencher;
use unreachable::UncheckedOptionExt;
use xalloc::*;

struct Xorshift32(u32);

impl Xorshift32 {
    fn next(&mut self) -> u32 {
        self.0 ^= self.0 << 13;
        self.0 ^= self.0 >> 17;
        self.0 ^= self.0 << 5;
        !self.0
    }
}

#[bench]
fn systlsf_random(b: &mut Bencher) {
    let mut v: Vec<_> = (0..512).map(|_| None).collect();
    let mut sa = SysTlsf::with_capacity(512u32, 512);
    b.iter(|| unsafe {
        let mut r = Xorshift32(0x11451419);
        for _ in 0..65536 {
            let i = ((r.next() >> 8) & 511) as usize;
            if v[i].is_some() {
                sa.dealloc_unchecked(v[i].take().unchecked_unwrap());
            } else {
                v[i] = Some(sa.alloc(1u32).unchecked_unwrap().0);
            }
        }
        for x in v.iter_mut() {
            if let Some(x) = x.take() {
                sa.dealloc_unchecked(x);
            }
        }
    });
}

#[bench]
fn sys_random(b: &mut Bencher) {
    let mut v: Vec<_> = (0..512).map(|_| None).collect();
    b.iter(|| {
        let mut r = Xorshift32(0x11451419);
        for _ in 0..65536 {
            let i = ((r.next() >> 8) & 511) as usize;
            if v[i].is_some() {
                v[i].take();
            } else {
                v[i] = Some(Box::new(1u32));
            }
        }
        for x in v.iter_mut() {
            x.take();
        }
    });
}

#[bench]
fn systlsf_stack(b: &mut Bencher) {
    let mut sa = SysTlsf::with_capacity(65536u32, 65536);
    let mut v = Vec::with_capacity(65536);
    b.iter(|| unsafe {
        for _ in 0..65536 {
            v.push(sa.alloc(1u32).unchecked_unwrap().0);
        }
        while let Some(x) = v.pop() {
            sa.dealloc_unchecked(x);
        }
    });
}

#[bench]
fn sys_stack(b: &mut Bencher) {
    let mut v = Vec::with_capacity(65536);
    b.iter(|| {
        for _ in 0..65536 {
            v.push(Box::new(1u32));
        }
        while let Some(_) = v.pop() {}
    });
}
<|endoftext|>


<commit_before>use {Borrowed, Value, Field, Color, Matrix2d};
use vecmath::{identity};
use {Fill, BackEnd, View};
use triangulation::{
    with_lerp_polygons_tri_list_xy_f32_rgba_f32
};

/// An animation inbetweening context with color.
pub struct TweenPolygonsColorContext<'a> {
    /// Base/origin transform.
    pub base: Field<'a, Matrix2d>,
    /// Current transform.
    pub transform: Field<'a, Matrix2d>,
    /// Current color.
    pub color: Field<'a, Color>,
    /// Animation inbetweening factor.
    pub tween_factor: Field<'a, f64>,
    /// The animated polygons.
    pub polygons: Field<'a, &'a [&'a [f64]]>,
}

impl<'a> Fill<'a> for TweenPolygonsColorContext<'a> {
    fn fill<B: BackEnd>(&'a self, back_end: &mut B) {
        if back_end.supports_tri_list_xy_f32_rgba_f32() {
            let polygons = self.polygons.get();
            let color = self.color.get();
            let color: [f32, ..4] = [color[0], color[1], color[2], color[3]];
            // Complete transparency does not need to be rendered.
            if color[3] == 0.0 { return; }
            // Turn on alpha blending if not completely opaque.
            let needs_alpha = color[3] != 1.0;
            if needs_alpha { back_end.enable_alpha_blend(); }
            with_lerp_polygons_tri_list_xy_f32_rgba_f32(
                self.transform.get(),
                *polygons,
                *self.tween_factor.get(),
                color,
                |vertices, colors| {
                    back_end.tri_list_xy_f32_rgba_f32(vertices, colors)
                }
            );
            if needs_alpha { back_end.disable_alpha_blend(); }
        } else {
            unimplemented!();
        }
    }
}

impl<'a> View<'a> for TweenPolygonsColorContext<'a> {
    #[inline(always)]
    fn view(&'a self) -> TweenPolygonsColorContext<'a> {
        TweenPolygonsColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.base.get()),
            polygons: Borrowed(self.polygons.get()),
            color: Borrowed(self.color.get()),
            tween_factor: Borrowed(self.tween_factor.get()),
        }
    }

    #[inline(always)]
    fn reset(&'a self) -> TweenPolygonsColorContext<'a> {
        TweenPolygonsColorContext {
            base: Borrowed(self.base.get()),
            transform: Value(identity()),
            polygons: Borrowed(self.polygons.get()),
            color: Borrowed(self.color.get()),
            tween_factor: Borrowed(self.tween_factor.get()),
        }
    }

    #[inline(always)]
    fn store_view(&'a self) -> TweenPolygonsColorContext<'a> {
        TweenPolygonsColorContext {
            base: Borrowed(self.transform.get()),
            transform: Borrowed(self.transform.get()),
            polygons: Borrowed(self.polygons.get()),
            color: Borrowed(self.color.get()),
            tween_factor: Borrowed(self.tween_factor.get()),
        }
    }
}

<commit_msg>Sorted use alphabetically<commit_after>use {
    BackEnd,
    Borrowed,
    Color,
    Field,
    Fill,
    Matrix2d,
    Value,
    View,
};
use vecmath::{
    identity
};
use triangulation::{
    with_lerp_polygons_tri_list_xy_f32_rgba_f32
};

/// An animation inbetweening context with color.
pub struct TweenPolygonsColorContext<'a> {
    /// Base/origin transform.
    pub base: Field<'a, Matrix2d>,
    /// Current transform.
    pub transform: Field<'a, Matrix2d>,
    /// Current color.
    pub color: Field<'a, Color>,
    /// Animation inbetweening factor.
    pub tween_factor: Field<'a, f64>,
    /// The animated polygons.
    pub polygons: Field<'a, &'a [&'a [f64]]>,
}

impl<'a> Fill<'a> for TweenPolygonsColorContext<'a> {
    fn fill<B: BackEnd>(&'a self, back_end: &mut B) {
        if back_end.supports_tri_list_xy_f32_rgba_f32() {
            let polygons = self.polygons.get();
            let color = self.color.get();
            let color: [f32, ..4] = [color[0], color[1], color[2], color[3]];
            // Complete transparency does not need to be rendered.
            if color[3] == 0.0 { return; }
            // Turn on alpha blending if not completely opaque.
            let needs_alpha = color[3] != 1.0;
            if needs_alpha { back_end.enable_alpha_blend(); }
            with_lerp_polygons_tri_list_xy_f32_rgba_f32(
                self.transform.get(),
                *polygons,
                *self.tween_factor.get(),
                color,
                |vertices, colors| {
                    back_end.tri_list_xy_f32_rgba_f32(vertices, colors)
                }
            );
            if needs_alpha { back_end.disable_alpha_blend(); }
        } else {
            unimplemented!();
        }
    }
}

impl<'a> View<'a> for TweenPolygonsColorContext<'a> {
    #[inline(always)]
    fn view(&'a self) -> TweenPolygonsColorContext<'a> {
        TweenPolygonsColorContext {
            base: Borrowed(self.base.get()),
            transform: Borrowed(self.base.get()),
            polygons: Borrowed(self.polygons.get()),
            color: Borrowed(self.color.get()),
            tween_factor: Borrowed(self.tween_factor.get()),
        }
    }

    #[inline(always)]
    fn reset(&'a self) -> TweenPolygonsColorContext<'a> {
        TweenPolygonsColorContext {
            base: Borrowed(self.base.get()),
            transform: Value(identity()),
            polygons: Borrowed(self.polygons.get()),
            color: Borrowed(self.color.get()),
            tween_factor: Borrowed(self.tween_factor.get()),
        }
    }

    #[inline(always)]
    fn store_view(&'a self) -> TweenPolygonsColorContext<'a> {
        TweenPolygonsColorContext {
            base: Borrowed(self.transform.get()),
            transform: Borrowed(self.transform.get()),
            polygons: Borrowed(self.polygons.get()),
            color: Borrowed(self.color.get()),
            tween_factor: Borrowed(self.tween_factor.get()),
        }
    }
}

<|endoftext|>


<commit_before>pub trait NumberOps : Sized {
   fn rounding_div(self, other: Self) -> Self;

   fn sqrt(self) -> Self;

   fn isqrt(self) -> Self;
}

impl NumberOps for i64 {
   #[inline]
   fn rounding_div(self, other: i64) -> i64 {
      if (self < 0) ^ (other < 0) {
         (self - (other / 2)) / other
      } else {
         (self + (other / 2)) / other
      }
   }

   #[inline]
   fn sqrt(self) -> i64 {
      (self as f64).sqrt().round() as i64
   }

   fn isqrt(self) -> i64 {
      let mut squaredbit = ((!0_u64 >> 1) & !(!0_u64 >> 2)) as i64;
      let mut remainder = self;
      let mut root = 0;

      while squaredbit > 0 {
         if remainder >= (squaredbit | root) {
            remainder -= squaredbit | root;
            root >>= 1;
            root |= squaredbit;
         } else {
            root >>= 1;
         }
         squaredbit >>= 2;
      }

      root
   }
}

#[cfg(test)]
mod tests {
   use test::{Bencher, black_box};
   use std::i64;

   use super::*;

   #[bench]
   fn bench_rounding_div(b: &mut Bencher) {
      b.iter(|| {
         for _ in 0..1000 {
            black_box(15023081_i64.rounding_div(black_box(108877_i64)));
         }
      });
   }

   #[bench]
   fn bench_sqrt(b: &mut Bencher) {
      b.iter(|| {
         let mut x = i64::MAX;
         for _ in 0..1000 {
            x = black_box(x.sqrt());
         }
      });
   }

   #[bench]
   fn bench_isqrt(b: &mut Bencher) {
      b.iter(|| {
         let mut x = i64::MAX;
         for _ in 0..1000 {
            x = black_box(x.isqrt());
         }
      });
   }
}
<commit_msg>Faster rounding_div using f64 conversion<commit_after>pub trait NumberOps : Sized {
   fn rounding_div(self, other: Self) -> Self;

   fn rounding_idiv(self, other: Self) -> Self;

   fn sqrt(self) -> Self;

   fn isqrt(self) -> Self;
}

impl NumberOps for i64 {
   #[inline]
   fn rounding_div(self, other: i64) -> i64 {
      (self as f64 / other as f64).round() as i64
   }

   #[inline]
   fn rounding_idiv(self, other: i64) -> i64 {
      if (self < 0) ^ (other < 0) {
         (self - (other / 2)) / other
      } else {
         (self + (other / 2)) / other
      }
   }

   #[inline]
   fn sqrt(self) -> i64 {
      (self as f64).sqrt().round() as i64
   }

   #[inline]
   fn isqrt(self) -> i64 {
      let mut squaredbit = ((!0_u64 >> 1) & !(!0_u64 >> 2)) as i64;
      let mut remainder = self;
      let mut root = 0;

      while squaredbit > 0 {
         if remainder >= (squaredbit | root) {
            remainder -= squaredbit | root;
            root >>= 1;
            root |= squaredbit;
         } else {
            root >>= 1;
         }
         squaredbit >>= 2;
      }

      root
   }
}

#[cfg(test)]
mod tests {
   use test::{Bencher, black_box};
   use std::i64;

   use super::*;

   #[inline]
   pub fn rand_i64(seed: &mut i64) -> i64 {
       *seed = seed.wrapping_mul(827329174364988385).wrapping_add(1235464122344149);
       seed.rotate_left(32)
   }

   #[test]
   fn test_rounding_div() {
      let mut seed: i64 = 783437865;

      for _ in 0..1_000_000 {
         let mut left = rand_i64(&mut seed);

         if left > i64::MAX / 2 || left < i64::MIN / 2 {
            left /= 2;
         }

         let mut right = rand_i64(&mut seed);

         if right > i64::MAX / 2 || right < i64::MIN / 2 {
            right /= 2;
         }

         assert_eq!(
            left.rounding_div(right), left.rounding_idiv(right)
         );
      }
   }

   #[bench]
   fn bench_rounding_div(b: &mut Bencher) {
      b.iter(|| {
         for _ in 0..1000 {
            black_box(15023081_i64.rounding_div(black_box(108877_i64)));
         }
      });
   }

   #[bench]
   fn bench_rounding_idiv(b: &mut Bencher) {
      b.iter(|| {
         for _ in 0..1000 {
            black_box(15023081_i64.rounding_idiv(black_box(108877_i64)));
         }
      });
   }

   #[bench]
   fn bench_sqrt(b: &mut Bencher) {
      b.iter(|| {
         let mut x = i64::MAX;
         for _ in 0..1000 {
            x = black_box(x.sqrt());
         }
      });
   }

   #[bench]
   fn bench_isqrt(b: &mut Bencher) {
      b.iter(|| {
         let mut x = i64::MAX;
         for _ in 0..1000 {
            x = black_box(x.isqrt());
         }
      });
   }
}
<|endoftext|>


<commit_before>use luminance::framebuffer::Framebuffer;
use luminance::pixel::{Depth32F, RGBA32F};
use luminance::tess::{Mode, Tess};
use luminance::texture::{Dim2, Flat, Texture, Unit};
use luminance::pipeline::Pipeline;
use luminance::tess::TessRender;
use std::ops::{Add, Mul, Sub};

pub use luminance::blending::{Equation, Factor};

use color::RGBA;
use resource::{Res, ResCache};
use shader::{Program, Uniform};

/// Simple texture that can be embedded into a compositing graph.
pub type TextureLayer<'a> = &'a ColorMap;

pub type ColorMap = Texture<Flat, Dim2, RGBA32F>;
pub type DepthMap = Texture<Flat, Dim2, Depth32F>;

/// Render layer used to host renders.
pub struct RenderLayer<'a> {
  render: Box<Fn(&Framebuffer<Flat, Dim2, ColorMap, DepthMap>) + 'a>
}

impl<'a> RenderLayer<'a> {
  pub fn new<F>(render: F) -> Self where F: 'a + Fn(&Framebuffer<Flat, Dim2, ColorMap, DepthMap>) {
    RenderLayer {
      render: Box::new(render)
    }
  }
}

/// Compositing node.
pub enum Node<'a> {
  /// A render node.
  ///
  /// Contains render layer.
  Render(RenderLayer<'a>),
  /// A texture node.
  ///
  /// Contains a single texture.
  Texture(TextureLayer<'a>),
  /// A single color.
  ///
  /// Keep in mind that such a node is great when you want to display a fullscreen colored quad but
  /// you shouldn’t use it for blending purpose. Adding color masking to your post-process is a
  /// better alternative and will avoid fillrate alteration.
  Color(RGBA),
  /// Composite node.
  ///
  /// Composite nodes are used to blend two compositing nodes according to a given `Equation` and
  /// two blending `Factor`s for source and destination, respectively.
  Composite(Box<Node<'a>>, Box<Node<'a>>, RGBA, Equation, Factor, Factor)
}

impl<'a> Node<'a> {
  /// Compose this node with another one.
  pub fn compose_with(self, rhs: Self, clear_color: RGBA, eq: Equation, src_fct: Factor, dst_fct: Factor) -> Self {
    Node::Composite(Box::new(self), Box::new(rhs), clear_color, eq, src_fct, dst_fct)
  }

  /// Compose this node over the other. In effect, the resulting node will replace any pixels covered
  /// by the right node by the ones of the left node unless the alpha value is different than `1`.
  /// In that case, an additive blending based on the alpha value of the left node will be performed.
  ///
  /// If you set the alpha value to `0` at a pixel in the left node, then the resulting pixel will be
  /// the one from the right node.
  pub fn over(self, rhs: Self) -> Self {
    rhs.compose_with(self, RGBA::new(0., 0., 0., 0.), Equation::Additive, Factor::SrcAlpha, Factor::SrcAlphaComplement)
  }
}

impl<'a> From<RenderLayer<'a>> for Node<'a> {
  fn from(layer: RenderLayer<'a>) -> Self {
    Node::Render(layer)
  }
}

impl<'a> From<TextureLayer<'a>> for Node<'a> {
  fn from(texture: TextureLayer<'a>) -> Self {
    Node::Texture(texture)
  }
}

impl<'a> From<RGBA> for Node<'a> {
  fn from(color: RGBA) -> Self {
    Node::Color(color)
  }
}

impl<'a> Add for Node<'a> {
  type Output = Self;

  fn add(self, rhs: Self) -> Self {
    self.compose_with(rhs, RGBA::new(0., 0., 0., 0.), Equation::Additive, Factor::One, Factor::One)
  }
}

impl<'a> Sub for Node<'a> {
  type Output = Self;

  fn sub(self, rhs: Self) -> Self {
    self.compose_with(rhs, RGBA::new(0., 0., 0., 0.), Equation::Subtract, Factor::One, Factor::One)
  }
}

impl<'a> Mul for Node<'a> {
  type Output = Self;

  fn mul(self, rhs: Self) -> Self {
    self.compose_with(rhs, RGBA::new(1., 1., 1., 1.), Equation::Additive, Factor::Zero, Factor::SrcColor)
  }
}

/// Compositor object; used to consume `Node`s and output to screen.
pub struct Compositor {
  // width
  w: u32,
  // height
  h: u32,
  // allocated framebuffers that might contain nodes’ output
  framebuffers: Vec<Framebuffer<Flat, Dim2, ColorMap, DepthMap>>,
  // free list of available framebuffers
  free_framebuffers: Vec<usize>,
  // program used to compose nodes
  compose_program: Res<Program>,
  // program used to render textures scaled
  texture_program: Res<Program>,
  // attributeless fullscreen quad for compositing
  quad: Tess
}

const FORWARD_SOURCE: &'static Uniform<Unit> = &Uniform::new(0);
const TEXTURE_SOURCE: &'static Uniform<Unit> = &Uniform::new(0);

impl Compositor {
  pub fn new(w: u32, h: u32, cache: &mut ResCache) -> Self {
    Compositor {
      w: w,
      h: h,
      framebuffers: Vec::new(),
      free_framebuffers: Vec::new(),
      compose_program: cache.get("spectra/compositing/forward.glsl", vec![FORWARD_SOURCE.sem("source")]).unwrap(),
      texture_program: cache.get("spectra/compositing/texture.glsl", vec![TEXTURE_SOURCE.sem("source")]).unwrap(),
      quad: Tess::attributeless(Mode::TriangleStrip, 4)
    }
  }

  /// Whenever a node must be composed, we need a framebuffer to render into. This function pulls a
  /// framebuffer to use (via self.framebuffers) by returing an index. It might allocate a new
  /// framebuffer if there isn’t enough framebuffers to be pulled.
  fn pull_framebuffer(&mut self) -> usize {
    self.free_framebuffers.pop().unwrap_or_else(|| {
      let framebuffer_index = self.framebuffers.len();

      let framebuffer = Framebuffer::new((self.w, self.h), 0).unwrap();
      self.framebuffers.push(framebuffer);

      framebuffer_index
    })
  }

  /// Whenever a node has finished being composed, we *might* need to dispose the framebuffer it has
  /// pulled. This funciton does that job.
  ///
  /// It never deallocates memory. It has an important property: once a framebuffer is pulled,
  /// calling that function will make it available for other nodes, improving memory usage for the
  /// next calls.
  #[inline]
  fn dispose_framebuffer(&mut self, framebuffer_index: usize) {
    self.free_framebuffers.push(framebuffer_index);
  }

  /// Consume and display a compositing graph represented by its nodes.
  pub fn display(&mut self, root: Node) {
    let fb_index = self.treat_node(root);

    {
      let fb = &self.framebuffers[fb_index];
      let screen = Framebuffer::default((self.w, self.h));
      let compose_program = self.compose_program.borrow();
      let tess_render = TessRender::from(&self.quad);

      Pipeline::new(&screen, [0., 0., 0., 1.], &[&*fb.color_slot], &[]).enter(|shd_gate| {
        shd_gate.new(&compose_program, &[], &[], &[]).enter(|rdr_gate| {
          rdr_gate.new(None, false, &[], &[], &[]).enter(|tess_gate| {
            let uniforms = [FORWARD_SOURCE.alter(Unit::new(0))];
            tess_gate.render(tess_render, &uniforms, &[], &[])
          });
        });
      });
    }

    self.dispose_framebuffer(fb_index);
  }

  /// Treat a node hierarchy and return the index  of the framebuffer that contains the result.
  fn treat_node(&mut self, node: Node) -> usize {
    match node {
      Node::Render(layer) => self.render(layer),
      Node::Texture(texture) => self.texturize(texture),
      Node::Color(color) => self.colorize(color),
      Node::Composite(left, right, clear_color, eq, src_fct, dst_fct) => self.composite(*left, *right, clear_color, eq, src_fct, dst_fct),
    }
  }

  fn render(&mut self, layer: RenderLayer) -> usize {
    let fb_index = self.pull_framebuffer();
    let fb = &self.framebuffers[fb_index];

    (layer.render)(&fb);

    fb_index
  }

  fn texturize(&mut self, texture: TextureLayer) -> usize {
    let fb_index = self.pull_framebuffer();
    let fb = &self.framebuffers[fb_index];

    let texture_program = self.texture_program.borrow();
    let tess_render = TessRender::from(&self.quad);

    Pipeline::new(fb, [0., 0., 0., 1.], &[&**texture], &[]).enter(|shd_gate| {
      shd_gate.new(&texture_program, &[], &[], &[]).enter(|rdr_gate| {
        rdr_gate.new(None, false, &[], &[], &[]).enter(|tess_gate| {
          let uniforms = [TEXTURE_SOURCE.alter(Unit::new(0))];
          tess_gate.render(tess_render, &uniforms, &[], &[]);
        });
      });
    });

    fb_index
  }

  fn colorize(&mut self, color: RGBA) -> usize {
    let fb_index = self.pull_framebuffer();
    let fb = &self.framebuffers[fb_index];

    let color = *color.as_ref();

    Pipeline::new(fb, color, &[], &[]).enter(|_| {});

    fb_index
  }

  fn composite(&mut self, left: Node, right: Node, clear_color: RGBA, eq: Equation, src_fct: Factor, dst_fct: Factor) -> usize {
    let left_index = self.treat_node(left);
    let right_index = self.treat_node(right);

    assert!(left_index < self.framebuffers.len());
    assert!(right_index < self.framebuffers.len());

    let fb_index = self.pull_framebuffer();

    {
      let fb = &self.framebuffers[fb_index];

      let left_fb = &self.framebuffers[left_index];
      let right_fb = &self.framebuffers[right_index];

      let texture_set = &[
        &*left_fb.color_slot,
        &*right_fb.color_slot
      ];
      let compose_program = self.compose_program.borrow();
      let tess_render = TessRender::from(&self.quad);

      Pipeline::new(fb, *clear_color.as_ref(), texture_set, &[]).enter(|shd_gate| {
        shd_gate.new(&compose_program, &[], &[], &[]).enter(|rdr_gate| {
          rdr_gate.new((eq, src_fct, dst_fct), false, &[], &[], &[]).enter(|tess_gate| {
            let uniforms = [FORWARD_SOURCE.alter(Unit::new(0))];
            tess_gate.render(tess_render.clone(), &uniforms, &[], &[]);

            let uniforms = [FORWARD_SOURCE.alter(Unit::new(1))];
            tess_gate.render(tess_render, &uniforms, &[], &[]);
          });
        });
      });
    }

    // dispose both left and right framebuffers
    self.dispose_framebuffer(left_index);
    self.dispose_framebuffer(right_index);

    fb_index
  }
}
<commit_msg>Added support for simple fullscreen shading effect.<commit_after>use luminance::framebuffer::Framebuffer;
use luminance::pixel::{Depth32F, RGBA32F};
use luminance::tess::{Mode, Tess};
use luminance::texture::{Dim2, Flat, Texture, Unit};
use luminance::pipeline::Pipeline;
use luminance::tess::TessRender;
use std::ops::{Add, Mul, Sub};

pub use luminance::blending::{Equation, Factor};

use color::RGBA;
use resource::{Res, ResCache};
use shader::{Program, Uniform};

/// Simple texture that can be embedded into a compositing graph.
pub type TextureLayer<'a> = &'a ColorMap;

pub type ColorMap = Texture<Flat, Dim2, RGBA32F>;
pub type DepthMap = Texture<Flat, Dim2, Depth32F>;

/// Render layer used to host renders.
pub struct RenderLayer<'a> {
  render: Box<Fn(&Framebuffer<Flat, Dim2, ColorMap, DepthMap>) + 'a>
}

impl<'a> RenderLayer<'a> {
  pub fn new<F>(render: F) -> Self where F: 'a + Fn(&Framebuffer<Flat, Dim2, ColorMap, DepthMap>) {
    RenderLayer {
      render: Box::new(render)
    }
  }
}

/// Compositing node.
pub enum Node<'a> {
  /// A render node.
  ///
  /// Contains render layer.
  Render(RenderLayer<'a>),
  /// A texture node.
  ///
  /// Contains a single texture.
  Texture(TextureLayer<'a>),
  /// A single color.
  ///
  /// Keep in mind that such a node is great when you want to display a fullscreen colored quad but
  /// you shouldn’t use it for blending purpose. Adding color masking to your post-process is a
  /// better alternative and will avoid fillrate alteration.
  Color(RGBA),
  /// Composite node.
  ///
  /// Composite nodes are used to blend two compositing nodes according to a given `Equation` and
  /// two blending `Factor`s for source and destination, respectively.
  Composite(Box<Node<'a>>, Box<Node<'a>>, RGBA, Equation, Factor, Factor),
  /// Simple fullscreen effect.
  ///
  /// Such a node is used to apply a user-defined shader on a fullscreen quad. The shader should
  /// provide both the vertex and fragment shader. The vertex shader doesn’t take any inputs but is
  /// invoked in an *attributeless* context on a triangle fan configuration. The fragment shader
  /// should output only one *RGBA* fragment.
  FullScreenEffect(&'a Program)
}

impl<'a> Node<'a> {
  /// Compose this node with another one.
  pub fn compose_with(self, rhs: Self, clear_color: RGBA, eq: Equation, src_fct: Factor, dst_fct: Factor) -> Self {
    Node::Composite(Box::new(self), Box::new(rhs), clear_color, eq, src_fct, dst_fct)
  }

  /// Compose this node over the other. In effect, the resulting node will replace any pixels covered
  /// by the right node by the ones of the left node unless the alpha value is different than `1`.
  /// In that case, an additive blending based on the alpha value of the left node will be performed.
  ///
  /// If you set the alpha value to `0` at a pixel in the left node, then the resulting pixel will be
  /// the one from the right node.
  pub fn over(self, rhs: Self) -> Self {
    rhs.compose_with(self, RGBA::new(0., 0., 0., 0.), Equation::Additive, Factor::SrcAlpha, Factor::SrcAlphaComplement)
  }
}

impl<'a> From<RenderLayer<'a>> for Node<'a> {
  fn from(layer: RenderLayer<'a>) -> Self {
    Node::Render(layer)
  }
}

impl<'a> From<TextureLayer<'a>> for Node<'a> {
  fn from(texture: TextureLayer<'a>) -> Self {
    Node::Texture(texture)
  }
}

impl<'a> From<RGBA> for Node<'a> {
  fn from(color: RGBA) -> Self {
    Node::Color(color)
  }
}

impl<'a> From<&'a Program> for Node<'a> {
  fn from(program: &'a Program) -> Self {
    Node::FullScreenEffect(program)
  }
}

impl<'a> Add for Node<'a> {
  type Output = Self;

  fn add(self, rhs: Self) -> Self {
    self.compose_with(rhs, RGBA::new(0., 0., 0., 0.), Equation::Additive, Factor::One, Factor::One)
  }
}

impl<'a> Sub for Node<'a> {
  type Output = Self;

  fn sub(self, rhs: Self) -> Self {
    self.compose_with(rhs, RGBA::new(0., 0., 0., 0.), Equation::Subtract, Factor::One, Factor::One)
  }
}

impl<'a> Mul for Node<'a> {
  type Output = Self;

  fn mul(self, rhs: Self) -> Self {
    self.compose_with(rhs, RGBA::new(1., 1., 1., 1.), Equation::Additive, Factor::Zero, Factor::SrcColor)
  }
}

/// Compositor object; used to consume `Node`s and output to screen.
pub struct Compositor {
  // width
  w: u32,
  // height
  h: u32,
  // allocated framebuffers that might contain nodes’ output
  framebuffers: Vec<Framebuffer<Flat, Dim2, ColorMap, DepthMap>>,
  // free list of available framebuffers
  free_framebuffers: Vec<usize>,
  // program used to compose nodes
  compose_program: Res<Program>,
  // program used to render textures scaled
  texture_program: Res<Program>,
  // attributeless fullscreen quad for compositing
  quad: Tess
}

const FORWARD_SOURCE: &'static Uniform<Unit> = &Uniform::new(0);
const TEXTURE_SOURCE: &'static Uniform<Unit> = &Uniform::new(0);

impl Compositor {
  pub fn new(w: u32, h: u32, cache: &mut ResCache) -> Self {
    Compositor {
      w: w,
      h: h,
      framebuffers: Vec::new(),
      free_framebuffers: Vec::new(),
      compose_program: cache.get("spectra/compositing/forward.glsl", vec![FORWARD_SOURCE.sem("source")]).unwrap(),
      texture_program: cache.get("spectra/compositing/texture.glsl", vec![TEXTURE_SOURCE.sem("source")]).unwrap(),
      quad: Tess::attributeless(Mode::TriangleStrip, 4)
    }
  }

  /// Whenever a node must be composed, we need a framebuffer to render into. This function pulls a
  /// framebuffer to use (via self.framebuffers) by returing an index. It might allocate a new
  /// framebuffer if there isn’t enough framebuffers to be pulled.
  fn pull_framebuffer(&mut self) -> usize {
    self.free_framebuffers.pop().unwrap_or_else(|| {
      let framebuffer_index = self.framebuffers.len();

      let framebuffer = Framebuffer::new((self.w, self.h), 0).unwrap();
      self.framebuffers.push(framebuffer);

      framebuffer_index
    })
  }

  /// Whenever a node has finished being composed, we *might* need to dispose the framebuffer it has
  /// pulled. This funciton does that job.
  ///
  /// It never deallocates memory. It has an important property: once a framebuffer is pulled,
  /// calling that function will make it available for other nodes, improving memory usage for the
  /// next calls.
  #[inline]
  fn dispose_framebuffer(&mut self, framebuffer_index: usize) {
    self.free_framebuffers.push(framebuffer_index);
  }

  /// Consume and display a compositing graph represented by its nodes.
  pub fn display(&mut self, root: Node) {
    let fb_index = self.treat_node(root);

    {
      let fb = &self.framebuffers[fb_index];
      let screen = Framebuffer::default((self.w, self.h));
      let compose_program = self.compose_program.borrow();
      let tess_render = TessRender::from(&self.quad);

      Pipeline::new(&screen, [0., 0., 0., 1.], &[&*fb.color_slot], &[]).enter(|shd_gate| {
        shd_gate.new(&compose_program, &[], &[], &[]).enter(|rdr_gate| {
          rdr_gate.new(None, false, &[], &[], &[]).enter(|tess_gate| {
            let uniforms = [FORWARD_SOURCE.alter(Unit::new(0))];
            tess_gate.render(tess_render, &uniforms, &[], &[])
          });
        });
      });
    }

    self.dispose_framebuffer(fb_index);
  }

  /// Treat a node hierarchy and return the index  of the framebuffer that contains the result.
  fn treat_node(&mut self, node: Node) -> usize {
    match node {
      Node::Render(layer) => self.render(layer),
      Node::Texture(texture) => self.texturize(texture),
      Node::Color(color) => self.colorize(color),
      Node::Composite(left, right, clear_color, eq, src_fct, dst_fct) => self.composite(*left, *right, clear_color, eq, src_fct, dst_fct),
      Node::FullScreenEffect(program) => self.fullscreen_effect(program)
    }
  }

  fn render(&mut self, layer: RenderLayer) -> usize {
    let fb_index = self.pull_framebuffer();
    let fb = &self.framebuffers[fb_index];

    (layer.render)(&fb);

    fb_index
  }

  fn texturize(&mut self, texture: TextureLayer) -> usize {
    let fb_index = self.pull_framebuffer();
    let fb = &self.framebuffers[fb_index];

    let texture_program = self.texture_program.borrow();
    let tess_render = TessRender::from(&self.quad);

    Pipeline::new(fb, [0., 0., 0., 1.], &[&**texture], &[]).enter(|shd_gate| {
      shd_gate.new(&texture_program, &[], &[], &[]).enter(|rdr_gate| {
        rdr_gate.new(None, false, &[], &[], &[]).enter(|tess_gate| {
          let uniforms = [TEXTURE_SOURCE.alter(Unit::new(0))];
          tess_gate.render(tess_render, &uniforms, &[], &[]);
        });
      });
    });

    fb_index
  }

  fn colorize(&mut self, color: RGBA) -> usize {
    let fb_index = self.pull_framebuffer();
    let fb = &self.framebuffers[fb_index];

    let color = *color.as_ref();

    Pipeline::new(fb, color, &[], &[]).enter(|_| {});

    fb_index
  }

  fn composite(&mut self, left: Node, right: Node, clear_color: RGBA, eq: Equation, src_fct: Factor, dst_fct: Factor) -> usize {
    let left_index = self.treat_node(left);
    let right_index = self.treat_node(right);

    assert!(left_index < self.framebuffers.len());
    assert!(right_index < self.framebuffers.len());

    let fb_index = self.pull_framebuffer();

    {
      let fb = &self.framebuffers[fb_index];

      let left_fb = &self.framebuffers[left_index];
      let right_fb = &self.framebuffers[right_index];

      let texture_set = &[
        &*left_fb.color_slot,
        &*right_fb.color_slot
      ];
      let compose_program = self.compose_program.borrow();
      let tess_render = TessRender::from(&self.quad);

      Pipeline::new(fb, *clear_color.as_ref(), texture_set, &[]).enter(|shd_gate| {
        shd_gate.new(&compose_program, &[], &[], &[]).enter(|rdr_gate| {
          rdr_gate.new((eq, src_fct, dst_fct), false, &[], &[], &[]).enter(|tess_gate| {
            let uniforms = [FORWARD_SOURCE.alter(Unit::new(0))];
            tess_gate.render(tess_render.clone(), &uniforms, &[], &[]);

            let uniforms = [FORWARD_SOURCE.alter(Unit::new(1))];
            tess_gate.render(tess_render, &uniforms, &[], &[]);
          });
        });
      });
    }

    // dispose both left and right framebuffers
    self.dispose_framebuffer(left_index);
    self.dispose_framebuffer(right_index);

    fb_index
  }

  fn fullscreen_effect(&mut self, program: &Program) -> usize {
    let fb_index = self.pull_framebuffer();
    let fb = &self.framebuffers[fb_index];

    let tess_render = TessRender::from(&self.quad);

    Pipeline::new(fb, [0., 0., 0., 1.], &[], &[]).enter(|shd_gate| {
      shd_gate.new(&program, &[], &[], &[]).enter(|rdr_gate| {
        rdr_gate.new(None, false, &[], &[], &[]).enter(|tess_gate| {
          tess_gate.render(tess_render, &[], &[], &[]);
        });
      });
    });

    fb_index
  }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use app_units::Au;
use webrender_traits::{FontKey, ColorU, FontRenderMode, GlyphDimensions};
use webrender_traits::{NativeFontHandle, GlyphOptions,  SubpixelOffset};
use webrender_traits::{GlyphKey};

use freetype::freetype::{FT_Render_Mode, FT_Pixel_Mode};
use freetype::freetype::{FT_Done_FreeType, FT_Library_SetLcdFilter};
use freetype::freetype::{FT_Library, FT_Set_Char_Size};
use freetype::freetype::{FT_Face, FT_Long, FT_UInt, FT_F26Dot6};
use freetype::freetype::{FT_Init_FreeType, FT_Load_Glyph, FT_Render_Glyph};
use freetype::freetype::{FT_New_Memory_Face, FT_GlyphSlot, FT_LcdFilter};

use std::{mem, ptr, slice};
use std::collections::HashMap;

struct Face {
    face: FT_Face,
}

pub struct FontContext {
    lib: FT_Library,
    faces: HashMap<FontKey, Face>,
}

pub struct RasterizedGlyph {
    pub width: u32,
    pub height: u32,
    pub bytes: Vec<u8>,
}

fn float_to_fixed(before: usize, f: f64) -> i32 {
    ((1i32 << before) as f64 * f) as i32
}

fn float_to_fixed_ft(f: f64) -> i32 {
    float_to_fixed(6, f)
}

impl FontContext {
    pub fn new() -> FontContext {
//        let _pf = util::ProfileScope::new("  FontContext::new");
        let mut lib: FT_Library = ptr::null_mut();
        unsafe {
            let result = FT_Init_FreeType(&mut lib);
            if !result.succeeded() {
                panic!("Unable to initialize FreeType library {:?}", result);
            }

            // TODO(gw): Check result of this to determine if freetype build supports subpixel.
            let result = FT_Library_SetLcdFilter(lib, FT_LcdFilter::FT_LCD_FILTER_DEFAULT);
            if !result.succeeded() {
                println!("WARN: Initializing a FreeType library build without subpixel AA enabled!");
            }
        }

        FontContext {
            lib: lib,
            faces: HashMap::new(),
        }
    }

    pub fn add_raw_font(&mut self, font_key: &FontKey, bytes: &[u8]) {
        if !self.faces.contains_key(&font_key) {
            let mut face: FT_Face = ptr::null_mut();
            let face_index = 0 as FT_Long;
            let result = unsafe {
                FT_New_Memory_Face(self.lib,
                                   bytes.as_ptr(),
                                   bytes.len() as FT_Long,
                                   face_index,
                                   &mut face)
            };
            if result.succeeded() && !face.is_null() {
                self.faces.insert(*font_key, Face {
                    face: face,
                    //_bytes: bytes
                });
            } else {
                println!("WARN: webrender failed to load font {:?}", font_key);
            }
        }
    }

    pub fn add_native_font(&mut self, _font_key: &FontKey, _native_font_handle: NativeFontHandle) {
        panic!("TODO: Not supported on Linux");
    }

    fn load_glyph(&self,
                  font_key: FontKey,
                  size: Au,
                  character: u32) -> Option<FT_GlyphSlot> {
        debug_assert!(self.faces.contains_key(&font_key));
        let face = self.faces.get(&font_key).unwrap();

        unsafe {
            let char_size = float_to_fixed_ft(size.to_f64_px());
            let result = FT_Set_Char_Size(face.face, char_size as FT_F26Dot6, 0, 0, 0);
            assert!(result.succeeded());

            let result =  FT_Load_Glyph(face.face, character as FT_UInt, 0);
            if result.succeeded() {
                let void_glyph = (*face.face).glyph;
                let slot_ptr: FT_GlyphSlot = mem::transmute(void_glyph);
                assert!(!slot_ptr.is_null());
                return Some(slot_ptr);
            }
        }

        None
    }

     pub fn get_glyph_dimensions(&mut self,
                                 key: &GlyphKey) -> Option<GlyphDimensions> {
        self.load_glyph(key.font_key, key.size, key.index).and_then(|slot| {
            let metrics = unsafe { &(*slot).metrics };
            if metrics.width == 0 || metrics.height == 0 {
                None
            } else {
                Some(GlyphDimensions {
                    left: (metrics.horiBearingX >> 6) as i32,
                    top: (metrics.horiBearingY >> 6) as i32,
                    width: (metrics.width >> 6) as u32,
                    height: (metrics.height >> 6) as u32,
                })
            }
        })
    }

    pub fn rasterize_glyph(&mut self,
                           key: &GlyphKey,
                           render_mode: FontRenderMode,
                           _glyph_options: Option<GlyphOptions>)
                           -> Option<RasterizedGlyph> {
        let mut glyph = None;

        if let Some(slot) = self.load_glyph(key.font_key,
                                            key.size,
                                            key.index) {
            let render_mode = match render_mode {
                FontRenderMode::Mono => FT_Render_Mode::FT_RENDER_MODE_MONO,
                FontRenderMode::Alpha => FT_Render_Mode::FT_RENDER_MODE_NORMAL,
                FontRenderMode::Subpixel => FT_Render_Mode::FT_RENDER_MODE_LCD,
            };

            let result = unsafe { FT_Render_Glyph(slot, render_mode) };

            if result.succeeded() {
                let bitmap = unsafe { &(*slot).bitmap };

                let metrics = unsafe { &(*slot).metrics };
                let mut glyph_width = (metrics.width >> 6) as i32;
                let glyph_height = (metrics.height >> 6) as i32;
                let mut final_buffer = Vec::with_capacity(glyph_width as usize *
                                                          glyph_height as usize *
                                                          4);

                if bitmap.pixel_mode == FT_Pixel_Mode::FT_PIXEL_MODE_MONO as u8 {
                    // This is not exactly efficient... but it's only used by the
                    // reftest pass when we have AA disabled on glyphs.
                    let offset_x = unsafe { (metrics.horiBearingX >> 6) as i32 - (*slot).bitmap_left };
                    let offset_y = unsafe { (metrics.horiBearingY >> 6) as i32 - (*slot).bitmap_top };

                    // Due to AA being disabled, the bitmap produced for mono
                    // glyphs is often smaller than the reported glyph dimensions.
                    // To account for this, place the rendered glyph within the
                    // box of the glyph dimensions, filling in invalid pixels with
                    // zero alpha.
                    for iy in 0..glyph_height {
                        let y = iy - offset_y;
                        for ix in 0..glyph_width {
                            let x = ix + offset_x;
                            let valid_byte = x >= 0 &&
                                y >= 0 &&
                                x < bitmap.width as i32 &&
                                y < bitmap.rows as i32;
                            let byte_value = if valid_byte {
                                let byte_index = (y * bitmap.pitch as i32) + (x >> 3);

                                unsafe {
                                    let bit_index = x & 7;
                                    let byte_ptr = bitmap.buffer.offset(byte_index as isize);
                                    let bit = (*byte_ptr & (0x80 >> bit_index)) != 0;
                                    if bit {
                                        0xff
                                    } else {
                                        0
                                    }
                                }
                            } else {
                                0
                            };

                            final_buffer.extend_from_slice(&[ 0xff, 0xff, 0xff, byte_value ]);
                        }
                    }
                } else if bitmap.pixel_mode == FT_Pixel_Mode::FT_PIXEL_MODE_GRAY as u8 {
                    // We can assume that the reported glyph dimensions exactly
                    // match the rasterized bitmap for normal alpha coverage glyphs.

                    let buffer = unsafe {
                        slice::from_raw_parts(
                            bitmap.buffer,
                            (bitmap.width * bitmap.rows) as usize
                        )
                    };

                    // Convert to RGBA.
                    for &byte in buffer.iter() {
                        final_buffer.extend_from_slice(&[ 0xff, 0xff, 0xff, byte ]);
                    }
                } else if bitmap.pixel_mode == FT_Pixel_Mode::FT_PIXEL_MODE_LCD as u8 {
                    // Extra subpixel on each side of the glyph.
                    glyph_width += 2;

                    for y in 0..bitmap.rows {
                        for x in 0..(bitmap.width / 3) {
                            let index = (y as i32 * bitmap.pitch) + (x as i32 * 3);

                            unsafe {
                                let ptr = bitmap.buffer.offset(index as isize);
                                let b = *ptr;
                                let g = *(ptr.offset(1));
                                let r = *(ptr.offset(2));

                                final_buffer.extend_from_slice(&[r, g, b, 0xff]);
                            }
                        }
                    }
                } else {
                    panic!("Unexpected render mode: {}!", bitmap.pixel_mode);
                }

                glyph = Some(RasterizedGlyph {
                    width: glyph_width as u32,
                    height: glyph_height as u32,
                    bytes: final_buffer,
                });
            }
        }

        glyph
    }
}

impl Drop for FontContext {
    fn drop(&mut self) {
        unsafe {
            FT_Done_FreeType(self.lib);
        }
    }
}
<commit_msg>Fix a few unused variable warnings.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use app_units::Au;
use webrender_traits::{FontKey, FontRenderMode, GlyphDimensions};
use webrender_traits::{NativeFontHandle, GlyphOptions};
use webrender_traits::{GlyphKey};

use freetype::freetype::{FT_Render_Mode, FT_Pixel_Mode};
use freetype::freetype::{FT_Done_FreeType, FT_Library_SetLcdFilter};
use freetype::freetype::{FT_Library, FT_Set_Char_Size};
use freetype::freetype::{FT_Face, FT_Long, FT_UInt, FT_F26Dot6};
use freetype::freetype::{FT_Init_FreeType, FT_Load_Glyph, FT_Render_Glyph};
use freetype::freetype::{FT_New_Memory_Face, FT_GlyphSlot, FT_LcdFilter};

use std::{mem, ptr, slice};
use std::collections::HashMap;

struct Face {
    face: FT_Face,
}

pub struct FontContext {
    lib: FT_Library,
    faces: HashMap<FontKey, Face>,
}

pub struct RasterizedGlyph {
    pub width: u32,
    pub height: u32,
    pub bytes: Vec<u8>,
}

fn float_to_fixed(before: usize, f: f64) -> i32 {
    ((1i32 << before) as f64 * f) as i32
}

fn float_to_fixed_ft(f: f64) -> i32 {
    float_to_fixed(6, f)
}

impl FontContext {
    pub fn new() -> FontContext {
//        let _pf = util::ProfileScope::new("  FontContext::new");
        let mut lib: FT_Library = ptr::null_mut();
        unsafe {
            let result = FT_Init_FreeType(&mut lib);
            if !result.succeeded() {
                panic!("Unable to initialize FreeType library {:?}", result);
            }

            // TODO(gw): Check result of this to determine if freetype build supports subpixel.
            let result = FT_Library_SetLcdFilter(lib, FT_LcdFilter::FT_LCD_FILTER_DEFAULT);
            if !result.succeeded() {
                println!("WARN: Initializing a FreeType library build without subpixel AA enabled!");
            }
        }

        FontContext {
            lib: lib,
            faces: HashMap::new(),
        }
    }

    pub fn add_raw_font(&mut self, font_key: &FontKey, bytes: &[u8]) {
        if !self.faces.contains_key(&font_key) {
            let mut face: FT_Face = ptr::null_mut();
            let face_index = 0 as FT_Long;
            let result = unsafe {
                FT_New_Memory_Face(self.lib,
                                   bytes.as_ptr(),
                                   bytes.len() as FT_Long,
                                   face_index,
                                   &mut face)
            };
            if result.succeeded() && !face.is_null() {
                self.faces.insert(*font_key, Face {
                    face: face,
                    //_bytes: bytes
                });
            } else {
                println!("WARN: webrender failed to load font {:?}", font_key);
            }
        }
    }

    pub fn add_native_font(&mut self, _font_key: &FontKey, _native_font_handle: NativeFontHandle) {
        panic!("TODO: Not supported on Linux");
    }

    fn load_glyph(&self,
                  font_key: FontKey,
                  size: Au,
                  character: u32) -> Option<FT_GlyphSlot> {
        debug_assert!(self.faces.contains_key(&font_key));
        let face = self.faces.get(&font_key).unwrap();

        unsafe {
            let char_size = float_to_fixed_ft(size.to_f64_px());
            let result = FT_Set_Char_Size(face.face, char_size as FT_F26Dot6, 0, 0, 0);
            assert!(result.succeeded());

            let result =  FT_Load_Glyph(face.face, character as FT_UInt, 0);
            if result.succeeded() {
                let void_glyph = (*face.face).glyph;
                let slot_ptr: FT_GlyphSlot = mem::transmute(void_glyph);
                assert!(!slot_ptr.is_null());
                return Some(slot_ptr);
            }
        }

        None
    }

     pub fn get_glyph_dimensions(&mut self,
                                 key: &GlyphKey) -> Option<GlyphDimensions> {
        self.load_glyph(key.font_key, key.size, key.index).and_then(|slot| {
            let metrics = unsafe { &(*slot).metrics };
            if metrics.width == 0 || metrics.height == 0 {
                None
            } else {
                Some(GlyphDimensions {
                    left: (metrics.horiBearingX >> 6) as i32,
                    top: (metrics.horiBearingY >> 6) as i32,
                    width: (metrics.width >> 6) as u32,
                    height: (metrics.height >> 6) as u32,
                })
            }
        })
    }

    pub fn rasterize_glyph(&mut self,
                           key: &GlyphKey,
                           render_mode: FontRenderMode,
                           _glyph_options: Option<GlyphOptions>)
                           -> Option<RasterizedGlyph> {
        let mut glyph = None;

        if let Some(slot) = self.load_glyph(key.font_key,
                                            key.size,
                                            key.index) {
            let render_mode = match render_mode {
                FontRenderMode::Mono => FT_Render_Mode::FT_RENDER_MODE_MONO,
                FontRenderMode::Alpha => FT_Render_Mode::FT_RENDER_MODE_NORMAL,
                FontRenderMode::Subpixel => FT_Render_Mode::FT_RENDER_MODE_LCD,
            };

            let result = unsafe { FT_Render_Glyph(slot, render_mode) };

            if result.succeeded() {
                let bitmap = unsafe { &(*slot).bitmap };

                let metrics = unsafe { &(*slot).metrics };
                let mut glyph_width = (metrics.width >> 6) as i32;
                let glyph_height = (metrics.height >> 6) as i32;
                let mut final_buffer = Vec::with_capacity(glyph_width as usize *
                                                          glyph_height as usize *
                                                          4);

                if bitmap.pixel_mode == FT_Pixel_Mode::FT_PIXEL_MODE_MONO as u8 {
                    // This is not exactly efficient... but it's only used by the
                    // reftest pass when we have AA disabled on glyphs.
                    let offset_x = unsafe { (metrics.horiBearingX >> 6) as i32 - (*slot).bitmap_left };
                    let offset_y = unsafe { (metrics.horiBearingY >> 6) as i32 - (*slot).bitmap_top };

                    // Due to AA being disabled, the bitmap produced for mono
                    // glyphs is often smaller than the reported glyph dimensions.
                    // To account for this, place the rendered glyph within the
                    // box of the glyph dimensions, filling in invalid pixels with
                    // zero alpha.
                    for iy in 0..glyph_height {
                        let y = iy - offset_y;
                        for ix in 0..glyph_width {
                            let x = ix + offset_x;
                            let valid_byte = x >= 0 &&
                                y >= 0 &&
                                x < bitmap.width as i32 &&
                                y < bitmap.rows as i32;
                            let byte_value = if valid_byte {
                                let byte_index = (y * bitmap.pitch as i32) + (x >> 3);

                                unsafe {
                                    let bit_index = x & 7;
                                    let byte_ptr = bitmap.buffer.offset(byte_index as isize);
                                    let bit = (*byte_ptr & (0x80 >> bit_index)) != 0;
                                    if bit {
                                        0xff
                                    } else {
                                        0
                                    }
                                }
                            } else {
                                0
                            };

                            final_buffer.extend_from_slice(&[ 0xff, 0xff, 0xff, byte_value ]);
                        }
                    }
                } else if bitmap.pixel_mode == FT_Pixel_Mode::FT_PIXEL_MODE_GRAY as u8 {
                    // We can assume that the reported glyph dimensions exactly
                    // match the rasterized bitmap for normal alpha coverage glyphs.

                    let buffer = unsafe {
                        slice::from_raw_parts(
                            bitmap.buffer,
                            (bitmap.width * bitmap.rows) as usize
                        )
                    };

                    // Convert to RGBA.
                    for &byte in buffer.iter() {
                        final_buffer.extend_from_slice(&[ 0xff, 0xff, 0xff, byte ]);
                    }
                } else if bitmap.pixel_mode == FT_Pixel_Mode::FT_PIXEL_MODE_LCD as u8 {
                    // Extra subpixel on each side of the glyph.
                    glyph_width += 2;

                    for y in 0..bitmap.rows {
                        for x in 0..(bitmap.width / 3) {
                            let index = (y as i32 * bitmap.pitch) + (x as i32 * 3);

                            unsafe {
                                let ptr = bitmap.buffer.offset(index as isize);
                                let b = *ptr;
                                let g = *(ptr.offset(1));
                                let r = *(ptr.offset(2));

                                final_buffer.extend_from_slice(&[r, g, b, 0xff]);
                            }
                        }
                    }
                } else {
                    panic!("Unexpected render mode: {}!", bitmap.pixel_mode);
                }

                glyph = Some(RasterizedGlyph {
                    width: glyph_width as u32,
                    height: glyph_height as u32,
                    bytes: final_buffer,
                });
            }
        }

        glyph
    }
}

impl Drop for FontContext {
    fn drop(&mut self) {
        unsafe {
            FT_Done_FreeType(self.lib);
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

//! Interface between Consensus and Network layers.

use crate::counters;
use anyhow::anyhow;
use aptos_config::network_id::{NetworkId, PeerNetworkId};
use aptos_logger::prelude::*;
use aptos_types::{epoch_change::EpochChangeProof, PeerId};
use async_trait::async_trait;
use channel::{aptos_channel, message_queues::QueueStyle};
use consensus_types::{
    block_retrieval::{BlockRetrievalRequest, BlockRetrievalResponse},
    epoch_retrieval::EpochRetrievalRequest,
    experimental::{commit_decision::CommitDecision, commit_vote::CommitVote},
    proposal_msg::ProposalMsg,
    sync_info::SyncInfo,
    vote_msg::VoteMsg,
};
use network::{
    application::storage::PeerMetadataStorage,
    constants::NETWORK_CHANNEL_SIZE,
    error::NetworkError,
    peer_manager::{ConnectionRequestSender, PeerManagerRequestSender},
    protocols::{
        network::{
            AppConfig, ApplicationNetworkSender, NetworkEvents, NetworkSender, NewNetworkSender,
        },
        rpc::error::RpcError,
        wire::handshake::v1::ProtocolIdSet,
    },
    ProtocolId,
};
use serde::{Deserialize, Serialize};
use std::{collections::HashMap, sync::Arc, time::Duration};

/// Network type for consensus
#[derive(Clone, Debug, Deserialize, Serialize)]
pub enum ConsensusMsg {
    /// RPC to get a chain of block of the given length starting from the given block id.
    BlockRetrievalRequest(Box<BlockRetrievalRequest>),
    /// Carries the returned blocks and the retrieval status.
    BlockRetrievalResponse(Box<BlockRetrievalResponse>),
    /// Request to get a EpochChangeProof from current_epoch to target_epoch
    EpochRetrievalRequest(Box<EpochRetrievalRequest>),
    /// ProposalMsg contains the required information for the proposer election protocol to make
    /// its choice (typically depends on round and proposer info).
    ProposalMsg(Box<ProposalMsg>),
    /// This struct describes basic synchronization metadata.
    SyncInfo(Box<SyncInfo>),
    /// A vector of LedgerInfo with contiguous increasing epoch numbers to prove a sequence of
    /// epoch changes from the first LedgerInfo's epoch.
    EpochChangeProof(Box<EpochChangeProof>),
    /// VoteMsg is the struct that is ultimately sent by the voter in response for receiving a
    /// proposal.
    VoteMsg(Box<VoteMsg>),
    /// CommitProposal is the struct that is sent by the validator after execution to propose
    /// on the committed state hash root.
    CommitVoteMsg(Box<CommitVote>),
    /// CommitDecision is the struct that is sent by the validator after collecting no fewer
    /// than 2f + 1 signatures on the commit proposal. This part is not on the critical path, but
    /// it can save slow machines to quickly confirm the execution result.
    CommitDecisionMsg(Box<CommitDecision>),
}

/// The interface from Network to Consensus layer.
///
/// `ConsensusNetworkEvents` is a `Stream` of `PeerManagerNotification` where the
/// raw `Bytes` direct-send and rpc messages are deserialized into
/// `ConsensusMessage` types. `ConsensusNetworkEvents` is a thin wrapper around
/// an `channel::Receiver<PeerManagerNotification>`.
pub type ConsensusNetworkEvents = NetworkEvents<ConsensusMsg>;

/// The interface from Consensus to Networking layer.
///
/// This is a thin wrapper around a `NetworkSender<ConsensusMsg>`, so it is easy
/// to clone and send off to a separate task. For example, the rpc requests
/// return Futures that encapsulate the whole flow, from sending the request to
/// remote, to finally receiving the response and deserializing. It therefore
/// makes the most sense to make the rpc call on a separate async task, which
/// requires the `ConsensusNetworkSender` to be `Clone` and `Send`.
#[derive(Clone)]
pub struct ConsensusNetworkSender {
    network_sender: NetworkSender<ConsensusMsg>,
    peer_metadata_storage: Option<Arc<PeerMetadataStorage>>,
}

/// Supported protocols in preferred order (from highest priority to lowest).
pub const RPC: &[ProtocolId] = &[ProtocolId::ConsensusRpcJson, ProtocolId::ConsensusRpcBcs];
/// Supported protocols in preferred order (from highest priority to lowest).
pub const DIRECT_SEND: &[ProtocolId] = &[
    ProtocolId::ConsensusDirectSendJson,
    ProtocolId::ConsensusDirectSendBcs,
];

/// Configuration for the network endpoints to support consensus.
/// TODO: make this configurable
pub fn network_endpoint_config() -> AppConfig {
    let protos = RPC.iter().chain(DIRECT_SEND.iter()).copied();
    AppConfig::p2p(
        protos,
        aptos_channel::Config::new(NETWORK_CHANNEL_SIZE)
            .queue_style(QueueStyle::LIFO)
            .counters(&counters::PENDING_CONSENSUS_NETWORK_EVENTS),
    )
}

impl NewNetworkSender for ConsensusNetworkSender {
    /// Returns a Sender that only sends for the `CONSENSUS_DIRECT_SEND_PROTOCOL` and
    /// `CONSENSUS_RPC_PROTOCOL` ProtocolId.
    fn new(
        peer_mgr_reqs_tx: PeerManagerRequestSender,
        connection_reqs_tx: ConnectionRequestSender,
    ) -> Self {
        Self {
            network_sender: NetworkSender::new(peer_mgr_reqs_tx, connection_reqs_tx),
            peer_metadata_storage: None,
        }
    }
}

impl ConsensusNetworkSender {
    /// Initialize a shared hashmap about connections metadata that is updated by the receiver.
    pub fn initialize(&mut self, peer_metadata_storage: Arc<PeerMetadataStorage>) {
        self.peer_metadata_storage = Some(peer_metadata_storage);
    }

    /// Query the supported protocols from this peer's connection.
    fn supported_protocols(&self, peer: PeerId) -> anyhow::Result<ProtocolIdSet> {
        if let Some(peer_metadata_storage) = &self.peer_metadata_storage {
            let peer_network_id = PeerNetworkId::new(NetworkId::Validator, peer);
            peer_metadata_storage
                .read(peer_network_id)
                .map(|peer_info| peer_info.active_connection.application_protocols)
                .ok_or_else(|| anyhow!("Peer not connected"))
        } else {
            Err(anyhow!("ConsensusNetworkSender not initialized"))
        }
    }

    /// Choose the overlapping protocol for peer. The local protocols are sorted from most to least preferred.
    fn preferred_protocol_for_peer(
        &self,
        peer: PeerId,
        local_protocols: &[ProtocolId],
    ) -> anyhow::Result<ProtocolId> {
        let remote_protocols = self.supported_protocols(peer)?;
        for protocol in local_protocols {
            if remote_protocols.contains(*protocol) {
                return Ok(*protocol);
            }
        }
        Err(anyhow!("No available protocols for peer {}", peer))
    }
}

#[async_trait]
impl ApplicationNetworkSender<ConsensusMsg> for ConsensusNetworkSender {
    /// Send a single message to the destination peer using available ProtocolId.
    fn send_to(&self, recipient: PeerId, message: ConsensusMsg) -> Result<(), NetworkError> {
        let protocol = self.preferred_protocol_for_peer(recipient, DIRECT_SEND)?;
        self.network_sender.send_to(recipient, protocol, message)
    }

    /// Send a single message to the destination peers using available ProtocolId.
    fn send_to_many(
        &self,
        recipients: impl Iterator<Item = PeerId>,
        message: ConsensusMsg,
    ) -> Result<(), NetworkError> {
        let mut peers_per_protocol = HashMap::new();
        for peer in recipients {
            match self.preferred_protocol_for_peer(peer, DIRECT_SEND) {
                Ok(protocol) => peers_per_protocol
                    .entry(protocol)
                    .or_insert_with(Vec::new)
                    .push(peer),
                Err(e) => error!("{}", e),
            }
        }
        for (protocol, peers) in peers_per_protocol {
            self.network_sender
                .send_to_many(peers.into_iter(), protocol, message.clone())?;
        }
        Ok(())
    }

    /// Send a RPC to the destination peer using the `CONSENSUS_RPC_PROTOCOL` ProtocolId.
    async fn send_rpc(
        &self,
        recipient: PeerId,
        message: ConsensusMsg,
        timeout: Duration,
    ) -> Result<ConsensusMsg, RpcError> {
        let protocol = self.preferred_protocol_for_peer(recipient, RPC)?;
        self.network_sender
            .send_rpc(recipient, protocol, message, timeout)
            .await
    }
}
<commit_msg>[consensus] switch back to bcs for consensus messages<commit_after>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

//! Interface between Consensus and Network layers.

use crate::counters;
use anyhow::anyhow;
use aptos_config::network_id::{NetworkId, PeerNetworkId};
use aptos_logger::prelude::*;
use aptos_types::{epoch_change::EpochChangeProof, PeerId};
use async_trait::async_trait;
use channel::{aptos_channel, message_queues::QueueStyle};
use consensus_types::{
    block_retrieval::{BlockRetrievalRequest, BlockRetrievalResponse},
    epoch_retrieval::EpochRetrievalRequest,
    experimental::{commit_decision::CommitDecision, commit_vote::CommitVote},
    proposal_msg::ProposalMsg,
    sync_info::SyncInfo,
    vote_msg::VoteMsg,
};
use network::{
    application::storage::PeerMetadataStorage,
    constants::NETWORK_CHANNEL_SIZE,
    error::NetworkError,
    peer_manager::{ConnectionRequestSender, PeerManagerRequestSender},
    protocols::{
        network::{
            AppConfig, ApplicationNetworkSender, NetworkEvents, NetworkSender, NewNetworkSender,
        },
        rpc::error::RpcError,
        wire::handshake::v1::ProtocolIdSet,
    },
    ProtocolId,
};
use serde::{Deserialize, Serialize};
use std::{collections::HashMap, sync::Arc, time::Duration};

/// Network type for consensus
#[derive(Clone, Debug, Deserialize, Serialize)]
pub enum ConsensusMsg {
    /// RPC to get a chain of block of the given length starting from the given block id.
    BlockRetrievalRequest(Box<BlockRetrievalRequest>),
    /// Carries the returned blocks and the retrieval status.
    BlockRetrievalResponse(Box<BlockRetrievalResponse>),
    /// Request to get a EpochChangeProof from current_epoch to target_epoch
    EpochRetrievalRequest(Box<EpochRetrievalRequest>),
    /// ProposalMsg contains the required information for the proposer election protocol to make
    /// its choice (typically depends on round and proposer info).
    ProposalMsg(Box<ProposalMsg>),
    /// This struct describes basic synchronization metadata.
    SyncInfo(Box<SyncInfo>),
    /// A vector of LedgerInfo with contiguous increasing epoch numbers to prove a sequence of
    /// epoch changes from the first LedgerInfo's epoch.
    EpochChangeProof(Box<EpochChangeProof>),
    /// VoteMsg is the struct that is ultimately sent by the voter in response for receiving a
    /// proposal.
    VoteMsg(Box<VoteMsg>),
    /// CommitProposal is the struct that is sent by the validator after execution to propose
    /// on the committed state hash root.
    CommitVoteMsg(Box<CommitVote>),
    /// CommitDecision is the struct that is sent by the validator after collecting no fewer
    /// than 2f + 1 signatures on the commit proposal. This part is not on the critical path, but
    /// it can save slow machines to quickly confirm the execution result.
    CommitDecisionMsg(Box<CommitDecision>),
}

/// The interface from Network to Consensus layer.
///
/// `ConsensusNetworkEvents` is a `Stream` of `PeerManagerNotification` where the
/// raw `Bytes` direct-send and rpc messages are deserialized into
/// `ConsensusMessage` types. `ConsensusNetworkEvents` is a thin wrapper around
/// an `channel::Receiver<PeerManagerNotification>`.
pub type ConsensusNetworkEvents = NetworkEvents<ConsensusMsg>;

/// The interface from Consensus to Networking layer.
///
/// This is a thin wrapper around a `NetworkSender<ConsensusMsg>`, so it is easy
/// to clone and send off to a separate task. For example, the rpc requests
/// return Futures that encapsulate the whole flow, from sending the request to
/// remote, to finally receiving the response and deserializing. It therefore
/// makes the most sense to make the rpc call on a separate async task, which
/// requires the `ConsensusNetworkSender` to be `Clone` and `Send`.
#[derive(Clone)]
pub struct ConsensusNetworkSender {
    network_sender: NetworkSender<ConsensusMsg>,
    peer_metadata_storage: Option<Arc<PeerMetadataStorage>>,
}

/// Supported protocols in preferred order (from highest priority to lowest).
pub const RPC: &[ProtocolId] = &[ProtocolId::ConsensusRpcBcs, ProtocolId::ConsensusRpcJson];
/// Supported protocols in preferred order (from highest priority to lowest).
pub const DIRECT_SEND: &[ProtocolId] = &[
    ProtocolId::ConsensusDirectSendBcs,
    ProtocolId::ConsensusDirectSendJson,
];

/// Configuration for the network endpoints to support consensus.
/// TODO: make this configurable
pub fn network_endpoint_config() -> AppConfig {
    let protos = RPC.iter().chain(DIRECT_SEND.iter()).copied();
    AppConfig::p2p(
        protos,
        aptos_channel::Config::new(NETWORK_CHANNEL_SIZE)
            .queue_style(QueueStyle::LIFO)
            .counters(&counters::PENDING_CONSENSUS_NETWORK_EVENTS),
    )
}

impl NewNetworkSender for ConsensusNetworkSender {
    /// Returns a Sender that only sends for the `CONSENSUS_DIRECT_SEND_PROTOCOL` and
    /// `CONSENSUS_RPC_PROTOCOL` ProtocolId.
    fn new(
        peer_mgr_reqs_tx: PeerManagerRequestSender,
        connection_reqs_tx: ConnectionRequestSender,
    ) -> Self {
        Self {
            network_sender: NetworkSender::new(peer_mgr_reqs_tx, connection_reqs_tx),
            peer_metadata_storage: None,
        }
    }
}

impl ConsensusNetworkSender {
    /// Initialize a shared hashmap about connections metadata that is updated by the receiver.
    pub fn initialize(&mut self, peer_metadata_storage: Arc<PeerMetadataStorage>) {
        self.peer_metadata_storage = Some(peer_metadata_storage);
    }

    /// Query the supported protocols from this peer's connection.
    fn supported_protocols(&self, peer: PeerId) -> anyhow::Result<ProtocolIdSet> {
        if let Some(peer_metadata_storage) = &self.peer_metadata_storage {
            let peer_network_id = PeerNetworkId::new(NetworkId::Validator, peer);
            peer_metadata_storage
                .read(peer_network_id)
                .map(|peer_info| peer_info.active_connection.application_protocols)
                .ok_or_else(|| anyhow!("Peer not connected"))
        } else {
            Err(anyhow!("ConsensusNetworkSender not initialized"))
        }
    }

    /// Choose the overlapping protocol for peer. The local protocols are sorted from most to least preferred.
    fn preferred_protocol_for_peer(
        &self,
        peer: PeerId,
        local_protocols: &[ProtocolId],
    ) -> anyhow::Result<ProtocolId> {
        let remote_protocols = self.supported_protocols(peer)?;
        for protocol in local_protocols {
            if remote_protocols.contains(*protocol) {
                return Ok(*protocol);
            }
        }
        Err(anyhow!("No available protocols for peer {}", peer))
    }
}

#[async_trait]
impl ApplicationNetworkSender<ConsensusMsg> for ConsensusNetworkSender {
    /// Send a single message to the destination peer using available ProtocolId.
    fn send_to(&self, recipient: PeerId, message: ConsensusMsg) -> Result<(), NetworkError> {
        let protocol = self.preferred_protocol_for_peer(recipient, DIRECT_SEND)?;
        self.network_sender.send_to(recipient, protocol, message)
    }

    /// Send a single message to the destination peers using available ProtocolId.
    fn send_to_many(
        &self,
        recipients: impl Iterator<Item = PeerId>,
        message: ConsensusMsg,
    ) -> Result<(), NetworkError> {
        let mut peers_per_protocol = HashMap::new();
        for peer in recipients {
            match self.preferred_protocol_for_peer(peer, DIRECT_SEND) {
                Ok(protocol) => peers_per_protocol
                    .entry(protocol)
                    .or_insert_with(Vec::new)
                    .push(peer),
                Err(e) => error!("{}", e),
            }
        }
        for (protocol, peers) in peers_per_protocol {
            self.network_sender
                .send_to_many(peers.into_iter(), protocol, message.clone())?;
        }
        Ok(())
    }

    /// Send a RPC to the destination peer using the `CONSENSUS_RPC_PROTOCOL` ProtocolId.
    async fn send_rpc(
        &self,
        recipient: PeerId,
        message: ConsensusMsg,
        timeout: Duration,
    ) -> Result<ConsensusMsg, RpcError> {
        let protocol = self.preferred_protocol_for_peer(recipient, RPC)?;
        self.network_sender
            .send_rpc(recipient, protocol, message, timeout)
            .await
    }
}
<|endoftext|>


<commit_before>use std::{
    fmt::{self, Write},
};

use libsyntax2::{
    File, TextUnit,
    ast::{self, AstNode, AttrsOwner, TypeParamsOwner, NameOwner},
    SyntaxKind::COMMA,
    SyntaxNodeRef,
    algo::{
        Direction, siblings,
        find_leaf_at_offset,
    },
};

use {EditBuilder, Edit, find_node_at_offset};

#[derive(Debug)]
pub struct ActionResult {
    pub edit: Edit,
    pub cursor_position: Option<TextUnit>,
}

pub fn flip_comma<'a>(file: &'a File, offset: TextUnit) -> Option<impl FnOnce() -> ActionResult + 'a> {
    let syntax = file.syntax();

    let comma = find_leaf_at_offset(syntax, offset).find(|leaf| leaf.kind() == COMMA)?;
    let left = non_trivia_sibling(comma, Direction::Backward)?;
    let right = non_trivia_sibling(comma, Direction::Forward)?;
    Some(move || {
        let mut edit = EditBuilder::new();
        edit.replace(left.range(), right.text().to_string());
        edit.replace(right.range(), left.text().to_string());
        ActionResult {
            edit: edit.finish(),
            cursor_position: None,
        }
    })
}

pub fn add_derive<'a>(file: &'a File, offset: TextUnit) -> Option<impl FnOnce() -> ActionResult + 'a> {
    let nominal = find_node_at_offset::<ast::NominalDef>(file.syntax(), offset)?;
    Some(move || {
        let derive_attr = nominal
            .attrs()
            .filter_map(|x| x.as_call())
            .filter(|(name, _arg)| name == "derive")
            .map(|(_name, arg)| arg)
            .next();
        let mut edit = EditBuilder::new();
        let offset = match derive_attr {
            None => {
                let node_start = nominal.syntax().range().start();
                edit.insert(node_start, "#[derive()]\n".to_string());
                node_start + TextUnit::of_str("#[derive(")
            }
            Some(tt) => {
                tt.syntax().range().end() - TextUnit::of_char(')')
            }
        };
        ActionResult {
            edit: edit.finish(),
            cursor_position: Some(offset),
        }
    })
}

pub fn add_impl<'a>(file: &'a File, offset: TextUnit) -> Option<impl FnOnce() -> ActionResult + 'a> {
    let nominal = find_node_at_offset::<ast::NominalDef>(file.syntax(), offset)?;
    let name = nominal.name()?;

    Some(move || {
        let type_params = nominal.type_param_list();
        let mut edit = EditBuilder::new();
        let start_offset = nominal.syntax().range().end();
        let mut buf = String::new();
        buf.push_str("\n\nimpl");
        if let Some(type_params) = type_params {
            buf.push_display(&type_params.syntax().text());
        }
        buf.push_str(" ");
        buf.push_str(name.text().as_str());
        if let Some(type_params) = type_params {
            comma_list(
                &mut buf, "<", ">",
                type_params.type_params()
                    .filter_map(|it| it.name())
                    .map(|it| it.text())
            );
        }
        buf.push_str(" {\n");
        let offset = start_offset + TextUnit::of_str(&buf);
        buf.push_str("\n}");
        edit.insert(start_offset, buf);
        ActionResult {
            edit: edit.finish(),
            cursor_position: Some(offset),
        }
    })
}

fn non_trivia_sibling(node: SyntaxNodeRef, direction: Direction) -> Option<SyntaxNodeRef> {
    siblings(node, direction)
        .skip(1)
        .find(|node| !node.kind().is_trivia())
}

fn comma_list(buf: &mut String, bra: &str, ket: &str, items: impl Iterator<Item=impl fmt::Display>) {
    buf.push_str(bra);
    let mut first = true;
    for item in items {
        if !first {
            first = false;
            buf.push_str(", ");
        }
        write!(buf, "{}", item).unwrap();
    }
    buf.push_str(ket);
}

trait PushDisplay {
    fn push_display<T: fmt::Display>(&mut self, item: &T);
}

impl PushDisplay for String {
    fn push_display<T: fmt::Display>(&mut self, item: &T) {
        use std::fmt::Write;
        write!(self, "{}", item).unwrap()
    }
}

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

    #[test]
    fn test_swap_comma() {
        check_action(
            "fn foo(x: i32,<|> y: Result<(), ()>) {}",
            "fn foo(y: Result<(), ()>,<|> x: i32) {}",
            |file, off| flip_comma(file, off).map(|f| f()),
        )
    }

    #[test]
    fn test_add_derive() {
        check_action(
            "struct Foo { a: i32, <|>}",
            "#[derive(<|>)]\nstruct Foo { a: i32, }",
            |file, off| add_derive(file, off).map(|f| f()),
        );
        check_action(
            "struct Foo { <|> a: i32, }",
            "#[derive(<|>)]\nstruct Foo {  a: i32, }",
            |file, off| add_derive(file, off).map(|f| f()),
        );
        check_action(
            "#[derive(Clone)]\nstruct Foo { a: i32<|>, }",
            "#[derive(Clone<|>)]\nstruct Foo { a: i32, }",
            |file, off| add_derive(file, off).map(|f| f()),
        );
    }

    #[test]
    fn test_add_impl() {
        check_action(
            "struct Foo {<|>}\n",
            "struct Foo {}\n\nimpl Foo {\n<|>\n}\n",
            |file, off| add_impl(file, off).map(|f| f()),
        );
        check_action(
            "struct Foo<T: Clone> {<|>}",
            "struct Foo<T: Clone> {}\n\nimpl<T: Clone> Foo<T> {\n<|>\n}",
            |file, off| add_impl(file, off).map(|f| f()),
        );
    }

}
<commit_msg>fix comma list<commit_after>use std::{
    fmt::{self, Write},
};

use libsyntax2::{
    File, TextUnit,
    ast::{self, AstNode, AttrsOwner, TypeParamsOwner, NameOwner},
    SyntaxKind::COMMA,
    SyntaxNodeRef,
    algo::{
        Direction, siblings,
        find_leaf_at_offset,
    },
};

use {EditBuilder, Edit, find_node_at_offset};

#[derive(Debug)]
pub struct ActionResult {
    pub edit: Edit,
    pub cursor_position: Option<TextUnit>,
}

pub fn flip_comma<'a>(file: &'a File, offset: TextUnit) -> Option<impl FnOnce() -> ActionResult + 'a> {
    let syntax = file.syntax();

    let comma = find_leaf_at_offset(syntax, offset).find(|leaf| leaf.kind() == COMMA)?;
    let left = non_trivia_sibling(comma, Direction::Backward)?;
    let right = non_trivia_sibling(comma, Direction::Forward)?;
    Some(move || {
        let mut edit = EditBuilder::new();
        edit.replace(left.range(), right.text().to_string());
        edit.replace(right.range(), left.text().to_string());
        ActionResult {
            edit: edit.finish(),
            cursor_position: None,
        }
    })
}

pub fn add_derive<'a>(file: &'a File, offset: TextUnit) -> Option<impl FnOnce() -> ActionResult + 'a> {
    let nominal = find_node_at_offset::<ast::NominalDef>(file.syntax(), offset)?;
    Some(move || {
        let derive_attr = nominal
            .attrs()
            .filter_map(|x| x.as_call())
            .filter(|(name, _arg)| name == "derive")
            .map(|(_name, arg)| arg)
            .next();
        let mut edit = EditBuilder::new();
        let offset = match derive_attr {
            None => {
                let node_start = nominal.syntax().range().start();
                edit.insert(node_start, "#[derive()]\n".to_string());
                node_start + TextUnit::of_str("#[derive(")
            }
            Some(tt) => {
                tt.syntax().range().end() - TextUnit::of_char(')')
            }
        };
        ActionResult {
            edit: edit.finish(),
            cursor_position: Some(offset),
        }
    })
}

pub fn add_impl<'a>(file: &'a File, offset: TextUnit) -> Option<impl FnOnce() -> ActionResult + 'a> {
    let nominal = find_node_at_offset::<ast::NominalDef>(file.syntax(), offset)?;
    let name = nominal.name()?;

    Some(move || {
        let type_params = nominal.type_param_list();
        let mut edit = EditBuilder::new();
        let start_offset = nominal.syntax().range().end();
        let mut buf = String::new();
        buf.push_str("\n\nimpl");
        if let Some(type_params) = type_params {
            buf.push_display(&type_params.syntax().text());
        }
        buf.push_str(" ");
        buf.push_str(name.text().as_str());
        if let Some(type_params) = type_params {
            comma_list(
                &mut buf, "<", ">",
                type_params.type_params()
                    .filter_map(|it| it.name())
                    .map(|it| it.text())
            );
        }
        buf.push_str(" {\n");
        let offset = start_offset + TextUnit::of_str(&buf);
        buf.push_str("\n}");
        edit.insert(start_offset, buf);
        ActionResult {
            edit: edit.finish(),
            cursor_position: Some(offset),
        }
    })
}

fn non_trivia_sibling(node: SyntaxNodeRef, direction: Direction) -> Option<SyntaxNodeRef> {
    siblings(node, direction)
        .skip(1)
        .find(|node| !node.kind().is_trivia())
}

fn comma_list(buf: &mut String, bra: &str, ket: &str, items: impl Iterator<Item=impl fmt::Display>) {
    buf.push_str(bra);
    let mut first = true;
    for item in items {
        if !first {
            buf.push_str(", ");
        }
        first = false;
        write!(buf, "{}", item).unwrap();
    }
    buf.push_str(ket);
}

trait PushDisplay {
    fn push_display<T: fmt::Display>(&mut self, item: &T);
}

impl PushDisplay for String {
    fn push_display<T: fmt::Display>(&mut self, item: &T) {
        use std::fmt::Write;
        write!(self, "{}", item).unwrap()
    }
}

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

    #[test]
    fn test_swap_comma() {
        check_action(
            "fn foo(x: i32,<|> y: Result<(), ()>) {}",
            "fn foo(y: Result<(), ()>,<|> x: i32) {}",
            |file, off| flip_comma(file, off).map(|f| f()),
        )
    }

    #[test]
    fn test_add_derive() {
        check_action(
            "struct Foo { a: i32, <|>}",
            "#[derive(<|>)]\nstruct Foo { a: i32, }",
            |file, off| add_derive(file, off).map(|f| f()),
        );
        check_action(
            "struct Foo { <|> a: i32, }",
            "#[derive(<|>)]\nstruct Foo {  a: i32, }",
            |file, off| add_derive(file, off).map(|f| f()),
        );
        check_action(
            "#[derive(Clone)]\nstruct Foo { a: i32<|>, }",
            "#[derive(Clone<|>)]\nstruct Foo { a: i32, }",
            |file, off| add_derive(file, off).map(|f| f()),
        );
    }

    #[test]
    fn test_add_impl() {
        check_action(
            "struct Foo {<|>}\n",
            "struct Foo {}\n\nimpl Foo {\n<|>\n}\n",
            |file, off| add_impl(file, off).map(|f| f()),
        );
        check_action(
            "struct Foo<T: Clone> {<|>}",
            "struct Foo<T: Clone> {}\n\nimpl<T: Clone> Foo<T> {\n<|>\n}",
            |file, off| add_impl(file, off).map(|f| f()),
        );
    }

}
<|endoftext|>