session: Port to glib::Properties macro

This commit is contained in:
Kévin Commaille 2023-12-12 23:00:02 +01:00
parent 46d585b185
commit 7869be72c1
No known key found for this signature in database
GPG Key ID: 29A48C1F03620416
24 changed files with 174 additions and 202 deletions

View File

@ -100,7 +100,7 @@ mod imp {
if let Some(session) = session {
if let Some(session) = session.downcast_ref::<Session>() {
let user = session.user().unwrap();
let user = session.user();
let avatar_data_handler = user
.bind_property("avatar-data", &*self.avatar, "data")

View File

@ -262,7 +262,7 @@ impl AuthDialog {
stack.set_visible_child_name(AuthType::Password.as_ref());
self.show_and_wait_for_response().await?;
let user_id = session.user().unwrap().user_id().to_string();
let user_id = session.user_id().to_string();
let password = self.imp().password.text().to_string();
let data = assign!(

View File

@ -162,7 +162,8 @@ impl UserFacingError for oo7::dbus::Error {
}
}
#[derive(Clone)]
#[derive(Clone, glib::Boxed)]
#[boxed_type(name = "StoredSession")]
pub struct StoredSession {
pub homeserver: Url,
pub user_id: OwnedUserId,

View File

@ -288,8 +288,7 @@ impl Event {
fn set_room(&self, room: Room) {
let imp = self.imp();
imp.room.set(Some(&room));
imp.reactions
.set_user(room.session().user().unwrap().clone());
imp.reactions.set_user(room.session().user());
}
/// The underlying SDK timeline item of this `Event`.

View File

@ -219,10 +219,8 @@ impl Member {
self.set_membership((&event.content().membership).into());
let session = self.session();
if let Some(user) = session.user() {
if user.user_id() == self.user_id() {
session.update_user_profile();
}
if session.user_id() == self.user_id() {
session.update_user_profile();
}
}
}

View File

@ -746,11 +746,12 @@ impl Room {
}
fn handle_receipt_event(&self, content: ReceiptEventContent) {
let own_user_id = self.session().user().unwrap().user_id();
let session = self.session();
let own_user_id = session.user_id();
for (_event_id, receipts) in content.iter() {
if let Some(users) = receipts.get(&ReceiptType::Read) {
if users.contains_key(&own_user_id) {
if users.contains_key(own_user_id) {
self.update_is_read();
}
}
@ -767,7 +768,8 @@ impl Room {
return;
};
let own_user_id = self.session().user().unwrap().user_id();
let session = self.session();
let own_user_id = session.user_id();
let members = content
.user_ids
@ -982,10 +984,7 @@ impl Room {
return;
}
let Some(own_user_id) = self.session().user().map(|user| user.user_id()) else {
return;
};
let own_user_id = self.session().user_id().to_owned();
let matrix_room_clone = matrix_room.clone();
let handle =
spawn_tokio!(async move { matrix_room_clone.get_member_no_sync(&own_user_id).await });
@ -1211,7 +1210,7 @@ impl Room {
room_action: PowerLevelAction,
) -> gtk::ClosureExpression {
let session = self.session();
let user_id = session.user().unwrap().user_id();
let user_id = session.user_id().to_owned();
self.power_levels()
.member_is_allowed_to_expr(user_id, room_action)
}
@ -1626,7 +1625,8 @@ impl Room {
}
};
let own_user_id = self.session().user().unwrap().user_id();
let session = self.session();
let own_user_id = session.user_id();
let mut has_own_member = false;
let mut other_member = None;

View File

@ -715,7 +715,7 @@ impl Timeline {
/// Returns `None` if it is not possible to know, for example if there are
/// no events in the Timeline.
pub async fn has_unread_messages(&self) -> Option<bool> {
let own_user_id = self.room().session().user().unwrap().user_id();
let own_user_id = self.room().session().user_id().to_owned();
let matrix_timeline = self.matrix_timeline();
let user_receipt_item = spawn_tokio!(async move {

View File

@ -35,7 +35,7 @@ use super::{
use crate::{
prelude::*,
secret::StoredSession,
session_list::{BoxedStoredSession, SessionInfo, SessionInfoImpl},
session_list::{SessionInfo, SessionInfoImpl},
spawn, spawn_tokio,
utils::{
check_if_reachable,
@ -57,23 +57,39 @@ pub enum SessionState {
Ready = 2,
}
mod imp {
use std::cell::{Cell, RefCell};
#[derive(Clone, Debug, glib::Boxed)]
#[boxed_type(name = "BoxedClient")]
pub struct BoxedClient(Client);
use once_cell::{sync::Lazy, unsync::OnceCell};
mod imp {
use std::cell::{Cell, OnceCell, RefCell};
use super::*;
#[derive(Debug, Default)]
#[derive(Debug, Default, glib::Properties)]
#[properties(wrapper_type = super::Session)]
pub struct Session {
pub client: TokioDrop<Client>,
/// The Matrix client.
#[property(construct_only)]
pub client: TokioDrop<BoxedClient>,
/// The list model of the sidebar.
#[property(get = Self::sidebar_list_model)]
pub sidebar_list_model: OnceCell<SidebarListModel>,
/// The user of this session.
#[property(get = Self::user)]
pub user: OnceCell<User>,
/// The current state of the session.
#[property(get, builder(SessionState::default()))]
pub state: Cell<SessionState>,
pub sync_tokio_handle: RefCell<Option<JoinHandle<()>>>,
pub offline_handler_id: RefCell<Option<SignalHandlerId>>,
/// Whether this session has a connection to the homeserver.
#[property(get)]
pub offline: Cell<bool>,
/// The current settings for this session.
#[property(get, construct_only)]
pub settings: OnceCell<SessionSettings>,
/// The notifications API for this session.
pub notifications: Notifications,
}
@ -84,51 +100,8 @@ mod imp {
type ParentType = SessionInfo;
}
#[glib::derived_properties]
impl ObjectImpl for Session {
fn properties() -> &'static [glib::ParamSpec] {
static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
vec![
glib::ParamSpecObject::builder::<SidebarListModel>("sidebar-list-model")
.read_only()
.build(),
glib::ParamSpecObject::builder::<User>("user")
.read_only()
.build(),
glib::ParamSpecBoolean::builder("offline")
.read_only()
.build(),
glib::ParamSpecEnum::builder::<SessionState>("state")
.read_only()
.build(),
glib::ParamSpecObject::builder::<SessionSettings>("settings")
.construct_only()
.build(),
]
});
PROPERTIES.as_ref()
}
fn set_property(&self, _id: usize, value: &glib::Value, pspec: &glib::ParamSpec) {
match pspec.name() {
"settings" => self.settings.set(value.get().unwrap()).unwrap(),
_ => unimplemented!(),
}
}
fn property(&self, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
let obj = self.obj();
match pspec.name() {
"sidebar-list-model" => obj.sidebar_list_model().to_value(),
"user" => obj.user().to_value(),
"offline" => obj.is_offline().to_value(),
"state" => obj.state().to_value(),
"settings" => obj.settings().to_value(),
_ => unimplemented!(),
}
}
fn constructed(&self) {
self.parent_constructed();
let obj = self.obj();
@ -159,7 +132,29 @@ mod imp {
impl SessionInfoImpl for Session {
fn avatar_data(&self) -> AvatarData {
self.obj().user().unwrap().avatar_data().clone()
self.obj().user().avatar_data().clone()
}
}
impl Session {
/// The list model of the sidebar.
fn sidebar_list_model(&self) -> SidebarListModel {
let obj = self.obj();
self.sidebar_list_model
.get_or_init(|| {
let item_list =
ItemList::new(&RoomList::new(&obj), &VerificationList::new(&obj));
SidebarListModel::new(&item_list)
})
.clone()
}
/// The user of the session.
fn user(&self) -> User {
let obj = self.obj();
self.user
.get_or_init(|| User::new(&obj, &obj.info().user_id))
.clone()
}
}
}
@ -187,29 +182,19 @@ impl Session {
stored_session: StoredSession,
settings: SessionSettings,
) -> Result<Self, ClientSetupError> {
let obj = glib::Object::builder::<Self>()
.property("info", BoxedStoredSession(stored_session.clone()))
.property("settings", settings)
.build();
let stored_session_clone = stored_session.clone();
let client =
spawn_tokio!(async move { matrix::client_with_stored_session(stored_session).await })
.await
.unwrap()?;
spawn_tokio!(
async move { matrix::client_with_stored_session(stored_session_clone).await }
)
.await
.unwrap()?;
let imp = obj.imp();
imp.client.set(client).unwrap();
let user = User::new(&obj, &obj.info().user_id);
imp.user.set(user).unwrap();
obj.notify("user");
Ok(obj)
}
/// The current state of the session.
pub fn state(&self) -> SessionState {
self.imp().state.get()
Ok(glib::Object::builder()
.property("info", &stored_session)
.property("settings", settings)
.property("client", &BoxedClient(client))
.build())
}
/// Set the current state of the session.
@ -223,9 +208,10 @@ impl Session {
}
self.imp().state.set(state);
self.notify("state");
self.notify_state();
}
/// Finish initialization of this session.
pub async fn prepare(&self) {
self.update_user_profile();
self.update_offline().await;
@ -240,8 +226,9 @@ impl Session {
debug!("A new session was prepared");
}
/// Start syncing the Matrix client.
fn sync(&self) {
if self.state() < SessionState::InitialSync || self.is_offline() {
if self.state() < SessionState::InitialSync || self.offline() {
return;
}
@ -326,38 +313,22 @@ impl Session {
.unwrap();
}
/// The current settings for this session.
pub fn settings(&self) -> &SessionSettings {
self.imp().settings.get().unwrap()
}
/// The room list of this session.
pub fn room_list(&self) -> RoomList {
self.sidebar_list_model().item_list().room_list()
}
/// The verification list of this session.
pub fn verification_list(&self) -> VerificationList {
self.sidebar_list_model().item_list().verification_list()
}
/// The list model of the sidebar.
pub fn sidebar_list_model(&self) -> &SidebarListModel {
self.imp().sidebar_list_model.get_or_init(|| {
let item_list = ItemList::new(&RoomList::new(self), &VerificationList::new(self));
SidebarListModel::new(&item_list)
})
}
/// The user of this session.
pub fn user(&self) -> Option<&User> {
self.imp().user.get()
}
/// Update the profile of this sessions user.
///
/// Fetches the updated profile and updates the local data.
pub fn update_user_profile(&self) {
let client = self.client();
let user = self.user().unwrap().to_owned();
let user = self.user();
let handle = spawn_tokio!(async move { client.account().get_profile().await });
@ -372,40 +343,38 @@ impl Session {
});
}
/// The Matrix client.
pub fn client(&self) -> Client {
self.imp()
.client
.get()
.expect("The session wasn't prepared")
.0
.clone()
}
/// Whether this session has a connection to the homeserver.
pub fn is_offline(&self) -> bool {
self.imp().offline.get()
}
/// Update whether this session is offline.
async fn update_offline(&self) {
let imp = self.imp();
let monitor = gio::NetworkMonitor::default();
let is_offline = if monitor.is_network_available() {
let offline = if monitor.is_network_available() {
!check_if_reachable(&self.homeserver()).await
} else {
true
};
if self.is_offline() == is_offline {
if self.offline() == offline {
return;
}
if is_offline {
if offline {
debug!("This session is now offline");
} else {
debug!("This session is now online");
}
imp.offline.set(is_offline);
imp.offline.set(offline);
if let Some(handle) = imp.sync_tokio_handle.take() {
handle.abort();
@ -414,25 +383,28 @@ impl Session {
// Restart the sync loop when online
self.sync();
self.notify("offline");
self.notify_offline();
}
/// Connect to the signal emitted when this session is logged out.
pub fn connect_logged_out<F: Fn(&Self) + 'static>(&self, f: F) -> glib::SignalHandlerId {
self.connect_notify_local(Some("state"), move |obj, _| {
self.connect_state_notify(move |obj| {
if obj.state() == SessionState::LoggedOut {
f(obj);
}
})
}
/// Connect to the signal emitted when this session is ready.
pub fn connect_ready<F: Fn(&Self) + 'static>(&self, f: F) -> glib::SignalHandlerId {
self.connect_notify_local(Some("state"), move |obj, _| {
self.connect_state_notify(move |obj| {
if obj.state() == SessionState::Ready {
f(obj);
}
})
}
/// Handle the response received via sync.
fn handle_sync_response(&self, response: Result<SyncResponse, matrix_sdk::Error>) {
debug!("Received sync response");
match response {
@ -456,6 +428,7 @@ impl Session {
}
}
/// Log out of this session.
pub async fn logout(&self) -> Result<(), String> {
debug!("The session is about to be logged out");
@ -494,6 +467,7 @@ impl Session {
);
}
/// Clean up this session after it was logged out.
async fn cleanup_session(&self) {
let imp = self.imp();
@ -514,6 +488,7 @@ impl Session {
debug!("The logged out session was cleaned up");
}
/// Listen to changes to the list of direct rooms.
fn setup_direct_room_handler(&self) {
let session_weak = glib::SendWeakRef::from(self.downgrade());
self.client().add_event_handler(
@ -556,6 +531,7 @@ impl Session {
);
}
/// The notifications API of this session.
pub fn notifications(&self) -> &Notifications {
&self.imp().notifications
}

View File

@ -7,6 +7,7 @@ use tracing::error;
use crate::{
components::Pill,
prelude::*,
session::model::{
AvatarData, AvatarImage, AvatarUriSource, IdentityVerification, Session, VerificationState,
},
@ -157,7 +158,7 @@ impl User {
}
pub async fn verify_identity(&self) -> IdentityVerification {
let request = IdentityVerification::create(self.session(), Some(self)).await;
let request = IdentityVerification::create(self.session(), Some(self.clone())).await;
self.session().verification_list().add(request.clone());
// FIXME: actually listen to room events to get updates for verification state
request.connect_notify_local(
@ -240,9 +241,7 @@ pub trait UserExt: IsA<User> {
fn allowed_actions(&self) -> UserActions {
let user = self.upcast_ref();
let is_other = self.session().user().map_or(false, |session_user| {
session_user.user_id() != self.user_id()
});
let is_other = self.session().user_id() != self.user_id();
if !user.is_verified() && is_other {
UserActions::VERIFY

View File

@ -278,7 +278,7 @@ mod imp {
// We don't need to track ourselves because we show "Login Request" as name in
// that case.
if obj.user() != obj.session().user().unwrap() {
if obj.user() != &obj.session().user() {
obj.user().connect_notify_local(
Some("display-name"),
clone!(@weak obj => move |_, _| {
@ -337,11 +337,11 @@ impl IdentityVerification {
///
/// If `User` is `None` a new session verification is started for our own
/// user and send to other devices.
pub async fn create(session: &Session, user: Option<&User>) -> Self {
pub async fn create(session: &Session, user: Option<User>) -> Self {
let user = if let Some(user) = user {
user
} else {
session.user().unwrap()
session.user()
};
let has_camera =
@ -364,7 +364,7 @@ impl IdentityVerification {
.property("supported-methods", supported_methods)
.property("flow-id", request.flow_id())
.property("session", session)
.property("user", user)
.property("user", &user)
.property("start-time", &glib::DateTime::now_local().unwrap())
.build();
@ -378,7 +378,7 @@ impl IdentityVerification {
error!("Starting a verification failed: Crypto identity wasn't found");
}
Self::for_error(session, user, &glib::DateTime::now_local().unwrap())
Self::for_error(session, &user, &glib::DateTime::now_local().unwrap())
}
fn start_handler(&self) {
@ -595,7 +595,7 @@ impl IdentityVerification {
/// The mode of this verification.
pub fn mode(&self) -> Mode {
let session = self.session();
let our_user = session.user().unwrap();
let our_user = session.user();
if our_user.user_id() == self.user().user_id() {
if self.force_current_session() {
Mode::CurrentSession
@ -622,7 +622,7 @@ impl IdentityVerification {
/// The display name of this verification request.
pub fn display_name(&self) -> String {
if self.user() != self.session().user().unwrap() {
if self.user() != &self.session().user() {
self.user().display_name()
} else {
// TODO: give this request a name based on the device

View File

@ -140,7 +140,7 @@ impl VerificationList {
Some(request)
} else {
let session = self.session();
let user = session.user().unwrap();
let user = session.user();
// ToDevice verifications can only be send by us
if *e.sender != *user.user_id() {
warn!("Received a device verification event from a different user, which isn't allowed");
@ -158,7 +158,7 @@ impl VerificationList {
let request = IdentityVerification::for_flow_id(
e.content.transaction_id.as_str(),
&session,
user,
&user,
&start_time,
);
self.add(request.clone());
@ -228,7 +228,7 @@ impl VerificationList {
};
let session = self.session();
let own_user_id = session.user().unwrap().user_id();
let own_user_id = session.user_id();
let user_id_to_verify = if request.to == own_user_id {
// The request was sent by another user to verify us
@ -407,7 +407,7 @@ impl VerificationList {
pub fn get_session(&self) -> Option<IdentityVerification> {
let list = self.imp().list.borrow();
let session = self.session();
let user_id = session.user().unwrap().user_id();
let user_id = session.user_id();
for (_, item) in list.iter() {
if !item.is_finished() && item.user().user_id() == user_id {

View File

@ -128,10 +128,8 @@ impl DeactivateAccountSubpage {
fn user_id(&self) -> String {
self.session()
.as_ref()
.and_then(|session| session.user())
.map(|session| session.user_id().to_string())
.unwrap()
.user_id()
.to_string()
}
fn update_button(&self) {

View File

@ -198,9 +198,8 @@ impl GeneralPage {
fn user(&self) -> User {
self.session()
.as_ref()
.and_then(|session| session.user())
.map(|session| session.user())
.unwrap()
.to_owned()
}
fn init_avatar(&self) {

View File

@ -180,8 +180,8 @@ impl NotificationsPage {
},
Ok(None) => {
warn!("Could not find push rules, using the default ruleset instead.");
let user_id = session.user().unwrap().user_id();
self.update_page(Ruleset::server_default(&user_id));
let user_id = session.user_id();
self.update_page(Ruleset::server_default(user_id));
}
Err(error) => {
error!("Could not get push rules: {error}");

View File

@ -88,7 +88,7 @@ impl ServerList {
imp.session.set(Some(&session));
let user_id = session.user().unwrap().user_id();
let user_id = session.user_id();
imp.list.replace(vec![Server::with_default_server(
user_id.server_name().as_str(),
)]);

View File

@ -477,12 +477,8 @@ impl ItemRow {
]);
if let TimelineItemContent::Message(message) = event.content() {
let own_user_id = event
.room()
.session()
.user()
.map(|user| user.user_id())
.unwrap();
let session = event.room().session();
let own_user_id = session.user_id();
let is_from_own_user = event.sender_id() == own_user_id;
// Remove message

View File

@ -880,8 +880,7 @@ impl MessageToolbar {
fn update_completion(&self, room: Option<&Room>) {
let completion = &self.imp().completion;
completion
.set_user_id(room.and_then(|r| r.session().user().map(|u| u.user_id().to_string())));
completion.set_user_id(room.map(|r| r.session().user_id().to_string()));
// `RoomHistory` should have a strong reference to the list so we can use
// `get_or_create_members()`.
completion.set_members(room.map(|r| r.get_or_create_members()));
@ -928,31 +927,30 @@ impl MessageToolbar {
fn set_up_can_send_messages(&self, room: Option<&Room>) {
if let Some(room) = room {
if let Some(own_user_id) = room.session().user().map(|u| u.user_id().to_owned()) {
let imp = self.imp();
let own_user_id = room.session().user_id().to_owned();
let imp = self.imp();
let own_member = room
.get_or_create_members()
.get_or_create(own_user_id.clone());
let own_member = room
.get_or_create_members()
.get_or_create(own_user_id.clone());
// We don't need to keep the handler around, the member should be dropped when
// switching rooms.
own_member.connect_notify_local(
Some("membership"),
clone!(@weak self as obj => move |_, _| {
obj.update_can_send_messages();
}),
);
imp.own_member.set(Some(&own_member));
// We don't need to keep the handler around, the member should be dropped when
// switching rooms.
own_member.connect_notify_local(
Some("membership"),
clone!(@weak self as obj => move |_, _| {
obj.update_can_send_messages();
}),
);
imp.own_member.set(Some(&own_member));
let power_levels_handler = room.power_levels().connect_notify_local(
Some("power-levels"),
clone!(@weak self as obj => move |_, _| {
obj.update_can_send_messages();
}),
);
imp.power_levels_handler.replace(Some(power_levels_handler));
}
let power_levels_handler = room.power_levels().connect_notify_local(
Some("power-levels"),
clone!(@weak self as obj => move |_, _| {
obj.update_can_send_messages();
}),
);
imp.power_levels_handler.replace(Some(power_levels_handler));
}
self.update_can_send_messages();

View File

@ -220,7 +220,7 @@ impl DmUserList {
}
self.load_dm_rooms().await;
let own_user_id = session.user().unwrap().user_id();
let own_user_id = session.user_id();
let dm_rooms = self.imp().dm_rooms.borrow().clone();
let mut users: Vec<DmUser> = vec![];

View File

@ -139,9 +139,9 @@ impl RoomCreation {
return;
}
if let Some(user) = session.as_ref().and_then(|session| session.user()) {
if let Some(session) = session {
imp.server_name
.set_label(&format!(":{}", user.user_id().server_name()));
.set_label(&format!(":{}", session.user_id().server_name()));
}
imp.session.set(session);

View File

@ -278,10 +278,10 @@ impl Sidebar {
let handler_id = session.connect_notify_local(
Some("offline"),
clone!(@weak self as obj => move |session, _| {
obj.imp().offline_banner.set_revealed(session.is_offline());
obj.imp().offline_banner.set_revealed(session.offline());
}),
);
self.imp().offline_banner.set_revealed(session.is_offline());
self.imp().offline_banner.set_revealed(session.offline());
self.imp().offline_handler_id.replace(Some(handler_id));
}

View File

@ -2,7 +2,7 @@ use std::{ops::Deref, sync::Arc};
use gtk::{glib, prelude::*, subclass::prelude::*};
use super::{BoxedStoredSession, SessionInfo, SessionInfoImpl};
use super::{SessionInfo, SessionInfoImpl};
use crate::{
prelude::*, secret::StoredSession, session::model::AvatarData, utils::matrix::ClientSetupError,
};
@ -67,7 +67,7 @@ impl FailedSession {
/// Constructs a new `FailedSession` with the given info and error.
pub fn new(stored_session: StoredSession, error: ClientSetupError) -> Self {
glib::Object::builder()
.property("info", BoxedStoredSession(stored_session))
.property("info", &stored_session)
.property("error", BoxedClientSetupError(Arc::new(error)))
.build()
}

View File

@ -1,6 +1,6 @@
use gtk::{glib, subclass::prelude::*};
use super::{BoxedStoredSession, SessionInfo, SessionInfoImpl};
use super::{SessionInfo, SessionInfoImpl};
use crate::{prelude::*, secret::StoredSession, session::model::AvatarData};
mod imp {
@ -48,7 +48,7 @@ impl NewSession {
/// Constructs a new `NewSession` with the given info.
pub fn new(stored_session: StoredSession) -> Self {
glib::Object::builder()
.property("info", BoxedStoredSession(stored_session))
.property("info", &stored_session)
.build()
}
}

View File

@ -1,23 +1,9 @@
use std::ops::Deref;
use gtk::{glib, prelude::*, subclass::prelude::*};
use ruma::{DeviceId, UserId};
use url::Url;
use crate::{secret::StoredSession, session::model::AvatarData};
#[derive(Clone, Debug, glib::Boxed)]
#[boxed_type(name = "BoxedStoredSession")]
pub struct BoxedStoredSession(pub StoredSession);
impl Deref for BoxedStoredSession {
type Target = StoredSession;
fn deref(&self) -> &Self::Target {
&self.0
}
}
mod imp {
use std::{cell::OnceCell, marker::PhantomData};
@ -43,7 +29,7 @@ mod imp {
pub struct SessionInfo {
/// The Matrix session's info.
#[property(get, construct_only)]
pub info: OnceCell<BoxedStoredSession>,
pub info: OnceCell<StoredSession>,
/// The Matrix session's user ID.
#[property(get = Self::user_id)]
pub user_id: PhantomData<String>,
@ -75,7 +61,7 @@ mod imp {
impl SessionInfo {
/// The Matrix session's info.
pub fn info(&self) -> &StoredSession {
&self.info.get().unwrap().0
self.info.get().unwrap()
}
/// The Matrix session's user ID.

View File

@ -417,6 +417,28 @@ impl<T> Drop for TokioDrop<T> {
}
}
impl<T: glib::Property> glib::Property for TokioDrop<T> {
type Value = T::Value;
}
impl<T> glib::PropertyGet for TokioDrop<T> {
type Value = T;
fn get<R, F: Fn(&Self::Value) -> R>(&self, f: F) -> R {
f(self.get().unwrap())
}
}
impl<T> glib::PropertySet for TokioDrop<T> {
type SetValue = T;
fn set(&self, v: Self::SetValue) {
if self.set(v).is_err() {
panic!("TokioDrop value was already set");
}
}
}
/// The state of a resource that can be loaded.
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, glib::Enum)]
#[enum_type(name = "LoadingState")]