uniui_core 0.0.4

Basic structures like Signal and Slot for uniui_* crates familiy
Documentation
use std::sync::mpsc::{
	self,
	Receiver,
	Sender,
	TryIter,
};

/// Slot represents a queue where data may be placed.
pub trait Slot<T> {
	/// Add new instance of data to the queue.
	///
	/// Return true if data was added or false if the other side is not interested
	/// in data receiving anymore (and never will be interested again).
	fn exec_for(
		&self,
		t: T,
	) -> bool;

	/// Creates [SlotProxy] for particular slot. The [SlotProxy] may be saved
	/// separatedly from the original [Slot] but still may be used to send new
	/// instance of data to the original [Slot]. [SlotProxy] do not provide
	/// any mechanism to retrive data from the queue.
	///
	/// Proxy created for another [SlotProxy] still will refer to the original [Slot].
	fn proxy(&self) -> SlotProxy<T>;
}


/// The main implementation for [Slot] trait. Allows to pull data from queue.
pub struct SlotImpl<T> {
	receiver: Receiver<T>,
	sender: Sender<T>,
}

impl<T> SlotImpl<T> {
	/// Creates new instance
	pub fn new() -> SlotImpl<T> {
		let (sender, receiver) = mpsc::channel();
		return SlotImpl {
			sender,
			receiver,
		};
	}

	/// Try to obtain next value from [SlotImpl]'s queue.
	pub fn next(&self) -> Option<T> {
		return self.receiver.try_recv().ok();
	}

	/// Return TryIter to access to the queue's content
	pub fn data_iter(&self) -> TryIter<T> {
		return self.receiver.try_iter();
	}

	/// Return last element from the queue
	pub fn last(&self) -> Option<T> {
		return self.data_iter().last();
	}

	/// Clean queue
	pub fn discard_pending(&self) {
		self.data_iter().last();
	}

	/// Add new data instance to the queue
	pub fn exec_for(
		&self,
		t: T,
	) -> bool {
		return match self.sender.send(t) {
			Ok(_) => {
				trace!("exec_for:ok");
				true
			},
			Err(e) => {
				warn!("exec_for:err:{:?}", e);
				false
			},
		};
	}

	/// Creates proxy which is refer to the [SlotImpl]
	pub fn proxy(&self) -> SlotProxy<T> {
		return SlotProxy {
			sender: self.sender.clone(),
		};
	}
}

impl<T> Slot<T> for SlotImpl<T> {
	fn exec_for(
		&self,
		t: T,
	) -> bool {
		return self.exec_for(t);
	}

	fn proxy(&self) -> SlotProxy<T> {
		return self.proxy();
	}
}

impl<T> Default for SlotImpl<T> {
	fn default() -> Self {
		return Self::new();
	}
}

/// [SlotProxy] may be used as independed reference to the original [Slot]'s queue.
#[derive(Clone)]
pub struct SlotProxy<T> {
	sender: Sender<T>,
}

impl<T> SlotProxy<T> {
	/// Create [SlotProxy] which is not coupled with any [SlotImpl]
	pub fn empty() -> SlotProxy<T> {
		let (sender, _) = mpsc::channel();
		return SlotProxy {
			sender,
		};
	}

	/// Put new data instance to the related [SlotImpl]'s queue
	pub fn exec_for(
		&self,
		t: T,
	) -> bool {
		return match self.sender.send(t) {
			Ok(_) => {
				trace!("exec_for:ok");
				true
			},
			Err(e) => {
				warn!("exec_for:err:{:?}", e);
				false
			},
		};
	}

	/// Create proxy which is refer to the same [SlotImpl]
	///
	/// It's improtant that [SlotProxy] doesn't organized in the chain. New
	/// [SlotProxy] will refer to the original [SlotImpl] and will not have any
	/// reference to the [SlotProxy].
	pub fn proxy(&self) -> SlotProxy<T> {
		return SlotProxy {
			sender: self.sender.clone(),
		};
	}
}

impl<T> Slot<T> for SlotProxy<T> {
	fn exec_for(
		&self,
		t: T,
	) -> bool {
		return self.exec_for(t);
	}

	fn proxy(&self) -> SlotProxy<T> {
		return self.proxy();
	}
}

impl<T> Default for SlotProxy<T> {
	fn default() -> Self {
		return Self::empty();
	}
}