<commit_before>use std::collections::BTreeMap;
use rustc_serialize::json::{Json, ToJson};
pub use optional::Optional;
pub use sensors::{SensorTemplate, Sensors};
pub use sensors::{TemperatureSensor, PeopleNowPresentSensor};

#[derive(Debug, Clone)]
pub struct Location {
    pub address: Optional<String>,
    pub lat: f64,
    pub lon: f64,
}

#[derive(Debug, Clone)]
pub struct Spacefed {
    pub spacenet: bool,
    pub spacesaml: bool,
    pub spacephone: bool,
}

#[derive(Debug, Clone)]
pub struct Icon {
    pub open: String,
    pub close: String,
}

#[derive(Debug, Clone)]
pub struct State {
    pub open: Option<bool>,
    pub lastchange: Optional<u64>,
    pub trigger_person: Optional<String>,
    pub message: Optional<String>,
    pub icon: Optional<Icon>,
}

#[derive(Debug, Clone)]
pub struct Event {
    pub name: String,
    pub _type: String,
    pub timestamp: u64,
    pub extra: Optional<String>,
}

#[derive(Debug, Clone)]
pub struct Contact {
    pub irc: Optional<String>,
    pub twitter: Optional<String>,
    pub foursquare: Optional<String>,
    pub email: Optional<String>,
}

#[derive(Debug, Clone)]
pub struct Feed {
    pub _type: Optional<String>,
    pub url: String,
}

#[derive(Debug, Clone)]
pub struct Feeds {
    pub blog: Optional<Feed>,
    pub wiki: Optional<Feed>,
    pub calendar: Optional<Feed>,
    pub flickr: Optional<Feed>,
}

#[derive(Debug, Clone)]
pub struct Cache {
    pub schedule: String,
}

#[derive(Debug, Clone)]
pub struct RadioShow {
    pub name: String,
    pub url: String,
    pub _type: String,
    pub start: String,
    pub end: String,
}

/// The main Space API status object.
#[derive(Debug, Clone)]
pub struct Status {

    // Hackerspace properties
    pub api: String,
    pub space: String,
    pub logo: String,
    pub url: String,
    pub location: Location,
    pub contact: Contact,

    // Hackerspace features / projects
    pub spacefed: Optional<Spacefed>,
    pub projects: Optional<Vec<String>>,
    pub cam: Optional<Vec<String>>,
    pub feeds: Optional<Feeds>,
    pub events: Optional<Vec<Event>>,
    pub radio_show: Optional<Vec<RadioShow>>,

    // SpaceAPI internal usage
    pub cache: Optional<Cache>,
    pub issue_report_channels: Vec<String>,

    // Mutable data
    pub state: State,
    pub sensors: Optional<Sensors>,
}

impl Status {

    /// Create a new Status object with only the minimum amount of fields.
    pub fn new(space: String, logo: String, url: String, location: Location, contact: Contact, issue_report_channels: Vec<String>) -> Status {
        Status {
            api: "0.13".to_string(),
            space: space,
            logo: logo,
            url: url,
            location: location,
            contact: contact,

            spacefed: Optional::Absent,
            projects: Optional::Absent,
            cam: Optional::Absent,
            feeds: Optional::Absent,
            events: Optional::Absent,
            radio_show: Optional::Absent,

            cache: Optional::Absent,
            issue_report_channels: issue_report_channels,

            state: State {
                open: None,
                lastchange: Optional::Absent,
                trigger_person: Optional::Absent,
                message: Optional::Absent,
                icon: Optional::Absent,
            },
            sensors: Optional::Absent,
        }
    }

}

impl ToJson for Status {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();

        d.insert("api".to_string(), self.api.to_json());
        d.insert("space".to_string(), self.space.to_json());
        d.insert("logo".to_string(), self.logo.to_json());
        d.insert("url".to_string(), self.url.to_json());
        d.insert("location".to_string(), self.location.to_json());
        d.insert("contact".to_string(), self.contact.to_json());

        self.spacefed.as_ref().map_or((), |v| { d.insert("spacefed".to_string(), v.to_json()); } );
        self.projects.as_ref().map_or((), |v| { d.insert("projects".to_string(), v.to_json()); });
        self.cam.as_ref().map_or((), |v| { d.insert("cam".to_string(), v.to_json()); });
        self.feeds.as_ref().map_or((), |v| { d.insert("feeds".to_string(), v.to_json()); });
        self.events.as_ref().map_or((), |v| { d.insert("events".to_string(), v.to_json()); });
        self.radio_show.as_ref().map_or((), |v| { d.insert("radio_show".to_string(), v.to_json()); });

        self.cache.as_ref().map_or((), |v| { d.insert("cache".to_string(), v.to_json()); });
        d.insert("issue_report_channels".to_string(), self.issue_report_channels.to_json());

        d.insert("state".to_string(), self.state.to_json());
        self.sensors.as_ref().map_or((), |v| { d.insert("sensors".to_string(), v.to_json()); });

        Json::Object(d)
    }
}

impl ToJson for Location {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("lat".to_string(), self.lat.to_json());
        d.insert("lon".to_string(), self.lon.to_json());
        match self.address {
            Optional::Value(ref address) => {
                d.insert("address".to_string(), address.to_json());
            },
            Optional::Absent => (),
        };
        Json::Object(d)
    }
}

impl ToJson for Spacefed {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("spacenet".to_string(), self.spacenet.to_json());
        d.insert("spacesaml".to_string(), self.spacesaml.to_json());
        d.insert("spacephone".to_string(), self.spacephone.to_json());
        Json::Object(d)
    }
}

impl ToJson for Icon {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("open".to_string(), self.open.to_json());
        d.insert("close".to_string(), self.close.to_json());
        Json::Object(d)
    }
}

impl ToJson for State {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("open".to_string(), self.open.to_json());
        self.lastchange.as_ref().map_or((), |v| { d.insert("lastchange".to_string(), v.to_json()); });
        self.trigger_person.as_ref().map_or((), |v| { d.insert("trigger_person".to_string(), v.to_json()); });
        self.message.as_ref().map_or((), |v| { d.insert("message".to_string(), v.to_json()); });
        self.icon.as_ref().map_or((), |v| { d.insert("icon".to_string(), v.to_json()); });
        Json::Object(d)
    }
}

impl ToJson for Event {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("name".to_string(), self.name.to_json());
        d.insert("type".to_string(), self._type.to_json());
        d.insert("timestamp".to_string(), self.timestamp.to_json());
        self.extra.as_ref().map_or((), |v| { d.insert("extra".to_string(), v.to_json()); });
        Json::Object(d)
    }
}

impl ToJson for Contact {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        self.irc.as_ref().map_or((), |v| { d.insert("irc".to_string(), v.to_json()); });
        self.twitter.as_ref().map_or((), |v| { d.insert("twitter".to_string(), v.to_json()); });
        self.foursquare.as_ref().map_or((), |v| { d.insert("foursquare".to_string(), v.to_json()); });
        self.email.as_ref().map_or((), |v| { d.insert("email".to_string(), v.to_json()); });
        Json::Object(d)
    }
}

impl ToJson for Feed {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("url".to_string(), self.url.to_json());
        self._type.as_ref().map_or((), |v| { d.insert("type".to_string(), v.to_json()); });
        Json::Object(d)
    }
}

impl ToJson for Feeds {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        self.blog.as_ref().map_or((), |v| { d.insert("blog".to_string(), v.to_json()); });
        self.wiki.as_ref().map_or((), |v| { d.insert("wiki".to_string(), v.to_json()); });
        self.calendar.as_ref().map_or((), |v| { d.insert("calendar".to_string(), v.to_json()); });
        self.flickr.as_ref().map_or((), |v| { d.insert("flickr".to_string(), v.to_json()); });
        Json::Object(d)
    }
}

impl ToJson for Cache {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("schedule".to_string(), self.schedule.to_json());
        Json::Object(d)
    }
}

impl ToJson for RadioShow {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("name".to_string(), self.name.to_json());
        d.insert("url".to_string(), self.url.to_json());
        d.insert("type".to_string(), self._type.to_json());
        d.insert("start".to_string(), self.start.to_json()); d.insert("end".to_string(), self.end.to_json());
        Json::Object(d)
    }
}
<commit_msg>api: Use a static reference for the api string<commit_after>use std::collections::BTreeMap;
use rustc_serialize::json::{Json, ToJson};
pub use optional::Optional;
pub use sensors::{SensorTemplate, Sensors};
pub use sensors::{TemperatureSensor, PeopleNowPresentSensor};

#[derive(Debug, Clone)]
pub struct Location {
    pub address: Optional<String>,
    pub lat: f64,
    pub lon: f64,
}

#[derive(Debug, Clone)]
pub struct Spacefed {
    pub spacenet: bool,
    pub spacesaml: bool,
    pub spacephone: bool,
}

#[derive(Debug, Clone)]
pub struct Icon {
    pub open: String,
    pub close: String,
}

#[derive(Debug, Clone)]
pub struct State {
    pub open: Option<bool>,
    pub lastchange: Optional<u64>,
    pub trigger_person: Optional<String>,
    pub message: Optional<String>,
    pub icon: Optional<Icon>,
}

#[derive(Debug, Clone)]
pub struct Event {
    pub name: String,
    pub _type: String,
    pub timestamp: u64,
    pub extra: Optional<String>,
}

#[derive(Debug, Clone)]
pub struct Contact {
    pub irc: Optional<String>,
    pub twitter: Optional<String>,
    pub foursquare: Optional<String>,
    pub email: Optional<String>,
}

#[derive(Debug, Clone)]
pub struct Feed {
    pub _type: Optional<String>,
    pub url: String,
}

#[derive(Debug, Clone)]
pub struct Feeds {
    pub blog: Optional<Feed>,
    pub wiki: Optional<Feed>,
    pub calendar: Optional<Feed>,
    pub flickr: Optional<Feed>,
}

#[derive(Debug, Clone)]
pub struct Cache {
    pub schedule: String,
}

#[derive(Debug, Clone)]
pub struct RadioShow {
    pub name: String,
    pub url: String,
    pub _type: String,
    pub start: String,
    pub end: String,
}

/// The main Space API status object.
#[derive(Debug, Clone)]
pub struct Status {

    // Hackerspace properties
    pub api: &'static str,
    pub space: String,
    pub logo: String,
    pub url: String,
    pub location: Location,
    pub contact: Contact,

    // Hackerspace features / projects
    pub spacefed: Optional<Spacefed>,
    pub projects: Optional<Vec<String>>,
    pub cam: Optional<Vec<String>>,
    pub feeds: Optional<Feeds>,
    pub events: Optional<Vec<Event>>,
    pub radio_show: Optional<Vec<RadioShow>>,

    // SpaceAPI internal usage
    pub cache: Optional<Cache>,
    pub issue_report_channels: Vec<String>,

    // Mutable data
    pub state: State,
    pub sensors: Optional<Sensors>,
}

impl Status {

    /// Create a new Status object with only the minimum amount of fields.
    pub fn new(space: String, logo: String, url: String, location: Location, contact: Contact, issue_report_channels: Vec<String>) -> Status {
        Status {
            api: "0.13",
            space: space,
            logo: logo,
            url: url,
            location: location,
            contact: contact,

            spacefed: Optional::Absent,
            projects: Optional::Absent,
            cam: Optional::Absent,
            feeds: Optional::Absent,
            events: Optional::Absent,
            radio_show: Optional::Absent,

            cache: Optional::Absent,
            issue_report_channels: issue_report_channels,

            state: State {
                open: None,
                lastchange: Optional::Absent,
                trigger_person: Optional::Absent,
                message: Optional::Absent,
                icon: Optional::Absent,
            },
            sensors: Optional::Absent,
        }
    }

}

impl ToJson for Status {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();

        d.insert("api".to_string(), self.api.to_json());
        d.insert("space".to_string(), self.space.to_json());
        d.insert("logo".to_string(), self.logo.to_json());
        d.insert("url".to_string(), self.url.to_json());
        d.insert("location".to_string(), self.location.to_json());
        d.insert("contact".to_string(), self.contact.to_json());

        self.spacefed.as_ref().map_or((), |v| { d.insert("spacefed".to_string(), v.to_json()); } );
        self.projects.as_ref().map_or((), |v| { d.insert("projects".to_string(), v.to_json()); });
        self.cam.as_ref().map_or((), |v| { d.insert("cam".to_string(), v.to_json()); });
        self.feeds.as_ref().map_or((), |v| { d.insert("feeds".to_string(), v.to_json()); });
        self.events.as_ref().map_or((), |v| { d.insert("events".to_string(), v.to_json()); });
        self.radio_show.as_ref().map_or((), |v| { d.insert("radio_show".to_string(), v.to_json()); });

        self.cache.as_ref().map_or((), |v| { d.insert("cache".to_string(), v.to_json()); });
        d.insert("issue_report_channels".to_string(), self.issue_report_channels.to_json());

        d.insert("state".to_string(), self.state.to_json());
        self.sensors.as_ref().map_or((), |v| { d.insert("sensors".to_string(), v.to_json()); });

        Json::Object(d)
    }
}

impl ToJson for Location {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("lat".to_string(), self.lat.to_json());
        d.insert("lon".to_string(), self.lon.to_json());
        match self.address {
            Optional::Value(ref address) => {
                d.insert("address".to_string(), address.to_json());
            },
            Optional::Absent => (),
        };
        Json::Object(d)
    }
}

impl ToJson for Spacefed {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("spacenet".to_string(), self.spacenet.to_json());
        d.insert("spacesaml".to_string(), self.spacesaml.to_json());
        d.insert("spacephone".to_string(), self.spacephone.to_json());
        Json::Object(d)
    }
}

impl ToJson for Icon {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("open".to_string(), self.open.to_json());
        d.insert("close".to_string(), self.close.to_json());
        Json::Object(d)
    }
}

impl ToJson for State {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("open".to_string(), self.open.to_json());
        self.lastchange.as_ref().map_or((), |v| { d.insert("lastchange".to_string(), v.to_json()); });
        self.trigger_person.as_ref().map_or((), |v| { d.insert("trigger_person".to_string(), v.to_json()); });
        self.message.as_ref().map_or((), |v| { d.insert("message".to_string(), v.to_json()); });
        self.icon.as_ref().map_or((), |v| { d.insert("icon".to_string(), v.to_json()); });
        Json::Object(d)
    }
}

impl ToJson for Event {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("name".to_string(), self.name.to_json());
        d.insert("type".to_string(), self._type.to_json());
        d.insert("timestamp".to_string(), self.timestamp.to_json());
        self.extra.as_ref().map_or((), |v| { d.insert("extra".to_string(), v.to_json()); });
        Json::Object(d)
    }
}

impl ToJson for Contact {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        self.irc.as_ref().map_or((), |v| { d.insert("irc".to_string(), v.to_json()); });
        self.twitter.as_ref().map_or((), |v| { d.insert("twitter".to_string(), v.to_json()); });
        self.foursquare.as_ref().map_or((), |v| { d.insert("foursquare".to_string(), v.to_json()); });
        self.email.as_ref().map_or((), |v| { d.insert("email".to_string(), v.to_json()); });
        Json::Object(d)
    }
}

impl ToJson for Feed {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("url".to_string(), self.url.to_json());
        self._type.as_ref().map_or((), |v| { d.insert("type".to_string(), v.to_json()); });
        Json::Object(d)
    }
}

impl ToJson for Feeds {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        self.blog.as_ref().map_or((), |v| { d.insert("blog".to_string(), v.to_json()); });
        self.wiki.as_ref().map_or((), |v| { d.insert("wiki".to_string(), v.to_json()); });
        self.calendar.as_ref().map_or((), |v| { d.insert("calendar".to_string(), v.to_json()); });
        self.flickr.as_ref().map_or((), |v| { d.insert("flickr".to_string(), v.to_json()); });
        Json::Object(d)
    }
}

impl ToJson for Cache {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("schedule".to_string(), self.schedule.to_json());
        Json::Object(d)
    }
}

impl ToJson for RadioShow {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("name".to_string(), self.name.to_json());
        d.insert("url".to_string(), self.url.to_json());
        d.insert("type".to_string(), self._type.to_json());
        d.insert("start".to_string(), self.start.to_json()); d.insert("end".to_string(), self.end.to_json());
        Json::Object(d)
    }
}
<|endoftext|>


<commit_before>use chrono::{offset::Utc, DateTime};
use diesel::{self, pg::PgConnection};
use uuid::Uuid;

use crate::{
    generate_urls::GenerateUrls,
    schema::base_actors,
    sql_types::{FollowPolicy, Url},
    user::UserLike,
};

pub mod follow_request;
pub mod follower;
pub mod group;
pub mod persona;

use self::follower::Follower;

#[derive(Debug, AsChangeset)]
#[table_name = "base_actors"]
pub struct ModifiedBaseActor {
    id: i32,
    display_name: String,
    profile_url: Url,
    inbox_url: Url,
    outbox_url: Url,
    follow_policy: FollowPolicy,
    private_key_der: Option<Vec<u8>>,
    public_key_der: Vec<u8>,
}

impl ModifiedBaseActor {
    pub fn set_display_name(&mut self, display_name: String) {
        self.display_name = display_name;
    }

    pub fn set_profile_url<U: Into<Url>>(&mut self, profile_url: U) {
        self.profile_url = profile_url.into();
    }

    pub fn set_inbox_url<U: Into<Url>>(&mut self, inbox_url: U) {
        self.inbox_url = inbox_url.into();
    }

    pub fn set_outbox_url<U: Into<Url>>(&mut self, outbox_url: U) {
        self.outbox_url = outbox_url.into();
    }

    pub fn set_follow_policy(&mut self, follow_policy: FollowPolicy) {
        self.follow_policy = follow_policy;
    }

    pub fn save_changes(self, conn: &PgConnection) -> Result<BaseActor, diesel::result::Error> {
        use diesel::prelude::*;

        diesel::update(base_actors::table)
            .set(&self)
            .get_result(conn)
    }
}

#[derive(Clone, Debug, Queryable, QueryableByName)]
#[table_name = "base_actors"]
pub struct BaseActor {
    id: i32,
    display_name: String,        // max_length: 80
    profile_url: Url,            // max_length: 2048
    inbox_url: Url,              // max_length: 2048
    outbox_url: Url,             // max_length: 2048
    local_user: Option<i32>,     // foreign key to User
    follow_policy: FollowPolicy, // max_length: 8
    created_at: DateTime<Utc>,
    updated_at: DateTime<Utc>,
    private_key_der: Option<Vec<u8>>,
    public_key_der: Vec<u8>,
    local_uuid: Option<Uuid>,
    activitypub_id: String,
}

impl BaseActor {
    pub fn id(&self) -> i32 {
        self.id
    }

    pub fn modify(self) -> ModifiedBaseActor {
        ModifiedBaseActor {
            id: self.id,
            display_name: self.display_name,
            profile_url: self.profile_url,
            inbox_url: self.inbox_url,
            outbox_url: self.outbox_url,
            follow_policy: self.follow_policy,
            private_key_der: self.private_key_der,
            public_key_der: self.public_key_der,
        }
    }

    pub fn is_following(
        &self,
        follows: &BaseActor,
        conn: &PgConnection,
    ) -> Result<bool, diesel::result::Error> {
        self.is_following_id(follows.id, conn)
    }

    pub fn is_following_id(
        &self,
        follows: i32,
        conn: &PgConnection,
    ) -> Result<bool, diesel::result::Error> {
        use crate::schema::followers;
        use diesel::prelude::*;

        followers::table
            .filter(followers::dsl::follower.eq(self.id))
            .filter(followers::dsl::follows.eq(follows))
            .get_result(conn)
            .map(|_: Follower| true)
            .or_else(|e| match e {
                diesel::result::Error::NotFound => Ok(false),
                e => Err(e),
            })
    }

    pub fn display_name(&self) -> &str {
        &self.display_name
    }

    pub fn profile_url(&self) -> &Url {
        &self.profile_url
    }

    pub fn inbox_url(&self) -> &Url {
        &self.inbox_url
    }

    pub fn outbox_url(&self) -> &Url {
        &self.outbox_url
    }

    pub fn local_user(&self) -> Option<i32> {
        self.local_user
    }

    pub fn follow_policy(&self) -> FollowPolicy {
        self.follow_policy
    }
}

#[derive(Insertable)]
#[table_name = "base_actors"]
pub struct NewBaseActor {
    display_name: String,
    profile_url: Url,
    inbox_url: Url,
    outbox_url: Url,
    local_user: Option<i32>,
    follow_policy: FollowPolicy,
    private_key_der: Option<Vec<u8>>,
    public_key_der: Vec<u8>,
    local_uuid: Option<Uuid>,
    activitypub_id: String,
}

impl NewBaseActor {
    pub fn insert(self, conn: &PgConnection) -> Result<BaseActor, diesel::result::Error> {
        use diesel::prelude::*;

        diesel::insert_into(base_actors::table)
            .values(&self)
            .get_result(conn)
    }

    pub fn local<U: UserLike>(
        display_name: String,
        local_user: &U,
        follow_policy: FollowPolicy,
        private_key_der: Vec<u8>,
        public_key_der: Vec<u8>,
        generate_urls: impl GenerateUrls,
    ) -> Self {
        let uuid = Uuid::new_v4();

        NewBaseActor {
            display_name,
            profile_url: generate_urls.profile_url(&uuid),
            inbox_url: generate_urls.inbox_url(&uuid),
            outbox_url: generate_urls.outbox_url(&uuid),
            local_user: Some(local_user.id()),
            follow_policy,
            private_key_der: Some(private_key_der),
            public_key_der,
            activitypub_id: generate_urls.activitypub_id(&uuid),
            local_uuid: Some(uuid),
        }
    }

    pub fn new(
        display_name: String,
        profile_url: Url,
        inbox_url: Url,
        outbox_url: Url,
        follow_policy: FollowPolicy,
        public_key_der: Vec<u8>,
        activitypub_id: String,
    ) -> Self {
        NewBaseActor {
            display_name,
            profile_url,
            inbox_url,
            outbox_url,
            local_user: None,
            follow_policy,
            private_key_der: None,
            public_key_der,
            local_uuid: None,
            activitypub_id,
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::test_helper::*;

    #[test]
    fn create_base_actor() {
        with_connection(|conn| with_base_actor(conn, |_| Ok(())))
    }
}
<commit_msg>Look up base actor by persona<commit_after>use chrono::{offset::Utc, DateTime};
use diesel::{self, pg::PgConnection};
use uuid::Uuid;

use crate::{
    generate_urls::GenerateUrls,
    schema::base_actors,
    sql_types::{FollowPolicy, Url},
    user::UserLike,
};

pub mod follow_request;
pub mod follower;
pub mod group;
pub mod persona;

use self::follower::Follower;

#[derive(Debug, AsChangeset)]
#[table_name = "base_actors"]
pub struct ModifiedBaseActor {
    id: i32,
    display_name: String,
    profile_url: Url,
    inbox_url: Url,
    outbox_url: Url,
    follow_policy: FollowPolicy,
    private_key_der: Option<Vec<u8>>,
    public_key_der: Vec<u8>,
}

impl ModifiedBaseActor {
    pub fn set_display_name(&mut self, display_name: String) {
        self.display_name = display_name;
    }

    pub fn set_profile_url<U: Into<Url>>(&mut self, profile_url: U) {
        self.profile_url = profile_url.into();
    }

    pub fn set_inbox_url<U: Into<Url>>(&mut self, inbox_url: U) {
        self.inbox_url = inbox_url.into();
    }

    pub fn set_outbox_url<U: Into<Url>>(&mut self, outbox_url: U) {
        self.outbox_url = outbox_url.into();
    }

    pub fn set_follow_policy(&mut self, follow_policy: FollowPolicy) {
        self.follow_policy = follow_policy;
    }

    pub fn save_changes(self, conn: &PgConnection) -> Result<BaseActor, diesel::result::Error> {
        use diesel::prelude::*;

        diesel::update(base_actors::table)
            .set(&self)
            .get_result(conn)
    }
}

#[derive(Clone, Debug, Queryable, QueryableByName)]
#[table_name = "base_actors"]
pub struct BaseActor {
    id: i32,
    display_name: String,        // max_length: 80
    profile_url: Url,            // max_length: 2048
    inbox_url: Url,              // max_length: 2048
    outbox_url: Url,             // max_length: 2048
    local_user: Option<i32>,     // foreign key to User
    follow_policy: FollowPolicy, // max_length: 8
    created_at: DateTime<Utc>,
    updated_at: DateTime<Utc>,
    private_key_der: Option<Vec<u8>>,
    public_key_der: Vec<u8>,
    local_uuid: Option<Uuid>,
    activitypub_id: String,
}

impl BaseActor {
    pub fn id(&self) -> i32 {
        self.id
    }

    pub fn modify(self) -> ModifiedBaseActor {
        ModifiedBaseActor {
            id: self.id,
            display_name: self.display_name,
            profile_url: self.profile_url,
            inbox_url: self.inbox_url,
            outbox_url: self.outbox_url,
            follow_policy: self.follow_policy,
            private_key_der: self.private_key_der,
            public_key_der: self.public_key_der,
        }
    }

    pub fn by_persona_id(
        persona_id: i32,
        conn: &PgConnection,
    ) -> Result<Self, diesel::result::Error> {
        use crate::schema::personas;
        use diesel::prelude::*;

        base_actors::table
            .inner_join(personas::table.on(base_actors::dsl::id.eq(personas::dsl::base_actor)))
            .filter(personas::dsl::id.eq(persona_id))
            .select((
                base_actors::dsl::id,
                base_actors::dsl::display_name,
                base_actors::dsl::profile_url,
                base_actors::dsl::inbox_url,
                base_actors::dsl::outbox_url,
                base_actors::dsl::local_user,
                base_actors::dsl::follow_policy,
                base_actors::dsl::created_at,
                base_actors::dsl::updated_at,
                base_actors::dsl::private_key_der,
                base_actors::dsl::public_key_der,
                base_actors::dsl::local_uuid,
                base_actors::dsl::activitypub_id,
            ))
            .get_result(conn)
    }

    pub fn is_following(
        &self,
        follows: &BaseActor,
        conn: &PgConnection,
    ) -> Result<bool, diesel::result::Error> {
        self.is_following_id(follows.id, conn)
    }

    pub fn is_following_id(
        &self,
        follows: i32,
        conn: &PgConnection,
    ) -> Result<bool, diesel::result::Error> {
        use crate::schema::followers;
        use diesel::prelude::*;

        followers::table
            .filter(followers::dsl::follower.eq(self.id))
            .filter(followers::dsl::follows.eq(follows))
            .get_result(conn)
            .map(|_: Follower| true)
            .or_else(|e| match e {
                diesel::result::Error::NotFound => Ok(false),
                e => Err(e),
            })
    }

    pub fn display_name(&self) -> &str {
        &self.display_name
    }

    pub fn profile_url(&self) -> &Url {
        &self.profile_url
    }

    pub fn inbox_url(&self) -> &Url {
        &self.inbox_url
    }

    pub fn outbox_url(&self) -> &Url {
        &self.outbox_url
    }

    pub fn local_user(&self) -> Option<i32> {
        self.local_user
    }

    pub fn follow_policy(&self) -> FollowPolicy {
        self.follow_policy
    }
}

#[derive(Insertable)]
#[table_name = "base_actors"]
pub struct NewBaseActor {
    display_name: String,
    profile_url: Url,
    inbox_url: Url,
    outbox_url: Url,
    local_user: Option<i32>,
    follow_policy: FollowPolicy,
    private_key_der: Option<Vec<u8>>,
    public_key_der: Vec<u8>,
    local_uuid: Option<Uuid>,
    activitypub_id: String,
}

impl NewBaseActor {
    pub fn insert(self, conn: &PgConnection) -> Result<BaseActor, diesel::result::Error> {
        use diesel::prelude::*;

        diesel::insert_into(base_actors::table)
            .values(&self)
            .get_result(conn)
    }

    pub fn local<U: UserLike>(
        display_name: String,
        local_user: &U,
        follow_policy: FollowPolicy,
        private_key_der: Vec<u8>,
        public_key_der: Vec<u8>,
        generate_urls: impl GenerateUrls,
    ) -> Self {
        let uuid = Uuid::new_v4();

        NewBaseActor {
            display_name,
            profile_url: generate_urls.profile_url(&uuid),
            inbox_url: generate_urls.inbox_url(&uuid),
            outbox_url: generate_urls.outbox_url(&uuid),
            local_user: Some(local_user.id()),
            follow_policy,
            private_key_der: Some(private_key_der),
            public_key_der,
            activitypub_id: generate_urls.activitypub_id(&uuid),
            local_uuid: Some(uuid),
        }
    }

    pub fn new(
        display_name: String,
        profile_url: Url,
        inbox_url: Url,
        outbox_url: Url,
        follow_policy: FollowPolicy,
        public_key_der: Vec<u8>,
        activitypub_id: String,
    ) -> Self {
        NewBaseActor {
            display_name,
            profile_url,
            inbox_url,
            outbox_url,
            local_user: None,
            follow_policy,
            private_key_der: None,
            public_key_der,
            local_uuid: None,
            activitypub_id,
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::test_helper::*;

    #[test]
    fn create_base_actor() {
        with_connection(|conn| with_base_actor(conn, |_| Ok(())))
    }
}
<|endoftext|>


<commit_before>//! Error types that represent migration errors.
//! These are split into multiple segments, depending on
//! where in the migration process an error occurs.

use std::convert::From;
use std::error::Error;
use std::path::PathBuf;
use std::{fmt, io};

use diesel::migration::MigrationVersion;

use crate::file_based_migrations::DieselMigrationName;

/// Errors that occur while preparing to run migrations
#[derive(Debug)]
#[non_exhaustive]
pub enum MigrationError {
    /// The migration directory wasn't found
    MigrationDirectoryNotFound(PathBuf),
    /// Provided migration was in an unknown format
    UnknownMigrationFormat(PathBuf),
    /// General system IO error
    IoError(io::Error),
    /// Provided migration had an incompatible version number
    UnknownMigrationVersion(MigrationVersion<'static>),
    /// No migrations had to be/ could be run
    NoMigrationRun,
}

impl Error for MigrationError {}

impl fmt::Display for MigrationError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            MigrationError::MigrationDirectoryNotFound(ref p) => write!(
                f,
                "Unable to find migrations directory in {:?} or any parent directories.",
                p
            ),
            MigrationError::UnknownMigrationFormat(_) => write!(
                f,
                "Invalid migration directory, the directory's name should be \
                 <timestamp>_<name_of_migration>, and it should only contain up.sql and down.sql."
            ),
            MigrationError::IoError(ref error) => write!(f, "{}", error),
            MigrationError::UnknownMigrationVersion(_) => write!(
                f,
                "Unable to find migration version to revert in the migrations directory."
            ),
            MigrationError::NoMigrationRun => write!(
                f,
                "No migrations have been run. Did you forget `diesel migration run`?"
            ),
        }
    }
}

impl PartialEq for MigrationError {
    fn eq(&self, other: &Self) -> bool {
        match (self, other) {
            (
                &MigrationError::MigrationDirectoryNotFound(_),
                &MigrationError::MigrationDirectoryNotFound(_),
            ) => true,
            (
                &MigrationError::UnknownMigrationFormat(ref p1),
                &MigrationError::UnknownMigrationFormat(ref p2),
            ) => p1 == p2,
            _ => false,
        }
    }
}

impl From<io::Error> for MigrationError {
    fn from(e: io::Error) -> Self {
        MigrationError::IoError(e)
    }
}

/// Errors that occur while running migrations
#[derive(Debug, PartialEq)]
#[allow(clippy::enum_variant_names)]
#[non_exhaustive]
pub enum RunMigrationsError {
    /// A general migration error occured
    MigrationError(DieselMigrationName, MigrationError),
    /// The provided migration included an invalid query
    QueryError(DieselMigrationName, diesel::result::Error),
    /// The provided migration was empty
    EmptyMigration(DieselMigrationName),
}

impl Error for RunMigrationsError {}

impl fmt::Display for RunMigrationsError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match self {
            RunMigrationsError::MigrationError(v, err) => {
                write!(f, "Failed to run {} with: {}", v, err)
            }
            RunMigrationsError::QueryError(v, err) => {
                write!(f, "Failed to run {} with: {}", v, err)
            }
            RunMigrationsError::EmptyMigration(v) => write!(
                f,
                "Failed to run {} with: Attempted to run an empty migration.",
                v
            ),
        }
    }
}
<commit_msg>Clarify a bit the error message 'Unable to find migration version'<commit_after>//! Error types that represent migration errors.
//! These are split into multiple segments, depending on
//! where in the migration process an error occurs.

use std::convert::From;
use std::error::Error;
use std::path::PathBuf;
use std::{fmt, io};

use diesel::migration::MigrationVersion;

use crate::file_based_migrations::DieselMigrationName;

/// Errors that occur while preparing to run migrations
#[derive(Debug)]
#[non_exhaustive]
pub enum MigrationError {
    /// The migration directory wasn't found
    MigrationDirectoryNotFound(PathBuf),
    /// Provided migration was in an unknown format
    UnknownMigrationFormat(PathBuf),
    /// General system IO error
    IoError(io::Error),
    /// Provided migration had an incompatible version number
    UnknownMigrationVersion(MigrationVersion<'static>),
    /// No migrations had to be/ could be run
    NoMigrationRun,
}

impl Error for MigrationError {}

impl fmt::Display for MigrationError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            MigrationError::MigrationDirectoryNotFound(ref p) => write!(
                f,
                "Unable to find migrations directory in {:?} or any parent directories.",
                p
            ),
            MigrationError::UnknownMigrationFormat(_) => write!(
                f,
                "Invalid migration directory, the directory's name should be \
                 <timestamp>_<name_of_migration>, and it should only contain up.sql and down.sql."
            ),
            MigrationError::IoError(ref error) => write!(f, "{}", error),
            MigrationError::UnknownMigrationVersion(ref version) => write!(
                f,
                "Unable to find migration version {} to revert in the migrations directory.",
                version
            ),
            MigrationError::NoMigrationRun => write!(
                f,
                "No migrations have been run. Did you forget `diesel migration run`?"
            ),
        }
    }
}

impl PartialEq for MigrationError {
    fn eq(&self, other: &Self) -> bool {
        match (self, other) {
            (
                &MigrationError::MigrationDirectoryNotFound(_),
                &MigrationError::MigrationDirectoryNotFound(_),
            ) => true,
            (
                &MigrationError::UnknownMigrationFormat(ref p1),
                &MigrationError::UnknownMigrationFormat(ref p2),
            ) => p1 == p2,
            _ => false,
        }
    }
}

impl From<io::Error> for MigrationError {
    fn from(e: io::Error) -> Self {
        MigrationError::IoError(e)
    }
}

/// Errors that occur while running migrations
#[derive(Debug, PartialEq)]
#[allow(clippy::enum_variant_names)]
#[non_exhaustive]
pub enum RunMigrationsError {
    /// A general migration error occured
    MigrationError(DieselMigrationName, MigrationError),
    /// The provided migration included an invalid query
    QueryError(DieselMigrationName, diesel::result::Error),
    /// The provided migration was empty
    EmptyMigration(DieselMigrationName),
}

impl Error for RunMigrationsError {}

impl fmt::Display for RunMigrationsError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match self {
            RunMigrationsError::MigrationError(v, err) => {
                write!(f, "Failed to run {} with: {}", v, err)
            }
            RunMigrationsError::QueryError(v, err) => {
                write!(f, "Failed to run {} with: {}", v, err)
            }
            RunMigrationsError::EmptyMigration(v) => write!(
                f,
                "Failed to run {} with: Attempted to run an empty migration.",
                v
            ),
        }
    }
}
<|endoftext|>


<commit_before>#![feature(test)]

extern crate test;
extern crate rust_decimal;
extern crate decimal;
use decimal::d128;
use rust_decimal::Decimal;
use std::str::FromStr;
use test::Bencher;

macro_rules! bench_bin_op {
    ($name:ident, $ty:ident, $op:tt) => {
        #[bench]
        fn $name(b: &mut Bencher) {
            b.iter(|| {

                let y = $ty::from_str("2").unwrap();
                for _ in 0..100 {
                    let mut x = y;
                    for _ in 0..50 {
                        x $op y;
                    }
                    test::black_box(x);
                }
            });
        }

    }
}

bench_bin_op!(bench_decimal_add, Decimal, +=);
bench_bin_op!(bench_d128_add, d128, +=);

bench_bin_op!(bench_decimal_sub, Decimal, -=);
bench_bin_op!(bench_d128_sub, d128, -=);

bench_bin_op!(bench_decimal_mul, Decimal, *=);
bench_bin_op!(bench_d128_mul, d128, *=);

bench_bin_op!(bench_decimal_div, Decimal, /=);
bench_bin_op!(bench_d128_div, d128, /=);

#[bench]
fn bench_rescale(b: &mut Bencher) {
    b.iter(|| {

        let mut x = Decimal::from_str("2").unwrap();
        for _ in 0..100 {
            for dp in 0..25 {
                x.bench_rescale(dp);
            }
        }
    });
}
<commit_msg>Remove benchmark test<commit_after>#![feature(test)]

extern crate test;
extern crate rust_decimal;
extern crate decimal;
use decimal::d128;
use rust_decimal::Decimal;
use std::str::FromStr;
use test::Bencher;

macro_rules! bench_bin_op {
    ($name:ident, $ty:ident, $op:tt) => {
        #[bench]
        fn $name(b: &mut Bencher) {
            b.iter(|| {

                let y = $ty::from_str("2").unwrap();
                for _ in 0..100 {
                    let mut x = y;
                    for _ in 0..50 {
                        x $op y;
                    }
                    test::black_box(x);
                }
            });
        }

    }
}

bench_bin_op!(bench_decimal_add, Decimal, +=);
bench_bin_op!(bench_d128_add, d128, +=);

bench_bin_op!(bench_decimal_sub, Decimal, -=);
bench_bin_op!(bench_d128_sub, d128, -=);

bench_bin_op!(bench_decimal_mul, Decimal, *=);
bench_bin_op!(bench_d128_mul, d128, *=);

bench_bin_op!(bench_decimal_div, Decimal, /=);
bench_bin_op!(bench_d128_div, d128, /=);
<|endoftext|>


<commit_before>// Functionality that is shared between the cxx_build::bridge entry point and
// the cxxbridge CLI command.

mod builtin;
mod check;
pub(super) mod error;
mod file;
pub(super) mod fs;
mod ifndef;
pub(super) mod include;
mod namespace_organizer;
pub(super) mod out;
mod write;

pub(super) use self::error::Error;
use self::error::{format_err, Result};
use self::file::File;
use self::include::Include;
use crate::syntax::report::Errors;
use crate::syntax::{self, Types};
use std::path::Path;

/// Options for C++ code generation.
///
/// We expect options to be added over time, so this is a non-exhaustive struct.
/// To instantiate one you need to crate a default value and mutate those fields
/// that you want to modify.
///
/// ```
/// # use cxx_gen::Opt;
/// #
/// let impl_annotations = r#"__attribute__((visibility("default")))"#.to_owned();
///
/// let mut opt = Opt::default();
/// opt.cxx_impl_annotations = Some(impl_annotations);
/// ```
#[non_exhaustive]
pub struct Opt {
    /// Any additional headers to #include. The cxxbridge tool does not parse or
    /// even require the given paths to exist; they simply go into the generated
    /// C++ code as #include lines.
    pub include: Vec<Include>,
    /// Optional annotation for implementations of C++ function wrappers that
    /// may be exposed to Rust. You may for example need to provide
    /// `__declspec(dllexport)` or `__attribute__((visibility("default")))` if
    /// Rust code from one shared object or executable depends on these C++
    /// functions in another.
    pub cxx_impl_annotations: Option<String>,

    pub(super) gen_header: bool,
    pub(super) gen_implementation: bool,
    pub(super) allow_dot_includes: bool,
}

/// Results of code generation.
#[derive(Default)]
pub struct GeneratedCode {
    /// The bytes of a C++ header file.
    pub header: Vec<u8>,
    /// The bytes of a C++ implementation file (e.g. .cc, cpp etc.)
    pub implementation: Vec<u8>,
}

impl Default for Opt {
    fn default() -> Self {
        Opt {
            include: Vec::new(),
            cxx_impl_annotations: None,
            gen_header: true,
            gen_implementation: true,
            allow_dot_includes: true,
        }
    }
}

pub(super) fn generate_from_path(path: &Path, opt: &Opt) -> GeneratedCode {
    let source = match read_to_string(path) {
        Ok(source) => source,
        Err(err) => format_err(path, "", err),
    };
    match generate_from_string(&source, opt) {
        Ok(out) => out,
        Err(err) => format_err(path, &source, err),
    }
}

fn read_to_string(path: &Path) -> Result<String> {
    let bytes = if path == Path::new("-") {
        fs::read_stdin()
    } else {
        fs::read(path)
    }?;
    match String::from_utf8(bytes) {
        Ok(string) => Ok(string),
        Err(err) => Err(Error::Utf8(path.to_owned(), err.utf8_error())),
    }
}

fn generate_from_string(source: &str, opt: &Opt) -> Result<GeneratedCode> {
    let mut source = source;
    if source.starts_with("#!") && !source.starts_with("#![") {
        let shebang_end = source.find('\n').unwrap_or(source.len());
        source = &source[shebang_end..];
    }
    let syntax: File = syn::parse_str(source)?;
    generate(syntax, opt)
}

pub(super) fn generate(syntax: File, opt: &Opt) -> Result<GeneratedCode> {
    proc_macro2::fallback::force();
    let ref mut errors = Errors::new();
    let bridge = syntax
        .modules
        .into_iter()
        .next()
        .ok_or(Error::NoBridgeMod)?;
    let ref namespace = bridge.namespace;
    let trusted = bridge.unsafety.is_some();
    let ref apis = syntax::parse_items(errors, bridge.content, trusted, namespace);
    let ref types = Types::collect(errors, apis);
    check::precheck(errors, apis, opt);
    errors.propagate()?;
    check::typecheck(errors, apis, types);
    errors.propagate()?;
    // Some callers may wish to generate both header and C++
    // from the same token stream to avoid parsing twice. But others
    // only need to generate one or the other.
    Ok(GeneratedCode {
        header: if opt.gen_header {
            write::gen(apis, types, opt, true).content()
        } else {
            Vec::new()
        },
        implementation: if opt.gen_implementation {
            write::gen(apis, types, opt, false).content()
        } else {
            Vec::new()
        },
    })
}
<commit_msg>Move proc-macro2 fallback to before starting to parse<commit_after>// Functionality that is shared between the cxx_build::bridge entry point and
// the cxxbridge CLI command.

mod builtin;
mod check;
pub(super) mod error;
mod file;
pub(super) mod fs;
mod ifndef;
pub(super) mod include;
mod namespace_organizer;
pub(super) mod out;
mod write;

pub(super) use self::error::Error;
use self::error::{format_err, Result};
use self::file::File;
use self::include::Include;
use crate::syntax::report::Errors;
use crate::syntax::{self, Types};
use std::path::Path;

/// Options for C++ code generation.
///
/// We expect options to be added over time, so this is a non-exhaustive struct.
/// To instantiate one you need to crate a default value and mutate those fields
/// that you want to modify.
///
/// ```
/// # use cxx_gen::Opt;
/// #
/// let impl_annotations = r#"__attribute__((visibility("default")))"#.to_owned();
///
/// let mut opt = Opt::default();
/// opt.cxx_impl_annotations = Some(impl_annotations);
/// ```
#[non_exhaustive]
pub struct Opt {
    /// Any additional headers to #include. The cxxbridge tool does not parse or
    /// even require the given paths to exist; they simply go into the generated
    /// C++ code as #include lines.
    pub include: Vec<Include>,
    /// Optional annotation for implementations of C++ function wrappers that
    /// may be exposed to Rust. You may for example need to provide
    /// `__declspec(dllexport)` or `__attribute__((visibility("default")))` if
    /// Rust code from one shared object or executable depends on these C++
    /// functions in another.
    pub cxx_impl_annotations: Option<String>,

    pub(super) gen_header: bool,
    pub(super) gen_implementation: bool,
    pub(super) allow_dot_includes: bool,
}

/// Results of code generation.
#[derive(Default)]
pub struct GeneratedCode {
    /// The bytes of a C++ header file.
    pub header: Vec<u8>,
    /// The bytes of a C++ implementation file (e.g. .cc, cpp etc.)
    pub implementation: Vec<u8>,
}

impl Default for Opt {
    fn default() -> Self {
        Opt {
            include: Vec::new(),
            cxx_impl_annotations: None,
            gen_header: true,
            gen_implementation: true,
            allow_dot_includes: true,
        }
    }
}

pub(super) fn generate_from_path(path: &Path, opt: &Opt) -> GeneratedCode {
    let source = match read_to_string(path) {
        Ok(source) => source,
        Err(err) => format_err(path, "", err),
    };
    match generate_from_string(&source, opt) {
        Ok(out) => out,
        Err(err) => format_err(path, &source, err),
    }
}

fn read_to_string(path: &Path) -> Result<String> {
    let bytes = if path == Path::new("-") {
        fs::read_stdin()
    } else {
        fs::read(path)
    }?;
    match String::from_utf8(bytes) {
        Ok(string) => Ok(string),
        Err(err) => Err(Error::Utf8(path.to_owned(), err.utf8_error())),
    }
}

fn generate_from_string(source: &str, opt: &Opt) -> Result<GeneratedCode> {
    let mut source = source;
    if source.starts_with("#!") && !source.starts_with("#![") {
        let shebang_end = source.find('\n').unwrap_or(source.len());
        source = &source[shebang_end..];
    }
    proc_macro2::fallback::force();
    let syntax: File = syn::parse_str(source)?;
    generate(syntax, opt)
}

pub(super) fn generate(syntax: File, opt: &Opt) -> Result<GeneratedCode> {
    let ref mut errors = Errors::new();
    let bridge = syntax
        .modules
        .into_iter()
        .next()
        .ok_or(Error::NoBridgeMod)?;
    let ref namespace = bridge.namespace;
    let trusted = bridge.unsafety.is_some();
    let ref apis = syntax::parse_items(errors, bridge.content, trusted, namespace);
    let ref types = Types::collect(errors, apis);
    check::precheck(errors, apis, opt);
    errors.propagate()?;
    check::typecheck(errors, apis, types);
    errors.propagate()?;
    // Some callers may wish to generate both header and C++
    // from the same token stream to avoid parsing twice. But others
    // only need to generate one or the other.
    Ok(GeneratedCode {
        header: if opt.gen_header {
            write::gen(apis, types, opt, true).content()
        } else {
            Vec::new()
        },
        implementation: if opt.gen_implementation {
            write::gen(apis, types, opt, false).content()
        } else {
            Vec::new()
        },
    })
}
<|endoftext|>


<commit_before>//! Tools to define Rust components compatible with the COM protocol.
//!
//! Intercom provides attributes to automatically derive `extern` compatible
//! functions for Rust methods. These functions are compatible with COM binary
//! interface standard, which allows them to be used from any language that
//! supports COM.
//!
//! # Examples
//!
//! A basic example of a calculator type exposed as a COM object.
//!
//! ```
//! use intercom::{com_library, com_class, com_interface, ComResult};
//!
//! // Define COM classes to expose from this library.
//! com_library!(class Calculator);
//!
//! // Define the COM class and the interfaces it implements.
//! #[com_class(Self)]
//! #[derive(Default)]
//! struct Calculator;
//!
//! // Define the implementation for the class. The COM interface is defined
//! // implicitly by the `impl`.
//! #[com_interface]
//! impl Calculator {
//!     fn add(&self, a: i32, b: i32) -> ComResult<i32> { Ok(a + b) }
//!     fn sub(&self, a: i32, b: i32) -> ComResult<i32> { Ok(a - b) }
//! }
//! # // Without 'main()' doctests wraps the whole thing into a function,
//! # // which would end up expanding com_library!(..) into a statement.
//! # // And proc macros into statements are not allowed.
//! # //
//! # // In addition to that, if we just have `fn main()` followed by open
//! # // brace _anywhere_ in this doctest (yes, including these comments),
//! # // clippy would discover that and yell at us for "needless doctest main".
//! # // Allowing that with a specific #[allow(..)] attribute is impossible
//! # // since this is crate-level documentation.
//! # //
//! # // Fortunately we can hide this from clippy by specifying the (empty)
//! # // return type.
//! # fn main() -> () { }
//! ```
//!
//! The above library can be used for example from C# in the following manner.
//!
//! ```csharp
//! void Main()
//! {
//!     var calculator = new CalculatorLib.Calculator();
//!     Console.WriteLine( calculator.Add( 1, 2 ) );
//! }
//! ```

#![crate_type = "dylib"]
#![allow(clippy::match_bool)]

extern crate self as intercom;

#[cfg(not(windows))]
extern crate libc;

extern crate intercom_attributes;
pub use intercom_attributes::*;

#[allow(clippy::useless_attribute)]
#[allow(unused_imports)]
#[macro_use]
extern crate failure;

#[cfg(feature = "log")]
extern crate log;

pub mod prelude;

mod classfactory;
pub use crate::classfactory::*;
mod combox;
pub use crate::combox::*;
mod comrc;
pub use crate::comrc::*;
mod comitf;
pub use crate::comitf::*;
mod strings;
pub use crate::strings::*;
mod guid;
pub use crate::guid::GUID;
pub mod error;
pub use crate::error::{load_error, store_error, ComError, ErrorValue};
pub mod alloc;
pub mod interfaces;
pub mod runtime;
mod variant;
pub use crate::variant::{Variant, VariantError};
pub mod type_system;
pub mod typelib;
pub use type_system::ForeignType;
pub mod attributes;
pub mod logging;

#[cfg(windows)]
pub mod registry;

// No-ops on non-windows platforms.
#[cfg(not(windows))]
pub mod registry
{
    use crate::typelib::TypeLib;
    use crate::raw::HRESULT;

    type HANDLE = *mut std::os::raw::c_void;

    /// Registers a type library.
    pub fn register(_dll: HANDLE, _lib: TypeLib) -> Result<(), HRESULT>
    {
        Ok(())
    }

    /// Unregisters a type library.
    pub fn unregister(_dll: HANDLE, _lib: TypeLib) -> Result<(), HRESULT>
    {
        Ok(())
    }
}

com_module!(
    class intercom::alloc::Allocator,
    class intercom::error::ErrorStore,
);

/// Raw COM pointer type.
/// Interface ID GUID.
pub type IID = GUID;

/// A reference to an interface ID.
pub type REFIID = *const IID;

/// Class ID GUID.
pub type CLSID = GUID;

/// A reference to a class ID.
pub type REFCLSID = *const IID;

pub mod raw
{
    use std::marker::PhantomData;
    use std::os::raw::c_void;
    use std::ptr::NonNull;

    pub use crate::error::raw::*;
    pub use crate::type_system::{ForeignType, TypeSystem};
    pub use crate::variant::raw::*;

    pub type RawComPtr = *mut c_void;

    #[derive(Clone, Copy, intercom_attributes::ExternInput, intercom_attributes::ForeignType)]
    #[repr(transparent)]
    pub struct InBSTR(pub *const u16);

    #[derive(
        Clone,
        Copy,
        intercom_attributes::ExternInput,
        intercom_attributes::ExternOutput,
        intercom_attributes::ForeignType,
    )]
    #[repr(transparent)]
    pub struct OutBSTR(pub *mut u16);

    pub type InCStr = *const std::os::raw::c_char;
    pub type OutCStr = *mut std::os::raw::c_char;

    #[repr(transparent)]
    #[derive(PartialEq, Eq)]
    pub struct InterfacePtr<TS: TypeSystem, I: ?Sized>
    {
        pub ptr: NonNull<c_void>,
        phantom_itf: PhantomData<I>,
        phantom_ts: PhantomData<TS>,
    }

    impl<TS: TypeSystem, I: ?Sized> Clone for InterfacePtr<TS, I>
    {
        fn clone(&self) -> Self
        {
            InterfacePtr {
                ptr: self.ptr,
                phantom_itf: PhantomData,
                phantom_ts: PhantomData,
            }
        }
    }

    impl<TS: TypeSystem, I: ?Sized> Copy for InterfacePtr<TS, I> {}

    impl<TS: TypeSystem, I: ?Sized> std::fmt::Debug for InterfacePtr<TS, I>
    {
        fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result
        {
            write!(f, "InterfacePtr({:?})", self.ptr)
        }
    }

    impl<TS: TypeSystem, I: ?Sized> InterfacePtr<TS, I>
    {
        /// # Safety
        ///
        /// The raw `ptr` must represent the correct type system and interface.
        pub unsafe fn new(ptr: RawComPtr) -> Option<InterfacePtr<TS, I>>
        {
            let ptr = NonNull::new(ptr);
            ptr.map(|ptr| InterfacePtr {
                ptr,
                phantom_itf: PhantomData,
                phantom_ts: PhantomData,
            })
        }
    }

    impl<TS: TypeSystem, I: crate::attributes::ComInterface + ?Sized> InterfacePtr<TS, I>
    {
        pub fn as_unknown(self) -> InterfacePtr<TS, dyn crate::IUnknown>
        {
            InterfacePtr {
                ptr: self.ptr,
                phantom_itf: PhantomData,
                phantom_ts: PhantomData,
            }
        }
    }

    impl<TS: TypeSystem, I: crate::attributes::ComInterface + ?Sized> ForeignType
        for Option<InterfacePtr<TS, I>>
    where
        I: ForeignType,
    {
        /// The name of the type.
        fn type_name() -> &'static str
        {
            <I as ForeignType>::type_name()
        }
        fn indirection_level() -> u32
        {
            <I as ForeignType>::indirection_level() + 1
        }
    }
}

/// `IClassFactory` interface ID.
#[allow(non_upper_case_globals)]
pub const IID_IClassFactory: GUID = GUID {
    data1: 0x0000_0001,
    data2: 0x0000,
    data3: 0x0000,
    data4: [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46],
};

/// `IErrorInfo` interface ID.
#[allow(non_upper_case_globals)]
pub const IID_IErrorInfo: GUID = GUID {
    data1: 0x1CF2_B120,
    data2: 0x547D,
    data3: 0x101B,
    data4: [0x8E, 0x65, 0x08, 0x00, 0x2B, 0x2B, 0xD1, 0x19],
};

pub use crate::interfaces::IUnknown;
// pub use crate::interfaces::__IUnknown_AutomationVtbl as IUnknownVtbl;

pub use crate::interfaces::ISupportErrorInfo;
// pub use crate::interfaces::__ISupportErrorInfo_AutomationVtbl as ISupportErrorInfoVtbl;

/// Basic COM result type.
///
/// The `ComResult` maps the Rust concept of `Ok` and `Err` values to COM
/// `[out, retval]` parameter and `HRESULT` return value.
pub type ComResult<A> = Result<A, ComError>;

/// Basic COM result type.
///
/// The `ComResult` maps the Rust concept of `Ok` and `Err` values to COM
/// `[out, retval]` parameter and `HRESULT` return value.
pub type RawComResult<A> = Result<A, raw::HRESULT>;
<commit_msg>Fix style<commit_after>//! Tools to define Rust components compatible with the COM protocol.
//!
//! Intercom provides attributes to automatically derive `extern` compatible
//! functions for Rust methods. These functions are compatible with COM binary
//! interface standard, which allows them to be used from any language that
//! supports COM.
//!
//! # Examples
//!
//! A basic example of a calculator type exposed as a COM object.
//!
//! ```
//! use intercom::{com_library, com_class, com_interface, ComResult};
//!
//! // Define COM classes to expose from this library.
//! com_library!(class Calculator);
//!
//! // Define the COM class and the interfaces it implements.
//! #[com_class(Self)]
//! #[derive(Default)]
//! struct Calculator;
//!
//! // Define the implementation for the class. The COM interface is defined
//! // implicitly by the `impl`.
//! #[com_interface]
//! impl Calculator {
//!     fn add(&self, a: i32, b: i32) -> ComResult<i32> { Ok(a + b) }
//!     fn sub(&self, a: i32, b: i32) -> ComResult<i32> { Ok(a - b) }
//! }
//! # // Without 'main()' doctests wraps the whole thing into a function,
//! # // which would end up expanding com_library!(..) into a statement.
//! # // And proc macros into statements are not allowed.
//! # //
//! # // In addition to that, if we just have `fn main()` followed by open
//! # // brace _anywhere_ in this doctest (yes, including these comments),
//! # // clippy would discover that and yell at us for "needless doctest main".
//! # // Allowing that with a specific #[allow(..)] attribute is impossible
//! # // since this is crate-level documentation.
//! # //
//! # // Fortunately we can hide this from clippy by specifying the (empty)
//! # // return type.
//! # fn main() -> () { }
//! ```
//!
//! The above library can be used for example from C# in the following manner.
//!
//! ```csharp
//! void Main()
//! {
//!     var calculator = new CalculatorLib.Calculator();
//!     Console.WriteLine( calculator.Add( 1, 2 ) );
//! }
//! ```

#![crate_type = "dylib"]
#![allow(clippy::match_bool)]

extern crate self as intercom;

#[cfg(not(windows))]
extern crate libc;

extern crate intercom_attributes;
pub use intercom_attributes::*;

#[allow(clippy::useless_attribute)]
#[allow(unused_imports)]
#[macro_use]
extern crate failure;

#[cfg(feature = "log")]
extern crate log;

pub mod prelude;

mod classfactory;
pub use crate::classfactory::*;
mod combox;
pub use crate::combox::*;
mod comrc;
pub use crate::comrc::*;
mod comitf;
pub use crate::comitf::*;
mod strings;
pub use crate::strings::*;
mod guid;
pub use crate::guid::GUID;
pub mod error;
pub use crate::error::{load_error, store_error, ComError, ErrorValue};
pub mod alloc;
pub mod interfaces;
pub mod runtime;
mod variant;
pub use crate::variant::{Variant, VariantError};
pub mod type_system;
pub mod typelib;
pub use type_system::ForeignType;
pub mod attributes;
pub mod logging;

#[cfg(windows)]
pub mod registry;

// No-ops on non-windows platforms.
#[cfg(not(windows))]
pub mod registry
{
    use crate::raw::HRESULT;
    use crate::typelib::TypeLib;

    type HANDLE = *mut std::os::raw::c_void;

    /// Registers a type library.
    pub fn register(_dll: HANDLE, _lib: TypeLib) -> Result<(), HRESULT>
    {
        Ok(())
    }

    /// Unregisters a type library.
    pub fn unregister(_dll: HANDLE, _lib: TypeLib) -> Result<(), HRESULT>
    {
        Ok(())
    }
}

com_module!(
    class intercom::alloc::Allocator,
    class intercom::error::ErrorStore,
);

/// Raw COM pointer type.
/// Interface ID GUID.
pub type IID = GUID;

/// A reference to an interface ID.
pub type REFIID = *const IID;

/// Class ID GUID.
pub type CLSID = GUID;

/// A reference to a class ID.
pub type REFCLSID = *const IID;

pub mod raw
{
    use std::marker::PhantomData;
    use std::os::raw::c_void;
    use std::ptr::NonNull;

    pub use crate::error::raw::*;
    pub use crate::type_system::{ForeignType, TypeSystem};
    pub use crate::variant::raw::*;

    pub type RawComPtr = *mut c_void;

    #[derive(Clone, Copy, intercom_attributes::ExternInput, intercom_attributes::ForeignType)]
    #[repr(transparent)]
    pub struct InBSTR(pub *const u16);

    #[derive(
        Clone,
        Copy,
        intercom_attributes::ExternInput,
        intercom_attributes::ExternOutput,
        intercom_attributes::ForeignType,
    )]
    #[repr(transparent)]
    pub struct OutBSTR(pub *mut u16);

    pub type InCStr = *const std::os::raw::c_char;
    pub type OutCStr = *mut std::os::raw::c_char;

    #[repr(transparent)]
    #[derive(PartialEq, Eq)]
    pub struct InterfacePtr<TS: TypeSystem, I: ?Sized>
    {
        pub ptr: NonNull<c_void>,
        phantom_itf: PhantomData<I>,
        phantom_ts: PhantomData<TS>,
    }

    impl<TS: TypeSystem, I: ?Sized> Clone for InterfacePtr<TS, I>
    {
        fn clone(&self) -> Self
        {
            InterfacePtr {
                ptr: self.ptr,
                phantom_itf: PhantomData,
                phantom_ts: PhantomData,
            }
        }
    }

    impl<TS: TypeSystem, I: ?Sized> Copy for InterfacePtr<TS, I> {}

    impl<TS: TypeSystem, I: ?Sized> std::fmt::Debug for InterfacePtr<TS, I>
    {
        fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result
        {
            write!(f, "InterfacePtr({:?})", self.ptr)
        }
    }

    impl<TS: TypeSystem, I: ?Sized> InterfacePtr<TS, I>
    {
        /// # Safety
        ///
        /// The raw `ptr` must represent the correct type system and interface.
        pub unsafe fn new(ptr: RawComPtr) -> Option<InterfacePtr<TS, I>>
        {
            let ptr = NonNull::new(ptr);
            ptr.map(|ptr| InterfacePtr {
                ptr,
                phantom_itf: PhantomData,
                phantom_ts: PhantomData,
            })
        }
    }

    impl<TS: TypeSystem, I: crate::attributes::ComInterface + ?Sized> InterfacePtr<TS, I>
    {
        pub fn as_unknown(self) -> InterfacePtr<TS, dyn crate::IUnknown>
        {
            InterfacePtr {
                ptr: self.ptr,
                phantom_itf: PhantomData,
                phantom_ts: PhantomData,
            }
        }
    }

    impl<TS: TypeSystem, I: crate::attributes::ComInterface + ?Sized> ForeignType
        for Option<InterfacePtr<TS, I>>
    where
        I: ForeignType,
    {
        /// The name of the type.
        fn type_name() -> &'static str
        {
            <I as ForeignType>::type_name()
        }
        fn indirection_level() -> u32
        {
            <I as ForeignType>::indirection_level() + 1
        }
    }
}

/// `IClassFactory` interface ID.
#[allow(non_upper_case_globals)]
pub const IID_IClassFactory: GUID = GUID {
    data1: 0x0000_0001,
    data2: 0x0000,
    data3: 0x0000,
    data4: [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46],
};

/// `IErrorInfo` interface ID.
#[allow(non_upper_case_globals)]
pub const IID_IErrorInfo: GUID = GUID {
    data1: 0x1CF2_B120,
    data2: 0x547D,
    data3: 0x101B,
    data4: [0x8E, 0x65, 0x08, 0x00, 0x2B, 0x2B, 0xD1, 0x19],
};

pub use crate::interfaces::IUnknown;
// pub use crate::interfaces::__IUnknown_AutomationVtbl as IUnknownVtbl;

pub use crate::interfaces::ISupportErrorInfo;
// pub use crate::interfaces::__ISupportErrorInfo_AutomationVtbl as ISupportErrorInfoVtbl;

/// Basic COM result type.
///
/// The `ComResult` maps the Rust concept of `Ok` and `Err` values to COM
/// `[out, retval]` parameter and `HRESULT` return value.
pub type ComResult<A> = Result<A, ComError>;

/// Basic COM result type.
///
/// The `ComResult` maps the Rust concept of `Ok` and `Err` values to COM
/// `[out, retval]` parameter and `HRESULT` return value.
pub type RawComResult<A> = Result<A, raw::HRESULT>;
<|endoftext|>


<commit_before>use livesplit_core::{Run, RunEditor, TimingMethod};
use super::{acc, acc_mut, alloc, output_vec, own, str, Json};
use run::OwnedRun;
use libc::c_char;
use std::{ptr, slice};

pub type OwnedRunEditor = *mut RunEditor;
pub type NullableOwnedRunEditor = *mut RunEditor;

#[no_mangle]
pub unsafe extern "C" fn RunEditor_new(run: OwnedRun) -> NullableOwnedRunEditor {
    RunEditor::new(own(run))
        .ok()
        .map_or_else(ptr::null_mut, alloc)
}

#[no_mangle]
pub unsafe extern "C" fn RunEditor_close(this: OwnedRunEditor) -> OwnedRun {
    alloc(own(this).close())
}

#[no_mangle]
pub unsafe extern "C" fn RunEditor_state_as_json(this: *mut RunEditor) -> Json {
    output_vec(|o| { acc_mut(this).state().write_json(o).unwrap(); })
}

#[no_mangle]
pub unsafe extern "C" fn RunEditor_select_timing_method(
    this: *mut RunEditor,
    method: TimingMethod,
) {
    acc_mut(this).select_timing_method(method);
}

#[no_mangle]
pub unsafe extern "C" fn RunEditor_unselect(this: *mut RunEditor, index: usize) {
    acc_mut(this).unselect(index);
}

#[no_mangle]
pub unsafe extern "C" fn RunEditor_select_additionally(this: *mut RunEditor, index: usize) {
    acc_mut(this).select_additionally(index);
}

#[no_mangle]
pub unsafe extern "C" fn RunEditor_select_only(this: *mut RunEditor, index: usize) {
    acc_mut(this).select_only(index);
}

#[no_mangle]
pub unsafe extern "C" fn RunEditor_set_game_name(this: *mut RunEditor, game: *const c_char) {
    acc_mut(this).set_game_name(str(game));
}

#[no_mangle]
pub unsafe extern "C" fn RunEditor_set_category_name(
    this: *mut RunEditor,
    category: *const c_char,
) {
    acc_mut(this).set_category_name(str(category));
}

#[no_mangle]
pub unsafe extern "C" fn RunEditor_parse_and_set_offset(
    this: *mut RunEditor,
    offset: *const c_char,
) -> bool {
    acc_mut(this).parse_and_set_offset(str(offset)).is_ok()
}

#[no_mangle]
pub unsafe extern "C" fn RunEditor_parse_and_set_attempt_count(
    this: *mut RunEditor,
    attempts: *const c_char,
) -> bool {
    acc_mut(this)
        .parse_and_set_attempt_count(str(attempts))
        .is_ok()
}

#[no_mangle]
pub unsafe extern "C" fn RunEditor_set_game_icon(
    this: *mut RunEditor,
    data: *const u8,
    length: usize,
) {
    acc_mut(this).set_game_icon(slice::from_raw_parts(data, length));
}

#[no_mangle]
pub unsafe extern "C" fn RunEditor_insert_segment_above(this: *mut RunEditor) {
    acc_mut(this).insert_segment_above();
}

#[no_mangle]
pub unsafe extern "C" fn RunEditor_insert_segment_below(this: *mut RunEditor) {
    acc_mut(this).insert_segment_below();
}

#[no_mangle]
pub unsafe extern "C" fn RunEditor_remove_segments(this: *mut RunEditor) {
    acc_mut(this).remove_segments();
}

#[no_mangle]
pub unsafe extern "C" fn RunEditor_move_segments_up(this: *mut RunEditor) {
    acc_mut(this).move_segments_up();
}

#[no_mangle]
pub unsafe extern "C" fn RunEditor_move_segments_down(this: *mut RunEditor) {
    acc_mut(this).move_segments_down();
}

#[no_mangle]
pub unsafe extern "C" fn RunEditor_selected_set_icon(
    this: *mut RunEditor,
    data: *const u8,
    length: usize,
) {
    acc_mut(this)
        .selected_segment()
        .set_icon(slice::from_raw_parts(data, length));
}

#[no_mangle]
pub unsafe extern "C" fn RunEditor_selected_set_name(this: *mut RunEditor, name: *const c_char) {
    acc_mut(this).selected_segment().set_name(str(name));
}

#[no_mangle]
pub unsafe extern "C" fn RunEditor_selected_parse_and_set_split_time(
    this: *mut RunEditor,
    time: *const c_char,
) -> bool {
    acc_mut(this)
        .selected_segment()
        .parse_and_set_split_time(str(time))
        .is_ok()
}

#[no_mangle]
pub unsafe extern "C" fn RunEditor_selected_parse_and_set_segment_time(
    this: *mut RunEditor,
    time: *const c_char,
) -> bool {
    acc_mut(this)
        .selected_segment()
        .parse_and_set_segment_time(str(time))
        .is_ok()
}

#[no_mangle]
pub unsafe extern "C" fn RunEditor_selected_parse_and_set_best_segment_time(
    this: *mut RunEditor,
    time: *const c_char,
) -> bool {
    acc_mut(this)
        .selected_segment()
        .parse_and_set_best_segment_time(str(time))
        .is_ok()
}

#[no_mangle]
pub unsafe extern "C" fn RunEditor_selected_parse_and_set_comparison_time(
    this: *mut RunEditor,
    comparison: *const c_char,
    time: *const c_char,
) -> bool {
    acc_mut(this)
        .selected_segment()
        .parse_and_set_comparison_time(str(comparison), str(time))
        .is_ok()
}

#[no_mangle]
pub unsafe extern "C" fn RunEditor_add_comparison(
    this: *mut RunEditor,
    comparison: *const c_char,
) -> bool {
    acc_mut(this).add_comparison(str(comparison)).is_ok()
}

#[no_mangle]
pub unsafe extern "C" fn RunEditor_import_comparison(
    this: *mut RunEditor,
    run: *const Run,
    comparison: *const c_char,
) -> bool {
    acc_mut(this)
        .import_comparison(acc(run), str(comparison))
        .is_ok()
}

#[no_mangle]
pub unsafe extern "C" fn RunEditor_remove_comparison(
    this: *mut RunEditor,
    comparison: *const c_char,
) {
    acc_mut(this).remove_comparison(str(comparison));
}

#[no_mangle]
pub unsafe extern "C" fn RunEditor_rename_comparison(
    this: *mut RunEditor,
    old: *const c_char,
    new: *const c_char,
) -> bool {
    acc_mut(this).rename_comparison(str(old), str(new)).is_ok()
}
<commit_msg>new is a keyword in some languages<commit_after>use livesplit_core::{Run, RunEditor, TimingMethod};
use super::{acc, acc_mut, alloc, output_vec, own, str, Json};
use run::OwnedRun;
use libc::c_char;
use std::{ptr, slice};

pub type OwnedRunEditor = *mut RunEditor;
pub type NullableOwnedRunEditor = *mut RunEditor;

#[no_mangle]
pub unsafe extern "C" fn RunEditor_new(run: OwnedRun) -> NullableOwnedRunEditor {
    RunEditor::new(own(run))
        .ok()
        .map_or_else(ptr::null_mut, alloc)
}

#[no_mangle]
pub unsafe extern "C" fn RunEditor_close(this: OwnedRunEditor) -> OwnedRun {
    alloc(own(this).close())
}

#[no_mangle]
pub unsafe extern "C" fn RunEditor_state_as_json(this: *mut RunEditor) -> Json {
    output_vec(|o| { acc_mut(this).state().write_json(o).unwrap(); })
}

#[no_mangle]
pub unsafe extern "C" fn RunEditor_select_timing_method(
    this: *mut RunEditor,
    method: TimingMethod,
) {
    acc_mut(this).select_timing_method(method);
}

#[no_mangle]
pub unsafe extern "C" fn RunEditor_unselect(this: *mut RunEditor, index: usize) {
    acc_mut(this).unselect(index);
}

#[no_mangle]
pub unsafe extern "C" fn RunEditor_select_additionally(this: *mut RunEditor, index: usize) {
    acc_mut(this).select_additionally(index);
}

#[no_mangle]
pub unsafe extern "C" fn RunEditor_select_only(this: *mut RunEditor, index: usize) {
    acc_mut(this).select_only(index);
}

#[no_mangle]
pub unsafe extern "C" fn RunEditor_set_game_name(this: *mut RunEditor, game: *const c_char) {
    acc_mut(this).set_game_name(str(game));
}

#[no_mangle]
pub unsafe extern "C" fn RunEditor_set_category_name(
    this: *mut RunEditor,
    category: *const c_char,
) {
    acc_mut(this).set_category_name(str(category));
}

#[no_mangle]
pub unsafe extern "C" fn RunEditor_parse_and_set_offset(
    this: *mut RunEditor,
    offset: *const c_char,
) -> bool {
    acc_mut(this).parse_and_set_offset(str(offset)).is_ok()
}

#[no_mangle]
pub unsafe extern "C" fn RunEditor_parse_and_set_attempt_count(
    this: *mut RunEditor,
    attempts: *const c_char,
) -> bool {
    acc_mut(this)
        .parse_and_set_attempt_count(str(attempts))
        .is_ok()
}

#[no_mangle]
pub unsafe extern "C" fn RunEditor_set_game_icon(
    this: *mut RunEditor,
    data: *const u8,
    length: usize,
) {
    acc_mut(this).set_game_icon(slice::from_raw_parts(data, length));
}

#[no_mangle]
pub unsafe extern "C" fn RunEditor_insert_segment_above(this: *mut RunEditor) {
    acc_mut(this).insert_segment_above();
}

#[no_mangle]
pub unsafe extern "C" fn RunEditor_insert_segment_below(this: *mut RunEditor) {
    acc_mut(this).insert_segment_below();
}

#[no_mangle]
pub unsafe extern "C" fn RunEditor_remove_segments(this: *mut RunEditor) {
    acc_mut(this).remove_segments();
}

#[no_mangle]
pub unsafe extern "C" fn RunEditor_move_segments_up(this: *mut RunEditor) {
    acc_mut(this).move_segments_up();
}

#[no_mangle]
pub unsafe extern "C" fn RunEditor_move_segments_down(this: *mut RunEditor) {
    acc_mut(this).move_segments_down();
}

#[no_mangle]
pub unsafe extern "C" fn RunEditor_selected_set_icon(
    this: *mut RunEditor,
    data: *const u8,
    length: usize,
) {
    acc_mut(this)
        .selected_segment()
        .set_icon(slice::from_raw_parts(data, length));
}

#[no_mangle]
pub unsafe extern "C" fn RunEditor_selected_set_name(this: *mut RunEditor, name: *const c_char) {
    acc_mut(this).selected_segment().set_name(str(name));
}

#[no_mangle]
pub unsafe extern "C" fn RunEditor_selected_parse_and_set_split_time(
    this: *mut RunEditor,
    time: *const c_char,
) -> bool {
    acc_mut(this)
        .selected_segment()
        .parse_and_set_split_time(str(time))
        .is_ok()
}

#[no_mangle]
pub unsafe extern "C" fn RunEditor_selected_parse_and_set_segment_time(
    this: *mut RunEditor,
    time: *const c_char,
) -> bool {
    acc_mut(this)
        .selected_segment()
        .parse_and_set_segment_time(str(time))
        .is_ok()
}

#[no_mangle]
pub unsafe extern "C" fn RunEditor_selected_parse_and_set_best_segment_time(
    this: *mut RunEditor,
    time: *const c_char,
) -> bool {
    acc_mut(this)
        .selected_segment()
        .parse_and_set_best_segment_time(str(time))
        .is_ok()
}

#[no_mangle]
pub unsafe extern "C" fn RunEditor_selected_parse_and_set_comparison_time(
    this: *mut RunEditor,
    comparison: *const c_char,
    time: *const c_char,
) -> bool {
    acc_mut(this)
        .selected_segment()
        .parse_and_set_comparison_time(str(comparison), str(time))
        .is_ok()
}

#[no_mangle]
pub unsafe extern "C" fn RunEditor_add_comparison(
    this: *mut RunEditor,
    comparison: *const c_char,
) -> bool {
    acc_mut(this).add_comparison(str(comparison)).is_ok()
}

#[no_mangle]
pub unsafe extern "C" fn RunEditor_import_comparison(
    this: *mut RunEditor,
    run: *const Run,
    comparison: *const c_char,
) -> bool {
    acc_mut(this)
        .import_comparison(acc(run), str(comparison))
        .is_ok()
}

#[no_mangle]
pub unsafe extern "C" fn RunEditor_remove_comparison(
    this: *mut RunEditor,
    comparison: *const c_char,
) {
    acc_mut(this).remove_comparison(str(comparison));
}

#[no_mangle]
pub unsafe extern "C" fn RunEditor_rename_comparison(
    this: *mut RunEditor,
    old_name: *const c_char,
    new_name: *const c_char,
) -> bool {
    acc_mut(this).rename_comparison(str(old_name), str(new_name)).is_ok()
}
<|endoftext|>