use futures_signals::signal::{Signal, SignalExt};
use std::marker::Unpin;
use std::pin::Pin;
use std::rc::Rc;
use std::sync::Arc;
use std::task::{Context, Poll};
pub type BoxSignalFn<T> = Box<dyn Fn() -> Pin<Box<dyn Signal<Item = T>>>>;
pub fn box_signal_fn<T, S: Signal<Item = T> + 'static>(
f: impl Fn() -> S + 'static,
) -> BoxSignalFn<T> {
Box::new(move || Box::pin(f()))
}
pub type RcSignalFn<T> = Rc<dyn Fn() -> Pin<Box<dyn Signal<Item = T>>>>;
pub fn rc_signal_fn<T, S: Signal<Item = T> + 'static>(
f: impl Fn() -> S + 'static,
) -> RcSignalFn<T> {
Rc::new(move || Box::pin(f()))
}
pub type ArcSignalFn<T> = Arc<dyn Fn() -> Pin<Box<dyn Signal<Item = T>>>>;
pub fn arc_signal_fn<T, S: Signal<Item = T> + 'static>(
f: impl Fn() -> S + 'static,
) -> ArcSignalFn<T> {
Arc::new(move || Box::pin(f()))
}
pub struct DefaultSignal<S, T>
where
S: Signal<Item = T>,
{
default: Option<T>,
value_signal: Option<S>,
const_has_fired: bool,
}
impl<S, T> DefaultSignal<S, T>
where
S: Signal<Item = T>,
{
pub fn new(default: T, value_signal: Option<S>) -> Self {
Self {
default: Some(default),
value_signal,
const_has_fired: false,
}
}
}
impl<S, T> Signal for DefaultSignal<S, T>
where
S: Signal<Item = T> + Unpin,
T: Unpin,
{
type Item = T;
fn poll_change(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
let _self = self.get_mut();
match &mut _self.value_signal {
None => {
if _self.const_has_fired {
Poll::Ready(None)
} else {
_self.const_has_fired = true;
Poll::Ready(_self.default.take())
}
}
Some(value_signal) => value_signal.poll_change_unpin(cx),
}
}
}
pub struct OptionSignal<S, T>
where
S: Signal<Item = T>,
{
value_signal: Option<S>,
const_has_fired: bool,
}
impl<S, T> OptionSignal<S, T>
where
S: Signal<Item = T>,
{
pub fn new(value_signal: Option<S>) -> Self {
Self {
value_signal,
const_has_fired: false,
}
}
}
impl<S, T> Signal for OptionSignal<S, T>
where
S: Signal<Item = T> + Unpin,
T: Unpin,
{
type Item = Option<T>;
fn poll_change(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
let _self = self.get_mut();
match &mut _self.value_signal {
None => {
if _self.const_has_fired {
Poll::Ready(None)
} else {
_self.const_has_fired = true;
Poll::Ready(Some(None))
}
}
Some(value_signal) => {
value_signal
.poll_change_unpin(cx)
.map(|value| value.map(|value| Some(value)))
}
}
}
}
pub enum EitherSignal<Left, Right> {
Left(Left),
Right(Right),
}
impl<Left, Right, T> Signal for EitherSignal<Left, Right>
where
Left: Signal<Item = T> + Unpin,
Right: Signal<Item = T> + Unpin,
{
type Item = T;
fn poll_change(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
match self.get_mut() {
Self::Left(x) => x.poll_change_unpin(cx),
Self::Right(x) => x.poll_change_unpin(cx),
}
}
}
#[cfg(feature = "dom")]
pub mod dom {
use awsm_web::dom::resize::ResizeObserver;
use futures_signals::signal::{channel, Receiver, Signal, SignalExt};
use std::pin::Pin;
use std::task::{Context, Poll};
use web_sys::{DomRect, Element};
pub struct DomRectSignal {
_observer: ResizeObserver,
receiver: Receiver<DomRect>,
}
impl Signal for DomRectSignal {
type Item = DomRect;
#[inline]
fn poll_change(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
self.receiver.poll_change_unpin(cx)
}
}
impl DomRectSignal {
pub fn new(element: &Element) -> Self {
let (sender, receiver) = channel(element.get_bounding_client_rect());
let observer = {
let element = element.clone();
ResizeObserver::new_simple(move || {
sender.send(element.get_bounding_client_rect()).unwrap();
})
};
observer.observe(element);
Self {
_observer: observer,
receiver,
}
}
}
pub struct DomRectMultiSignal {
_observer: ResizeObserver,
receiver: Receiver<Vec<DomRect>>,
}
impl Signal for DomRectMultiSignal {
type Item = Vec<DomRect>;
#[inline]
fn poll_change(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
self.receiver.poll_change_unpin(cx)
}
}
impl DomRectMultiSignal {
pub fn new(elements: &[Element]) -> Self {
let init_sizes = elements
.iter()
.map(|elem| elem.get_bounding_client_rect())
.collect();
let (sender, receiver) = channel(init_sizes);
let observer = {
ResizeObserver::new(
move |entries| {
let sizes = entries
.into_iter()
.map(|entry| entry.content_rect)
.collect();
sender.send(sizes).unwrap();
},
None,
)
};
for element in elements {
observer.observe(element);
}
Self {
_observer: observer,
receiver,
}
}
}
}