<commit_before>use rustc_serialize::json::{Json, ToJson};

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SendTextRequest {
    openid: String,
    account: Option<String>,
    content: String,
}

impl SendTextRequest {
    pub fn new(openid: &str, content: &str) -> SendTextRequest {
        SendTextRequest {
            openid: openid.to_owned(),
            content: content.to_owned(),
            account: None,
        }
    }

    pub fn with_account(openid: &str, content: &str, account: &str) -> SendTextRequest {
        SendTextRequest {
            openid: openid.to_owned(),
            content: content.to_owned(),
            account: Some(account.to_owned()),
        }
    }
}

impl ToJson for SendTextRequest {
    fn to_json(&self) -> Json {
        if let Some(ref account) = self.account {
            json!({
                "msgtype": "text",
                "touser": (self.openid),
                "text": {"content": (self.content)},
                "customservice": {"kf_account": (account)},
            })
        } else {
            json!({
                "msgtype": "text",
                "touser": (self.openid),
                "text": {"content": (self.content)},
            })
        }
    }
}

make_encodable!(SendTextRequest);

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SendImageRequest {
    openid: String,
    account: Option<String>,
    media_id: String,
}

impl SendImageRequest {
    pub fn new(openid: &str, media_id: &str) -> SendImageRequest {
        SendImageRequest {
            openid: openid.to_owned(),
            account: None,
            media_id: media_id.to_owned(),
        }
    }

    pub fn with_account(openid: &str, media_id: &str, account: &str) -> SendImageRequest {
        SendImageRequest {
            openid: openid.to_owned(),
            account: Some(account.to_owned()),
            media_id: media_id.to_owned(),
        }
    }
}
impl ToJson for SendImageRequest {
    fn to_json(&self) -> Json {
        if let Some(ref account) = self.account {
            json!({
                "msgtype": "image",
                "touser": (self.openid),
                "image": {"media_id": (self.media_id)},
                "customservice": {"kf_account": (account)},
            })
        } else {
            json!({
                "msgtype": "image",
                "touser": (self.openid),
                "image": {"media_id": (self.media_id)},
            })
        }
    }
}

make_encodable!(SendImageRequest);

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SendVoiceRequest {
    openid: String,
    account: Option<String>,
    media_id: String,
}

impl SendVoiceRequest {
    pub fn new(openid: &str, media_id: &str) -> SendVoiceRequest {
        SendVoiceRequest {
            openid: openid.to_owned(),
            account: None,
            media_id: media_id.to_owned(),
        }
    }

    pub fn with_account(openid: &str, media_id: &str, account: &str) -> SendVoiceRequest {
        SendVoiceRequest {
            openid: openid.to_owned(),
            account: Some(account.to_owned()),
            media_id: media_id.to_owned(),
        }
    }
}

impl ToJson for SendVoiceRequest {
    fn to_json(&self) -> Json {
        if let Some(ref account) = self.account {
            json!({
                "msgtype": "voice",
                "touser": (self.openid),
                "voice": {"media_id": (self.media_id)},
                "customservice": {"kf_account": (account)},
            })
        } else {
            json!({
                "msgtype": "voice",
                "touser": (self.openid),
                "voice": {"media_id": (self.media_id)},
            })
        }
    }
}

make_encodable!(SendVoiceRequest);

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SendVideoRequest {
    openid: String,
    account: Option<String>,
    media_id: String,
    thumb_media_id: String,
    title: Option<String>,
    description: Option<String>,
}

impl SendVideoRequest {
    pub fn new(openid: &str, media_id: &str, thumb_media_id: &str, title: Option<String>, description: Option<String>) -> SendVideoRequest {
        SendVideoRequest {
            openid: openid.to_owned(),
            account: None,
            media_id: media_id.to_owned(),
            thumb_media_id: thumb_media_id.to_owned(),
            title: title,
            description: description,
        }
    }

    pub fn with_account(openid: &str, account: &str, media_id: &str, thumb_media_id: &str, title: Option<String>, description: Option<String>) -> SendVideoRequest {
        SendVideoRequest {
            openid: openid.to_owned(),
            account: Some(account.to_owned()),
            media_id: media_id.to_owned(),
            thumb_media_id: thumb_media_id.to_owned(),
            title: title,
            description: description,
        }
    }
}

impl ToJson for SendVideoRequest {
    fn to_json(&self) -> Json {
        if let Some(ref account) = self.account {
            json!({
                "msgtype": "video",
                "touser": (self.openid),
                "video": {
                    "media_id": (self.media_id),
                    "thumb_media_id": (self.thumb_media_id),
                    "title": (self.title),
                    "description": (self.description),
                },
                "customservice": {"kf_account": (account)},
            })
        } else {
            json!({
                "msgtype": "video",
                "touser": (self.openid),
                "video": {
                    "media_id": (self.media_id),
                    "thumb_media_id": (self.thumb_media_id),
                    "title": (self.title),
                    "description": (self.description),
                },
            })
        }
    }
}

make_encodable!(SendVideoRequest);

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SendMusicRequest {
    openid: String,
    account: Option<String>,
    music_url: String,
    hq_music_url: String,
    thumb_media_id: String,
    title: Option<String>,
    description: Option<String>,
}

impl SendMusicRequest {
    pub fn new(openid: &str, music_url: &str, hq_music_url: &str, thumb_media_id: &str, title: Option<String>, description: Option<String>) -> SendMusicRequest {
        SendMusicRequest {
            openid: openid.to_owned(),
            account: None,
            music_url: music_url.to_owned(),
            hq_music_url: hq_music_url.to_owned(),
            thumb_media_id: thumb_media_id.to_owned(),
            title: title,
            description: description,
        }
    }

    pub fn with_account(openid: &str, account: &str, music_url: &str, hq_music_url: &str, thumb_media_id: &str, title: Option<String>, description: Option<String>) -> SendMusicRequest {
        SendMusicRequest {
            openid: openid.to_owned(),
            account: Some(account.to_owned()),
            music_url: music_url.to_owned(),
            hq_music_url: hq_music_url.to_owned(),
            thumb_media_id: thumb_media_id.to_owned(),
            title: title,
            description: description,
        }
    }
}

impl ToJson for SendMusicRequest {
    fn to_json(&self) -> Json {
        if let Some(ref account) = self.account {
            json!({
                "msgtype": "music",
                "touser": (self.openid),
                "music": {
                    "musicurl": (self.music_url),
                    "hqmusicurl": (self.hq_music_url),
                    "thumb_media_id": (self.thumb_media_id),
                    "title": (self.title),
                    "description": (self.description),
                },
                "customservice": {"kf_account": (account)},
            })
        } else {
            json!({
                "msgtype": "music",
                "touser": (self.openid),
                "music": {
                    "musicurl": (self.music_url),
                    "hqmusicurl": (self.hq_music_url),
                    "thumb_media_id": (self.thumb_media_id),
                    "title": (self.title),
                    "description": (self.description),
                },
            })
        }
    }
}

make_encodable!(SendMusicRequest);

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Article {
    title: String,
    url: String,
    description: Option<String>,
    image: Option<String>,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SendArticlesRequest {
    openid: String,
    account: Option<String>,
    articles: Vec<Article>,
}
<commit_msg>Impl SendArticlesRequest<commit_after>use rustc_serialize::json::{Json, ToJson};

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SendTextRequest {
    openid: String,
    account: Option<String>,
    content: String,
}

impl SendTextRequest {
    pub fn new(openid: &str, content: &str) -> SendTextRequest {
        SendTextRequest {
            openid: openid.to_owned(),
            content: content.to_owned(),
            account: None,
        }
    }

    pub fn with_account(openid: &str, content: &str, account: &str) -> SendTextRequest {
        SendTextRequest {
            openid: openid.to_owned(),
            content: content.to_owned(),
            account: Some(account.to_owned()),
        }
    }
}

impl ToJson for SendTextRequest {
    fn to_json(&self) -> Json {
        if let Some(ref account) = self.account {
            json!({
                "msgtype": "text",
                "touser": (self.openid),
                "text": {"content": (self.content)},
                "customservice": {"kf_account": (account)},
            })
        } else {
            json!({
                "msgtype": "text",
                "touser": (self.openid),
                "text": {"content": (self.content)},
            })
        }
    }
}

make_encodable!(SendTextRequest);

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SendImageRequest {
    openid: String,
    account: Option<String>,
    media_id: String,
}

impl SendImageRequest {
    pub fn new(openid: &str, media_id: &str) -> SendImageRequest {
        SendImageRequest {
            openid: openid.to_owned(),
            account: None,
            media_id: media_id.to_owned(),
        }
    }

    pub fn with_account(openid: &str, media_id: &str, account: &str) -> SendImageRequest {
        SendImageRequest {
            openid: openid.to_owned(),
            account: Some(account.to_owned()),
            media_id: media_id.to_owned(),
        }
    }
}
impl ToJson for SendImageRequest {
    fn to_json(&self) -> Json {
        if let Some(ref account) = self.account {
            json!({
                "msgtype": "image",
                "touser": (self.openid),
                "image": {"media_id": (self.media_id)},
                "customservice": {"kf_account": (account)},
            })
        } else {
            json!({
                "msgtype": "image",
                "touser": (self.openid),
                "image": {"media_id": (self.media_id)},
            })
        }
    }
}

make_encodable!(SendImageRequest);

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SendVoiceRequest {
    openid: String,
    account: Option<String>,
    media_id: String,
}

impl SendVoiceRequest {
    pub fn new(openid: &str, media_id: &str) -> SendVoiceRequest {
        SendVoiceRequest {
            openid: openid.to_owned(),
            account: None,
            media_id: media_id.to_owned(),
        }
    }

    pub fn with_account(openid: &str, media_id: &str, account: &str) -> SendVoiceRequest {
        SendVoiceRequest {
            openid: openid.to_owned(),
            account: Some(account.to_owned()),
            media_id: media_id.to_owned(),
        }
    }
}

impl ToJson for SendVoiceRequest {
    fn to_json(&self) -> Json {
        if let Some(ref account) = self.account {
            json!({
                "msgtype": "voice",
                "touser": (self.openid),
                "voice": {"media_id": (self.media_id)},
                "customservice": {"kf_account": (account)},
            })
        } else {
            json!({
                "msgtype": "voice",
                "touser": (self.openid),
                "voice": {"media_id": (self.media_id)},
            })
        }
    }
}

make_encodable!(SendVoiceRequest);

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SendVideoRequest {
    openid: String,
    account: Option<String>,
    media_id: String,
    thumb_media_id: String,
    title: Option<String>,
    description: Option<String>,
}

impl SendVideoRequest {
    pub fn new(openid: &str, media_id: &str, thumb_media_id: &str, title: Option<String>, description: Option<String>) -> SendVideoRequest {
        SendVideoRequest {
            openid: openid.to_owned(),
            account: None,
            media_id: media_id.to_owned(),
            thumb_media_id: thumb_media_id.to_owned(),
            title: title,
            description: description,
        }
    }

    pub fn with_account(openid: &str, account: &str, media_id: &str, thumb_media_id: &str, title: Option<String>, description: Option<String>) -> SendVideoRequest {
        SendVideoRequest {
            openid: openid.to_owned(),
            account: Some(account.to_owned()),
            media_id: media_id.to_owned(),
            thumb_media_id: thumb_media_id.to_owned(),
            title: title,
            description: description,
        }
    }
}

impl ToJson for SendVideoRequest {
    fn to_json(&self) -> Json {
        if let Some(ref account) = self.account {
            json!({
                "msgtype": "video",
                "touser": (self.openid),
                "video": {
                    "media_id": (self.media_id),
                    "thumb_media_id": (self.thumb_media_id),
                    "title": (self.title),
                    "description": (self.description),
                },
                "customservice": {"kf_account": (account)},
            })
        } else {
            json!({
                "msgtype": "video",
                "touser": (self.openid),
                "video": {
                    "media_id": (self.media_id),
                    "thumb_media_id": (self.thumb_media_id),
                    "title": (self.title),
                    "description": (self.description),
                },
            })
        }
    }
}

make_encodable!(SendVideoRequest);

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SendMusicRequest {
    openid: String,
    account: Option<String>,
    music_url: String,
    hq_music_url: String,
    thumb_media_id: String,
    title: Option<String>,
    description: Option<String>,
}

impl SendMusicRequest {
    pub fn new(openid: &str, music_url: &str, hq_music_url: &str, thumb_media_id: &str, title: Option<String>, description: Option<String>) -> SendMusicRequest {
        SendMusicRequest {
            openid: openid.to_owned(),
            account: None,
            music_url: music_url.to_owned(),
            hq_music_url: hq_music_url.to_owned(),
            thumb_media_id: thumb_media_id.to_owned(),
            title: title,
            description: description,
        }
    }

    pub fn with_account(openid: &str, account: &str, music_url: &str, hq_music_url: &str, thumb_media_id: &str, title: Option<String>, description: Option<String>) -> SendMusicRequest {
        SendMusicRequest {
            openid: openid.to_owned(),
            account: Some(account.to_owned()),
            music_url: music_url.to_owned(),
            hq_music_url: hq_music_url.to_owned(),
            thumb_media_id: thumb_media_id.to_owned(),
            title: title,
            description: description,
        }
    }
}

impl ToJson for SendMusicRequest {
    fn to_json(&self) -> Json {
        if let Some(ref account) = self.account {
            json!({
                "msgtype": "music",
                "touser": (self.openid),
                "music": {
                    "musicurl": (self.music_url),
                    "hqmusicurl": (self.hq_music_url),
                    "thumb_media_id": (self.thumb_media_id),
                    "title": (self.title),
                    "description": (self.description),
                },
                "customservice": {"kf_account": (account)},
            })
        } else {
            json!({
                "msgtype": "music",
                "touser": (self.openid),
                "music": {
                    "musicurl": (self.music_url),
                    "hqmusicurl": (self.hq_music_url),
                    "thumb_media_id": (self.thumb_media_id),
                    "title": (self.title),
                    "description": (self.description),
                },
            })
        }
    }
}

make_encodable!(SendMusicRequest);

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Article {
    title: String,
    url: String,
    description: Option<String>,
    image: Option<String>,
}

impl Article {
    pub fn new(title: &str, url: &str, description: Option<String>, image: Option<String>) -> Article {
        Article {
            title: title.to_owned(),
            url: url.to_owned(),
            description: description,
            image: image,
        }
    }
}

impl ToJson for Article {
    fn to_json(&self) -> Json {
        json!({
            "title": (self.title),
            "url": (self.url),
            "description": (self.description),
            "picurl": (self.image),
        })
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SendArticlesRequest {
    openid: String,
    account: Option<String>,
    articles: Vec<Article>,
}

impl SendArticlesRequest {
    pub fn new(openid: &str, articles: &[Article]) -> SendArticlesRequest {
        SendArticlesRequest {
            openid: openid.to_owned(),
            account: None,
            articles: articles.to_vec(),
        }
    }

    pub fn with_account(openid: &str, account: &str, articles: &[Article]) -> SendArticlesRequest {
        SendArticlesRequest {
            openid: openid.to_owned(),
            account: Some(account.to_owned()),
            articles: articles.to_vec(),
        }
    }

    pub fn add_article(&mut self, article: Article) {
        if self.articles.len() < 10 {
            self.articles.push(article);
        }
    }
}

impl ToJson for SendArticlesRequest {
    fn to_json(&self) -> Json {
        if let Some(ref account) = self.account {
            json!({
                "msgtype": "news",
                "touser": (self.openid),
                "news": {
                    "articles": (self.articles),
                },
                "customservice": {"kf_account": (account)},
            })
        } else {
            json!({
                "msgtype": "news",
                "touser": (self.openid),
                "news": {
                    "articles": (self.articles),
                },
            })
        }
    }
}

make_encodable!(SendArticlesRequest);
<|endoftext|>


<commit_before>//! Seat global utilities
//!
//! This module provides you with utilities for handling the seat globals
//! and the associated input Wayland objects.
//!
//! ## How to use it
//!
//! ### Initialization
//!
//! ```
//! # extern crate wayland_server;
//! use smithay::wayland::seat::Seat;
//!
//! # let mut display = wayland_server::Display::new();
//! // insert the seat:
//! let (seat, seat_global) = Seat::new(
//!     &mut display,             // the display
//!     "seat-0".into(),          // the name of the seat, will be advertized to clients
//!     None                      // insert a logger here
//! );
//! ```
//!
//! ### Run usage
//!
//! Once the seat is initialized, you can add capabilities to it.
//!
//! Currently, only pointer and keyboard capabilities are supported by smithay.
//!
//! You can add these capabilities via methods of the [`Seat`] struct:
//! [`Seat::add_keyboard`] and [`Seat::add_pointer`].
//! These methods return handles that can be cloned and sent across thread, so you can keep one around
//! in your event-handling code to forward inputs to your clients.
//!
//! This module further defines the `"cursor_image"` role, that is assigned to surfaces used by clients
//! to change the cursor icon.

use std::{cell::RefCell, fmt, ops::Deref as _, rc::Rc};

mod keyboard;
mod pointer;
mod touch;

pub use self::{
    keyboard::{
        keysyms, Error as KeyboardError, FilterResult, GrabStartData as KeyboardGrabStartData, KeyboardGrab,
        KeyboardHandle, KeyboardInnerHandle, Keysym, KeysymHandle, ModifiersState, XkbConfig,
    },
    pointer::{
        AxisFrame, CursorImageAttributes, CursorImageStatus, GrabStartData as PointerGrabStartData,
        PointerGrab, PointerHandle, PointerInnerHandle,
    },
    touch::TouchHandle,
};

use wayland_server::{
    protocol::{wl_seat, wl_surface},
    Display, Filter, Global, Main, UserDataMap,
};

#[derive(Debug)]
struct Inner {
    pointer: Option<PointerHandle>,
    keyboard: Option<KeyboardHandle>,
    touch: Option<TouchHandle>,
    known_seats: Vec<wl_seat::WlSeat>,
}

pub(crate) struct SeatRc {
    inner: RefCell<Inner>,
    user_data: UserDataMap,
    pub(crate) log: ::slog::Logger,
    name: String,
}

// UserDataMap does not implement debug, so we have to impl Debug manually
impl fmt::Debug for SeatRc {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("SeatRc")
            .field("inner", &self.inner)
            .field("user_data", &"...")
            .field("log", &self.log)
            .field("name", &self.name)
            .finish()
    }
}

impl Inner {
    fn compute_caps(&self) -> wl_seat::Capability {
        let mut caps = wl_seat::Capability::empty();
        if self.pointer.is_some() {
            caps |= wl_seat::Capability::Pointer;
        }
        if self.keyboard.is_some() {
            caps |= wl_seat::Capability::Keyboard;
        }
        caps
    }

    fn send_all_caps(&self) {
        let capabilities = self.compute_caps();
        for seat in &self.known_seats {
            seat.capabilities(capabilities);
        }
    }
}

/// A Seat handle
///
/// This struct gives you access to the control of the
/// capabilities of the associated seat.
///
/// It is directly inserted in the wayland display by its [`new`](Seat::new) method.
///
/// This is an handle to the inner logic, it can be cloned.
///
/// See module-level documentation for details of use.
#[derive(Debug, Clone)]
pub struct Seat {
    pub(crate) arc: Rc<SeatRc>,
}

impl Seat {
    /// Create a new seat global
    ///
    /// A new seat global is created with given name and inserted
    /// into this wayland display.
    ///
    /// You are provided with the state token to retrieve it (allowing
    /// you to add or remove capabilities from it), and the global handle,
    /// in case you want to remove it.
    pub fn new<L>(display: &mut Display, name: String, logger: L) -> (Seat, Global<wl_seat::WlSeat>)
    where
        L: Into<Option<::slog::Logger>>,
    {
        let log = crate::slog_or_fallback(logger);
        let arc = Rc::new(SeatRc {
            inner: RefCell::new(Inner {
                pointer: None,
                keyboard: None,
                touch: None,
                known_seats: Vec::new(),
            }),
            log: log.new(slog::o!("smithay_module" => "seat_handler", "seat_name" => name.clone())),
            name,
            user_data: UserDataMap::new(),
        });
        let seat = Seat { arc: arc.clone() };
        let global = display.create_global(
            5,
            Filter::new(move |(new_seat, _version), _, _| {
                let seat = implement_seat(new_seat, arc.clone());
                let mut inner = arc.inner.borrow_mut();
                if seat.as_ref().version() >= 2 {
                    seat.name(arc.name.clone());
                }
                seat.capabilities(inner.compute_caps());
                inner.known_seats.push(seat);
            }),
        );
        (seat, global)
    }

    /// Attempt to retrieve a [`Seat`] from an existing resource
    pub fn from_resource(seat: &wl_seat::WlSeat) -> Option<Seat> {
        seat.as_ref()
            .user_data()
            .get::<Rc<SeatRc>>()
            .cloned()
            .map(|arc| Seat { arc })
    }

    /// Access the `UserDataMap` associated with this `Seat`
    pub fn user_data(&self) -> &UserDataMap {
        &self.arc.user_data
    }

    /// Adds the pointer capability to this seat
    ///
    /// You are provided a [`PointerHandle`], which allows you to send input events
    /// to this pointer. This handle can be cloned.
    ///
    /// Calling this method on a seat that already has a pointer capability
    /// will overwrite it, and will be seen by the clients as if the
    /// mouse was unplugged and a new one was plugged.
    ///
    /// You need to provide a callback that will be notified whenever a client requests
    /// to set a custom cursor image.
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate wayland_server;
    /// #
    /// # use smithay::wayland::seat::Seat;
    /// #
    /// # let mut display = wayland_server::Display::new();
    /// # let (mut seat, seat_global) = Seat::new(
    /// #     &mut display,
    /// #     "seat-0".into(),
    /// #     None
    /// # );
    /// let pointer_handle = seat.add_pointer(
    ///     |new_status| { /* a closure handling requests from clients to change the cursor icon */ }
    /// );
    /// ```
    pub fn add_pointer<F>(&mut self, cb: F) -> PointerHandle
    where
        F: FnMut(CursorImageStatus) + 'static,
    {
        let mut inner = self.arc.inner.borrow_mut();
        let pointer = self::pointer::create_pointer_handler(cb);
        if inner.pointer.is_some() {
            // there is already a pointer, remove it and notify the clients
            // of the change
            inner.pointer = None;
            inner.send_all_caps();
        }
        inner.pointer = Some(pointer.clone());
        inner.send_all_caps();
        pointer
    }

    /// Access the pointer of this seat if any
    pub fn get_pointer(&self) -> Option<PointerHandle> {
        self.arc.inner.borrow_mut().pointer.clone()
    }

    /// Remove the pointer capability from this seat
    ///
    /// Clients will be appropriately notified.
    pub fn remove_pointer(&mut self) {
        let mut inner = self.arc.inner.borrow_mut();
        if inner.pointer.is_some() {
            inner.pointer = None;
            inner.send_all_caps();
        }
    }

    /// Adds the keyboard capability to this seat
    ///
    /// You are provided a [`KeyboardHandle`], which allows you to send input events
    /// to this keyboard. This handle can be cloned.
    ///
    /// You also provide a Model/Layout/Variant/Options specification of the
    /// keymap to be used for this keyboard, as well as any repeat-info that
    /// will be forwarded to the clients.
    ///
    /// Calling this method on a seat that already has a keyboard capability
    /// will overwrite it, and will be seen by the clients as if the
    /// keyboard was unplugged and a new one was plugged.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// # extern crate smithay;
    /// # use smithay::wayland::seat::{Seat, XkbConfig};
    /// # let mut seat: Seat = unimplemented!();
    /// let keyboard = seat
    ///     .add_keyboard(
    ///         XkbConfig {
    ///             layout: "de",
    ///             variant: "nodeadkeys",
    ///             ..XkbConfig::default()
    ///         },
    ///         200,
    ///         25,
    ///         |seat, focus| {
    ///             /* This closure is called whenever the keyboard focus
    ///              * changes, with the new focus as argument */
    ///         }
    ///     )
    ///     .expect("Failed to initialize the keyboard");
    /// ```
    pub fn add_keyboard<F>(
        &mut self,
        xkb_config: keyboard::XkbConfig<'_>,
        repeat_delay: i32,
        repeat_rate: i32,
        mut focus_hook: F,
    ) -> Result<KeyboardHandle, KeyboardError>
    where
        F: FnMut(&Seat, Option<&wl_surface::WlSurface>) + 'static,
    {
        let me = self.clone();
        let mut inner = self.arc.inner.borrow_mut();
        let keyboard = self::keyboard::create_keyboard_handler(
            xkb_config,
            repeat_delay,
            repeat_rate,
            &self.arc.log,
            move |focus| focus_hook(&me, focus),
        )?;
        if inner.keyboard.is_some() {
            // there is already a keyboard, remove it and notify the clients
            // of the change
            inner.keyboard = None;
            inner.send_all_caps();
        }
        inner.keyboard = Some(keyboard.clone());
        inner.send_all_caps();
        Ok(keyboard)
    }

    /// Access the keyboard of this seat if any
    pub fn get_keyboard(&self) -> Option<KeyboardHandle> {
        self.arc.inner.borrow_mut().keyboard.clone()
    }

    /// Remove the keyboard capability from this seat
    ///
    /// Clients will be appropriately notified.
    pub fn remove_keyboard(&mut self) {
        let mut inner = self.arc.inner.borrow_mut();
        if inner.keyboard.is_some() {
            inner.keyboard = None;
            inner.send_all_caps();
        }
    }

    /// Adds the touch capability to this seat
    ///
    /// You are provided a [`TouchHandle`], which allows you to send input events
    /// to this pointer. This handle can be cloned.
    ///
    /// Calling this method on a seat that already has a touch capability
    /// will overwrite it, and will be seen by the clients as if the
    /// touchscreen was unplugged and a new one was plugged in.
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate wayland_server;
    /// #
    /// # use smithay::wayland::seat::Seat;
    /// #
    /// # let mut display = wayland_server::Display::new();
    /// # let (mut seat, seat_global) = Seat::new(
    /// #     &mut display,
    /// #     "seat-0".into(),
    /// #     None
    /// # );
    /// let touch_handle = seat.add_touch();
    /// ```
    pub fn add_touch(&mut self) -> TouchHandle {
        let mut inner = self.arc.inner.borrow_mut();
        let touch = TouchHandle::new();
        if inner.touch.is_some() {
            // If there's already a tocuh device, remove it notify the clients about the change.
            inner.touch = None;
            inner.send_all_caps();
        }
        inner.touch = Some(touch.clone());
        inner.send_all_caps();
        touch
    }

    /// Access the touch device of this seat, if any.
    pub fn get_touch(&self) -> Option<TouchHandle> {
        self.arc.inner.borrow_mut().touch.clone()
    }

    /// Remove the touch capability from this seat
    ///
    /// Clients will be appropriately notified.
    pub fn remove_touch(&mut self) {
        let mut inner = self.arc.inner.borrow_mut();
        if inner.touch.is_some() {
            inner.touch = None;
            inner.send_all_caps();
        }
    }

    /// Checks whether a given [`WlSeat`](wl_seat::WlSeat) is associated with this [`Seat`]
    pub fn owns(&self, seat: &wl_seat::WlSeat) -> bool {
        let inner = self.arc.inner.borrow_mut();
        inner.known_seats.iter().any(|s| s.as_ref().equals(seat.as_ref()))
    }
}

impl ::std::cmp::PartialEq for Seat {
    fn eq(&self, other: &Seat) -> bool {
        Rc::ptr_eq(&self.arc, &other.arc)
    }
}

fn implement_seat(seat: Main<wl_seat::WlSeat>, arc: Rc<SeatRc>) -> wl_seat::WlSeat {
    let dest_arc = arc.clone();
    seat.quick_assign(move |seat, request, _| {
        let arc = seat.as_ref().user_data().get::<Rc<SeatRc>>().unwrap();
        let inner = arc.inner.borrow_mut();
        match request {
            wl_seat::Request::GetPointer { id } => {
                let pointer = self::pointer::implement_pointer(id, inner.pointer.as_ref());
                if let Some(ref ptr_handle) = inner.pointer {
                    ptr_handle.new_pointer(pointer);
                } else {
                    // we should send a protocol error... but the protocol does not allow
                    // us, so this pointer will just remain inactive ¯\_(ツ)_/¯
                }
            }
            wl_seat::Request::GetKeyboard { id } => {
                let keyboard = self::keyboard::implement_keyboard(id, inner.keyboard.as_ref());
                if let Some(ref kbd_handle) = inner.keyboard {
                    kbd_handle.new_kbd(keyboard);
                } else {
                    // same as pointer, should error but cannot
                }
            }
            wl_seat::Request::GetTouch { id } => {
                let touch = self::touch::implement_touch(id, inner.touch.as_ref());
                if let Some(ref touch_handle) = inner.touch {
                    touch_handle.new_touch(touch);
                } else {
                    // same as pointer, should error but cannot
                }
            }
            wl_seat::Request::Release => {
                // Our destructors already handle it
            }
            _ => unreachable!(),
        }
    });
    seat.assign_destructor(Filter::new(move |seat: wl_seat::WlSeat, _, _| {
        dest_arc
            .inner
            .borrow_mut()
            .known_seats
            .retain(|s| !s.as_ref().equals(seat.as_ref()));
    }));
    seat.as_ref().user_data().set(move || arc);

    seat.deref().clone()
}
<commit_msg>Update capabilities<commit_after>//! Seat global utilities
//!
//! This module provides you with utilities for handling the seat globals
//! and the associated input Wayland objects.
//!
//! ## How to use it
//!
//! ### Initialization
//!
//! ```
//! # extern crate wayland_server;
//! use smithay::wayland::seat::Seat;
//!
//! # let mut display = wayland_server::Display::new();
//! // insert the seat:
//! let (seat, seat_global) = Seat::new(
//!     &mut display,             // the display
//!     "seat-0".into(),          // the name of the seat, will be advertized to clients
//!     None                      // insert a logger here
//! );
//! ```
//!
//! ### Run usage
//!
//! Once the seat is initialized, you can add capabilities to it.
//!
//! Currently, only pointer and keyboard capabilities are supported by smithay.
//!
//! You can add these capabilities via methods of the [`Seat`] struct:
//! [`Seat::add_keyboard`] and [`Seat::add_pointer`].
//! These methods return handles that can be cloned and sent across thread, so you can keep one around
//! in your event-handling code to forward inputs to your clients.
//!
//! This module further defines the `"cursor_image"` role, that is assigned to surfaces used by clients
//! to change the cursor icon.

use std::{cell::RefCell, fmt, ops::Deref as _, rc::Rc};

mod keyboard;
mod pointer;
mod touch;

pub use self::{
    keyboard::{
        keysyms, Error as KeyboardError, FilterResult, GrabStartData as KeyboardGrabStartData, KeyboardGrab,
        KeyboardHandle, KeyboardInnerHandle, Keysym, KeysymHandle, ModifiersState, XkbConfig,
    },
    pointer::{
        AxisFrame, CursorImageAttributes, CursorImageStatus, GrabStartData as PointerGrabStartData,
        PointerGrab, PointerHandle, PointerInnerHandle,
    },
    touch::TouchHandle,
};

use wayland_server::{
    protocol::{wl_seat, wl_surface},
    Display, Filter, Global, Main, UserDataMap,
};

#[derive(Debug)]
struct Inner {
    pointer: Option<PointerHandle>,
    keyboard: Option<KeyboardHandle>,
    touch: Option<TouchHandle>,
    known_seats: Vec<wl_seat::WlSeat>,
}

pub(crate) struct SeatRc {
    inner: RefCell<Inner>,
    user_data: UserDataMap,
    pub(crate) log: ::slog::Logger,
    name: String,
}

// UserDataMap does not implement debug, so we have to impl Debug manually
impl fmt::Debug for SeatRc {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("SeatRc")
            .field("inner", &self.inner)
            .field("user_data", &"...")
            .field("log", &self.log)
            .field("name", &self.name)
            .finish()
    }
}

impl Inner {
    fn compute_caps(&self) -> wl_seat::Capability {
        let mut caps = wl_seat::Capability::empty();
        if self.pointer.is_some() {
            caps |= wl_seat::Capability::Pointer;
        }
        if self.keyboard.is_some() {
            caps |= wl_seat::Capability::Keyboard;
        }
        if self.touch.is_some() {
            caps |= wl_seat::Capability::Touch;
        }
        caps
    }

    fn send_all_caps(&self) {
        let capabilities = self.compute_caps();
        for seat in &self.known_seats {
            seat.capabilities(capabilities);
        }
    }
}

/// A Seat handle
///
/// This struct gives you access to the control of the
/// capabilities of the associated seat.
///
/// It is directly inserted in the wayland display by its [`new`](Seat::new) method.
///
/// This is an handle to the inner logic, it can be cloned.
///
/// See module-level documentation for details of use.
#[derive(Debug, Clone)]
pub struct Seat {
    pub(crate) arc: Rc<SeatRc>,
}

impl Seat {
    /// Create a new seat global
    ///
    /// A new seat global is created with given name and inserted
    /// into this wayland display.
    ///
    /// You are provided with the state token to retrieve it (allowing
    /// you to add or remove capabilities from it), and the global handle,
    /// in case you want to remove it.
    pub fn new<L>(display: &mut Display, name: String, logger: L) -> (Seat, Global<wl_seat::WlSeat>)
    where
        L: Into<Option<::slog::Logger>>,
    {
        let log = crate::slog_or_fallback(logger);
        let arc = Rc::new(SeatRc {
            inner: RefCell::new(Inner {
                pointer: None,
                keyboard: None,
                touch: None,
                known_seats: Vec::new(),
            }),
            log: log.new(slog::o!("smithay_module" => "seat_handler", "seat_name" => name.clone())),
            name,
            user_data: UserDataMap::new(),
        });
        let seat = Seat { arc: arc.clone() };
        let global = display.create_global(
            5,
            Filter::new(move |(new_seat, _version), _, _| {
                let seat = implement_seat(new_seat, arc.clone());
                let mut inner = arc.inner.borrow_mut();
                if seat.as_ref().version() >= 2 {
                    seat.name(arc.name.clone());
                }
                seat.capabilities(inner.compute_caps());
                inner.known_seats.push(seat);
            }),
        );
        (seat, global)
    }

    /// Attempt to retrieve a [`Seat`] from an existing resource
    pub fn from_resource(seat: &wl_seat::WlSeat) -> Option<Seat> {
        seat.as_ref()
            .user_data()
            .get::<Rc<SeatRc>>()
            .cloned()
            .map(|arc| Seat { arc })
    }

    /// Access the `UserDataMap` associated with this `Seat`
    pub fn user_data(&self) -> &UserDataMap {
        &self.arc.user_data
    }

    /// Adds the pointer capability to this seat
    ///
    /// You are provided a [`PointerHandle`], which allows you to send input events
    /// to this pointer. This handle can be cloned.
    ///
    /// Calling this method on a seat that already has a pointer capability
    /// will overwrite it, and will be seen by the clients as if the
    /// mouse was unplugged and a new one was plugged.
    ///
    /// You need to provide a callback that will be notified whenever a client requests
    /// to set a custom cursor image.
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate wayland_server;
    /// #
    /// # use smithay::wayland::seat::Seat;
    /// #
    /// # let mut display = wayland_server::Display::new();
    /// # let (mut seat, seat_global) = Seat::new(
    /// #     &mut display,
    /// #     "seat-0".into(),
    /// #     None
    /// # );
    /// let pointer_handle = seat.add_pointer(
    ///     |new_status| { /* a closure handling requests from clients to change the cursor icon */ }
    /// );
    /// ```
    pub fn add_pointer<F>(&mut self, cb: F) -> PointerHandle
    where
        F: FnMut(CursorImageStatus) + 'static,
    {
        let mut inner = self.arc.inner.borrow_mut();
        let pointer = self::pointer::create_pointer_handler(cb);
        if inner.pointer.is_some() {
            // there is already a pointer, remove it and notify the clients
            // of the change
            inner.pointer = None;
            inner.send_all_caps();
        }
        inner.pointer = Some(pointer.clone());
        inner.send_all_caps();
        pointer
    }

    /// Access the pointer of this seat if any
    pub fn get_pointer(&self) -> Option<PointerHandle> {
        self.arc.inner.borrow_mut().pointer.clone()
    }

    /// Remove the pointer capability from this seat
    ///
    /// Clients will be appropriately notified.
    pub fn remove_pointer(&mut self) {
        let mut inner = self.arc.inner.borrow_mut();
        if inner.pointer.is_some() {
            inner.pointer = None;
            inner.send_all_caps();
        }
    }

    /// Adds the keyboard capability to this seat
    ///
    /// You are provided a [`KeyboardHandle`], which allows you to send input events
    /// to this keyboard. This handle can be cloned.
    ///
    /// You also provide a Model/Layout/Variant/Options specification of the
    /// keymap to be used for this keyboard, as well as any repeat-info that
    /// will be forwarded to the clients.
    ///
    /// Calling this method on a seat that already has a keyboard capability
    /// will overwrite it, and will be seen by the clients as if the
    /// keyboard was unplugged and a new one was plugged.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// # extern crate smithay;
    /// # use smithay::wayland::seat::{Seat, XkbConfig};
    /// # let mut seat: Seat = unimplemented!();
    /// let keyboard = seat
    ///     .add_keyboard(
    ///         XkbConfig {
    ///             layout: "de",
    ///             variant: "nodeadkeys",
    ///             ..XkbConfig::default()
    ///         },
    ///         200,
    ///         25,
    ///         |seat, focus| {
    ///             /* This closure is called whenever the keyboard focus
    ///              * changes, with the new focus as argument */
    ///         }
    ///     )
    ///     .expect("Failed to initialize the keyboard");
    /// ```
    pub fn add_keyboard<F>(
        &mut self,
        xkb_config: keyboard::XkbConfig<'_>,
        repeat_delay: i32,
        repeat_rate: i32,
        mut focus_hook: F,
    ) -> Result<KeyboardHandle, KeyboardError>
    where
        F: FnMut(&Seat, Option<&wl_surface::WlSurface>) + 'static,
    {
        let me = self.clone();
        let mut inner = self.arc.inner.borrow_mut();
        let keyboard = self::keyboard::create_keyboard_handler(
            xkb_config,
            repeat_delay,
            repeat_rate,
            &self.arc.log,
            move |focus| focus_hook(&me, focus),
        )?;
        if inner.keyboard.is_some() {
            // there is already a keyboard, remove it and notify the clients
            // of the change
            inner.keyboard = None;
            inner.send_all_caps();
        }
        inner.keyboard = Some(keyboard.clone());
        inner.send_all_caps();
        Ok(keyboard)
    }

    /// Access the keyboard of this seat if any
    pub fn get_keyboard(&self) -> Option<KeyboardHandle> {
        self.arc.inner.borrow_mut().keyboard.clone()
    }

    /// Remove the keyboard capability from this seat
    ///
    /// Clients will be appropriately notified.
    pub fn remove_keyboard(&mut self) {
        let mut inner = self.arc.inner.borrow_mut();
        if inner.keyboard.is_some() {
            inner.keyboard = None;
            inner.send_all_caps();
        }
    }

    /// Adds the touch capability to this seat
    ///
    /// You are provided a [`TouchHandle`], which allows you to send input events
    /// to this pointer. This handle can be cloned.
    ///
    /// Calling this method on a seat that already has a touch capability
    /// will overwrite it, and will be seen by the clients as if the
    /// touchscreen was unplugged and a new one was plugged in.
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate wayland_server;
    /// #
    /// # use smithay::wayland::seat::Seat;
    /// #
    /// # let mut display = wayland_server::Display::new();
    /// # let (mut seat, seat_global) = Seat::new(
    /// #     &mut display,
    /// #     "seat-0".into(),
    /// #     None
    /// # );
    /// let touch_handle = seat.add_touch();
    /// ```
    pub fn add_touch(&mut self) -> TouchHandle {
        let mut inner = self.arc.inner.borrow_mut();
        let touch = TouchHandle::new();
        if inner.touch.is_some() {
            // If there's already a tocuh device, remove it notify the clients about the change.
            inner.touch = None;
            inner.send_all_caps();
        }
        inner.touch = Some(touch.clone());
        inner.send_all_caps();
        touch
    }

    /// Access the touch device of this seat, if any.
    pub fn get_touch(&self) -> Option<TouchHandle> {
        self.arc.inner.borrow_mut().touch.clone()
    }

    /// Remove the touch capability from this seat
    ///
    /// Clients will be appropriately notified.
    pub fn remove_touch(&mut self) {
        let mut inner = self.arc.inner.borrow_mut();
        if inner.touch.is_some() {
            inner.touch = None;
            inner.send_all_caps();
        }
    }

    /// Checks whether a given [`WlSeat`](wl_seat::WlSeat) is associated with this [`Seat`]
    pub fn owns(&self, seat: &wl_seat::WlSeat) -> bool {
        let inner = self.arc.inner.borrow_mut();
        inner.known_seats.iter().any(|s| s.as_ref().equals(seat.as_ref()))
    }
}

impl ::std::cmp::PartialEq for Seat {
    fn eq(&self, other: &Seat) -> bool {
        Rc::ptr_eq(&self.arc, &other.arc)
    }
}

fn implement_seat(seat: Main<wl_seat::WlSeat>, arc: Rc<SeatRc>) -> wl_seat::WlSeat {
    let dest_arc = arc.clone();
    seat.quick_assign(move |seat, request, _| {
        let arc = seat.as_ref().user_data().get::<Rc<SeatRc>>().unwrap();
        let inner = arc.inner.borrow_mut();
        match request {
            wl_seat::Request::GetPointer { id } => {
                let pointer = self::pointer::implement_pointer(id, inner.pointer.as_ref());
                if let Some(ref ptr_handle) = inner.pointer {
                    ptr_handle.new_pointer(pointer);
                } else {
                    // we should send a protocol error... but the protocol does not allow
                    // us, so this pointer will just remain inactive ¯\_(ツ)_/¯
                }
            }
            wl_seat::Request::GetKeyboard { id } => {
                let keyboard = self::keyboard::implement_keyboard(id, inner.keyboard.as_ref());
                if let Some(ref kbd_handle) = inner.keyboard {
                    kbd_handle.new_kbd(keyboard);
                } else {
                    // same as pointer, should error but cannot
                }
            }
            wl_seat::Request::GetTouch { id } => {
                let touch = self::touch::implement_touch(id, inner.touch.as_ref());
                if let Some(ref touch_handle) = inner.touch {
                    touch_handle.new_touch(touch);
                } else {
                    // same as pointer, should error but cannot
                }
            }
            wl_seat::Request::Release => {
                // Our destructors already handle it
            }
            _ => unreachable!(),
        }
    });
    seat.assign_destructor(Filter::new(move |seat: wl_seat::WlSeat, _, _| {
        dest_arc
            .inner
            .borrow_mut()
            .known_seats
            .retain(|s| !s.as_ref().equals(seat.as_ref()));
    }));
    seat.as_ref().user_data().set(move || arc);

    seat.deref().clone()
}
<|endoftext|>


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

#![forbid(unsafe_code)]

use aptos_config::config::ApiConfig;
use aptos_node::AptosNodeArgs;
use aptos_rosetta::bootstrap;
use aptos_types::chain_id::ChainId;
use clap::Parser;
use std::{
    net::SocketAddr,
    sync::{
        atomic::{AtomicBool, Ordering},
        Arc,
    },
    thread,
    time::Duration,
};
use tokio::time::Instant;

const REST_API_WAIT_DURATION_MS: u64 = 100;
const TOTAL_REST_API_WAIT_DURATION_S: u64 = 60;

#[tokio::main]
async fn main() {
    let args: CommandArgs = CommandArgs::parse();

    match args {
        CommandArgs::OnlineRemote(_) => {
            println!("Starting Rosetta in Online remote (no local full node) mode")
        }
        CommandArgs::Online(_) => {
            println!("Starting Rosetta in Online (with local full node) mode")
        }
        CommandArgs::Offline(_) => println!("Starting Rosetta in Offline mode"),
    }

    // If we're in online mode, we run a full node side by side, the fullnode sets up the logger
    let _maybe_node = if let CommandArgs::Online(OnlineLocalArgs {
        ref node_args,
        ref online_args,
    }) = args
    {
        println!("Starting local node");
        let node_args = node_args.clone();
        let runtime = thread::spawn(move || node_args.run());

        // Wait and ensure the node is running on the URL
        let client = aptos_rest_client::Client::new(online_args.rest_api_url.clone());
        let mut successful = false;
        let total_wait_duration = Duration::from_secs(TOTAL_REST_API_WAIT_DURATION_S);
        let start = Instant::now();
        while start.elapsed() < total_wait_duration {
            if client.get_index().await.is_ok() {
                successful = true;
                break;
            }

            tokio::time::sleep(Duration::from_millis(REST_API_WAIT_DURATION_MS)).await;
        }

        // If it didn't start up, we need to crash
        if !successful {
            panic!(
                "Node didn't start up on time after {} seconds at {}",
                TOTAL_REST_API_WAIT_DURATION_S, online_args.rest_api_url
            )
        }

        println!("Local node started successfully");
        Some(runtime)
    } else {
        // If we aren't running a full node, set up the logger now
        aptos_logger::Logger::new().init();
        None
    };

    println!("Starting rosetta");
    // Ensure runtime for Rosetta is up and running
    let _rosetta = bootstrap(args.chain_id(), args.api_config(), args.rest_client())
        .expect("Should bootstrap");

    // Run until there is an interrupt
    let term = Arc::new(AtomicBool::new(false));
    while !term.load(Ordering::Acquire) {
        std::thread::park();
    }
}

/// A trait to provide common values from both online and offline mode
trait ServerArgs {
    /// Retrieve the API config for the local server
    fn api_config(&self) -> ApiConfig;

    /// Retrieve the optional rest client for the local server
    fn rest_client(&self) -> Option<aptos_rest_client::Client>;

    /// Retrieve the chain id
    fn chain_id(&self) -> ChainId;
}

/// Aptos Rosetta API Server
///
/// Provides an implementation of [Rosetta](https://www.rosetta-api.org/docs/Reference.html) on Aptos.
#[derive(Debug, Parser)]
#[clap(name = "aptos-rosetta", author, version, propagate_version = true)]
pub enum CommandArgs {
    /// Run a local online server that connects to a fullnode endpoint
    OnlineRemote(OnlineRemoteArgs),
    /// Run a local full node in tandem with Rosetta
    Online(OnlineLocalArgs),
    /// Run a local online server that doesn't connect to a fullnode endpoint
    Offline(OfflineArgs),
}

impl ServerArgs for CommandArgs {
    fn api_config(&self) -> ApiConfig {
        match self {
            CommandArgs::OnlineRemote(args) => args.api_config(),
            CommandArgs::Offline(args) => args.api_config(),
            CommandArgs::Online(args) => args.api_config(),
        }
    }

    fn rest_client(&self) -> Option<aptos_rest_client::Client> {
        match self {
            CommandArgs::OnlineRemote(args) => args.rest_client(),
            CommandArgs::Offline(args) => args.rest_client(),
            CommandArgs::Online(args) => args.rest_client(),
        }
    }

    fn chain_id(&self) -> ChainId {
        match self {
            CommandArgs::OnlineRemote(args) => args.chain_id(),
            CommandArgs::Offline(args) => args.chain_id(),
            CommandArgs::Online(args) => args.chain_id(),
        }
    }
}

#[derive(Debug, Parser)]
pub struct OfflineArgs {
    /// Listen address for the server. e.g. 0.0.0.0:8082
    #[clap(long, default_value = "0.0.0.0:8082")]
    listen_address: SocketAddr,
    /// Path to TLS cert for HTTPS support
    #[clap(long)]
    tls_cert_path: Option<String>,
    /// Path to TLS key for HTTPS support
    #[clap(long)]
    tls_key_path: Option<String>,
    /// Limit to content length on all requests
    #[clap(long)]
    content_length_limit: Option<u64>,
    /// ChainId to be used for the server e.g. TESTNET
    #[clap(long, default_value = "TESTING")]
    chain_id: ChainId,
}

impl ServerArgs for OfflineArgs {
    fn api_config(&self) -> ApiConfig {
        ApiConfig {
            enabled: true,
            address: self.listen_address,
            tls_cert_path: self.tls_cert_path.clone(),
            tls_key_path: self.tls_key_path.clone(),
            content_length_limit: self.content_length_limit,
        }
    }

    fn rest_client(&self) -> Option<aptos_rest_client::Client> {
        None
    }

    fn chain_id(&self) -> ChainId {
        self.chain_id
    }
}

#[derive(Debug, Parser)]
pub struct OnlineRemoteArgs {
    #[clap(flatten)]
    offline_args: OfflineArgs,
    /// URL for the Aptos REST API. e.g. https://fullnode.devnet.aptoslabs.com
    #[clap(long, default_value = "http://localhost:8080")]
    rest_api_url: url::Url,
}

impl ServerArgs for OnlineRemoteArgs {
    fn api_config(&self) -> ApiConfig {
        self.offline_args.api_config()
    }

    fn rest_client(&self) -> Option<aptos_rest_client::Client> {
        Some(aptos_rest_client::Client::new(self.rest_api_url.clone()))
    }

    fn chain_id(&self) -> ChainId {
        self.offline_args.chain_id
    }
}

#[derive(Debug, Parser)]
pub struct OnlineLocalArgs {
    #[clap(flatten)]
    online_args: OnlineRemoteArgs,
    #[clap(flatten)]
    node_args: AptosNodeArgs,
}

impl ServerArgs for OnlineLocalArgs {
    fn api_config(&self) -> ApiConfig {
        self.online_args.offline_args.api_config()
    }

    fn rest_client(&self) -> Option<aptos_rest_client::Client> {
        Some(aptos_rest_client::Client::new(
            self.online_args.rest_api_url.clone(),
        ))
    }

    fn chain_id(&self) -> ChainId {
        self.online_args.offline_args.chain_id
    }
}
<commit_msg>[aptos-rosetta] Add output messages when running server<commit_after>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

#![forbid(unsafe_code)]

use aptos_config::config::ApiConfig;
use aptos_node::AptosNodeArgs;
use aptos_rosetta::bootstrap;
use aptos_types::chain_id::ChainId;
use clap::Parser;
use std::{
    net::SocketAddr,
    sync::{
        atomic::{AtomicBool, Ordering},
        Arc,
    },
    thread,
    time::Duration,
};
use tokio::time::Instant;

const REST_API_WAIT_DURATION_MS: u64 = 100;
const TOTAL_REST_API_WAIT_DURATION_S: u64 = 60;

#[tokio::main]
async fn main() {
    let args: CommandArgs = CommandArgs::parse();

    match args {
        CommandArgs::OnlineRemote(_) => {
            println!("aptos-rosetta: Starting Rosetta in Online remote (no local full node) mode")
        }
        CommandArgs::Online(_) => {
            println!("aptos-rosetta: Starting Rosetta in Online (with local full node) mode")
        }
        CommandArgs::Offline(_) => println!("aptos-rosetta: Starting Rosetta in Offline mode"),
    }

    // If we're in online mode, we run a full node side by side, the fullnode sets up the logger
    let _maybe_node = if let CommandArgs::Online(OnlineLocalArgs {
        ref node_args,
        ref online_args,
    }) = args
    {
        println!("aptos-rosetta: Starting local full node");
        let node_args = node_args.clone();
        let runtime = thread::spawn(move || node_args.run());

        // Wait and ensure the node is running on the URL
        let client = aptos_rest_client::Client::new(online_args.rest_api_url.clone());
        let mut successful = false;
        let total_wait_duration = Duration::from_secs(TOTAL_REST_API_WAIT_DURATION_S);
        let start = Instant::now();
        while start.elapsed() < total_wait_duration {
            if client.get_index().await.is_ok() {
                successful = true;
                break;
            }

            tokio::time::sleep(Duration::from_millis(REST_API_WAIT_DURATION_MS)).await;
        }

        // If it didn't start up, we need to crash
        if !successful {
            panic!(
                "aptos-rosetta: Local full node didn't start up on time after {} seconds at {}",
                TOTAL_REST_API_WAIT_DURATION_S, online_args.rest_api_url
            )
        }

        println!("aptos-rosetta: Local full node started successfully");
        Some(runtime)
    } else {
        // If we aren't running a full node, set up the logger now
        aptos_logger::Logger::new().init();
        None
    };

    println!("aptos-rosetta: Starting rosetta");
    // Ensure runtime for Rosetta is up and running
    let _rosetta = bootstrap(args.chain_id(), args.api_config(), args.rest_client())
        .expect("aptos-rosetta: Should bootstrap rosetta server");

    println!("aptos-rosetta: Rosetta started");
    // Run until there is an interrupt
    let term = Arc::new(AtomicBool::new(false));
    while !term.load(Ordering::Acquire) {
        std::thread::park();
    }
}

/// A trait to provide common values from both online and offline mode
trait ServerArgs {
    /// Retrieve the API config for the local server
    fn api_config(&self) -> ApiConfig;

    /// Retrieve the optional rest client for the local server
    fn rest_client(&self) -> Option<aptos_rest_client::Client>;

    /// Retrieve the chain id
    fn chain_id(&self) -> ChainId;
}

/// Aptos Rosetta API Server
///
/// Provides an implementation of [Rosetta](https://www.rosetta-api.org/docs/Reference.html) on Aptos.
#[derive(Debug, Parser)]
#[clap(name = "aptos-rosetta", author, version, propagate_version = true)]
pub enum CommandArgs {
    /// Run a local online server that connects to a fullnode endpoint
    OnlineRemote(OnlineRemoteArgs),
    /// Run a local full node in tandem with Rosetta
    Online(OnlineLocalArgs),
    /// Run a local online server that doesn't connect to a fullnode endpoint
    Offline(OfflineArgs),
}

impl ServerArgs for CommandArgs {
    fn api_config(&self) -> ApiConfig {
        match self {
            CommandArgs::OnlineRemote(args) => args.api_config(),
            CommandArgs::Offline(args) => args.api_config(),
            CommandArgs::Online(args) => args.api_config(),
        }
    }

    fn rest_client(&self) -> Option<aptos_rest_client::Client> {
        match self {
            CommandArgs::OnlineRemote(args) => args.rest_client(),
            CommandArgs::Offline(args) => args.rest_client(),
            CommandArgs::Online(args) => args.rest_client(),
        }
    }

    fn chain_id(&self) -> ChainId {
        match self {
            CommandArgs::OnlineRemote(args) => args.chain_id(),
            CommandArgs::Offline(args) => args.chain_id(),
            CommandArgs::Online(args) => args.chain_id(),
        }
    }
}

#[derive(Debug, Parser)]
pub struct OfflineArgs {
    /// Listen address for the server. e.g. 0.0.0.0:8082
    #[clap(long, default_value = "0.0.0.0:8082")]
    listen_address: SocketAddr,
    /// Path to TLS cert for HTTPS support
    #[clap(long)]
    tls_cert_path: Option<String>,
    /// Path to TLS key for HTTPS support
    #[clap(long)]
    tls_key_path: Option<String>,
    /// Limit to content length on all requests
    #[clap(long)]
    content_length_limit: Option<u64>,
    /// ChainId to be used for the server e.g. TESTNET
    #[clap(long, default_value = "TESTING")]
    chain_id: ChainId,
}

impl ServerArgs for OfflineArgs {
    fn api_config(&self) -> ApiConfig {
        ApiConfig {
            enabled: true,
            address: self.listen_address,
            tls_cert_path: self.tls_cert_path.clone(),
            tls_key_path: self.tls_key_path.clone(),
            content_length_limit: self.content_length_limit,
        }
    }

    fn rest_client(&self) -> Option<aptos_rest_client::Client> {
        None
    }

    fn chain_id(&self) -> ChainId {
        self.chain_id
    }
}

#[derive(Debug, Parser)]
pub struct OnlineRemoteArgs {
    #[clap(flatten)]
    offline_args: OfflineArgs,
    /// URL for the Aptos REST API. e.g. https://fullnode.devnet.aptoslabs.com
    #[clap(long, default_value = "http://localhost:8080")]
    rest_api_url: url::Url,
}

impl ServerArgs for OnlineRemoteArgs {
    fn api_config(&self) -> ApiConfig {
        self.offline_args.api_config()
    }

    fn rest_client(&self) -> Option<aptos_rest_client::Client> {
        Some(aptos_rest_client::Client::new(self.rest_api_url.clone()))
    }

    fn chain_id(&self) -> ChainId {
        self.offline_args.chain_id
    }
}

#[derive(Debug, Parser)]
pub struct OnlineLocalArgs {
    #[clap(flatten)]
    online_args: OnlineRemoteArgs,
    #[clap(flatten)]
    node_args: AptosNodeArgs,
}

impl ServerArgs for OnlineLocalArgs {
    fn api_config(&self) -> ApiConfig {
        self.online_args.offline_args.api_config()
    }

    fn rest_client(&self) -> Option<aptos_rest_client::Client> {
        Some(aptos_rest_client::Client::new(
            self.online_args.rest_api_url.clone(),
        ))
    }

    fn chain_id(&self) -> ChainId {
        self.online_args.offline_args.chain_id
    }
}
<|endoftext|>


<commit_before>use super::{db::Password, *};
use godcoin::prelude::*;
use reqwest::Client;
use std::{
    io::{Cursor, Read},
    time::{SystemTime, UNIX_EPOCH},
};

#[macro_use]
pub mod util;

pub mod account;

pub fn create_wallet(wallet: &mut Wallet, args: &mut Vec<String>) -> Result<bool, String> {
    let state = wallet.db.state();
    if state != DbState::New {
        if state == DbState::Locked {
            println!("Use unlock to use the existing wallet");
            return Ok(false);
        } else if state == DbState::Unlocked {
            println!("Existing wallet already unlocked");
            return Ok(false);
        } else {
            return Err(format!("Unknown state: {:?}", state));
        }
    }

    check_args!(args, 1);
    let pass = &Password(args.remove(1).into_bytes());
    wallet.db.set_password(pass);
    wallet.prompt = "locked>> ".to_owned();
    Ok(false)
}

pub fn unlock(wallet: &mut Wallet, args: &mut Vec<String>) -> Result<bool, String> {
    let state = wallet.db.state();
    if state != DbState::Locked {
        if state == DbState::New {
            println!("A wallet has not yet been created, use new to create one");
            return Ok(false);
        } else if state == DbState::Unlocked {
            println!("Wallet already unlocked");
            return Ok(false);
        }
        return Err(format!("Unknown state: {:?}", state));
    }

    check_args!(args, 1);
    let pass = &Password(args.remove(1).into_bytes());
    if wallet.db.unlock(pass) {
        wallet.prompt = "unlocked>> ".to_owned();
    } else {
        println!("Failed to unlock wallet...incorrect password");
    }
    Ok(false)
}

pub fn build_script(_wallet: &mut Wallet, args: &mut Vec<String>) -> Result<bool, String> {
    let script = script_builder::build(&args[1..]);
    match script {
        Ok(script) => {
            println!("{:?}", script);
            println!("{:?}", ScriptHash::from(script));
        }
        Err(e) => {
            println!("{:?}", e);
        }
    }
    Ok(true)
}

pub fn decode_tx(_wallet: &mut Wallet, args: &mut Vec<String>) -> Result<bool, String> {
    check_args!(args, 1);

    let tx_bytes = hex_to_bytes!(args[1])?;
    let cursor = &mut Cursor::<&[u8]>::new(&tx_bytes);
    let tx = TxVariant::decode_with_sigs(cursor).ok_or("Failed to decode tx")?;
    println!("{:#?}", tx);

    Ok(true)
}

pub fn sign_tx(wallet: &mut Wallet, args: &mut Vec<String>) -> Result<bool, String> {
    check_unlocked!(wallet);
    check_args!(args, 2);

    let account = wallet
        .db
        .get_account(&args[1])
        .ok_or("Account does not exist")?;

    let mut tx_bytes = hex_to_bytes!(args[2])?;
    let mut tx = {
        let cursor = &mut Cursor::<&[u8]>::new(&tx_bytes);
        TxVariant::decode_with_sigs(cursor).ok_or("Failed to decode tx")?
    };

    match &mut tx {
        TxVariant::OwnerTx(tx) => tx.append_sign(&account),
        TxVariant::MintTx(tx) => tx.append_sign(&account),
        TxVariant::RewardTx(_) => return Err("Cannot sign reward tx".to_owned()),
        TxVariant::TransferTx(tx) => tx.append_sign(&account),
    }

    tx_bytes.clear();
    tx_bytes.reserve(128);
    tx.encode_with_sigs(&mut tx_bytes);
    println!("{}", faster_hex::hex_string(&tx_bytes).unwrap());

    Ok(true)
}

pub fn unsign_tx(_wallet: &mut Wallet, args: &mut Vec<String>) -> Result<bool, String> {
    check_args!(args, 2);
    let sig_pos: usize = args[1]
        .parse()
        .map_err(|_| "Failed to parse signature position".to_owned())?;

    let mut tx_bytes = hex_to_bytes!(args[2])?;
    let mut tx = {
        let cursor = &mut Cursor::<&[u8]>::new(&tx_bytes);
        TxVariant::decode_with_sigs(cursor).ok_or("Failed to decode tx")?
    };

    if sig_pos < tx.signature_pairs.len() {
        tx.signature_pairs.remove(sig_pos);
    }

    tx_bytes.clear();
    tx.encode_with_sigs(&mut tx_bytes);
    println!("{}", faster_hex::hex_string(&tx_bytes).unwrap());

    Ok(true)
}

pub fn broadcast(wallet: &mut Wallet, args: &mut Vec<String>) -> Result<bool, String> {
    check_args!(args, 1);
    let tx_bytes = hex_to_bytes!(args[1])?;
    let tx = {
        let cursor = &mut Cursor::<&[u8]>::new(&tx_bytes);
        TxVariant::decode_with_sigs(cursor).ok_or("Failed to decode tx")?
    };

    send_print_rpc_req!(wallet, net::MsgRequest::Broadcast(tx));
    Ok(true)
}

pub fn build_mint_tx(wallet: &mut Wallet, args: &mut Vec<String>) -> Result<bool, String> {
    check_args!(args, 4);
    let timestamp: u64 = {
        let ts: u64 = args[1]
            .parse()
            .map_err(|_| "Failed to parse timestamp offset".to_owned())?;
        ts + SystemTime::now()
            .duration_since(UNIX_EPOCH)
            .unwrap()
            .as_millis() as u64
    };

    let amount = {
        let gold: Asset = args[2].parse().map_err(|_| "Failed to parse gold asset")?;
        let silver: Asset = args[3]
            .parse()
            .map_err(|_| "Failed to parse silver asset")?;
        if gold.symbol != AssetSymbol::GOLD {
            return Err("Expected gold asset".to_owned());
        } else if silver.symbol != AssetSymbol::SILVER {
            return Err("Expected silver asset".to_owned());
        }
        Balance::from(gold, silver).unwrap()
    };

    let script: Script = hex_to_bytes!(args[4])?.into();

    let res = send_rpc_req!(wallet, MsgRequest::GetProperties)?;
    let owner = match res {
        MsgResponse::GetProperties(props) => props,
        _ => return Err("wallet not unlocked".to_owned()),
    }
    .owner;

    let mint_tx = TxVariant::MintTx(MintTx {
        base: Tx {
            tx_type: TxType::MINT,
            timestamp,
            signature_pairs: vec![],
            fee: "0 GOLD".parse().unwrap(),
        },
        to: owner.wallet,
        amount,
        script,
    });
    let mut buf = Vec::with_capacity(4096);
    mint_tx.encode_with_sigs(&mut buf);
    println!("{}", faster_hex::hex_string(&buf).unwrap());

    Ok(true)
}

pub fn get_properties(wallet: &mut Wallet, _args: &mut Vec<String>) -> Result<bool, String> {
    send_print_rpc_req!(wallet, MsgRequest::GetProperties);
    Ok(true)
}

pub fn get_block(wallet: &mut Wallet, args: &mut Vec<String>) -> Result<bool, String> {
    check_args!(args, 1);
    let height: u64 = args[1]
        .parse()
        .map_err(|_| "Failed to parse height argument".to_owned())?;

    send_print_rpc_req!(wallet, MsgRequest::GetBlock(height));
    Ok(true)
}
<commit_msg>Print P2SH address rather than the digest in the build_script command<commit_after>use super::{db::Password, *};
use godcoin::prelude::*;
use reqwest::Client;
use std::{
    io::{Cursor, Read},
    time::{SystemTime, UNIX_EPOCH},
};

#[macro_use]
pub mod util;

pub mod account;

pub fn create_wallet(wallet: &mut Wallet, args: &mut Vec<String>) -> Result<bool, String> {
    let state = wallet.db.state();
    if state != DbState::New {
        if state == DbState::Locked {
            println!("Use unlock to use the existing wallet");
            return Ok(false);
        } else if state == DbState::Unlocked {
            println!("Existing wallet already unlocked");
            return Ok(false);
        } else {
            return Err(format!("Unknown state: {:?}", state));
        }
    }

    check_args!(args, 1);
    let pass = &Password(args.remove(1).into_bytes());
    wallet.db.set_password(pass);
    wallet.prompt = "locked>> ".to_owned();
    Ok(false)
}

pub fn unlock(wallet: &mut Wallet, args: &mut Vec<String>) -> Result<bool, String> {
    let state = wallet.db.state();
    if state != DbState::Locked {
        if state == DbState::New {
            println!("A wallet has not yet been created, use new to create one");
            return Ok(false);
        } else if state == DbState::Unlocked {
            println!("Wallet already unlocked");
            return Ok(false);
        }
        return Err(format!("Unknown state: {:?}", state));
    }

    check_args!(args, 1);
    let pass = &Password(args.remove(1).into_bytes());
    if wallet.db.unlock(pass) {
        wallet.prompt = "unlocked>> ".to_owned();
    } else {
        println!("Failed to unlock wallet...incorrect password");
    }
    Ok(false)
}

pub fn build_script(_wallet: &mut Wallet, args: &mut Vec<String>) -> Result<bool, String> {
    let script = script_builder::build(&args[1..]);
    match script {
        Ok(script) => {
            println!("{:?}", script);
            println!("P2SH Address => {}", ScriptHash::from(script).to_wif());
        }
        Err(e) => {
            println!("{:?}", e);
        }
    }
    Ok(true)
}

pub fn decode_tx(_wallet: &mut Wallet, args: &mut Vec<String>) -> Result<bool, String> {
    check_args!(args, 1);

    let tx_bytes = hex_to_bytes!(args[1])?;
    let cursor = &mut Cursor::<&[u8]>::new(&tx_bytes);
    let tx = TxVariant::decode_with_sigs(cursor).ok_or("Failed to decode tx")?;
    println!("{:#?}", tx);

    Ok(true)
}

pub fn sign_tx(wallet: &mut Wallet, args: &mut Vec<String>) -> Result<bool, String> {
    check_unlocked!(wallet);
    check_args!(args, 2);

    let account = wallet
        .db
        .get_account(&args[1])
        .ok_or("Account does not exist")?;

    let mut tx_bytes = hex_to_bytes!(args[2])?;
    let mut tx = {
        let cursor = &mut Cursor::<&[u8]>::new(&tx_bytes);
        TxVariant::decode_with_sigs(cursor).ok_or("Failed to decode tx")?
    };

    match &mut tx {
        TxVariant::OwnerTx(tx) => tx.append_sign(&account),
        TxVariant::MintTx(tx) => tx.append_sign(&account),
        TxVariant::RewardTx(_) => return Err("Cannot sign reward tx".to_owned()),
        TxVariant::TransferTx(tx) => tx.append_sign(&account),
    }

    tx_bytes.clear();
    tx_bytes.reserve(128);
    tx.encode_with_sigs(&mut tx_bytes);
    println!("{}", faster_hex::hex_string(&tx_bytes).unwrap());

    Ok(true)
}

pub fn unsign_tx(_wallet: &mut Wallet, args: &mut Vec<String>) -> Result<bool, String> {
    check_args!(args, 2);
    let sig_pos: usize = args[1]
        .parse()
        .map_err(|_| "Failed to parse signature position".to_owned())?;

    let mut tx_bytes = hex_to_bytes!(args[2])?;
    let mut tx = {
        let cursor = &mut Cursor::<&[u8]>::new(&tx_bytes);
        TxVariant::decode_with_sigs(cursor).ok_or("Failed to decode tx")?
    };

    if sig_pos < tx.signature_pairs.len() {
        tx.signature_pairs.remove(sig_pos);
    }

    tx_bytes.clear();
    tx.encode_with_sigs(&mut tx_bytes);
    println!("{}", faster_hex::hex_string(&tx_bytes).unwrap());

    Ok(true)
}

pub fn broadcast(wallet: &mut Wallet, args: &mut Vec<String>) -> Result<bool, String> {
    check_args!(args, 1);
    let tx_bytes = hex_to_bytes!(args[1])?;
    let tx = {
        let cursor = &mut Cursor::<&[u8]>::new(&tx_bytes);
        TxVariant::decode_with_sigs(cursor).ok_or("Failed to decode tx")?
    };

    send_print_rpc_req!(wallet, net::MsgRequest::Broadcast(tx));
    Ok(true)
}

pub fn build_mint_tx(wallet: &mut Wallet, args: &mut Vec<String>) -> Result<bool, String> {
    check_args!(args, 4);
    let timestamp: u64 = {
        let ts: u64 = args[1]
            .parse()
            .map_err(|_| "Failed to parse timestamp offset".to_owned())?;
        ts + SystemTime::now()
            .duration_since(UNIX_EPOCH)
            .unwrap()
            .as_millis() as u64
    };

    let amount = {
        let gold: Asset = args[2].parse().map_err(|_| "Failed to parse gold asset")?;
        let silver: Asset = args[3]
            .parse()
            .map_err(|_| "Failed to parse silver asset")?;
        if gold.symbol != AssetSymbol::GOLD {
            return Err("Expected gold asset".to_owned());
        } else if silver.symbol != AssetSymbol::SILVER {
            return Err("Expected silver asset".to_owned());
        }
        Balance::from(gold, silver).unwrap()
    };

    let script: Script = hex_to_bytes!(args[4])?.into();

    let res = send_rpc_req!(wallet, MsgRequest::GetProperties)?;
    let owner = match res {
        MsgResponse::GetProperties(props) => props,
        _ => return Err("wallet not unlocked".to_owned()),
    }
    .owner;

    let mint_tx = TxVariant::MintTx(MintTx {
        base: Tx {
            tx_type: TxType::MINT,
            timestamp,
            signature_pairs: vec![],
            fee: "0 GOLD".parse().unwrap(),
        },
        to: owner.wallet,
        amount,
        script,
    });
    let mut buf = Vec::with_capacity(4096);
    mint_tx.encode_with_sigs(&mut buf);
    println!("{}", faster_hex::hex_string(&buf).unwrap());

    Ok(true)
}

pub fn get_properties(wallet: &mut Wallet, _args: &mut Vec<String>) -> Result<bool, String> {
    send_print_rpc_req!(wallet, MsgRequest::GetProperties);
    Ok(true)
}

pub fn get_block(wallet: &mut Wallet, args: &mut Vec<String>) -> Result<bool, String> {
    check_args!(args, 1);
    let height: u64 = args[1]
        .parse()
        .map_err(|_| "Failed to parse height argument".to_owned())?;

    send_print_rpc_req!(wallet, MsgRequest::GetBlock(height));
    Ok(true)
}
<|endoftext|>


<commit_before>//! ARM C Language Extensions (ACLE)
//!
//! # Developer notes
//!
//! Below is a list of built-in targets that are representative of the different ARM
//! architectures; the list includes the `target_feature`s they possess.
//!
//! - `armv4t-unknown-linux-gnueabi` - **ARMv4** - `+v4t`
//! - `armv5te-unknown-linux-gnueabi` - **ARMv5TE** - `+v4t +v5te`
//! - `arm-unknown-linux-gnueabi` - **ARMv6** - `+v4t +v5te +v6`
//! - `thumbv6m-none-eabi` - **ARMv6-M** - `+v4t +v5te +v6 +thumb-mode +mclass`
//! - `armv7-unknown-linux-gnueabihf` - **ARMv7-A** - `+v4t +v5te +v6 +v6k +v6t2 +v7 +dsp +thumb2 +aclass`
//! - `armv7r-none-eabi` - **ARMv7-R** - `+v4t +v5te +v6 +v6k +v6t2  +v7 +dsp +thumb2 +rclass`
//! - `thumbv7m-none-eabi` - **ARMv7-M** - `+v4t +v5te +v6 +v6k +v6t2 +v7 +thumb2 +thumb-mode +mclass`
//! - `thumbv7em-none-eabi` - **ARMv7E-M** - `+v4t +v5te +v6 +v6k +v6t2 +v7 +dsp +thumb2 +thumb-mode +mclass`
//! - `aarch64-unknown-linux-gnu` - **ARMv8-A (AArch64)** - `+fp +neon`
//!
//! Section 10.1 of ACLE says:
//!
//! - "In the sequence of Arm architectures { v5, v5TE, v6, v6T2, v7 } each architecture includes
//! its predecessor instruction set."
//!
//! - "In the sequence of Thumb-only architectures { v6-M, v7-M, v7E-M } each architecture includes
//! its predecessor instruction set."
//!
//! From that info and from looking at how LLVM features work (using custom targets) we can identify
//! features that are subsets of others:
//!
//! Legend: `a < b` reads as "`a` is a subset of `b`"; this means that if `b` is enabled then `a` is
//! enabled as well.
//!
//! - `v4t < v5te < v6 < v6k < v6t2 < v7 < v8`
//! - `v6 < v8m < v6t2`
//! - `v7 < v8m.main`
//!
//! # References
//!
//! - [ACLE Q2 2018](https://developer.arm.com/docs/101028/latest)

// 8, 7 and 6-M are supported via dedicated instructions like DMB. All other arches are supported
// via CP15 instructions. See Section 10.1 of ACLE
mod barrier;

#[cfg(any(
    target_arch = "aarch64",
    target_feature = "v7",
    target_feature = "mclass"
))]
pub use self::barrier::*;

mod hints;

pub use self::hints::*;

mod registers;

pub use self::registers::*;

// Supported arches: 5TE, 7E-M. See Section 10.1 of ACLE (e.g. QADD)
// We also include the A profile even though DSP is deprecated on that profile as of ACLE 2.0 (see
// section 5.4.7)
#[cfg(any(
    // >= v5TE but excludes v7-A
    all(target_feature = "v5te", not(target_feature = "mclass")),
    // v7E-M
    all(target_feature = "mclass", target_feature = "dsp"),
))]
mod dsp;

#[cfg(any(
    all(target_feature = "v5te", not(target_feature = "mclass")),
    all(target_feature = "mclass", target_feature = "dsp"),
))]
pub use self::dsp::*;

// Deprecated in ACLE 2.0 for the A profile but fully supported on the M and R profiles, says
// Section 5.4.9 of ACLE. We'll expose these for the A profile even if deprecated
#[cfg(any(
    // v7-A, v7-R
    all(target_feature = "v6", not(target_feature = "mclass")),
    // v7E-M
    all(target_feature = "mclass", target_feature = "dsp")
))]
mod simd32;

#[cfg(any(
    all(target_feature = "v6", not(target_feature = "mclass")),
    all(target_feature = "mclass", target_feature = "dsp")
))]
pub use self::simd32::*;

mod sealed {
    pub trait Dmb {
        unsafe fn __dmb(&self);
    }

    pub trait Dsb {
        unsafe fn __dsb(&self);
    }

    pub trait Isb {
        unsafe fn __isb(&self);
    }

    pub trait Rsr {
        unsafe fn __rsr(&self) -> u32;
    }

    pub trait Rsr64 {
        unsafe fn __rsr64(&self) -> u64;
    }

    pub trait Rsrp {
        unsafe fn __rsrp(&self) -> *const u8;
    }

    pub trait Wsr {
        unsafe fn __wsr(&self, value: u32);
    }

    pub trait Wsr64 {
        unsafe fn __wsr64(&self, value: u64);
    }

    pub trait Wsrp {
        unsafe fn __wsrp(&self, value: *const u8);
    }
}
<commit_msg>acle/{simd32,dsp}: not available on aarch64<commit_after>//! ARM C Language Extensions (ACLE)
//!
//! # Developer notes
//!
//! Below is a list of built-in targets that are representative of the different ARM
//! architectures; the list includes the `target_feature`s they possess.
//!
//! - `armv4t-unknown-linux-gnueabi` - **ARMv4** - `+v4t`
//! - `armv5te-unknown-linux-gnueabi` - **ARMv5TE** - `+v4t +v5te`
//! - `arm-unknown-linux-gnueabi` - **ARMv6** - `+v4t +v5te +v6`
//! - `thumbv6m-none-eabi` - **ARMv6-M** - `+v4t +v5te +v6 +thumb-mode +mclass`
//! - `armv7-unknown-linux-gnueabihf` - **ARMv7-A** - `+v4t +v5te +v6 +v6k +v6t2 +v7 +dsp +thumb2 +aclass`
//! - `armv7r-none-eabi` - **ARMv7-R** - `+v4t +v5te +v6 +v6k +v6t2  +v7 +dsp +thumb2 +rclass`
//! - `thumbv7m-none-eabi` - **ARMv7-M** - `+v4t +v5te +v6 +v6k +v6t2 +v7 +thumb2 +thumb-mode +mclass`
//! - `thumbv7em-none-eabi` - **ARMv7E-M** - `+v4t +v5te +v6 +v6k +v6t2 +v7 +dsp +thumb2 +thumb-mode +mclass`
//! - `aarch64-unknown-linux-gnu` - **ARMv8-A (AArch64)** - `+fp +neon`
//!
//! Section 10.1 of ACLE says:
//!
//! - "In the sequence of Arm architectures { v5, v5TE, v6, v6T2, v7 } each architecture includes
//! its predecessor instruction set."
//!
//! - "In the sequence of Thumb-only architectures { v6-M, v7-M, v7E-M } each architecture includes
//! its predecessor instruction set."
//!
//! From that info and from looking at how LLVM features work (using custom targets) we can identify
//! features that are subsets of others:
//!
//! Legend: `a < b` reads as "`a` is a subset of `b`"; this means that if `b` is enabled then `a` is
//! enabled as well.
//!
//! - `v4t < v5te < v6 < v6k < v6t2 < v7 < v8`
//! - `v6 < v8m < v6t2`
//! - `v7 < v8m.main`
//!
//! # References
//!
//! - [ACLE Q2 2018](https://developer.arm.com/docs/101028/latest)

// 8, 7 and 6-M are supported via dedicated instructions like DMB. All other arches are supported
// via CP15 instructions. See Section 10.1 of ACLE
mod barrier;

#[cfg(any(
    target_arch = "aarch64",
    target_feature = "v7",
    target_feature = "mclass"
))]
pub use self::barrier::*;

mod hints;

pub use self::hints::*;

mod registers;

pub use self::registers::*;

// Supported arches: 5TE, 7E-M. See Section 10.1 of ACLE (e.g. QADD)
// We also include the A profile even though DSP is deprecated on that profile as of ACLE 2.0 (see
// section 5.4.7)
#[cfg(all(
    not(target_arch = "aarch64"),
    any(
        // >= v5TE but excludes v7-A
        all(target_feature = "v5te", not(target_feature = "mclass")),
        // v7E-M
        all(target_feature = "mclass", target_feature = "dsp"),
    )
))]
mod dsp;

#[cfg(all(
    not(target_arch = "aarch64"),
    any(
        all(target_feature = "v5te", not(target_feature = "mclass")),
        all(target_feature = "mclass", target_feature = "dsp"),
    )
))]
pub use self::dsp::*;

// Deprecated in ACLE 2.0 for the A profile but fully supported on the M and R profiles, says
// Section 5.4.9 of ACLE. We'll expose these for the A profile even if deprecated
#[cfg(all(
    not(target_arch = "aarch64"),
    any(
        // v7-A, v7-R
        all(target_feature = "v6", not(target_feature = "mclass")),
        // v7E-M
        all(target_feature = "mclass", target_feature = "dsp")
    )
))]
mod simd32;

#[cfg(all(
    not(target_arch = "aarch64"),
    any(
        all(target_feature = "v6", not(target_feature = "mclass")),
        all(target_feature = "mclass", target_feature = "dsp")
    )
))]
pub use self::simd32::*;

mod sealed {
    pub trait Dmb {
        unsafe fn __dmb(&self);
    }

    pub trait Dsb {
        unsafe fn __dsb(&self);
    }

    pub trait Isb {
        unsafe fn __isb(&self);
    }

    pub trait Rsr {
        unsafe fn __rsr(&self) -> u32;
    }

    pub trait Rsr64 {
        unsafe fn __rsr64(&self) -> u64;
    }

    pub trait Rsrp {
        unsafe fn __rsrp(&self) -> *const u8;
    }

    pub trait Wsr {
        unsafe fn __wsr(&self, value: u32);
    }

    pub trait Wsr64 {
        unsafe fn __wsr64(&self, value: u64);
    }

    pub trait Wsrp {
        unsafe fn __wsrp(&self, value: *const u8);
    }
}
<|endoftext|>