<commit_before>use num::Integer;
use std::convert::From;
use std::marker::PhantomData;
use std::mem;

pub trait Topological: Sized {
    type Vertex: Clone;
}

pub trait Polygonal: Topological {}

pub trait MapGeometry<T, U>: Topological<Vertex = T>
where
    T: Clone,
    U: Clone,
{
    type Output: Topological<Vertex = U>;

    fn map_geometry<F>(self, f: F) -> Self::Output
    where
        F: FnMut(T) -> U;
}

pub trait MapVertices<T, U>: Sized
where
    T: Clone,
    U: Clone,
{
    fn map_vertices<F>(self, f: F) -> Map<Self, T, U, F>
    where
        F: FnMut(T) -> U;
}

pub trait Rotate {
    fn rotate(&mut self, n: isize);
}

impl<I, T, U, P, Q> MapVertices<T, U> for I
where
    I: Iterator<Item = P>,
    P: MapGeometry<T, U, Output = Q>,
    Q: Topological<Vertex = U>,
    T: Clone,
    U: Clone,
{
    fn map_vertices<F>(self, f: F) -> Map<Self, T, U, F>
    where
        F: FnMut(T) -> U,
    {
        Map::new(self, f)
    }
}

pub struct Map<I, T, U, F> {
    topologies: I,
    f: F,
    phantom: PhantomData<(T, U)>,
}

impl<I, T, U, F> Map<I, T, U, F> {
    fn new(topologies: I, f: F) -> Self {
        Map {
            topologies: topologies,
            f: f,
            phantom: PhantomData,
        }
    }
}

impl<I, T, U, F, P, Q> Iterator for Map<I, T, U, F>
where
    I: Iterator<Item = P>,
    F: FnMut(T) -> U,
    P: MapGeometry<T, U, Output = Q>,
    Q: Topological<Vertex = U>,
    T: Clone,
    U: Clone,
{
    type Item = Q;

    fn next(&mut self) -> Option<Self::Item> {
        self.topologies
            .next()
            .map(|topology| topology.map_geometry(&mut self.f))
    }
}

pub struct Line<T> {
    pub a: T,
    pub b: T,
}

impl<T> Line<T> {
    pub fn new(a: T, b: T) -> Self {
        Line { a: a, b: b }
    }

    pub fn converged(value: T) -> Self
    where
        T: Clone,
    {
        Line::new(value.clone(), value)
    }
}

impl<T, U> MapGeometry<T, U> for Line<T>
where
    T: Clone,
    U: Clone,
{
    type Output = Line<U>;

    fn map_geometry<F>(self, mut f: F) -> Self::Output
    where
        F: FnMut(T) -> U,
    {
        let Line { a, b } = self;
        Line::new(f(a), f(b))
    }
}

impl<T> Topological for Line<T>
where
    T: Clone,
{
    type Vertex = T;
}

impl<T> Rotate for Line<T>
where
    T: Clone,
{
    fn rotate(&mut self, n: isize) {
        if n % 2 != 0 {
            mem::swap(&mut self.a, &mut self.b);
        }
    }
}

pub struct Triangle<T> {
    pub a: T,
    pub b: T,
    pub c: T,
}

impl<T> Triangle<T> {
    pub fn new(a: T, b: T, c: T) -> Self {
        Triangle { a: a, b: b, c: c }
    }

    pub fn converged(value: T) -> Self
    where
        T: Clone,
    {
        Triangle::new(value.clone(), value.clone(), value)
    }
}

impl<T, U> MapGeometry<T, U> for Triangle<T>
where
    T: Clone,
    U: Clone,
{
    type Output = Triangle<U>;

    fn map_geometry<F>(self, mut f: F) -> Self::Output
    where
        F: FnMut(T) -> U,
    {
        let Triangle { a, b, c } = self;
        Triangle::new(f(a), f(b), f(c))
    }
}

impl<T> Topological for Triangle<T>
where
    T: Clone,
{
    type Vertex = T;
}

impl<T> Polygonal for Triangle<T>
where
    T: Clone,
{
}

impl<T> Rotate for Triangle<T>
where
    T: Clone,
{
    fn rotate(&mut self, n: isize) {
        let n = umod(n, 3);
        if n == 1 {
            mem::swap(&mut self.a, &mut self.b);
            mem::swap(&mut self.b, &mut self.c);
        }
        else if n == 2 {
            mem::swap(&mut self.c, &mut self.b);
            mem::swap(&mut self.b, &mut self.a);
        }
    }
}

pub struct Quad<T> {
    pub a: T,
    pub b: T,
    pub c: T,
    pub d: T,
}

impl<T> Quad<T> {
    pub fn new(a: T, b: T, c: T, d: T) -> Self {
        Quad {
            a: a,
            b: b,
            c: c,
            d: d,
        }
    }

    pub fn converged(value: T) -> Self
    where
        T: Clone,
    {
        Quad::new(value.clone(), value.clone(), value.clone(), value)
    }
}

impl<T, U> MapGeometry<T, U> for Quad<T>
where
    T: Clone,
    U: Clone,
{
    type Output = Quad<U>;

    fn map_geometry<F>(self, mut f: F) -> Self::Output
    where
        F: FnMut(T) -> U,
    {
        let Quad { a, b, c, d } = self;
        Quad::new(f(a), f(b), f(c), f(d))
    }
}

impl<T> Topological for Quad<T>
where
    T: Clone,
{
    type Vertex = T;
}

impl<T> Polygonal for Quad<T>
where
    T: Clone,
{
}

impl<T> Rotate for Quad<T>
where
    T: Clone,
{
    fn rotate(&mut self, n: isize) {
        let n = umod(n, 4);
        if n == 1 {
            mem::swap(&mut self.a, &mut self.b);
            mem::swap(&mut self.b, &mut self.c);
            mem::swap(&mut self.c, &mut self.d);
        }
        else if n == 2 {
            mem::swap(&mut self.a, &mut self.c);
            mem::swap(&mut self.b, &mut self.d);
        }
        else if n == 3 {
            mem::swap(&mut self.d, &mut self.c);
            mem::swap(&mut self.c, &mut self.b);
            mem::swap(&mut self.b, &mut self.a);
        }
    }
}

pub enum Polygon<T> {
    Triangle(Triangle<T>),
    Quad(Quad<T>),
}

impl<T> From<Triangle<T>> for Polygon<T> {
    fn from(triangle: Triangle<T>) -> Self {
        Polygon::Triangle(triangle)
    }
}

impl<T> From<Quad<T>> for Polygon<T> {
    fn from(quad: Quad<T>) -> Self {
        Polygon::Quad(quad)
    }
}

impl<T, U> MapGeometry<T, U> for Polygon<T>
where
    T: Clone,
    U: Clone,
{
    type Output = Polygon<U>;

    fn map_geometry<F>(self, f: F) -> Self::Output
    where
        F: FnMut(T) -> U,
    {
        match self {
            Polygon::Triangle(triangle) => Polygon::Triangle(triangle.map_geometry(f)),
            Polygon::Quad(quad) => Polygon::Quad(quad.map_geometry(f)),
        }
    }
}

impl<T> Topological for Polygon<T>
where
    T: Clone,
{
    type Vertex = T;
}

impl<T> Polygonal for Polygon<T>
where
    T: Clone,
{
}

impl<T> Rotate for Polygon<T>
where
    T: Clone,
{
    fn rotate(&mut self, n: isize) {
        match *self {
            Polygon::Triangle(ref mut triangle) => triangle.rotate(n),
            Polygon::Quad(ref mut quad) => quad.rotate(n),
        }
    }
}

fn umod<T>(n: T, m: T) -> T
where
    T: Copy + Integer,
{
    ((n % m) + m) % m
}
<commit_msg>Remove unneeded import.<commit_after>use num::Integer;
use std::marker::PhantomData;
use std::mem;

pub trait Topological: Sized {
    type Vertex: Clone;
}

pub trait Polygonal: Topological {}

pub trait MapGeometry<T, U>: Topological<Vertex = T>
where
    T: Clone,
    U: Clone,
{
    type Output: Topological<Vertex = U>;

    fn map_geometry<F>(self, f: F) -> Self::Output
    where
        F: FnMut(T) -> U;
}

pub trait MapVertices<T, U>: Sized
where
    T: Clone,
    U: Clone,
{
    fn map_vertices<F>(self, f: F) -> Map<Self, T, U, F>
    where
        F: FnMut(T) -> U;
}

pub trait Rotate {
    fn rotate(&mut self, n: isize);
}

impl<I, T, U, P, Q> MapVertices<T, U> for I
where
    I: Iterator<Item = P>,
    P: MapGeometry<T, U, Output = Q>,
    Q: Topological<Vertex = U>,
    T: Clone,
    U: Clone,
{
    fn map_vertices<F>(self, f: F) -> Map<Self, T, U, F>
    where
        F: FnMut(T) -> U,
    {
        Map::new(self, f)
    }
}

pub struct Map<I, T, U, F> {
    topologies: I,
    f: F,
    phantom: PhantomData<(T, U)>,
}

impl<I, T, U, F> Map<I, T, U, F> {
    fn new(topologies: I, f: F) -> Self {
        Map {
            topologies: topologies,
            f: f,
            phantom: PhantomData,
        }
    }
}

impl<I, T, U, F, P, Q> Iterator for Map<I, T, U, F>
where
    I: Iterator<Item = P>,
    F: FnMut(T) -> U,
    P: MapGeometry<T, U, Output = Q>,
    Q: Topological<Vertex = U>,
    T: Clone,
    U: Clone,
{
    type Item = Q;

    fn next(&mut self) -> Option<Self::Item> {
        self.topologies
            .next()
            .map(|topology| topology.map_geometry(&mut self.f))
    }
}

pub struct Line<T> {
    pub a: T,
    pub b: T,
}

impl<T> Line<T> {
    pub fn new(a: T, b: T) -> Self {
        Line { a: a, b: b }
    }

    pub fn converged(value: T) -> Self
    where
        T: Clone,
    {
        Line::new(value.clone(), value)
    }
}

impl<T, U> MapGeometry<T, U> for Line<T>
where
    T: Clone,
    U: Clone,
{
    type Output = Line<U>;

    fn map_geometry<F>(self, mut f: F) -> Self::Output
    where
        F: FnMut(T) -> U,
    {
        let Line { a, b } = self;
        Line::new(f(a), f(b))
    }
}

impl<T> Topological for Line<T>
where
    T: Clone,
{
    type Vertex = T;
}

impl<T> Rotate for Line<T>
where
    T: Clone,
{
    fn rotate(&mut self, n: isize) {
        if n % 2 != 0 {
            mem::swap(&mut self.a, &mut self.b);
        }
    }
}

pub struct Triangle<T> {
    pub a: T,
    pub b: T,
    pub c: T,
}

impl<T> Triangle<T> {
    pub fn new(a: T, b: T, c: T) -> Self {
        Triangle { a: a, b: b, c: c }
    }

    pub fn converged(value: T) -> Self
    where
        T: Clone,
    {
        Triangle::new(value.clone(), value.clone(), value)
    }
}

impl<T, U> MapGeometry<T, U> for Triangle<T>
where
    T: Clone,
    U: Clone,
{
    type Output = Triangle<U>;

    fn map_geometry<F>(self, mut f: F) -> Self::Output
    where
        F: FnMut(T) -> U,
    {
        let Triangle { a, b, c } = self;
        Triangle::new(f(a), f(b), f(c))
    }
}

impl<T> Topological for Triangle<T>
where
    T: Clone,
{
    type Vertex = T;
}

impl<T> Polygonal for Triangle<T>
where
    T: Clone,
{
}

impl<T> Rotate for Triangle<T>
where
    T: Clone,
{
    fn rotate(&mut self, n: isize) {
        let n = umod(n, 3);
        if n == 1 {
            mem::swap(&mut self.a, &mut self.b);
            mem::swap(&mut self.b, &mut self.c);
        }
        else if n == 2 {
            mem::swap(&mut self.c, &mut self.b);
            mem::swap(&mut self.b, &mut self.a);
        }
    }
}

pub struct Quad<T> {
    pub a: T,
    pub b: T,
    pub c: T,
    pub d: T,
}

impl<T> Quad<T> {
    pub fn new(a: T, b: T, c: T, d: T) -> Self {
        Quad {
            a: a,
            b: b,
            c: c,
            d: d,
        }
    }

    pub fn converged(value: T) -> Self
    where
        T: Clone,
    {
        Quad::new(value.clone(), value.clone(), value.clone(), value)
    }
}

impl<T, U> MapGeometry<T, U> for Quad<T>
where
    T: Clone,
    U: Clone,
{
    type Output = Quad<U>;

    fn map_geometry<F>(self, mut f: F) -> Self::Output
    where
        F: FnMut(T) -> U,
    {
        let Quad { a, b, c, d } = self;
        Quad::new(f(a), f(b), f(c), f(d))
    }
}

impl<T> Topological for Quad<T>
where
    T: Clone,
{
    type Vertex = T;
}

impl<T> Polygonal for Quad<T>
where
    T: Clone,
{
}

impl<T> Rotate for Quad<T>
where
    T: Clone,
{
    fn rotate(&mut self, n: isize) {
        let n = umod(n, 4);
        if n == 1 {
            mem::swap(&mut self.a, &mut self.b);
            mem::swap(&mut self.b, &mut self.c);
            mem::swap(&mut self.c, &mut self.d);
        }
        else if n == 2 {
            mem::swap(&mut self.a, &mut self.c);
            mem::swap(&mut self.b, &mut self.d);
        }
        else if n == 3 {
            mem::swap(&mut self.d, &mut self.c);
            mem::swap(&mut self.c, &mut self.b);
            mem::swap(&mut self.b, &mut self.a);
        }
    }
}

pub enum Polygon<T> {
    Triangle(Triangle<T>),
    Quad(Quad<T>),
}

impl<T> From<Triangle<T>> for Polygon<T> {
    fn from(triangle: Triangle<T>) -> Self {
        Polygon::Triangle(triangle)
    }
}

impl<T> From<Quad<T>> for Polygon<T> {
    fn from(quad: Quad<T>) -> Self {
        Polygon::Quad(quad)
    }
}

impl<T, U> MapGeometry<T, U> for Polygon<T>
where
    T: Clone,
    U: Clone,
{
    type Output = Polygon<U>;

    fn map_geometry<F>(self, f: F) -> Self::Output
    where
        F: FnMut(T) -> U,
    {
        match self {
            Polygon::Triangle(triangle) => Polygon::Triangle(triangle.map_geometry(f)),
            Polygon::Quad(quad) => Polygon::Quad(quad.map_geometry(f)),
        }
    }
}

impl<T> Topological for Polygon<T>
where
    T: Clone,
{
    type Vertex = T;
}

impl<T> Polygonal for Polygon<T>
where
    T: Clone,
{
}

impl<T> Rotate for Polygon<T>
where
    T: Clone,
{
    fn rotate(&mut self, n: isize) {
        match *self {
            Polygon::Triangle(ref mut triangle) => triangle.rotate(n),
            Polygon::Quad(ref mut quad) => quad.rotate(n),
        }
    }
}

fn umod<T>(n: T, m: T) -> T
where
    T: Copy + Integer,
{
    ((n % m) + m) % m
}
<|endoftext|>


<commit_before>pub use objekt::clone_box;
use time::Tm;

/// Target of a message to be shown in a UI.
#[derive(Debug)]
pub enum MsgTarget<'a> {
    /// Show the message in the server tab.
    Server { serv: &'a str },

    /// Show the message in the channel tab.
    Chan { serv: &'a str, chan: &'a str },

    /// Show the message in the privmsg tab.
    User { serv: &'a str, nick: &'a str },

    /// Show the message in all tabs of a server.
    AllServTabs { serv: &'a str },

    /// Show the message in currently active tab.
    CurrentTab,
}

/// Source of a message from the user.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum MsgSource {
    /// Message sent in a server tab.
    Serv { serv: String },

    /// Message sent in a channel tab.
    Chan { serv: String, chan: String },

    /// Message sent in a privmsg tab.
    User { serv: String, nick: String },
}

impl MsgSource {
    pub fn serv_name(&self) -> &str {
        match *self {
            MsgSource::Serv { ref serv }
            | MsgSource::Chan { ref serv, .. }
            | MsgSource::User { ref serv, .. } => serv,
        }
    }

    pub fn to_target(&self) -> MsgTarget {
        match *self {
            MsgSource::Serv { ref serv } => MsgTarget::Server { serv },
            MsgSource::Chan { ref serv, ref chan } => MsgTarget::Chan { serv, chan },
            MsgSource::User { ref serv, ref nick } => MsgTarget::User { serv, nick },
        }
    }

    pub fn visible_name(&self) -> &str {
        match *self {
            MsgSource::Serv { ref serv, .. } => serv,
            MsgSource::Chan { ref chan, .. } => chan,
            MsgSource::User { ref nick, .. } => nick,
        }
    }
}

// NOTE: Keep the variants sorted in increasing significance, to avoid updating
// style with higher significance for a less significant style (e.g. updating
// from `Highlight` to `NewMsg` in `set_tab_style`).
// TODO: This shouldn't be a part of the API
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum TabStyle {
    Normal,
    NewMsg,
    Highlight,
}

/// UI events
#[derive(Debug)]
pub enum Event {
    Abort,
    Msg {
        msg: String,
        source: MsgSource,
    },
    Lines {
        lines: Vec<String>,
        source: MsgSource,
    },
    Cmd {
        cmd: String,
        source: MsgSource,
    },
}

pub trait UI: objekt::Clone {
    fn draw(&self);

    /// Create a new server tab.
    fn new_server_tab(&self, serv: &str, alias: Option<String>);

    /// Close a server tab and all channel and user tabs for that server.
    fn close_server_tab(&self, serv: &str);

    /// Create a channel tab in the given server.
    fn new_chan_tab(&self, serv: &str, chan: &str);

    /// Close a channel tab.
    fn close_chan_tab(&self, serv: &str, chan: &str);

    /// Close a user tab.
    fn close_user_tab(&self, serv: &str, nick: &str);

    /// Show a message coming from a client in the given tabs.
    fn add_client_msg(&self, msg: &str, target: &MsgTarget);

    /// Show a plain message with a timestamp in the given tabs.
    // TODO: What is a "plain message"? Not descriptive.
    fn add_msg(&self, msg: &str, ts: Tm, target: &MsgTarget);

    /// Show an IRC error message in the given tabs.
    fn add_err_msg(&self, msg: &str, ts: Tm, target: &MsgTarget);

    /// Show a client error message in the given tabs. Usuallys generated in case of a command
    /// error, e.g. "unknown command".
    fn add_client_err_msg(&self, msg: &str, target: &MsgTarget);

    /// Clear all nicks in a server from the UI's cache. Does not show anything.
    fn clear_nicks(&self, serv: &str);

    /// Set the client's nick in the given server.
    fn set_nick(&self, serv: &str, nick: &str);

    /// Show a user message sent to the client or to a channel.
    ///
    /// - highlight: Whether to highlight the message. Usually set `true` when the message mentions
    ///   the client's nick.
    ///
    /// - is_action: `true` when this is a CTCP ACTION message.
    ///
    fn add_privmsg(
        &self,
        sender: &str,
        msg: &str,
        ts: Tm,
        target: &MsgTarget,
        highlight: bool,
        is_action: bool,
    );

    /// Add a nick to the given tabs. When `ts` is not provided this does not show anything; just
    /// updated the channel nick list etc. Otherwise this shows a line like "foo joined channel".
    fn add_nick(&self, nick: &str, ts: Option<Tm>, target: &MsgTarget);

    /// Remove a nick from given tabs. Similar to `add_nick`, when `ts` is not provided this does
    /// not show a "foo left channel" line.
    fn remove_nick(&self, nick: &str, ts: Option<Tm>, target: &MsgTarget);

    /// Rename a nick in the given tabs.
    fn rename_nick(&self, old_nick: &str, new_nick: &str, ts: Tm, target: &MsgTarget);

    /// Set topic of given tabs.
    fn set_topic(&self, topic: &str, ts: Tm, serv: &str, chan: &str);

    /// Set style of the given tabs.
    fn set_tab_style(&self, style: TabStyle, target: &MsgTarget);

    /// Do we have a tab for the given user? This is useful for deciding where to show a PRIVMSG
    /// coming from server; e.g. messages from services sometimes shown in their own tabs,
    /// sometimes in the server tab.
    fn user_tab_exists(&self, serv: &str, nick: &str) -> bool;
}

#[derive(Clone)]
pub struct CombinedUIs<UI1, UI2> {
    ui1: UI1,
    ui2: UI2,
}

impl<UI1: UI + Clone, UI2: UI + Clone> UI for CombinedUIs<UI1, UI2> {
    fn draw(&self) {
        self.ui1.draw();
        self.ui2.draw();
    }

    fn new_server_tab(&self, serv: &str, alias: Option<String>) {
        self.ui1.new_server_tab(serv, alias.clone());
        self.ui2.new_server_tab(serv, alias);
    }

    fn close_server_tab(&self, serv: &str) {
        self.ui1.close_server_tab(serv);
        self.ui2.close_server_tab(serv);
    }

    fn new_chan_tab(&self, serv: &str, chan: &str) {
        self.ui1.new_chan_tab(serv, chan);
        self.ui2.new_chan_tab(serv, chan);
    }

    fn close_chan_tab(&self, serv: &str, chan: &str) {
        self.ui1.close_chan_tab(serv, chan);
        self.ui2.close_chan_tab(serv, chan);
    }

    fn close_user_tab(&self, serv: &str, nick: &str) {
        self.ui1.close_user_tab(serv, nick);
        self.ui2.close_user_tab(serv, nick);
    }

    fn add_client_msg(&self, msg: &str, target: &MsgTarget) {
        self.ui1.add_client_msg(msg, target);
        self.ui2.add_client_msg(msg, target);
    }

    fn add_msg(&self, msg: &str, ts: Tm, target: &MsgTarget) {
        self.ui1.add_msg(msg, ts, target);
        self.ui2.add_msg(msg, ts, target);
    }

    fn add_err_msg(&self, msg: &str, ts: Tm, target: &MsgTarget) {
        self.ui1.add_err_msg(msg, ts, target);
        self.ui2.add_err_msg(msg, ts, target);
    }

    fn add_client_err_msg(&self, msg: &str, target: &MsgTarget) {
        self.ui1.add_client_err_msg(msg, target);
        self.ui2.add_client_err_msg(msg, target);
    }

    fn clear_nicks(&self, serv: &str) {
        self.ui1.clear_nicks(serv);
        self.ui2.clear_nicks(serv);
    }

    fn set_nick(&self, serv: &str, nick: &str) {
        self.ui1.set_nick(serv, nick);
        self.ui2.set_nick(serv, nick);
    }

    fn add_privmsg(
        &self,
        sender: &str,
        msg: &str,
        ts: Tm,
        target: &MsgTarget,
        highlight: bool,
        is_action: bool,
    ) {
        self.ui1
            .add_privmsg(sender, msg, ts, target, highlight, is_action);
        self.ui2
            .add_privmsg(sender, msg, ts, target, highlight, is_action);
    }

    fn add_nick(&self, nick: &str, ts: Option<Tm>, target: &MsgTarget) {
        self.ui1.add_nick(nick, ts, target);
        self.ui2.add_nick(nick, ts, target);
    }

    fn remove_nick(&self, nick: &str, ts: Option<Tm>, target: &MsgTarget) {
        self.ui1.remove_nick(nick, ts, target);
        self.ui2.remove_nick(nick, ts, target);
    }

    fn rename_nick(&self, old_nick: &str, new_nick: &str, ts: Tm, target: &MsgTarget) {
        self.ui1.rename_nick(old_nick, new_nick, ts, target);
        self.ui2.rename_nick(old_nick, new_nick, ts, target);
    }

    fn set_topic(&self, topic: &str, ts: Tm, serv: &str, chan: &str) {
        self.ui1.set_topic(topic, ts, serv, chan);
        self.ui2.set_topic(topic, ts, serv, chan);
    }

    fn set_tab_style(&self, style: TabStyle, target: &MsgTarget) {
        self.ui1.set_tab_style(style, target);
        self.ui2.set_tab_style(style, target);
    }

    fn user_tab_exists(&self, serv: &str, nick: &str) -> bool {
        // TODO weird
        self.ui1.user_tab_exists(serv, nick)
    }
}

pub fn combine<UI1: UI, UI2: UI>(ui1: UI1, ui2: UI2) -> CombinedUIs<UI1, UI2> {
    CombinedUIs { ui1, ui2 }
}
<commit_msg>libtiny_ui: Minor refactoring, remove ref pats<commit_after>pub use objekt::clone_box;
use time::Tm;

/// Target of a message to be shown in a UI.
#[derive(Debug)]
pub enum MsgTarget<'a> {
    /// Show the message in the server tab.
    Server { serv: &'a str },

    /// Show the message in the channel tab.
    Chan { serv: &'a str, chan: &'a str },

    /// Show the message in the privmsg tab.
    User { serv: &'a str, nick: &'a str },

    /// Show the message in all tabs of a server.
    AllServTabs { serv: &'a str },

    /// Show the message in currently active tab.
    CurrentTab,
}

/// Source of a message from the user.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum MsgSource {
    /// Message sent in a server tab.
    Serv { serv: String },

    /// Message sent in a channel tab.
    Chan { serv: String, chan: String },

    /// Message sent in a privmsg tab.
    User { serv: String, nick: String },
}

impl MsgSource {
    pub fn serv_name(&self) -> &str {
        match self {
            MsgSource::Serv { serv }
            | MsgSource::Chan { serv, .. }
            | MsgSource::User { serv, .. } => serv,
        }
    }

    pub fn to_target(&self) -> MsgTarget {
        match self {
            MsgSource::Serv { serv } => MsgTarget::Server { serv },
            MsgSource::Chan { serv, chan } => MsgTarget::Chan { serv, chan },
            MsgSource::User { serv, nick } => MsgTarget::User { serv, nick },
        }
    }

    pub fn visible_name(&self) -> &str {
        match self {
            MsgSource::Serv { serv, .. } => serv,
            MsgSource::Chan { chan, .. } => chan,
            MsgSource::User { nick, .. } => nick,
        }
    }
}

// NOTE: Keep the variants sorted in increasing significance, to avoid updating
// style with higher significance for a less significant style (e.g. updating
// from `Highlight` to `NewMsg` in `set_tab_style`).
// TODO: This shouldn't be a part of the API
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum TabStyle {
    Normal,
    NewMsg,
    Highlight,
}

/// UI events
#[derive(Debug)]
pub enum Event {
    Abort,
    Msg {
        msg: String,
        source: MsgSource,
    },
    Lines {
        lines: Vec<String>,
        source: MsgSource,
    },
    Cmd {
        cmd: String,
        source: MsgSource,
    },
}

pub trait UI: objekt::Clone {
    fn draw(&self);

    /// Create a new server tab.
    fn new_server_tab(&self, serv: &str, alias: Option<String>);

    /// Close a server tab and all channel and user tabs for that server.
    fn close_server_tab(&self, serv: &str);

    /// Create a channel tab in the given server.
    fn new_chan_tab(&self, serv: &str, chan: &str);

    /// Close a channel tab.
    fn close_chan_tab(&self, serv: &str, chan: &str);

    /// Close a user tab.
    fn close_user_tab(&self, serv: &str, nick: &str);

    /// Show a message coming from a client in the given tabs.
    fn add_client_msg(&self, msg: &str, target: &MsgTarget);

    /// Show a plain message with a timestamp in the given tabs.
    // TODO: What is a "plain message"? Not descriptive.
    fn add_msg(&self, msg: &str, ts: Tm, target: &MsgTarget);

    /// Show an IRC error message in the given tabs.
    fn add_err_msg(&self, msg: &str, ts: Tm, target: &MsgTarget);

    /// Show a client error message in the given tabs. Usuallys generated in case of a command
    /// error, e.g. "unknown command".
    fn add_client_err_msg(&self, msg: &str, target: &MsgTarget);

    /// Clear all nicks in a server from the UI's cache. Does not show anything.
    fn clear_nicks(&self, serv: &str);

    /// Set the client's nick in the given server.
    fn set_nick(&self, serv: &str, nick: &str);

    /// Show a user message sent to the client or to a channel.
    ///
    /// - highlight: Whether to highlight the message. Usually set `true` when the message mentions
    ///   the client's nick.
    ///
    /// - is_action: `true` when this is a CTCP ACTION message.
    ///
    fn add_privmsg(
        &self,
        sender: &str,
        msg: &str,
        ts: Tm,
        target: &MsgTarget,
        highlight: bool,
        is_action: bool,
    );

    /// Add a nick to the given tabs. When `ts` is not provided this does not show anything; just
    /// updated the channel nick list etc. Otherwise this shows a line like "foo joined channel".
    fn add_nick(&self, nick: &str, ts: Option<Tm>, target: &MsgTarget);

    /// Remove a nick from given tabs. Similar to `add_nick`, when `ts` is not provided this does
    /// not show a "foo left channel" line.
    fn remove_nick(&self, nick: &str, ts: Option<Tm>, target: &MsgTarget);

    /// Rename a nick in the given tabs.
    fn rename_nick(&self, old_nick: &str, new_nick: &str, ts: Tm, target: &MsgTarget);

    /// Set topic of given tabs.
    fn set_topic(&self, topic: &str, ts: Tm, serv: &str, chan: &str);

    /// Set style of the given tabs.
    fn set_tab_style(&self, style: TabStyle, target: &MsgTarget);

    /// Do we have a tab for the given user? This is useful for deciding where to show a PRIVMSG
    /// coming from server; e.g. messages from services sometimes shown in their own tabs,
    /// sometimes in the server tab.
    fn user_tab_exists(&self, serv: &str, nick: &str) -> bool;
}

#[derive(Clone)]
pub struct CombinedUIs<UI1, UI2> {
    ui1: UI1,
    ui2: UI2,
}

impl<UI1: UI + Clone, UI2: UI + Clone> UI for CombinedUIs<UI1, UI2> {
    fn draw(&self) {
        self.ui1.draw();
        self.ui2.draw();
    }

    fn new_server_tab(&self, serv: &str, alias: Option<String>) {
        self.ui1.new_server_tab(serv, alias.clone());
        self.ui2.new_server_tab(serv, alias);
    }

    fn close_server_tab(&self, serv: &str) {
        self.ui1.close_server_tab(serv);
        self.ui2.close_server_tab(serv);
    }

    fn new_chan_tab(&self, serv: &str, chan: &str) {
        self.ui1.new_chan_tab(serv, chan);
        self.ui2.new_chan_tab(serv, chan);
    }

    fn close_chan_tab(&self, serv: &str, chan: &str) {
        self.ui1.close_chan_tab(serv, chan);
        self.ui2.close_chan_tab(serv, chan);
    }

    fn close_user_tab(&self, serv: &str, nick: &str) {
        self.ui1.close_user_tab(serv, nick);
        self.ui2.close_user_tab(serv, nick);
    }

    fn add_client_msg(&self, msg: &str, target: &MsgTarget) {
        self.ui1.add_client_msg(msg, target);
        self.ui2.add_client_msg(msg, target);
    }

    fn add_msg(&self, msg: &str, ts: Tm, target: &MsgTarget) {
        self.ui1.add_msg(msg, ts, target);
        self.ui2.add_msg(msg, ts, target);
    }

    fn add_err_msg(&self, msg: &str, ts: Tm, target: &MsgTarget) {
        self.ui1.add_err_msg(msg, ts, target);
        self.ui2.add_err_msg(msg, ts, target);
    }

    fn add_client_err_msg(&self, msg: &str, target: &MsgTarget) {
        self.ui1.add_client_err_msg(msg, target);
        self.ui2.add_client_err_msg(msg, target);
    }

    fn clear_nicks(&self, serv: &str) {
        self.ui1.clear_nicks(serv);
        self.ui2.clear_nicks(serv);
    }

    fn set_nick(&self, serv: &str, nick: &str) {
        self.ui1.set_nick(serv, nick);
        self.ui2.set_nick(serv, nick);
    }

    fn add_privmsg(
        &self,
        sender: &str,
        msg: &str,
        ts: Tm,
        target: &MsgTarget,
        highlight: bool,
        is_action: bool,
    ) {
        self.ui1
            .add_privmsg(sender, msg, ts, target, highlight, is_action);
        self.ui2
            .add_privmsg(sender, msg, ts, target, highlight, is_action);
    }

    fn add_nick(&self, nick: &str, ts: Option<Tm>, target: &MsgTarget) {
        self.ui1.add_nick(nick, ts, target);
        self.ui2.add_nick(nick, ts, target);
    }

    fn remove_nick(&self, nick: &str, ts: Option<Tm>, target: &MsgTarget) {
        self.ui1.remove_nick(nick, ts, target);
        self.ui2.remove_nick(nick, ts, target);
    }

    fn rename_nick(&self, old_nick: &str, new_nick: &str, ts: Tm, target: &MsgTarget) {
        self.ui1.rename_nick(old_nick, new_nick, ts, target);
        self.ui2.rename_nick(old_nick, new_nick, ts, target);
    }

    fn set_topic(&self, topic: &str, ts: Tm, serv: &str, chan: &str) {
        self.ui1.set_topic(topic, ts, serv, chan);
        self.ui2.set_topic(topic, ts, serv, chan);
    }

    fn set_tab_style(&self, style: TabStyle, target: &MsgTarget) {
        self.ui1.set_tab_style(style, target);
        self.ui2.set_tab_style(style, target);
    }

    fn user_tab_exists(&self, serv: &str, nick: &str) -> bool {
        // TODO weird
        self.ui1.user_tab_exists(serv, nick)
    }
}

pub fn combine<UI1: UI, UI2: UI>(ui1: UI1, ui2: UI2) -> CombinedUIs<UI1, UI2> {
    CombinedUIs { ui1, ui2 }
}
<|endoftext|>


<commit_before>// * This file is part of the uutils coreutils package.
// *
// * (c) 2015 Wiktor Kuropatwa <wiktor.kuropatwa@gmail.com>
// * (c) 2020 nicoo <nicoo@debian.org>
// *
// * For the full copyright and license information, please view the LICENSE file
// * that was distributed with this source code.

use rand::distributions::{Distribution, Uniform};
use rand::rngs::SmallRng;
use rand::{thread_rng, SeedableRng};
use std::cmp::{max, min};

use crate::miller_rabin::Result::*;
use crate::numeric::*;
use crate::{miller_rabin, Factors};

fn find_divisor<A: Arithmetic>(n: A) -> u64 {
    #![allow(clippy::many_single_char_names)]
    let mut rand = {
        let range = Uniform::new(1, n.modulus());
        let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap();
        move || n.from_u64(range.sample(&mut rng))
    };

    let quadratic = |a, b| move |x| n.add(n.mul(a, n.mul(x, x)), b);

    loop {
        let f = quadratic(rand(), rand());
        let mut x = rand();
        let mut y = x;

        loop {
            x = f(x);
            y = f(f(y));
            let d = {
                let _x = n.to_u64(x);
                let _y = n.to_u64(y);
                gcd(n.modulus(), max(_x, _y) - min(_x, _y))
            };
            if d == n.modulus() {
                // Failure, retry with a different quadratic
                break;
            } else if d > 1 {
                return d;
            }
        }
    }
}

fn _factor<A: Arithmetic>(num: u64) -> Factors {
    // Shadow the name, so the recursion automatically goes from “Big” arithmetic to small.
    let _factor = |n| {
        // TODO: Optimise with 32 and 64b versions
        _factor::<A>(n)
    };

    if num == 1 {
        return Factors::one();
    }

    let n = A::new(num);
    let divisor;
    match miller_rabin::test::<A>(n) {
        Prime => {
            return Factors::prime(num);
        }

        Composite(d) => {
            divisor = d;
        }

        Pseudoprime => {
            divisor = find_divisor::<A>(n);
        }
    };

    let mut factors = _factor(divisor);
    factors *= _factor(num / divisor);
    factors
}

pub(crate) fn factor(n: u64) -> Factors {
    _factor::<Montgomery>(n)
}
<commit_msg>factor::rho: Minor refactor for readability<commit_after>// * This file is part of the uutils coreutils package.
// *
// * (c) 2015 Wiktor Kuropatwa <wiktor.kuropatwa@gmail.com>
// * (c) 2020 nicoo <nicoo@debian.org>
// *
// * For the full copyright and license information, please view the LICENSE file
// * that was distributed with this source code.

use rand::distributions::{Distribution, Uniform};
use rand::rngs::SmallRng;
use rand::{thread_rng, SeedableRng};
use std::cmp::{max, min};

use crate::miller_rabin::Result::*;
use crate::numeric::*;
use crate::{miller_rabin, Factors};

fn find_divisor<A: Arithmetic>(n: A) -> u64 {
    #![allow(clippy::many_single_char_names)]
    let mut rand = {
        let range = Uniform::new(1, n.modulus());
        let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap();
        move || n.from_u64(range.sample(&mut rng))
    };

    let quadratic = |a, b| move |x| n.add(n.mul(a, n.mul(x, x)), b);

    loop {
        let f = quadratic(rand(), rand());
        let mut x = rand();
        let mut y = x;

        loop {
            x = f(x);
            y = f(f(y));
            let d = {
                let _x = n.to_u64(x);
                let _y = n.to_u64(y);
                gcd(n.modulus(), max(_x, _y) - min(_x, _y))
            };
            if d == n.modulus() {
                // Failure, retry with a different quadratic
                break;
            } else if d > 1 {
                return d;
            }
        }
    }
}

fn _factor<A: Arithmetic>(num: u64) -> Factors {
    // Shadow the name, so the recursion automatically goes from “Big” arithmetic to small.
    let _factor = |n| {
        // TODO: Optimise with 32 and 64b versions
        _factor::<A>(n)
    };

    if num == 1 {
        return Factors::one();
    }

    let n = A::new(num);
    let divisor = match miller_rabin::test::<A>(n) {
        Prime => {
            return Factors::prime(num);
        }

        Composite(d) => d,
        Pseudoprime => find_divisor::<A>(n),
    };

    let mut factors = _factor(divisor);
    factors *= _factor(num / divisor);
    factors
}

pub(crate) fn factor(n: u64) -> Factors {
    _factor::<Montgomery>(n)
}
<|endoftext|>


<commit_before>// Copyright 2019 Google LLC
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.

//! A TCP [`Transport`] that serializes as JSON.

#![deny(missing_docs)]

use futures::{prelude::*, ready};
use pin_project::pin_project;
use serde::{Deserialize, Serialize};
use std::{
    error::Error,
    io,
    marker::PhantomData,
    net::SocketAddr,
    pin::Pin,
    task::{Context, Poll},
};
use tokio::codec::{length_delimited::LengthDelimitedCodec, Framed};
use tokio::io::{AsyncRead, AsyncWrite};
use tokio::net::{TcpListener, TcpStream};
use tokio_net::ToSocketAddrs;
use tokio_serde_json::*;

/// A transport that serializes to, and deserializes from, a [`TcpStream`].
#[pin_project]
pub struct Transport<S, Item, SinkItem> {
    #[pin]
    inner: ReadJson<WriteJson<Framed<S, LengthDelimitedCodec>, SinkItem>, Item>,
}

impl<S, Item, SinkItem> Stream for Transport<S, Item, SinkItem>
where
    S: AsyncWrite + AsyncRead + Unpin,
    Item: for<'a> Deserialize<'a>,
{
    type Item = io::Result<Item>;

    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<io::Result<Item>>> {
        match self.project().inner.poll_next(cx) {
            Poll::Pending => Poll::Pending,
            Poll::Ready(None) => Poll::Ready(None),
            Poll::Ready(Some(Ok(next))) => Poll::Ready(Some(Ok(next))),
            Poll::Ready(Some(Err(e))) => {
                Poll::Ready(Some(Err(io::Error::new(io::ErrorKind::Other, e))))
            }
        }
    }
}

impl<S, Item, SinkItem> Sink<SinkItem> for Transport<S, Item, SinkItem>
where
    S: AsyncWrite + Unpin,
    SinkItem: Serialize,
{
    type Error = io::Error;

    fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
        convert(self.project().inner.poll_ready(cx))
    }

    fn start_send(self: Pin<&mut Self>, item: SinkItem) -> io::Result<()> {
        self.project()
            .inner
            .start_send(item)
            .map_err(|e| io::Error::new(io::ErrorKind::Other, e))
    }

    fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
        convert(self.project().inner.poll_flush(cx))
    }

    fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
        convert(self.project().inner.poll_close(cx))
    }
}

fn convert<E: Into<Box<dyn Error + Send + Sync>>>(
    poll: Poll<Result<(), E>>,
) -> Poll<io::Result<()>> {
    match poll {
        Poll::Pending => Poll::Pending,
        Poll::Ready(Ok(())) => Poll::Ready(Ok(())),
        Poll::Ready(Err(e)) => Poll::Ready(Err(io::Error::new(io::ErrorKind::Other, e))),
    }
}

impl<Item, SinkItem> Transport<TcpStream, Item, SinkItem> {
    /// Returns the peer address of the underlying TcpStream.
    pub fn peer_addr(&self) -> io::Result<SocketAddr> {
        self.inner.get_ref().get_ref().get_ref().peer_addr()
    }

    /// Returns the local address of the underlying TcpStream.
    pub fn local_addr(&self) -> io::Result<SocketAddr> {
        self.inner.get_ref().get_ref().get_ref().local_addr()
    }
}

/// Returns a new JSON transport that reads from and writes to `io`.
pub fn new<Item, SinkItem>(io: TcpStream) -> Transport<TcpStream, Item, SinkItem>
where
    Item: for<'de> Deserialize<'de>,
    SinkItem: Serialize,
{
    Transport::from(io)
}

impl<S: AsyncWrite + AsyncRead, Item: serde::de::DeserializeOwned, SinkItem: Serialize> From<S>
    for Transport<S, Item, SinkItem>
{
    fn from(inner: S) -> Self {
        Transport {
            inner: ReadJson::new(WriteJson::new(Framed::new(
                inner,
                LengthDelimitedCodec::new(),
            ))),
        }
    }
}

/// Connects to `addr`, wrapping the connection in a JSON transport.
pub async fn connect<Item, SinkItem>(
    addr: &SocketAddr,
) -> io::Result<Transport<TcpStream, Item, SinkItem>>
where
    Item: for<'de> Deserialize<'de>,
    SinkItem: Serialize,
{
    Ok(new(TcpStream::connect(addr).await?))
}

/// Listens on `addr`, wrapping accepted connections in JSON transports.
pub async fn listen<A, Item, SinkItem>(addr: A) -> io::Result<Incoming<Item, SinkItem>>
where
    A: ToSocketAddrs,
    Item: for<'de> Deserialize<'de>,
    SinkItem: Serialize,
{
    let listener = TcpListener::bind(addr).await?;
    let local_addr = listener.local_addr()?;
    let incoming = Box::pin(listener.incoming());
    Ok(Incoming {
        incoming,
        local_addr,
        ghost: PhantomData,
    })
}

trait IncomingTrait: Stream<Item = io::Result<TcpStream>> + std::fmt::Debug + Send {}
impl<T: Stream<Item = io::Result<TcpStream>> + std::fmt::Debug + Send> IncomingTrait for T {}

/// A [`TcpListener`] that wraps connections in JSON transports.
#[pin_project]
#[derive(Debug)]
pub struct Incoming<Item, SinkItem> {
    #[pin]
    incoming: Pin<Box<dyn IncomingTrait>>,
    local_addr: SocketAddr,
    ghost: PhantomData<(Item, SinkItem)>,
}

impl<Item, SinkItem> Incoming<Item, SinkItem> {
    /// Returns the address being listened on.
    pub fn local_addr(&self) -> SocketAddr {
        self.local_addr
    }
}

impl<Item, SinkItem> Stream for Incoming<Item, SinkItem>
where
    Item: for<'a> Deserialize<'a>,
    SinkItem: Serialize,
{
    type Item = io::Result<Transport<TcpStream, Item, SinkItem>>;

    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        let next = ready!(self.project().incoming.poll_next(cx)?);
        Poll::Ready(next.map(|conn| Ok(new(conn))))
    }
}

#[cfg(test)]
mod tests {
    use super::Transport;
    use assert_matches::assert_matches;
    use futures::task::noop_waker_ref;
    use futures::{Sink, Stream};
    use pin_utils::pin_mut;
    use std::{
        io::{self, Cursor},
        pin::Pin,
        task::{Context, Poll},
    };
    use tokio::io::{AsyncRead, AsyncWrite};

    fn ctx() -> Context<'static> {
        Context::from_waker(&noop_waker_ref())
    }

    #[test]
    fn test_stream() {
        struct TestIo(Cursor<&'static [u8]>);

        impl AsyncRead for TestIo {
            fn poll_read(
                mut self: Pin<&mut Self>,
                cx: &mut Context<'_>,
                buf: &mut [u8],
            ) -> Poll<io::Result<usize>> {
                AsyncRead::poll_read(Pin::new(self.0.get_mut()), cx, buf)
            }
        }

        impl AsyncWrite for TestIo {
            fn poll_write(
                self: Pin<&mut Self>,
                _cx: &mut Context<'_>,
                _buf: &[u8],
            ) -> Poll<io::Result<usize>> {
                unreachable!()
            }

            fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
                unreachable!()
            }

            fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
                unreachable!()
            }
        }

        let data = b"\x00\x00\x00\x18\"Test one, check check.\"";
        let transport = Transport::<_, String, String>::from(TestIo(Cursor::new(data)));
        pin_mut!(transport);

        assert_matches!(
            transport.poll_next(&mut ctx()),
            Poll::Ready(Some(Ok(ref s))) if s == "Test one, check check.");
    }

    #[test]
    fn test_sink() {
        struct TestIo<'a>(&'a mut Vec<u8>);

        impl<'a> AsyncRead for TestIo<'a> {
            fn poll_read(
                self: Pin<&mut Self>,
                _cx: &mut Context<'_>,
                _buf: &mut [u8],
            ) -> Poll<io::Result<usize>> {
                unreachable!()
            }
        }

        impl<'a> AsyncWrite for TestIo<'a> {
            fn poll_write(
                mut self: Pin<&mut Self>,
                cx: &mut Context<'_>,
                buf: &[u8],
            ) -> Poll<io::Result<usize>> {
                AsyncWrite::poll_write(Pin::new(&mut *self.0), cx, buf)
            }

            fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
                AsyncWrite::poll_flush(Pin::new(&mut *self.0), cx)
            }

            fn poll_shutdown(
                mut self: Pin<&mut Self>,
                cx: &mut Context<'_>,
            ) -> Poll<io::Result<()>> {
                AsyncWrite::poll_shutdown(Pin::new(&mut *self.0), cx)
            }
        }

        let mut writer = vec![];
        let transport = Transport::<_, String, String>::from(TestIo(&mut writer));
        pin_mut!(transport);

        assert_matches!(
            transport.as_mut().poll_ready(&mut ctx()),
            Poll::Ready(Ok(()))
        );
        assert_matches!(
            transport
                .as_mut()
                .start_send("Test one, check check.".into()),
            Ok(())
        );
        assert_matches!(transport.poll_flush(&mut ctx()), Poll::Ready(Ok(())));
        assert_eq!(writer, b"\x00\x00\x00\x18\"Test one, check check.\"");
    }
}
<commit_msg>Add Unpin note<commit_after>// Copyright 2019 Google LLC
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.

//! A TCP [`Transport`] that serializes as JSON.

#![deny(missing_docs)]

use futures::{prelude::*, ready};
use pin_project::pin_project;
use serde::{Deserialize, Serialize};
use std::{
    error::Error,
    io,
    marker::PhantomData,
    net::SocketAddr,
    pin::Pin,
    task::{Context, Poll},
};
use tokio::codec::{length_delimited::LengthDelimitedCodec, Framed};
use tokio::io::{AsyncRead, AsyncWrite};
use tokio::net::{TcpListener, TcpStream};
use tokio_net::ToSocketAddrs;
use tokio_serde_json::*;

/// A transport that serializes to, and deserializes from, a [`TcpStream`].
#[pin_project]
pub struct Transport<S, Item, SinkItem> {
    #[pin]
    inner: ReadJson<WriteJson<Framed<S, LengthDelimitedCodec>, SinkItem>, Item>,
}

impl<S, Item, SinkItem> Stream for Transport<S, Item, SinkItem>
where
    // TODO: Remove Unpin bound when tokio-rs/tokio#1272 is resolved.
    S: AsyncWrite + AsyncRead + Unpin,
    Item: for<'a> Deserialize<'a>,
{
    type Item = io::Result<Item>;

    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<io::Result<Item>>> {
        match self.project().inner.poll_next(cx) {
            Poll::Pending => Poll::Pending,
            Poll::Ready(None) => Poll::Ready(None),
            Poll::Ready(Some(Ok(next))) => Poll::Ready(Some(Ok(next))),
            Poll::Ready(Some(Err(e))) => {
                Poll::Ready(Some(Err(io::Error::new(io::ErrorKind::Other, e))))
            }
        }
    }
}

impl<S, Item, SinkItem> Sink<SinkItem> for Transport<S, Item, SinkItem>
where
    S: AsyncWrite + Unpin,
    SinkItem: Serialize,
{
    type Error = io::Error;

    fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
        convert(self.project().inner.poll_ready(cx))
    }

    fn start_send(self: Pin<&mut Self>, item: SinkItem) -> io::Result<()> {
        self.project()
            .inner
            .start_send(item)
            .map_err(|e| io::Error::new(io::ErrorKind::Other, e))
    }

    fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
        convert(self.project().inner.poll_flush(cx))
    }

    fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
        convert(self.project().inner.poll_close(cx))
    }
}

fn convert<E: Into<Box<dyn Error + Send + Sync>>>(
    poll: Poll<Result<(), E>>,
) -> Poll<io::Result<()>> {
    match poll {
        Poll::Pending => Poll::Pending,
        Poll::Ready(Ok(())) => Poll::Ready(Ok(())),
        Poll::Ready(Err(e)) => Poll::Ready(Err(io::Error::new(io::ErrorKind::Other, e))),
    }
}

impl<Item, SinkItem> Transport<TcpStream, Item, SinkItem> {
    /// Returns the peer address of the underlying TcpStream.
    pub fn peer_addr(&self) -> io::Result<SocketAddr> {
        self.inner.get_ref().get_ref().get_ref().peer_addr()
    }

    /// Returns the local address of the underlying TcpStream.
    pub fn local_addr(&self) -> io::Result<SocketAddr> {
        self.inner.get_ref().get_ref().get_ref().local_addr()
    }
}

/// Returns a new JSON transport that reads from and writes to `io`.
pub fn new<Item, SinkItem>(io: TcpStream) -> Transport<TcpStream, Item, SinkItem>
where
    Item: for<'de> Deserialize<'de>,
    SinkItem: Serialize,
{
    Transport::from(io)
}

impl<S: AsyncWrite + AsyncRead, Item: serde::de::DeserializeOwned, SinkItem: Serialize> From<S>
    for Transport<S, Item, SinkItem>
{
    fn from(inner: S) -> Self {
        Transport {
            inner: ReadJson::new(WriteJson::new(Framed::new(
                inner,
                LengthDelimitedCodec::new(),
            ))),
        }
    }
}

/// Connects to `addr`, wrapping the connection in a JSON transport.
pub async fn connect<Item, SinkItem>(
    addr: &SocketAddr,
) -> io::Result<Transport<TcpStream, Item, SinkItem>>
where
    Item: for<'de> Deserialize<'de>,
    SinkItem: Serialize,
{
    Ok(new(TcpStream::connect(addr).await?))
}

/// Listens on `addr`, wrapping accepted connections in JSON transports.
pub async fn listen<A, Item, SinkItem>(addr: A) -> io::Result<Incoming<Item, SinkItem>>
where
    A: ToSocketAddrs,
    Item: for<'de> Deserialize<'de>,
    SinkItem: Serialize,
{
    let listener = TcpListener::bind(addr).await?;
    let local_addr = listener.local_addr()?;
    let incoming = Box::pin(listener.incoming());
    Ok(Incoming {
        incoming,
        local_addr,
        ghost: PhantomData,
    })
}

trait IncomingTrait: Stream<Item = io::Result<TcpStream>> + std::fmt::Debug + Send {}
impl<T: Stream<Item = io::Result<TcpStream>> + std::fmt::Debug + Send> IncomingTrait for T {}

/// A [`TcpListener`] that wraps connections in JSON transports.
#[pin_project]
#[derive(Debug)]
pub struct Incoming<Item, SinkItem> {
    #[pin]
    incoming: Pin<Box<dyn IncomingTrait>>,
    local_addr: SocketAddr,
    ghost: PhantomData<(Item, SinkItem)>,
}

impl<Item, SinkItem> Incoming<Item, SinkItem> {
    /// Returns the address being listened on.
    pub fn local_addr(&self) -> SocketAddr {
        self.local_addr
    }
}

impl<Item, SinkItem> Stream for Incoming<Item, SinkItem>
where
    Item: for<'a> Deserialize<'a>,
    SinkItem: Serialize,
{
    type Item = io::Result<Transport<TcpStream, Item, SinkItem>>;

    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        let next = ready!(self.project().incoming.poll_next(cx)?);
        Poll::Ready(next.map(|conn| Ok(new(conn))))
    }
}

#[cfg(test)]
mod tests {
    use super::Transport;
    use assert_matches::assert_matches;
    use futures::task::noop_waker_ref;
    use futures::{Sink, Stream};
    use pin_utils::pin_mut;
    use std::{
        io::{self, Cursor},
        pin::Pin,
        task::{Context, Poll},
    };
    use tokio::io::{AsyncRead, AsyncWrite};

    fn ctx() -> Context<'static> {
        Context::from_waker(&noop_waker_ref())
    }

    #[test]
    fn test_stream() {
        struct TestIo(Cursor<&'static [u8]>);

        impl AsyncRead for TestIo {
            fn poll_read(
                mut self: Pin<&mut Self>,
                cx: &mut Context<'_>,
                buf: &mut [u8],
            ) -> Poll<io::Result<usize>> {
                AsyncRead::poll_read(Pin::new(self.0.get_mut()), cx, buf)
            }
        }

        impl AsyncWrite for TestIo {
            fn poll_write(
                self: Pin<&mut Self>,
                _cx: &mut Context<'_>,
                _buf: &[u8],
            ) -> Poll<io::Result<usize>> {
                unreachable!()
            }

            fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
                unreachable!()
            }

            fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
                unreachable!()
            }
        }

        let data = b"\x00\x00\x00\x18\"Test one, check check.\"";
        let transport = Transport::<_, String, String>::from(TestIo(Cursor::new(data)));
        pin_mut!(transport);

        assert_matches!(
            transport.poll_next(&mut ctx()),
            Poll::Ready(Some(Ok(ref s))) if s == "Test one, check check.");
    }

    #[test]
    fn test_sink() {
        struct TestIo<'a>(&'a mut Vec<u8>);

        impl<'a> AsyncRead for TestIo<'a> {
            fn poll_read(
                self: Pin<&mut Self>,
                _cx: &mut Context<'_>,
                _buf: &mut [u8],
            ) -> Poll<io::Result<usize>> {
                unreachable!()
            }
        }

        impl<'a> AsyncWrite for TestIo<'a> {
            fn poll_write(
                mut self: Pin<&mut Self>,
                cx: &mut Context<'_>,
                buf: &[u8],
            ) -> Poll<io::Result<usize>> {
                AsyncWrite::poll_write(Pin::new(&mut *self.0), cx, buf)
            }

            fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
                AsyncWrite::poll_flush(Pin::new(&mut *self.0), cx)
            }

            fn poll_shutdown(
                mut self: Pin<&mut Self>,
                cx: &mut Context<'_>,
            ) -> Poll<io::Result<()>> {
                AsyncWrite::poll_shutdown(Pin::new(&mut *self.0), cx)
            }
        }

        let mut writer = vec![];
        let transport = Transport::<_, String, String>::from(TestIo(&mut writer));
        pin_mut!(transport);

        assert_matches!(
            transport.as_mut().poll_ready(&mut ctx()),
            Poll::Ready(Ok(()))
        );
        assert_matches!(
            transport
                .as_mut()
                .start_send("Test one, check check.".into()),
            Ok(())
        );
        assert_matches!(transport.poll_flush(&mut ctx()), Poll::Ready(Ok(())));
        assert_eq!(writer, b"\x00\x00\x00\x18\"Test one, check check.\"");
    }
}
<|endoftext|>


<commit_before>use alloc::arc::Arc;
use alloc::boxed::Box;
use collections::Vec;
use spin::Mutex;

use arch;
use super::file::File;
use super::memory::{Grant, Memory, SharedMemory};

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Status {
    Runnable,
    Blocked,
    Exited(usize)
}

/// A context, which identifies either a process or a thread
#[derive(Debug)]
pub struct Context {
    /// The ID of this context
    pub id: usize,
    /// Status of context
    pub status: Status,
    /// Context running or not
    pub running: bool,
    /// The architecture specific context
    pub arch: arch::context::Context,
    /// Kernel FX
    pub kfx: Option<Box<[u8]>>,
    /// Kernel stack
    pub kstack: Option<Box<[u8]>>,
    /// Executable image
    pub image: Vec<SharedMemory>,
    /// User heap
    pub heap: Option<SharedMemory>,
    /// User stack
    pub stack: Option<Memory>,
    /// User grants
    pub grants: Arc<Mutex<Vec<Grant>>>,
    /// The current working directory
    pub cwd: Arc<Mutex<Vec<u8>>>,
    /// The open files in the scheme
    pub files: Arc<Mutex<Vec<Option<File>>>>
}

impl Context {
    /// Create a new context
    pub fn new(id: usize) -> Context {
        Context {
            id: id,
            status: Status::Blocked,
            running: false,
            arch: arch::context::Context::new(),
            kfx: None,
            kstack: None,
            image: Vec::new(),
            heap: None,
            stack: None,
            grants: Arc::new(Mutex::new(Vec::new())),
            cwd: Arc::new(Mutex::new(Vec::new())),
            files: Arc::new(Mutex::new(Vec::new()))
        }
    }

    pub fn canonicalize(&self, path: &[u8]) -> Vec<u8> {
        if path.iter().position(|&b| b == b':').is_none() {
            let cwd = self.cwd.lock();
            if path == b"." {
                cwd.clone()
            } else if path == b".." {
                cwd[..cwd[..cwd.len() - 1]
                                   .iter().rposition(|&b| b == b'/')
                                   .map_or(cwd.len(), |i| i + 1)]
                   .to_vec()
            } else if path.starts_with(b"./") {
                let mut canon = cwd.clone();
                canon.extend_from_slice(&path[2..]);
                canon
            } else if path.starts_with(b"../") {
                let mut canon = cwd[..cwd[..cwd.len() - 1]
                                   .iter().rposition(|&b| b == b'/')
                                   .map_or(cwd.len(), |i| i + 1)]
                   .to_vec();
                canon.extend_from_slice(&path[3..]);
                canon
            } else if path.starts_with(b"/") {
                let mut canon = cwd[..cwd.iter().position(|&b| b == b':').map_or(1, |i| i + 1)].to_vec();
                canon.extend_from_slice(&path);
                canon
            } else {
                let mut canon = cwd.clone();
                canon.extend_from_slice(&path);
                canon
            }
        } else {
            path.to_vec()
        }
    }

    /// Add a file to the lowest available slot.
    /// Return the file descriptor number or None if no slot was found
    pub fn add_file(&self, file: File) -> Option<usize> {
        let mut files = self.files.lock();
        for (i, mut file_option) in files.iter_mut().enumerate() {
            if file_option.is_none() {
                *file_option = Some(file);
                return Some(i);
            }
        }
        let len = files.len();
        if len < super::CONTEXT_MAX_FILES {
            files.push(Some(file));
            Some(len)
        } else {
            None
        }
    }

    /// Get a file
    pub fn get_file(&self, i: usize) -> Option<File> {
        let files = self.files.lock();
        if i < files.len() {
            files[i]
        } else {
            None
        }
    }

    /// Remove a file
    // TODO: adjust files vector to smaller size if possible
    pub fn remove_file(&self, i: usize) -> Option<File> {
        let mut files = self.files.lock();
        if i < files.len() {
            files[i].take()
        } else {
            None
        }
    }
}
<commit_msg>Fix path lookup<commit_after>use alloc::arc::Arc;
use alloc::boxed::Box;
use collections::Vec;
use spin::Mutex;

use arch;
use super::file::File;
use super::memory::{Grant, Memory, SharedMemory};

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Status {
    Runnable,
    Blocked,
    Exited(usize)
}

/// A context, which identifies either a process or a thread
#[derive(Debug)]
pub struct Context {
    /// The ID of this context
    pub id: usize,
    /// Status of context
    pub status: Status,
    /// Context running or not
    pub running: bool,
    /// The architecture specific context
    pub arch: arch::context::Context,
    /// Kernel FX
    pub kfx: Option<Box<[u8]>>,
    /// Kernel stack
    pub kstack: Option<Box<[u8]>>,
    /// Executable image
    pub image: Vec<SharedMemory>,
    /// User heap
    pub heap: Option<SharedMemory>,
    /// User stack
    pub stack: Option<Memory>,
    /// User grants
    pub grants: Arc<Mutex<Vec<Grant>>>,
    /// The current working directory
    pub cwd: Arc<Mutex<Vec<u8>>>,
    /// The open files in the scheme
    pub files: Arc<Mutex<Vec<Option<File>>>>
}

impl Context {
    /// Create a new context
    pub fn new(id: usize) -> Context {
        Context {
            id: id,
            status: Status::Blocked,
            running: false,
            arch: arch::context::Context::new(),
            kfx: None,
            kstack: None,
            image: Vec::new(),
            heap: None,
            stack: None,
            grants: Arc::new(Mutex::new(Vec::new())),
            cwd: Arc::new(Mutex::new(Vec::new())),
            files: Arc::new(Mutex::new(Vec::new()))
        }
    }

    pub fn canonicalize(&self, path: &[u8]) -> Vec<u8> {
        if path.iter().position(|&b| b == b':').is_none() {
            let cwd = self.cwd.lock();
            if path == b"." {
                cwd.clone()
            } else if path == b".." {
                cwd[..cwd[..cwd.len() - 1]
                                   .iter().rposition(|&b| b == b'/' || b == b':')
                                   .map_or(cwd.len(), |i| i + 1)]
                   .to_vec()
            } else if path.starts_with(b"./") {
                let mut canon = cwd.clone();
                canon.extend_from_slice(&path[2..]);
                canon
            } else if path.starts_with(b"../") {
                let mut canon = cwd[..cwd[..cwd.len() - 1]
                                   .iter().rposition(|&b| b == b'/' || b == b':')
                                   .map_or(cwd.len(), |i| i + 1)]
                   .to_vec();
                canon.extend_from_slice(&path[3..]);
                canon
            } else if path.starts_with(b"/") {
                let mut canon = cwd[..cwd.iter().position(|&b| b == b':').map_or(1, |i| i + 1)].to_vec();
                canon.extend_from_slice(&path);
                canon
            } else {
                let mut canon = cwd.clone();
                canon.extend_from_slice(&path);
                canon
            }
        } else {
            path.to_vec()
        }
    }

    /// Add a file to the lowest available slot.
    /// Return the file descriptor number or None if no slot was found
    pub fn add_file(&self, file: File) -> Option<usize> {
        let mut files = self.files.lock();
        for (i, mut file_option) in files.iter_mut().enumerate() {
            if file_option.is_none() {
                *file_option = Some(file);
                return Some(i);
            }
        }
        let len = files.len();
        if len < super::CONTEXT_MAX_FILES {
            files.push(Some(file));
            Some(len)
        } else {
            None
        }
    }

    /// Get a file
    pub fn get_file(&self, i: usize) -> Option<File> {
        let files = self.files.lock();
        if i < files.len() {
            files[i]
        } else {
            None
        }
    }

    /// Remove a file
    // TODO: adjust files vector to smaller size if possible
    pub fn remove_file(&self, i: usize) -> Option<File> {
        let mut files = self.files.lock();
        if i < files.len() {
            files[i].take()
        } else {
            None
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use anyhow::{format_err, Error};
use hex;
use libra_types::{
    account_config::{
        received_payment_tag, sent_payment_tag, AccountResource, ReceivedPaymentEvent,
        SentPaymentEvent,
    },
    contract_event::ContractEvent,
    language_storage::TypeTag,
    transaction::{Transaction, TransactionArgument, TransactionPayload},
};
use serde::{Deserialize, Serialize};
use std::convert::TryFrom;
use transaction_builder::get_transaction_name;

#[derive(Serialize, Deserialize, Debug, PartialEq)]
pub struct AccountView {
    balance: u64,
    sequence_number: u64,
    authentication_key: BytesView,
    pub sent_events_key: BytesView,
    pub received_events_key: BytesView,
    delegated_key_rotation_capability: bool,
    delegated_withdrawal_capability: bool,
}

impl AccountView {
    pub fn new(account: &AccountResource) -> Self {
        Self {
            balance: account.balance(),
            sequence_number: account.sequence_number(),
            authentication_key: BytesView::from(account.authentication_key()),
            sent_events_key: BytesView::from(account.sent_events().key().as_bytes()),
            received_events_key: BytesView::from(account.received_events().key().as_bytes()),

            delegated_key_rotation_capability: account.delegated_key_rotation_capability(),
            delegated_withdrawal_capability: account.delegated_withdrawal_capability(),
        }
    }

    // TODO remove test tag once used by CLI client
    #[cfg(test)]
    pub(crate) fn balance(&self) -> u64 {
        self.balance
    }
}

#[derive(Serialize, Deserialize)]
pub struct EventView {
    pub key: BytesView,
    pub sequence_number: u64,
    pub transaction_version: u64,
    pub data: EventDataView,
}

#[derive(Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum EventDataView {
    ReceivedPayment {
        amount: u64,
        sender: BytesView,
        metadata: BytesView,
    },
    SentPayment {
        amount: u64,
        receiver: BytesView,
        metadata: BytesView,
    },
    SystemEvent,
}

impl TryFrom<(u64, ContractEvent)> for EventView {
    type Error = Error;

    /// Tries to convert the provided byte array into Event Key.
    fn try_from((txn_version, event): (u64, ContractEvent)) -> Result<EventView, Error> {
        let event_data = if event.type_tag() == &TypeTag::Struct(received_payment_tag()) {
            let received_event = ReceivedPaymentEvent::try_from(&event)?;
            EventDataView::ReceivedPayment {
                amount: received_event.amount(),
                sender: BytesView::from(received_event.sender().as_ref()),
                metadata: BytesView::from(received_event.metadata()),
            }
        } else if event.type_tag() == &TypeTag::Struct(sent_payment_tag()) {
            let sent_event = SentPaymentEvent::try_from(&event)?;
            EventDataView::SentPayment {
                amount: sent_event.amount(),
                receiver: BytesView::from(sent_event.receiver().as_ref()),
                metadata: BytesView::from(sent_event.metadata()),
            }
        } else {
            EventDataView::SystemEvent
        };
        Ok(EventView {
            key: BytesView::from(event.key().as_bytes()),
            sequence_number: event.sequence_number(),
            transaction_version: txn_version,
            data: event_data,
        })
    }
}

#[derive(Deserialize, Serialize)]
pub struct BlockMetadata {
    pub version: u64,
    pub timestamp: u64,
}

#[derive(Serialize, Deserialize, Debug, PartialEq)]
pub struct BytesView(String);

impl From<&[u8]> for BytesView {
    fn from(bytes: &[u8]) -> Self {
        Self(hex::encode(bytes))
    }
}

impl From<&Vec<u8>> for BytesView {
    fn from(bytes: &Vec<u8>) -> Self {
        Self(hex::encode(bytes))
    }
}

#[derive(Deserialize, Serialize)]
pub struct TransactionView {
    pub version: u64,
    pub transaction: TransactionDataView,
}

#[derive(Deserialize, Serialize)]
#[serde(tag = "type")]
pub enum TransactionDataView {
    #[serde(rename = "blockmetadata")]
    BlockMetadata { timestamp_usecs: u64 },
    #[serde(rename = "writeset")]
    WriteSet {},
    #[serde(rename = "user")]
    UserTransaction {
        sender: String,
        signature: String,
        public_key: String,
        sequence_number: u64,
        max_gas_amount: u64,
        gas_unit_price: u64,
        expiration_time: u64,
        script: ScriptView,
    },
    #[serde(rename = "unknown")]
    UnknownTransaction {},
}

#[derive(Deserialize, Serialize)]
#[serde(tag = "type")]
pub enum ScriptView {
    #[serde(rename = "peer_to_peer_transaction")]
    PeerToPeer { receiver: String, amount: u64 },

    #[serde(rename = "unknown_transaction")]
    Unknown {},
}

impl From<Transaction> for TransactionDataView {
    fn from(tx: Transaction) -> Self {
        let x = match tx {
            Transaction::BlockMetadata(t) => {
                if let Ok(x) = t.into_inner() {
                    Ok(TransactionDataView::BlockMetadata {
                        timestamp_usecs: x.1,
                    })
                } else {
                    Err(format_err!("Unable to parse metadata"))
                }
            }
            Transaction::WriteSet(_) => Ok(TransactionDataView::WriteSet {}),
            Transaction::UserTransaction(t) => Ok(TransactionDataView::UserTransaction {
                sender: t.sender().to_string(),
                signature: t.signature().to_string(),
                public_key: t.public_key().to_string(),
                sequence_number: t.sequence_number(),
                max_gas_amount: t.max_gas_amount(),
                gas_unit_price: t.gas_unit_price(),
                expiration_time: t.expiration_time().as_secs(),
                script: t.into_raw_transaction().into_payload().into(),
            }),
        };

        x.unwrap_or(TransactionDataView::UnknownTransaction {})
    }
}

impl From<TransactionPayload> for ScriptView {
    fn from(value: TransactionPayload) -> Self {
        let empty_vec: Vec<TransactionArgument> = vec![];
        let (code, args) = match value {
            TransactionPayload::Program => ("deprecated".to_string(), empty_vec),
            TransactionPayload::WriteSet(_) => ("genesis".to_string(), empty_vec),
            TransactionPayload::Script(script) => {
                (get_transaction_name(script.code()), script.args().to_vec())
            }
            TransactionPayload::Module(_) => ("module publishing".to_string(), empty_vec),
        };

        let res = match code.as_str() {
            "PeerToPeer" => {
                if let [TransactionArgument::Address(receiver), TransactionArgument::U64(amount)] =
                    &args[..]
                {
                    Ok(ScriptView::PeerToPeer {
                        receiver: receiver.to_string(),
                        amount: *amount,
                    })
                } else {
                    Err(format_err!("Unable to parse PeerToPeer arguments"))
                }
            }
            _ => Err(format_err!("Unknown scripts")),
        };
        res.unwrap_or(ScriptView::Unknown {})
    }
}
<commit_msg>fixup! review changes 2<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use anyhow::{format_err, Error};
use hex;
use libra_types::{
    account_config::{
        received_payment_tag, sent_payment_tag, AccountResource, ReceivedPaymentEvent,
        SentPaymentEvent,
    },
    contract_event::ContractEvent,
    language_storage::TypeTag,
    transaction::{Transaction, TransactionArgument, TransactionPayload},
};
use serde::{Deserialize, Serialize};
use std::convert::TryFrom;
use transaction_builder::get_transaction_name;

#[derive(Serialize, Deserialize, Debug, PartialEq)]
pub struct AccountView {
    balance: u64,
    sequence_number: u64,
    authentication_key: BytesView,
    pub sent_events_key: BytesView,
    pub received_events_key: BytesView,
    delegated_key_rotation_capability: bool,
    delegated_withdrawal_capability: bool,
}

impl AccountView {
    pub fn new(account: &AccountResource) -> Self {
        Self {
            balance: account.balance(),
            sequence_number: account.sequence_number(),
            authentication_key: BytesView::from(account.authentication_key()),
            sent_events_key: BytesView::from(account.sent_events().key().as_bytes()),
            received_events_key: BytesView::from(account.received_events().key().as_bytes()),

            delegated_key_rotation_capability: account.delegated_key_rotation_capability(),
            delegated_withdrawal_capability: account.delegated_withdrawal_capability(),
        }
    }

    // TODO remove test tag once used by CLI client
    #[cfg(test)]
    pub(crate) fn balance(&self) -> u64 {
        self.balance
    }
}

#[derive(Serialize, Deserialize)]
pub struct EventView {
    pub key: BytesView,
    pub sequence_number: u64,
    pub transaction_version: u64,
    pub data: EventDataView,
}

#[derive(Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum EventDataView {
    ReceivedPayment {
        amount: u64,
        sender: BytesView,
        metadata: BytesView,
    },
    SentPayment {
        amount: u64,
        receiver: BytesView,
        metadata: BytesView,
    },
    SystemEvent,
}

impl TryFrom<(u64, ContractEvent)> for EventView {
    type Error = Error;

    /// Tries to convert the provided byte array into Event Key.
    fn try_from((txn_version, event): (u64, ContractEvent)) -> Result<EventView, Error> {
        let event_data = if event.type_tag() == &TypeTag::Struct(received_payment_tag()) {
            let received_event = ReceivedPaymentEvent::try_from(&event)?;
            EventDataView::ReceivedPayment {
                amount: received_event.amount(),
                sender: BytesView::from(received_event.sender().as_ref()),
                metadata: BytesView::from(received_event.metadata()),
            }
        } else if event.type_tag() == &TypeTag::Struct(sent_payment_tag()) {
            let sent_event = SentPaymentEvent::try_from(&event)?;
            EventDataView::SentPayment {
                amount: sent_event.amount(),
                receiver: BytesView::from(sent_event.receiver().as_ref()),
                metadata: BytesView::from(sent_event.metadata()),
            }
        } else {
            EventDataView::SystemEvent
        };
        Ok(EventView {
            key: BytesView::from(event.key().as_bytes()),
            sequence_number: event.sequence_number(),
            transaction_version: txn_version,
            data: event_data,
        })
    }
}

#[derive(Deserialize, Serialize)]
pub struct BlockMetadata {
    pub version: u64,
    pub timestamp: u64,
}

#[derive(Serialize, Deserialize, Debug, PartialEq)]
pub struct BytesView(String);

impl From<&[u8]> for BytesView {
    fn from(bytes: &[u8]) -> Self {
        Self(hex::encode(bytes))
    }
}

impl From<&Vec<u8>> for BytesView {
    fn from(bytes: &Vec<u8>) -> Self {
        Self(hex::encode(bytes))
    }
}

#[derive(Deserialize, Serialize)]
pub struct TransactionView {
    pub version: u64,
    pub transaction: TransactionDataView,
}

#[derive(Deserialize, Serialize)]
#[serde(tag = "type")]
pub enum TransactionDataView {
    #[serde(rename = "blockmetadata")]
    BlockMetadata { timestamp_usecs: u64 },
    #[serde(rename = "writeset")]
    WriteSet {},
    #[serde(rename = "user")]
    UserTransaction {
        sender: String,
        signature: String,
        public_key: String,
        sequence_number: u64,
        max_gas_amount: u64,
        gas_unit_price: u64,
        expiration_time: u64,
        script: ScriptView,
    },
    #[serde(rename = "unknown")]
    UnknownTransaction {},
}

#[derive(Deserialize, Serialize)]
#[serde(tag = "type")]
pub enum ScriptView {
    #[serde(rename = "peer_to_peer_transaction")]
    PeerToPeer { receiver: String, amount: u64 },

    #[serde(rename = "unknown_transaction")]
    Unknown {},
}

impl From<Transaction> for TransactionDataView {
    fn from(tx: Transaction) -> Self {
        let x = match tx {
            Transaction::BlockMetadata(t) => {
                t.into_inner().map(|x| TransactionDataView::BlockMetadata {
                    timestamp_usecs: x.1,
                })
            }
            Transaction::WriteSet(_) => Ok(TransactionDataView::WriteSet {}),
            Transaction::UserTransaction(t) => Ok(TransactionDataView::UserTransaction {
                sender: t.sender().to_string(),
                signature: t.signature().to_string(),
                public_key: t.public_key().to_string(),
                sequence_number: t.sequence_number(),
                max_gas_amount: t.max_gas_amount(),
                gas_unit_price: t.gas_unit_price(),
                expiration_time: t.expiration_time().as_secs(),
                script: t.into_raw_transaction().into_payload().into(),
            }),
        };

        x.unwrap_or(TransactionDataView::UnknownTransaction {})
    }
}

impl From<TransactionPayload> for ScriptView {
    fn from(value: TransactionPayload) -> Self {
        let empty_vec: Vec<TransactionArgument> = vec![];
        let (code, args) = match value {
            TransactionPayload::Program => ("deprecated".to_string(), empty_vec),
            TransactionPayload::WriteSet(_) => ("genesis".to_string(), empty_vec),
            TransactionPayload::Script(script) => {
                (get_transaction_name(script.code()), script.args().to_vec())
            }
            TransactionPayload::Module(_) => ("module publishing".to_string(), empty_vec),
        };

        let res = match code.as_str() {
            "PeerToPeer" => {
                if let [TransactionArgument::Address(receiver), TransactionArgument::U64(amount)] =
                    &args[..]
                {
                    Ok(ScriptView::PeerToPeer {
                        receiver: receiver.to_string(),
                        amount: *amount,
                    })
                } else {
                    Err(format_err!("Unable to parse PeerToPeer arguments"))
                }
            }
            _ => Err(format_err!("Unknown scripts")),
        };
        res.unwrap_or(ScriptView::Unknown {})
    }
}
<|endoftext|>


<commit_before>use index::btree::external::ExtNode;
use index::btree::internal::InNode;
use index::btree::node::is_node_locked;
use index::btree::node::read_node;
use index::btree::node::read_unchecked;
use index::btree::node::write_node;
use index::btree::node::write_non_empty;
use index::btree::node::write_targeted;
use index::btree::node::EmptyNode;
use index::btree::node::Node;
use index::btree::node::NodeData;
use index::btree::node::NodeWriteGuard;
use index::btree::search::mut_search;
use index::btree::search::MutSearchResult;
use index::btree::LevelTree;
use index::btree::NodeCellRef;
use index::btree::{external, BPlusTree};
use index::lsmtree::tree::{LEVEL_2, LEVEL_3, LEVEL_PAGE_DIFF_MULTIPLIER};
use index::EntryKey;
use index::Slice;
use itertools::Itertools;
use smallvec::SmallVec;
use std::cmp::min;
use std::collections::{BTreeSet, HashSet};
use std::fmt::Debug;
use std::mem;
use std::sync::atomic::Ordering::Relaxed;
use index::btree::dump::dump_tree;

enum Selection<KS, PS>
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    Selected(Vec<NodeWriteGuard<KS, PS>>),
    Innode(NodeCellRef),
}

fn select<KS, PS>(node: &NodeCellRef) -> Vec<NodeWriteGuard<KS, PS>>
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    let search = mut_search::<KS, PS>(node, &smallvec!());
    match search {
        MutSearchResult::External => {
            let first_node = write_node(node);
            let mut collected_keys = first_node.len();
            let mut collected = vec![first_node];
            let target_keys = min(KS::slice_len() * LEVEL_PAGE_DIFF_MULTIPLIER, LEVEL_3);
            let target_guards = LEVEL_2;
            while collected_keys < target_keys && collected.len() < target_guards {
                let right = write_node(
                    collected
                        .last_mut()
                        .unwrap()
                        .right_ref_mut_no_empty()
                        .unwrap(),
                );
                if right.is_none() {
                    break;
                } else {
                    collected_keys += right.len();
                    collected.push(right);
                }
            }
            return collected;
        }
        MutSearchResult::Internal(node) => select::<KS, PS>(&node),
    }
}

fn prune_selected<'a, KS, PS>(node: &NodeCellRef, bound: &EntryKey)
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    let first_search = mut_search::<KS, PS>(node, &smallvec!());
    match first_search {
        MutSearchResult::Internal(sub_node_ref) => {
            let sub_node = read_unchecked::<KS, PS>(&sub_node_ref);
            if !sub_node.is_empty_node() && !sub_node.is_ext() {
                prune_selected::<KS, PS>(&sub_node_ref, bound);
            }
        }
        MutSearchResult::External => unreachable!(),
    };
    let mut prev_node_guard: Option<NodeWriteGuard<KS, PS>> = None;
    let mut node_ref = node.clone();
    loop {
        let mut page = write_node::<KS, PS>(&node_ref);
        let page_len = page.len();
        let page_right_ref = page.right_ref().unwrap().clone();
        if !page.is_empty_node() {
            if page.right_bound() >= bound {
                break;
            }
            let mut ptr_indices: HashSet<_> = page.innode().ptrs.as_slice_immute()[..page_len + 1]
                .iter()
                .enumerate()
                .filter_map(|(i, sub_level)| {
                    if read_unchecked::<KS, PS>(sub_level).is_empty_node() {
                        Some(i)
                    } else {
                        None
                    }
                })
                .collect();
            if ptr_indices.len() == page.len() + 1 {
                // all sub nodes are empty
                // will set current node empty either
                let next_page_ref = page.innode().right.clone();
                if let Some(ref mut prev_guard) = &mut prev_node_guard {
                    *prev_guard.right_ref_mut().unwrap() = next_page_ref.clone();
                }
                *page = NodeData::Empty(box EmptyNode {
                    left: None,
                    right: next_page_ref,
                });
            } else {
                {
                    let mut innode = page.innode_mut();
                    let mut new_keys = KS::init();
                    let mut new_ptrs = PS::init();
                    {
                        let ptrs: Vec<&mut _> = innode.ptrs.as_slice()[..page_len + 1]
                            .iter_mut()
                            .enumerate()
                            .filter(|(i, _)| !ptr_indices.contains(&i))
                            .map(|(_, p)| p)
                            .collect();

                        let keys: Vec<&mut _> = innode.keys.as_slice()[..page_len]
                            .iter_mut()
                            .enumerate()
                            .filter(|(i, _)| !ptr_indices.contains(&i))
                            .map(|(_, k)| k)
                            .collect();
                        debug!("Prune filtered page have keys {:?}", &keys);
                        debug_assert_eq!(ptrs.len(), keys.len() + 1);
                        innode.len = keys.len();
                        let new_keys = new_keys.as_slice();
                        let new_ptrs = new_ptrs.as_slice();
                        for (i, key) in keys.into_iter().enumerate() {
                            debug_assert!(key > &mut smallvec!(0));
                            mem::swap(&mut new_keys[i], key);
                        }
                        for (i, ptr) in ptrs.into_iter().enumerate() {
                            debug_assert!(!ptr.is_default());
                            mem::swap(&mut new_ptrs[i], ptr);
                        }
                    }
                    innode.keys = new_keys;
                    innode.ptrs = new_ptrs;
                }
                prev_node_guard = Some(page);
            }
            node_ref = page_right_ref;
        } else {
            unreachable!();
        }
    }
}

pub fn level_merge<KS, PS>(src_tree: &BPlusTree<KS, PS>, dest_tree: &LevelTree) -> usize
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    let mut left_most_leaf_guards = select::<KS, PS>(&src_tree.get_root());
    let merge_page_len = left_most_leaf_guards.len();
    let mut num_keys_removed = 0;
    let left_most_id = left_most_leaf_guards.first().unwrap().ext_id();
    let prune_bound = left_most_leaf_guards.last().unwrap().right_bound().clone();

    debug!("Merge selected {} pages", left_most_leaf_guards.len());
    if cfg!(debug_assertions) {
        if left_most_id != src_tree.head_page_id {
            dump_tree(src_tree, "level_lsm_merge_failure_dump.json");
        }
    }
    debug_assert_eq!(
        left_most_id,
        src_tree.head_page_id,
        "{}",
        left_most_leaf_guards.first().unwrap().type_name()
    );

    // merge to dest_tree
    {
        let mut deleted_keys = src_tree.deleted.write();
        let mut merged_deleted_keys = vec![];
        let keys: Vec<EntryKey> = left_most_leaf_guards
            .iter()
            .filter(|&g| !g.is_empty_node())
            .map(|g| &g.keys()[..g.len()])
            .flatten()
            .filter(|&k| {
                if deleted_keys.contains(k) {
                    merged_deleted_keys.push(k.clone());
                    false
                } else {
                    true
                }
            })
            .cloned()
            .collect_vec();
        num_keys_removed = keys.len();
        debug!("Merge selected keys are {:?}", &keys);
        dest_tree.merge_with_keys(box keys);
        for rk in &merged_deleted_keys {
            deleted_keys.remove(rk);
        }
    }

    // adjust leaf left, right references
    {
        let right_right_most = left_most_leaf_guards
            .last()
            .unwrap()
            .right_ref()
            .unwrap()
            .clone();

        let left_left_most = left_most_leaf_guards
            .first()
            .unwrap()
            .left_ref()
            .unwrap()
            .clone();

        debug_assert!(read_unchecked::<KS, PS>(&left_left_most).is_none());

        for mut g in &mut left_most_leaf_guards {
            external::make_deleted(&g.ext_id());
            **g = NodeData::Empty(box EmptyNode {
                left: Some(left_left_most.clone()),
                right: right_right_most.clone(),
            });
        }

        let mut new_first_node = write_node::<KS, PS>(&right_right_most);
        let mut new_first_node_ext = new_first_node.extnode_mut();
        new_first_node_ext.id = src_tree.head_page_id;
        new_first_node_ext.prev = left_left_most;

        ExtNode::<KS, PS>::make_changed(&right_right_most, src_tree);
    }

    // cleanup upper level references
    prune_selected::<KS, PS>(&src_tree.get_root(), &prune_bound);

    src_tree.len.fetch_sub(num_keys_removed, Relaxed);

    merge_page_len
}
<commit_msg>alternative prune selection<commit_after>use index::btree::dump::dump_tree;
use index::btree::external::ExtNode;
use index::btree::internal::InNode;
use index::btree::node::is_node_locked;
use index::btree::node::read_node;
use index::btree::node::read_unchecked;
use index::btree::node::write_node;
use index::btree::node::write_non_empty;
use index::btree::node::write_targeted;
use index::btree::node::EmptyNode;
use index::btree::node::Node;
use index::btree::node::NodeData;
use index::btree::node::NodeWriteGuard;
use index::btree::search::mut_search;
use index::btree::search::MutSearchResult;
use index::btree::LevelTree;
use index::btree::NodeCellRef;
use index::btree::{external, BPlusTree};
use index::lsmtree::tree::{LEVEL_2, LEVEL_3, LEVEL_PAGE_DIFF_MULTIPLIER};
use index::EntryKey;
use index::Slice;
use itertools::Itertools;
use smallvec::SmallVec;
use std::cmp::min;
use std::collections::{BTreeSet, HashSet, HashMap};
use std::fmt::Debug;
use std::mem;
use std::sync::atomic::Ordering::Relaxed;

enum Selection<KS, PS>
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    Selected(Vec<NodeWriteGuard<KS, PS>>),
    Innode(NodeCellRef),
}

fn select<KS, PS>(node: &NodeCellRef) -> Vec<NodeWriteGuard<KS, PS>>
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    let search = mut_search::<KS, PS>(node, &smallvec!());
    match search {
        MutSearchResult::External => {
            let first_node = write_node(node);
            let mut collected_keys = first_node.len();
            let mut collected = vec![first_node];
            let target_keys = min(KS::slice_len() * LEVEL_PAGE_DIFF_MULTIPLIER, LEVEL_3);
            let target_guards = LEVEL_2;
            while collected_keys < target_keys && collected.len() < target_guards {
                let right = write_node(
                    collected
                        .last_mut()
                        .unwrap()
                        .right_ref_mut_no_empty()
                        .unwrap(),
                );
                if right.is_none() {
                    break;
                } else {
                    collected_keys += right.len();
                    collected.push(right);
                }
            }
            return collected;
        }
        MutSearchResult::Internal(node) => select::<KS, PS>(&node),
    }
}

fn prune_selected<'a, KS, PS>(node: &NodeCellRef, bound: &EntryKey)
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    let first_search = mut_search::<KS, PS>(node, &smallvec!());
    match first_search {
        MutSearchResult::Internal(sub_node_ref) => {
            let sub_node = read_unchecked::<KS, PS>(&sub_node_ref);
            if !sub_node.is_empty_node() && !sub_node.is_ext() {
                prune_selected::<KS, PS>(&sub_node_ref, bound);
            }
        }
        MutSearchResult::External => unreachable!(),
    };
    let mut prev_node_guard: Option<NodeWriteGuard<KS, PS>> = None;
    let mut node_ref = node.clone();
    loop {
        let mut page = write_node::<KS, PS>(&node_ref);
        let page_len = page.len();
        let page_right_ref = page.right_ref().unwrap().clone();
        let page_right_bound = page.right_bound().clone();
        if !page.is_empty_node() {
            let mut live_ptrs: HashMap<_, _> = page.innode().ptrs.as_slice_immute()[..page_len + 1]
                .iter()
                .enumerate()
                .filter_map(|(i, sub_level)| {
                    if !read_unchecked::<KS, PS>(sub_level).is_empty_node() {
                        Some((i, sub_level.clone()))
                    } else {
                        None
                    }
                })
                .collect();
            if live_ptrs.len() == 0 {
                // all sub nodes are empty
                // will set current node empty either
                let next_page_ref = page.innode().right.clone();
                if let Some(ref mut prev_guard) = &mut prev_node_guard {
                    *prev_guard.right_ref_mut().unwrap() = next_page_ref.clone();
                }
                *page = NodeData::Empty(box EmptyNode {
                    left: None,
                    right: next_page_ref,
                });
            } else {
                {
                    let mut innode = page.innode_mut();
                    let mut new_keys = KS::init();
                    let mut new_ptrs = PS::init();
                    {
                        let keys: Vec<&mut _> = innode.keys.as_slice()[..page_len]
                            .iter_mut()
                            .enumerate()
                            .filter(|(i, _)| live_ptrs.contains_key(&i))
                            .map(|(_, k)| k)
                            .collect();
                        debug!("Prune filtered page have keys {:?}", &keys);
                        debug_assert_eq!(live_ptrs.len(), keys.len() + 1);
                        innode.len = keys.len();
                        let new_keys = new_keys.as_slice();
                        let new_ptrs = new_ptrs.as_slice();
                        for (i, key) in keys.into_iter().enumerate() {
                            debug_assert!(key > &mut smallvec!(0));
                            mem::swap(&mut new_keys[i], key);
                        }
                        for (i, (_, ptr)) in live_ptrs.into_iter().enumerate() {
                            debug_assert!(!ptr.is_default());
                            mem::replace(&mut new_ptrs[i], ptr);
                        }
                    }
                    innode.keys = new_keys;
                    innode.ptrs = new_ptrs;
                }
                prev_node_guard = Some(page);
            }
            if &page_right_bound >= bound {
                break;
            }
            node_ref = page_right_ref;
        } else {
            unreachable!();
        }
    }
}

pub fn level_merge<KS, PS>(src_tree: &BPlusTree<KS, PS>, dest_tree: &LevelTree) -> usize
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    let mut left_most_leaf_guards = select::<KS, PS>(&src_tree.get_root());
    let merge_page_len = left_most_leaf_guards.len();
    let mut num_keys_removed = 0;
    let left_most_id = left_most_leaf_guards.first().unwrap().ext_id();
    let prune_bound = left_most_leaf_guards.last().unwrap().right_bound().clone();

    debug!("Merge selected {} pages", left_most_leaf_guards.len());
    if cfg!(debug_assertions) {
        if left_most_id != src_tree.head_page_id {
            dump_tree(src_tree, "level_lsm_merge_failure_dump.json");
        }
    }
    debug_assert_eq!(
        left_most_id,
        src_tree.head_page_id,
        "{}",
        left_most_leaf_guards.first().unwrap().type_name()
    );

    // merge to dest_tree
    {
        let mut deleted_keys = src_tree.deleted.write();
        let mut merged_deleted_keys = vec![];
        let keys: Vec<EntryKey> = left_most_leaf_guards
            .iter()
            .filter(|&g| !g.is_empty_node())
            .map(|g| &g.keys()[..g.len()])
            .flatten()
            .filter(|&k| {
                if deleted_keys.contains(k) {
                    merged_deleted_keys.push(k.clone());
                    false
                } else {
                    true
                }
            })
            .cloned()
            .collect_vec();
        num_keys_removed = keys.len();
        debug!("Merge selected keys are {:?}", &keys);
        dest_tree.merge_with_keys(box keys);
        for rk in &merged_deleted_keys {
            deleted_keys.remove(rk);
        }
    }

    // adjust leaf left, right references
    {
        let right_right_most = left_most_leaf_guards
            .last()
            .unwrap()
            .right_ref()
            .unwrap()
            .clone();

        let left_left_most = left_most_leaf_guards
            .first()
            .unwrap()
            .left_ref()
            .unwrap()
            .clone();

        debug_assert!(read_unchecked::<KS, PS>(&left_left_most).is_none());

        for mut g in &mut left_most_leaf_guards {
            external::make_deleted(&g.ext_id());
            **g = NodeData::Empty(box EmptyNode {
                left: Some(left_left_most.clone()),
                right: right_right_most.clone(),
            });
        }

        let mut new_first_node = write_node::<KS, PS>(&right_right_most);
        let mut new_first_node_ext = new_first_node.extnode_mut();
        new_first_node_ext.id = src_tree.head_page_id;
        new_first_node_ext.prev = left_left_most;

        ExtNode::<KS, PS>::make_changed(&right_right_most, src_tree);
    }

    // cleanup upper level references
    prune_selected::<KS, PS>(&src_tree.get_root(), &prune_bound);

    src_tree.len.fetch_sub(num_keys_removed, Relaxed);

    merge_page_len
}
<|endoftext|>