use crate::{Receiver, Sender};
use crate::factory::sync::builder::FactoryBuilder;
use crate::factory::sync::handle::FactoryHandle;
use crate::factory::{CloneableFactoryComponent, FactoryComponent, FactoryView};
use std::collections::HashMap;
use std::collections::hash_map::RandomState;
use std::hash::{BuildHasher, Hash, Hasher};
use std::iter::FusedIterator;
use std::marker::PhantomData;
use std::ops;
use gtk::prelude::IsA;
#[derive(Debug)]
#[must_use]
pub struct FactoryElementGuard<'a, C>
where
C: FactoryComponent,
{
inner: &'a mut FactoryHandle<C>,
}
impl<C> ops::Deref for FactoryElementGuard<'_, C>
where
C: FactoryComponent,
{
type Target = C;
fn deref(&self) -> &Self::Target {
self.inner.data.get()
}
}
impl<C> ops::DerefMut for FactoryElementGuard<'_, C>
where
C: FactoryComponent,
{
fn deref_mut(&mut self) -> &mut Self::Target {
self.inner.data.get_mut()
}
}
impl<C> Drop for FactoryElementGuard<'_, C>
where
C: FactoryComponent,
{
fn drop(&mut self) {
self.inner.notifier.send(()).unwrap()
}
}
#[derive(Debug)]
pub struct FactoryHashMapBuilder<K, C: FactoryComponent, S = RandomState> {
hasher: S,
component: PhantomData<C>,
key: PhantomData<K>,
}
impl<K, C> Default for FactoryHashMapBuilder<K, C>
where
C: FactoryComponent,
{
fn default() -> Self {
Self::new()
}
}
impl<K, C> FactoryHashMapBuilder<K, C>
where
C: FactoryComponent,
C::ParentWidget: Default,
{
#[must_use]
pub fn launch_default(self) -> FactoryHashMapConnector<K, C> {
self.launch(Default::default())
}
}
impl<K, C> FactoryHashMapBuilder<K, C>
where
C: FactoryComponent,
{
#[must_use]
pub fn new() -> Self {
Self {
hasher: RandomState::default(),
component: PhantomData,
key: PhantomData,
}
}
pub fn hasher<H: Hasher>(self, hasher: H) -> FactoryHashMapBuilder<K, C, H> {
let Self { component, key, .. } = self;
FactoryHashMapBuilder {
hasher,
component,
key,
}
}
pub fn launch(self, widget: C::ParentWidget) -> FactoryHashMapConnector<K, C> {
let Self { hasher, key, .. } = self;
let (output_sender, output_receiver) = crate::channel();
FactoryHashMapConnector {
widget,
output_sender,
output_receiver,
hasher,
_key: key,
}
}
}
#[derive(Debug)]
pub struct FactoryHashMapConnector<K, C, S = RandomState>
where
C: FactoryComponent,
{
widget: C::ParentWidget,
output_sender: Sender<C::Output>,
output_receiver: Receiver<C::Output>,
hasher: S,
_key: PhantomData<K>,
}
impl<K, C> FactoryHashMapConnector<K, C>
where
C: FactoryComponent,
{
pub fn forward<F, Msg>(self, sender_: &Sender<Msg>, f: F) -> FactoryHashMap<K, C>
where
F: Fn(C::Output) -> Msg + Send + 'static,
C::Output: Send,
Msg: Send + 'static,
{
let Self {
widget,
output_sender,
output_receiver,
hasher,
..
} = self;
let sender_clone = sender_.clone();
crate::spawn(async move {
while let Some(msg) = output_receiver.recv().await {
if sender_clone.send(f(msg)).is_err() {
break;
}
}
});
FactoryHashMap {
widget,
output_sender,
inner: HashMap::with_hasher(hasher),
}
}
pub fn detach(self) -> FactoryHashMap<K, C> {
let Self {
widget,
output_sender,
hasher,
..
} = self;
FactoryHashMap {
widget,
output_sender,
inner: HashMap::with_hasher(hasher),
}
}
}
#[derive(Debug)]
pub struct FactoryHashMap<K, C: FactoryComponent, S = RandomState> {
widget: C::ParentWidget,
output_sender: Sender<C::Output>,
inner: HashMap<K, FactoryHandle<C>, S>,
}
impl<K, C, S> Drop for FactoryHashMap<K, C, S>
where
C: FactoryComponent,
{
fn drop(&mut self) {
self.clear();
}
}
impl<K, C, S> ops::Index<&K> for FactoryHashMap<K, C, S>
where
C: FactoryComponent<Index = K>,
K: Hash + Eq,
S: BuildHasher,
{
type Output = C;
fn index(&self, key: &K) -> &Self::Output {
self.get(key).expect("Called `get` on an invalid key")
}
}
impl<K, C> FactoryHashMap<K, C, RandomState>
where
C: FactoryComponent,
{
#[must_use]
pub fn builder() -> FactoryHashMapBuilder<K, C> {
FactoryHashMapBuilder::new()
}
}
impl<K, C, S> FactoryHashMap<K, C, S>
where
C: FactoryComponent,
{
pub fn len(&self) -> usize {
self.inner.len()
}
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
pub fn broadcast(&self, msg: C::Input)
where
C::Input: Clone,
{
self.inner.values().for_each(|c| c.input.emit(msg.clone()));
}
pub const fn widget(&self) -> &C::ParentWidget {
&self.widget
}
pub fn iter(&self) -> impl ExactSizeIterator<Item = (&K, &C)> + FusedIterator {
self.inner.iter().map(|(k, c)| (k, c.data.get()))
}
pub fn values(&self) -> impl ExactSizeIterator<Item = &C> + FusedIterator {
self.inner.values().map(|c| c.data.get())
}
pub fn keys(&self) -> impl ExactSizeIterator<Item = &K> + FusedIterator {
self.inner.keys()
}
pub fn clear(&mut self) {
for (_, handle) in self.inner.drain() {
self.widget.factory_remove(&handle.returned_widget);
}
}
}
impl<K, C> FactoryHashMap<K, C, RandomState>
where
C: FactoryComponent<Index = K>,
K: Hash + Eq,
{
pub fn from_vec(component_vec: Vec<(K, C::Init)>, widget: C::ParentWidget) -> Self {
let mut output = Self::builder().launch(widget).detach();
for (key, init) in component_vec {
output.insert(key, init);
}
output
}
}
impl<K, C, S> FactoryHashMap<K, C, S>
where
C: FactoryComponent<Index = K>,
K: Hash + Eq,
S: BuildHasher,
{
pub fn send(&self, key: &K, msg: C::Input) {
self.inner[key].input.emit(msg);
}
pub fn get(&self, key: &K) -> Option<&C> {
self.inner.get(key).map(|c| c.data.get())
}
pub fn get_mut(&mut self, key: &K) -> Option<FactoryElementGuard<'_, C>> {
self.inner
.get_mut(key)
.map(|c| FactoryElementGuard { inner: c })
}
pub fn insert(&mut self, key: K, init: C::Init) -> Option<C> {
let existing = self.remove(&key);
let builder = FactoryBuilder::new(&key, init, self.output_sender.clone());
let position = C::position(&builder.data, &key);
let returned_widget = self
.widget
.factory_append(builder.root_widget.clone(), &position);
let component = builder.launch(&key, returned_widget);
assert!(self.inner.insert(key, component).is_none());
existing
}
pub fn remove(&mut self, key: &K) -> Option<C> {
if let Some(handle) = self.inner.remove(key) {
self.widget.factory_remove(&handle.returned_widget);
Some(handle.data.into_inner())
} else {
None
}
}
}
impl<K, C> Clone for FactoryHashMap<K, C, RandomState>
where
C: CloneableFactoryComponent,
K: Clone + Hash + Eq,
C: FactoryComponent<Index = K>,
{
fn clone(&self) -> Self {
let mut clone = FactoryHashMap::builder()
.launch(self.widget.clone())
.detach();
for (k, item) in self.iter() {
let init = C::get_init(item);
clone.insert(k.clone(), init);
}
clone
}
}
impl<K, C> FactoryHashMap<K, C, RandomState>
where
C: FactoryComponent,
K: Clone + Hash + Eq,
C::ParentWidget: IsA<gtk::Stack>,
C::Root: IsA<gtk::Widget>,
{
pub fn set_visible(&self, key: &K) -> bool {
if let Some(handle) = self.inner.get(key) {
self.widget
.as_ref()
.set_visible_child(handle.root_widget.as_ref());
true
} else {
false
}
}
}