Struct Action
pub struct Action<I, O> {
inner: ArenaItem<ArcAction<I, O>>,
}
Expand description
An action runs some asynchronous code when you dispatch a new value to it, and gives you reactive access to the result.
Actions are intended for mutating or updating data, not for loading data. If you find yourself creating an action and immediately dispatching a value to it, this is probably the wrong primitive.
The reference-counted, Clone
(but not Copy
version of an Action
is an ArcAction
.
async fn send_new_todo_to_api(task: String) -> usize {
// do something...
// return a task id
42
}
let save_data = Action::new(|task: &String| {
// `task` is given as `&String` because its value is available in `input`
send_new_todo_to_api(task.clone())
});
// the argument currently running
let input = save_data.input();
// the most recent returned result
let result_of_call = save_data.value();
// whether the call is pending
let pending = save_data.pending();
// how many times the action has run
// useful for reactively updating something else in response to a `dispatch` and response
let version = save_data.version();
// before we do anything
assert_eq!(input.get(), None); // no argument yet
assert_eq!(pending.get(), false); // isn't pending a response
assert_eq!(result_of_call.get(), None); // there's no "last value"
assert_eq!(version.get(), 0);
// dispatch the action
save_data.dispatch("My todo".to_string());
// when we're making the call
assert_eq!(input.get(), Some("My todo".to_string()));
assert_eq!(pending.get(), true); // is pending
assert_eq!(result_of_call.get(), None); // has not yet gotten a response
// after call has resolved
assert_eq!(input.get(), None); // input clears out after resolved
assert_eq!(pending.get(), false); // no longer pending
assert_eq!(result_of_call.get(), Some(42));
assert_eq!(version.get(), 1);
The input to the async
function should always be a single value,
but it can be of any type. The argument is always passed by reference to the
function, because it is stored in Action::input as well.
// if there's a single argument, just use that
let action1 = Action::new(|input: &String| {
let input = input.clone();
async move { todo!() }
});
// if there are no arguments, use the unit type `()`
let action2 = Action::new(|input: &()| async { todo!() });
// if there are multiple arguments, use a tuple
let action3 = Action::new(|input: &(usize, String)| async { todo!() });
Fields§
§inner: ArenaItem<ArcAction<I, O>>
Implementations§
§impl<I, O> Action<I, O>
impl<I, O> Action<I, O>
pub fn new<F, Fu>(action_fn: F) -> Action<I, O>
pub fn new<F, Fu>(action_fn: F) -> Action<I, O>
Creates a new action. This is lazy: it does not run the action function until some value is dispatched.
The constructor takes a function which will create a new Future
from some input data.
When the action is dispatched, this action_fn
will run, and the Future
it returns will
be spawned.
The action_fn
must be Send + Sync
so that the ArcAction
is Send + Sync
. The
Future
must be Send
so that it can be moved across threads by the async executor as
needed. In order to be stored in the Copy
arena, the input and output types should also
be Send + Sync
.
let act = Action::new(|n: &u8| {
let n = n.to_owned();
async move { n * 2 }
});
act.dispatch(3);
assert_eq!(act.input().get(), Some(3));
// Remember that async functions already return a future if they are
// not `await`ed. You can save keystrokes by leaving out the `async move`
let act2 = Action::new(|n: &String| yell(n.to_owned()));
act2.dispatch(String::from("i'm in a doctest"));
// after it resolves
assert_eq!(act2.value().get(), Some("I'M IN A DOCTEST".to_string()));
async fn yell(n: String) -> String {
n.to_uppercase()
}
pub fn new_with_value<F, Fu>(value: Option<O>, action_fn: F) -> Action<I, O>
pub fn new_with_value<F, Fu>(value: Option<O>, action_fn: F) -> Action<I, O>
Creates a new action, initializing it with the given value.
This is lazy: it does not run the action function until some value is dispatched.
The constructor takes a function which will create a new Future
from some input data.
When the action is dispatched, this action_fn
will run, and the Future
it returns will
be spawned.
The action_fn
must be Send + Sync
so that the ArcAction
is Send + Sync
. The
Future
must be Send
so that it can be moved across threads by the async executor as
needed. In order to be stored in the Copy
arena, the input and output types should also
be Send + Sync
.
§impl<I, O> Action<I, O>where
I: 'static,
O: 'static,
impl<I, O> Action<I, O>where
I: 'static,
O: 'static,
pub fn clear(&self)
pub fn clear(&self)
Clears the value of the action, setting its current value to None
.
This has no other effect: i.e., it will not cancel in-flight actions, set the input, etc.
§impl<I, O> Action<I, O>where
I: 'static,
O: 'static,
impl<I, O> Action<I, O>where
I: 'static,
O: 'static,
pub fn new_local<F, Fu>(action_fn: F) -> Action<I, O>
pub fn new_local<F, Fu>(action_fn: F) -> Action<I, O>
Creates a new action, which does not require its inputs or outputs to be Send
. In all other
ways, this is the same as Action::new
. If this action is accessed from outside the
thread on which it was created, it panics.
pub fn new_local_with_value<F, Fu>(
value: Option<O>,
action_fn: F,
) -> Action<I, O>
pub fn new_local_with_value<F, Fu>( value: Option<O>, action_fn: F, ) -> Action<I, O>
Creates a new action with the initial value, which does not require its inputs or outputs to be Send
. In all other
ways, this is the same as Action::new_with_value
. If this action is accessed from outside the
thread on which it was created, it panics.
§impl<I, O> Action<I, O>where
I: 'static,
O: 'static,
impl<I, O> Action<I, O>where
I: 'static,
O: 'static,
pub fn version(&self) -> RwSignal<usize>
pub fn version(&self) -> RwSignal<usize>
The number of times the action has successfully completed.
let act = Action::new(|n: &u8| {
let n = n.to_owned();
async move { n * 2 }
});
let version = act.version();
act.dispatch(3);
assert_eq!(version.get(), 0);
// after it resolves
assert_eq!(version.get(), 1);
pub fn pending(&self) -> Memo<bool>
pub fn pending(&self) -> Memo<bool>
Whether the action has been dispatched and is currently waiting to resolve.
let act = Action::new(|n: &u8| {
let n = n.to_owned();
async move { n * 2 }
});
let pending = act.pending();
assert_eq!(pending.get(), false);
act.dispatch(3);
assert_eq!(pending.get(), true);
// after it resolves
assert_eq!(pending.get(), false);
§impl<I, O> Action<I, O>where
I: 'static,
O: 'static,
impl<I, O> Action<I, O>where
I: 'static,
O: 'static,
pub fn input(&self) -> MappedSignal<Option<I>>
pub fn input(&self) -> MappedSignal<Option<I>>
The current argument that was dispatched to the async function. This value will
be Some
while we are waiting for it to resolve, and None
after it has resolved.
let act = Action::new(|n: &u8| {
let n = n.to_owned();
async move { n * 2 }
});
let input = act.input();
assert_eq!(input.get(), None);
act.dispatch(3);
assert_eq!(input.get(), Some(3));
// after it resolves
assert_eq!(input.get(), None);
pub fn input_local(&self) -> MappedSignal<Option<I>>
👎Deprecated: You can now use .input() for any value, whether it’s thread-safe or not.
pub fn input_local(&self) -> MappedSignal<Option<I>>
The current argument that was dispatched to the async function. This value will
be Some
while we are waiting for it to resolve, and None
after it has resolved.
Returns a thread-local signal using [LocalStorage
].
§impl<I, O> Action<I, O>where
I: 'static,
O: 'static,
impl<I, O> Action<I, O>where
I: 'static,
O: 'static,
pub fn value(&self) -> MappedSignal<Option<O>>
pub fn value(&self) -> MappedSignal<Option<O>>
The most recent return value of the async
function. This will be None
before
the action has ever run successfully, and subsequently will always be Some(_)
,
holding the old value until a new value has been received.
let act = Action::new(|n: &u8| {
let n = n.to_owned();
async move { n * 2 }
});
let value = act.value();
assert_eq!(value.get(), None);
act.dispatch(3);
assert_eq!(value.get(), None);
// after it resolves
assert_eq!(value.get(), Some(6));
// dispatch another value, and it still holds the old value
act.dispatch(3);
assert_eq!(value.get(), Some(6));
pub fn value_local(&self) -> MappedSignal<Option<O>>
👎Deprecated: You can now use .value() for any value, whether it’s thread-safe or not.
pub fn value_local(&self) -> MappedSignal<Option<O>>
The most recent return value of the async
function. This will be None
before
the action has ever run successfully, and subsequently will always be Some(_)
,
holding the old value until a new value has been received.
Returns a thread-local signal using [LocalStorage
].
§impl<I, O> Action<I, O>
impl<I, O> Action<I, O>
pub fn dispatch(&self, input: I) -> ActionAbortHandle
pub fn dispatch(&self, input: I) -> ActionAbortHandle
Calls the async
function with a reference to the input type as its argument.
§impl<I, O> Action<I, O>where
I: 'static,
O: 'static,
impl<I, O> Action<I, O>where
I: 'static,
O: 'static,
pub fn dispatch_local(&self, input: I) -> ActionAbortHandle
pub fn dispatch_local(&self, input: I) -> ActionAbortHandle
Calls the async
function with a reference to the input type as its argument.
§impl<I, O> Action<I, O>
impl<I, O> Action<I, O>
pub fn new_unsync<F, Fu>(action_fn: F) -> Action<I, O>
pub fn new_unsync<F, Fu>(action_fn: F) -> Action<I, O>
Creates a new action, which does not require the action itself to be Send
, but will run
it on the same thread it was created on.
In all other ways, this is identical to Action::new
.
pub fn new_unsync_with_value<F, Fu>(
value: Option<O>,
action_fn: F,
) -> Action<I, O>
pub fn new_unsync_with_value<F, Fu>( value: Option<O>, action_fn: F, ) -> Action<I, O>
Creates a new action, which does not require the action itself to be Send
, but will run
it on the same thread it was created on, and gives an initial value.
In all other ways, this is identical to Action::new
.
§impl<I, O> Action<I, O>where
I: 'static,
O: 'static,
impl<I, O> Action<I, O>where
I: 'static,
O: 'static,
pub fn new_unsync_local<F, Fu>(action_fn: F) -> Action<I, O>
pub fn new_unsync_local<F, Fu>(action_fn: F) -> Action<I, O>
Creates a new action, which neither requires the action itself nor the
value it returns to be Send
. If this action is accessed from outside the
thread on which it was created, it panics.
This combines the features of Action::new_local
and Action::new_unsync
.
pub fn new_unsync_local_with_value<F, Fu>(
value: Option<O>,
action_fn: F,
) -> Action<I, O>
pub fn new_unsync_local_with_value<F, Fu>( value: Option<O>, action_fn: F, ) -> Action<I, O>
Creates a new action, which neither requires the action itself nor the
value it returns to be Send
, and provides it with an initial value.
If this action is accessed from outside the thread on which it was created, it panics.
This combines the features of Action::new_local_with_value
and
Action::new_unsync_with_value
.
Trait Implementations§
§impl<I, O> DefinedAt for Action<I, O>
impl<I, O> DefinedAt for Action<I, O>
§fn defined_at(&self) -> Option<&'static Location<'static>>
fn defined_at(&self) -> Option<&'static Location<'static>>
None
in
release mode.§impl<S> From<ServerAction<S>> for Action<S, Result<<S as ServerFn>::Output, <S as ServerFn>::Error>>
impl<S> From<ServerAction<S>> for Action<S, Result<<S as ServerFn>::Output, <S as ServerFn>::Error>>
impl<I, O> Copy for Action<I, O>
Auto Trait Implementations§
impl<I, O> Freeze for Action<I, O>
impl<I, O> RefUnwindSafe for Action<I, O>
impl<I, O> Send for Action<I, O>
impl<I, O> Sync for Action<I, O>
impl<I, O> Unpin for Action<I, O>
impl<I, O> UnwindSafe for Action<I, O>
Blanket Implementations§
Source§impl<S, D, Swp, Dwp, T> AdaptInto<D, Swp, Dwp, T> for Swhere
T: Real + Zero + Arithmetics + Clone,
Swp: WhitePoint<T>,
Dwp: WhitePoint<T>,
D: AdaptFrom<S, Swp, Dwp, T>,
impl<S, D, Swp, Dwp, T> AdaptInto<D, Swp, Dwp, T> for Swhere
T: Real + Zero + Arithmetics + Clone,
Swp: WhitePoint<T>,
Dwp: WhitePoint<T>,
D: AdaptFrom<S, Swp, Dwp, T>,
Source§fn adapt_into_using<M>(self, method: M) -> Dwhere
M: TransformMatrix<T>,
fn adapt_into_using<M>(self, method: M) -> Dwhere
M: TransformMatrix<T>,
Source§fn adapt_into(self) -> D
fn adapt_into(self) -> D
§impl<T> ArchivePointee for T
impl<T> ArchivePointee for T
§type ArchivedMetadata = ()
type ArchivedMetadata = ()
§fn pointer_metadata(
_: &<T as ArchivePointee>::ArchivedMetadata,
) -> <T as Pointee>::Metadata
fn pointer_metadata( _: &<T as ArchivePointee>::ArchivedMetadata, ) -> <T as Pointee>::Metadata
Source§impl<T, C> ArraysFrom<C> for Twhere
C: IntoArrays<T>,
impl<T, C> ArraysFrom<C> for Twhere
C: IntoArrays<T>,
Source§fn arrays_from(colors: C) -> T
fn arrays_from(colors: C) -> T
Source§impl<T, C> ArraysInto<C> for Twhere
C: FromArrays<T>,
impl<T, C> ArraysInto<C> for Twhere
C: FromArrays<T>,
Source§fn arrays_into(self) -> C
fn arrays_into(self) -> C
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<WpParam, T, U> Cam16IntoUnclamped<WpParam, T> for Uwhere
T: FromCam16Unclamped<WpParam, U>,
impl<WpParam, T, U> Cam16IntoUnclamped<WpParam, T> for Uwhere
T: FromCam16Unclamped<WpParam, U>,
Source§type Scalar = <T as FromCam16Unclamped<WpParam, U>>::Scalar
type Scalar = <T as FromCam16Unclamped<WpParam, U>>::Scalar
parameters
when converting.Source§fn cam16_into_unclamped(
self,
parameters: BakedParameters<WpParam, <U as Cam16IntoUnclamped<WpParam, T>>::Scalar>,
) -> T
fn cam16_into_unclamped( self, parameters: BakedParameters<WpParam, <U as Cam16IntoUnclamped<WpParam, T>>::Scalar>, ) -> T
self
into C
, using the provided parameters.Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T, C> ComponentsFrom<C> for Twhere
C: IntoComponents<T>,
impl<T, C> ComponentsFrom<C> for Twhere
C: IntoComponents<T>,
Source§fn components_from(colors: C) -> T
fn components_from(colors: C) -> T
§impl<F, W, T, D> Deserialize<With<T, W>, D> for F
impl<F, W, T, D> Deserialize<With<T, W>, D> for F
§fn deserialize(
&self,
deserializer: &mut D,
) -> Result<With<T, W>, <D as Fallible>::Error>
fn deserialize( &self, deserializer: &mut D, ) -> Result<With<T, W>, <D as Fallible>::Error>
§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait>
(where Trait: Downcast
) to Box<dyn Any>
, which can then be
downcast
into Box<dyn ConcreteType>
where ConcreteType
implements Trait
.§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait>
(where Trait: Downcast
) to Rc<Any>
, which can then be further
downcast
into Rc<ConcreteType>
where ConcreteType
implements Trait
.§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &Any
’s vtable from &Trait
’s.§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &mut Any
’s vtable from &mut Trait
’s.§impl<T> DowncastSend for T
impl<T> DowncastSend for T
§impl<T> DowncastSync for T
impl<T> DowncastSync for T
Source§impl<T> FromAngle<T> for T
impl<T> FromAngle<T> for T
Source§fn from_angle(angle: T) -> T
fn from_angle(angle: T) -> T
angle
.Source§impl<T, U> FromStimulus<U> for Twhere
U: IntoStimulus<T>,
impl<T, U> FromStimulus<U> for Twhere
U: IntoStimulus<T>,
Source§fn from_stimulus(other: U) -> T
fn from_stimulus(other: U) -> T
other
into Self
, while performing the appropriate scaling,
rounding and clamping.§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§impl<T, U> IntoAngle<U> for Twhere
U: FromAngle<T>,
impl<T, U> IntoAngle<U> for Twhere
U: FromAngle<T>,
Source§fn into_angle(self) -> U
fn into_angle(self) -> U
T
.Source§impl<WpParam, T, U> IntoCam16Unclamped<WpParam, T> for Uwhere
T: Cam16FromUnclamped<WpParam, U>,
impl<WpParam, T, U> IntoCam16Unclamped<WpParam, T> for Uwhere
T: Cam16FromUnclamped<WpParam, U>,
Source§type Scalar = <T as Cam16FromUnclamped<WpParam, U>>::Scalar
type Scalar = <T as Cam16FromUnclamped<WpParam, U>>::Scalar
parameters
when converting.Source§fn into_cam16_unclamped(
self,
parameters: BakedParameters<WpParam, <U as IntoCam16Unclamped<WpParam, T>>::Scalar>,
) -> T
fn into_cam16_unclamped( self, parameters: BakedParameters<WpParam, <U as IntoCam16Unclamped<WpParam, T>>::Scalar>, ) -> T
self
into C
, using the provided parameters.Source§impl<T, U> IntoColor<U> for Twhere
U: FromColor<T>,
impl<T, U> IntoColor<U> for Twhere
U: FromColor<T>,
Source§fn into_color(self) -> U
fn into_color(self) -> U
Source§impl<T, U> IntoColorUnclamped<U> for Twhere
U: FromColorUnclamped<T>,
impl<T, U> IntoColorUnclamped<U> for Twhere
U: FromColorUnclamped<T>,
Source§fn into_color_unclamped(self) -> U
fn into_color_unclamped(self) -> U
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self
into a Left
variant of Either<Self, Self>
if into_left
is true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self
into a Left
variant of Either<Self, Self>
if into_left(&self)
returns true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> IntoStimulus<T> for T
impl<T> IntoStimulus<T> for T
Source§fn into_stimulus(self) -> T
fn into_stimulus(self) -> T
self
into T
, while performing the appropriate scaling,
rounding and clamping.§impl<T> Pointable for T
impl<T> Pointable for T
§impl<T> Pointee for T
impl<T> Pointee for T
§impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> PolicyExt for Twhere
T: ?Sized,
§impl<T> SerializableKey for T
impl<T> SerializableKey for T
§impl<T> StorageAccess<T> for T
impl<T> StorageAccess<T> for T
§fn as_borrowed(&self) -> &T
fn as_borrowed(&self) -> &T
§fn into_taken(self) -> T
fn into_taken(self) -> T
Source§impl<T, C> TryComponentsInto<C> for Twhere
C: TryFromComponents<T>,
impl<T, C> TryComponentsInto<C> for Twhere
C: TryFromComponents<T>,
Source§type Error = <C as TryFromComponents<T>>::Error
type Error = <C as TryFromComponents<T>>::Error
try_into_colors
fails to cast.Source§fn try_components_into(self) -> Result<C, <T as TryComponentsInto<C>>::Error>
fn try_components_into(self) -> Result<C, <T as TryComponentsInto<C>>::Error>
Source§impl<T, U> TryIntoColor<U> for Twhere
U: TryFromColor<T>,
impl<T, U> TryIntoColor<U> for Twhere
U: TryFromColor<T>,
Source§fn try_into_color(self) -> Result<U, OutOfBounds<U>>
fn try_into_color(self) -> Result<U, OutOfBounds<U>>
OutOfBounds
error is returned which contains
the unclamped color. Read more