kas-core 0.12.1

KAS GUI / core
Documentation
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License in the LICENSE-APACHE file or at:
//     https://www.apache.org/licenses/LICENSE-2.0

//! Traits for shared data objects

#[allow(unused)] // doc links
use crate::event::Event;
use crate::event::EventMgr;
use crate::{autoimpl, WidgetId};
use std::borrow::{Borrow, BorrowMut};
#[allow(unused)] // doc links
use std::cell::RefCell;
use std::fmt::Debug;

/// Bounds on the key type
pub trait DataKey: Clone + Debug + PartialEq + Eq + 'static {}
impl<Key: Clone + Debug + PartialEq + Eq + 'static> DataKey for Key {}

/// Trait for shared data
///
/// By design, all methods take only `&self` and only allow immutable access to
/// data. See also [`SharedDataMut`].
#[autoimpl(for<T: trait + ?Sized>
    &T, &mut T, std::rc::Rc<T>, std::sync::Arc<T>, Box<T>)]
pub trait SharedData: Debug {
    /// Key type
    type Key: DataKey;

    /// Item type
    type Item: Clone + Debug + 'static;

    /// A borrow of the item type
    ///
    /// This type must support [`Borrow`] over [`Self::Item`]. This is, for
    /// example, supported by `Self::Item` and `&Self::Item`.
    ///
    /// It is also recommended (but not required) that the type support
    /// [`std::ops::Deref`]: this allows easier usage of [`Self::borrow`].
    ///
    /// TODO(spec): once Rust supports some form of specialization, `AsRef` will
    /// presumably get blanket impls over `T` and `&T`, and will then be more
    /// appropriate to use than `Borrow`.
    type ItemRef<'b>: Borrow<Self::Item>
    where
        Self: 'b;

    /// Get the data version
    ///
    /// The version is increased on change and may be used to detect when views
    /// over the data need to be refreshed. The initial version number must be
    /// at least 1 (allowing 0 to represent an uninitialized state).
    ///
    /// Whenever the data is updated, [`Event::Update`] must be sent via
    /// [`EventMgr::update_all`] to notify other users of this data of the
    /// update.
    fn version(&self) -> u64;

    /// Check whether a key has data
    fn contains_key(&self, key: &Self::Key) -> bool;

    /// Borrow an item by `key`
    ///
    /// Returns `None` if `key` has no associated item.
    ///
    /// Depending on the implementation, this may involve some form of lock
    /// such as `RefCell::borrow` or `Mutex::lock`. The implementation should
    /// panic on lock failure, not return `None`.
    fn borrow(&self, key: &Self::Key) -> Option<Self::ItemRef<'_>>;

    /// Access a borrow of an item
    ///
    /// This is a convenience method over [`Self::borrow`].
    fn with_ref<V>(&self, key: &Self::Key, f: impl FnOnce(&Self::Item) -> V) -> Option<V>
    where
        Self: Sized,
    {
        self.borrow(key).map(|borrow| f(borrow.borrow()))
    }

    /// Get data by key (clone)
    ///
    /// Returns `None` if `key` has no associated item.
    ///
    /// This has a default implementation over [`Self::borrow`].
    #[inline]
    fn get_cloned(&self, key: &Self::Key) -> Option<Self::Item> {
        self.borrow(key).map(|r| r.borrow().to_owned())
    }
}

/// Trait for shared mutable data
///
/// By design, all methods take only `&self`: since data is shared, an internal
/// locking or synchronization mechanism is required (e.g. `RefCell` or `Mutex`).
#[autoimpl(for<T: trait + ?Sized>
    &T, &mut T, std::rc::Rc<T>, std::sync::Arc<T>, Box<T>)]
pub trait SharedDataMut: SharedData {
    /// A mutable borrow of the item type
    ///
    /// This type must support [`BorrowMut`] over [`SharedData::Item`]. This is, for
    /// example, supported by `&mut Self::Item`.
    ///
    /// It is also recommended (but not required) that the type support
    /// [`std::ops::DerefMut`]: this allows easier usage of [`Self::borrow_mut`].
    type ItemRefMut<'b>: BorrowMut<Self::Item>
    where
        Self: 'b;

    /// Mutably borrow an item by `key` and notify of an update
    ///
    /// Returns `None` if the data is by design not mutable or if `key` has no
    /// associated item. Otherwise, this notifies
    /// users of a data update (by calling [`EventMgr::update_all`] *and*
    /// incrementing the number returned by [`SharedData::version`]).
    ///
    /// Depending on the implementation, this may involve some form of lock
    /// such as `RefCell::borrow_mut` or `Mutex::lock`. The implementation
    /// should panic on lock failure, not return `None`.
    ///
    /// Note: implementations of the return type *might* rely on [`Drop`] for
    /// synchronization. Failing to drop the return value may thus cause errors.
    fn borrow_mut(&self, mgr: &mut EventMgr, key: &Self::Key) -> Option<Self::ItemRefMut<'_>>;

    /// Access a mutable borrow of an item
    ///
    /// This is a convenience method over [`Self::borrow_mut`].
    fn with_ref_mut<V>(
        &self,
        mgr: &mut EventMgr,
        key: &Self::Key,
        f: impl FnOnce(&mut Self::Item) -> V,
    ) -> Option<V>
    where
        Self: Sized,
    {
        self.borrow_mut(mgr, key)
            .map(|mut borrow| f(borrow.borrow_mut()))
    }

    /// Set an item
    ///
    /// This is a convenience method over [`Self::borrow_mut`].
    #[inline]
    fn set(&self, mgr: &mut EventMgr, key: &Self::Key, item: Self::Item) {
        if let Some(mut borrow) = self.borrow_mut(mgr, key) {
            *borrow.borrow_mut() = item;
        }
    }
}

/// Trait bound for viewable single data
///
/// This is automatically implemented for every type implementing `SharedData<()>`.
///
/// Provided implementations: [`SharedRc`](super::SharedRc),
/// [`SharedArc`](super::SharedArc).
// TODO(trait aliases): make this an actual trait alias
pub trait SingleData: SharedData<Key = ()> {}
impl<T: SharedData<Key = ()>> SingleData for T {}

/// Trait bound for mutable single data
///
/// This is automatically implemented for every type implementing `SharedDataMut<()>`.
///
/// Provided implementations: [`SharedRc`](super::SharedRc),
/// [`SharedArc`](super::SharedArc).
// TODO(trait aliases): make this an actual trait alias
pub trait SingleDataMut: SharedDataMut<Key = ()> {}
impl<T: SharedDataMut<Key = ()>> SingleDataMut for T {}

/// Trait for viewable data lists
///
/// Provided implementations: `[T]`, `Vec<T>`.
#[allow(clippy::len_without_is_empty)]
#[autoimpl(for<T: trait + ?Sized> &T, &mut T, std::rc::Rc<T>, std::sync::Arc<T>, Box<T>)]
pub trait ListData: SharedData {
    type KeyIter<'b>: Iterator<Item = Self::Key>
    where
        Self: 'b;

    /// No data is available
    fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Number of data items available
    ///
    /// Note: users may assume this is `O(1)`.
    fn len(&self) -> usize;

    /// Make a [`WidgetId`] for a key
    ///
    /// Suggested impl, converting `key` as necessary:
    ///
    /// -   `parent.make_child(key)`
    ///
    /// See: [`WidgetId::make_child`]
    fn make_id(&self, parent: &WidgetId, key: &Self::Key) -> WidgetId;

    /// Reconstruct a key from a [`WidgetId`]
    ///
    /// Where `child` is the output of [`Self::make_id`] for the same `parent`
    /// *or any [`WidgetId`] descended from that*, this should return a copy of
    /// the `key` passed to `make_id`.
    ///
    /// See: [`WidgetId::next_key_after`], [`WidgetId::iter_keys_after`]
    fn reconstruct_key(&self, parent: &WidgetId, child: &WidgetId) -> Option<Self::Key>;

    /// Iterate over keys
    ///
    /// The result will be in deterministic implementation-defined order, with
    /// a length of `max(limit, data_len)` where `data_len` is the number of
    /// items available.
    #[inline]
    fn iter_limit(&self, limit: usize) -> Self::KeyIter<'_> {
        self.iter_from(0, limit)
    }

    /// Iterate over keys from an arbitrary start-point
    ///
    /// The result is the same as `self.iter_limit(start + limit).skip(start)`.
    fn iter_from(&self, start: usize, limit: usize) -> Self::KeyIter<'_>;
}

/// Trait for viewable data matrices
///
/// Data matrices are a kind of table where each cell has the same type.
#[autoimpl(for<T: trait + ?Sized> &T, &mut T, std::rc::Rc<T>, std::sync::Arc<T>, Box<T>)]
pub trait MatrixData: SharedData {
    /// Column key type
    type ColKey: DataKey;
    /// Row key type
    type RowKey: DataKey;

    type ColKeyIter<'b>: Iterator<Item = Self::ColKey>
    where
        Self: 'b;
    type RowKeyIter<'b>: Iterator<Item = Self::RowKey>
    where
        Self: 'b;

    /// No data is available
    fn is_empty(&self) -> bool;

    /// Number of `(cols, rows)` available
    ///
    /// Note: users may assume this is `O(1)`.
    fn len(&self) -> (usize, usize);

    /// Make a [`WidgetId`] for a key
    ///
    /// Suggested impls, converting keys as necessary:
    ///
    /// -   `parent.make_child(combined_key)`
    /// -   `parent.make_child(col_key).make_child(row_key)`
    ///
    /// See: [`WidgetId::make_child`]
    fn make_id(&self, parent: &WidgetId, key: &Self::Key) -> WidgetId;

    /// Reconstruct a key from a [`WidgetId`]
    ///
    /// Where `child` is the output of [`Self::make_id`] for the same `parent`
    /// *or any [`WidgetId`] descended from that*, this should return a copy of
    /// the `key` passed to `make_id`.
    ///
    /// See: [`WidgetId::next_key_after`], [`WidgetId::iter_keys_after`]
    fn reconstruct_key(&self, parent: &WidgetId, child: &WidgetId) -> Option<Self::Key>;

    /// Iterate over column keys
    ///
    /// The result will be in deterministic implementation-defined order, with
    /// a length of `max(limit, data_len)` where `data_len` is the number of
    /// items available.
    #[inline]
    fn col_iter_limit(&self, limit: usize) -> Self::ColKeyIter<'_> {
        self.col_iter_from(0, limit)
    }

    /// Iterate over column keys from an arbitrary start-point
    ///
    /// The result is the same as `self.iter_limit(start + limit).skip(start)`.
    fn col_iter_from(&self, start: usize, limit: usize) -> Self::ColKeyIter<'_>;

    /// Iterate over row keys
    ///
    /// The result will be in deterministic implementation-defined order, with
    /// a length of `max(limit, data_len)` where `data_len` is the number of
    /// items available.
    #[inline]
    fn row_iter_limit(&self, limit: usize) -> Self::RowKeyIter<'_> {
        self.row_iter_from(0, limit)
    }

    /// Iterate over row keys from an arbitrary start-point
    ///
    /// The result is the same as `self.iter_limit(start + limit).skip(start)`.
    fn row_iter_from(&self, start: usize, limit: usize) -> Self::RowKeyIter<'_>;

    /// Make a key from parts
    fn make_key(col: &Self::ColKey, row: &Self::RowKey) -> Self::Key;
}