Make Xilem Views `must_use` (#742)

Also fixes `unused_qualifications` as an easy fix.

---------

Co-authored-by: Kaur Kuut <strom@nevermore.ee>
This commit is contained in:
Daniel McNab 2024-11-12 11:12:27 +00:00 committed by GitHub
parent 751bd62765
commit 41207effce
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
24 changed files with 37 additions and 23 deletions

View File

@ -33,9 +33,7 @@ type MessagePackage = (Arc<[ViewId]>, DynMessage);
impl RawProxy for MasonryProxy { impl RawProxy for MasonryProxy {
fn send_message(&self, path: Arc<[ViewId]>, message: DynMessage) -> Result<(), ProxyError> { fn send_message(&self, path: Arc<[ViewId]>, message: DynMessage) -> Result<(), ProxyError> {
match self match self.0.send_event(MasonryUserEvent::Action(
.0
.send_event(event_loop_runner::MasonryUserEvent::Action(
async_action(path, message), async_action(path, message),
ASYNC_MARKER_WIDGET, ASYNC_MARKER_WIDGET,
)) { )) {
@ -74,7 +72,7 @@ where
fn on_action( fn on_action(
&mut self, &mut self,
masonry_ctx: &mut masonry::DriverCtx<'_>, masonry_ctx: &mut masonry::DriverCtx<'_>,
widget_id: masonry::WidgetId, widget_id: WidgetId,
action: masonry::Action, action: masonry::Action,
) { ) {
let message_result = if widget_id == ASYNC_MARKER_WIDGET { let message_result = if widget_id == ASYNC_MARKER_WIDGET {

View File

@ -18,12 +18,13 @@
)] )]
// TODO: Remove any items listed as "Deferred" // TODO: Remove any items listed as "Deferred"
#![cfg_attr(not(debug_assertions), allow(unused))] #![cfg_attr(not(debug_assertions), allow(unused))]
#![expect(missing_debug_implementations, reason = "Deferred: Noisy")] #![expect(
#![expect(unused_qualifications, reason = "Deferred: Noisy")] missing_debug_implementations,
reason = "Deferred: Noisy. Requires same lint to be addressed in Masonry"
)]
#![expect(clippy::exhaustive_enums, reason = "Deferred: Noisy")] #![expect(clippy::exhaustive_enums, reason = "Deferred: Noisy")]
#![expect(clippy::match_same_arms, reason = "Deferred: Noisy")] #![expect(clippy::match_same_arms, reason = "Deferred: Noisy")]
#![expect(clippy::missing_assert_message, reason = "Deferred: Noisy")] #![expect(clippy::missing_assert_message, reason = "Deferred: Noisy")]
#![expect(clippy::return_self_not_must_use, reason = "Deferred: Noisy")]
#![expect(elided_lifetimes_in_paths, reason = "Deferred: Noisy")] #![expect(elided_lifetimes_in_paths, reason = "Deferred: Noisy")]
#![expect(clippy::use_self, reason = "Deferred: Noisy")] #![expect(clippy::use_self, reason = "Deferred: Noisy")]
// https://github.com/rust-lang/rust/pull/130025 // https://github.com/rust-lang/rust/pull/130025
@ -65,6 +66,7 @@ pub mod view;
pub use any_view::AnyWidgetView; pub use any_view::AnyWidgetView;
pub use driver::{async_action, MasonryDriver, MasonryProxy, ASYNC_MARKER_WIDGET}; pub use driver::{async_action, MasonryDriver, MasonryProxy, ASYNC_MARKER_WIDGET};
#[must_use = "A Xilem app does nothing unless ran."]
pub struct Xilem<State, Logic> { pub struct Xilem<State, Logic> {
state: State, state: State,
logic: Logic, logic: Logic,

View File

@ -35,6 +35,7 @@ pub fn button_any_pointer<State, Action>(
} }
} }
#[must_use = "View values do nothing unless provided to Xilem."]
pub struct Button<F> { pub struct Button<F> {
label: ArcStr, label: ArcStr,
callback: F, callback: F,

View File

@ -22,6 +22,7 @@ where
} }
} }
#[must_use = "View values do nothing unless provided to Xilem."]
pub struct Checkbox<F> { pub struct Checkbox<F> {
label: ArcStr, label: ArcStr,
checked: bool, checked: bool,
@ -38,10 +39,7 @@ where
fn build(&self, ctx: &mut ViewCtx) -> (Self::Element, Self::ViewState) { fn build(&self, ctx: &mut ViewCtx) -> (Self::Element, Self::ViewState) {
ctx.with_leaf_action_widget(|ctx| { ctx.with_leaf_action_widget(|ctx| {
ctx.new_pod(masonry::widget::Checkbox::new( ctx.new_pod(widget::Checkbox::new(self.checked, self.label.clone()))
self.checked,
self.label.clone(),
))
}) })
} }

View File

@ -27,6 +27,7 @@ pub fn flex<State, Action, Seq: FlexSequence<State, Action>>(
} }
} }
#[must_use = "View values do nothing unless provided to Xilem."]
pub struct Flex<Seq, State, Action = ()> { pub struct Flex<Seq, State, Action = ()> {
sequence: Seq, sequence: Seq,
axis: Axis, axis: Axis,

View File

@ -26,6 +26,7 @@ pub fn grid<State, Action, Seq: GridSequence<State, Action>>(
} }
} }
#[must_use = "View values do nothing unless provided to Xilem."]
pub struct Grid<Seq, State, Action = ()> { pub struct Grid<Seq, State, Action = ()> {
sequence: Seq, sequence: Seq,
spacing: f64, spacing: f64,

View File

@ -31,6 +31,7 @@ pub fn image(image: &vello::peniko::Image) -> Image {
/// The [`View`] created by [`image`]. /// The [`View`] created by [`image`].
/// ///
/// See `image`'s docs for more details. /// See `image`'s docs for more details.
#[must_use = "View values do nothing unless provided to Xilem."]
pub struct Image { pub struct Image {
image: vello::peniko::Image, image: vello::peniko::Image,
object_fit: ObjectFit, object_fit: ObjectFit,

View File

@ -17,6 +17,7 @@ pub fn label(label: impl Into<ArcStr>) -> Label {
} }
} }
#[must_use = "View values do nothing unless provided to Xilem."]
pub struct Label { pub struct Label {
label: ArcStr, label: ArcStr,
@ -99,7 +100,7 @@ impl<State, Action> View<State, Action, ViewCtx> for Label {
_id_path: &[ViewId], _id_path: &[ViewId],
message: DynMessage, message: DynMessage,
_app_state: &mut State, _app_state: &mut State,
) -> crate::MessageResult<Action> { ) -> MessageResult<Action> {
tracing::error!("Message arrived in Label::message, but Label doesn't consume any messages, this is a bug"); tracing::error!("Message arrived in Label::message, but Label doesn't consume any messages, this is a bug");
MessageResult::Stale(message) MessageResult::Stale(message)
} }

View File

@ -21,6 +21,7 @@ where
} }
} }
#[must_use = "View values do nothing unless provided to Xilem."]
pub struct Portal<V, State, Action> { pub struct Portal<V, State, Action> {
child: V, child: V,
phantom: PhantomData<(State, Action)>, phantom: PhantomData<(State, Action)>,

View File

@ -20,9 +20,7 @@ impl<State, Action> View<State, Action, ViewCtx> for ProgressBar {
type ViewState = (); type ViewState = ();
fn build(&self, ctx: &mut ViewCtx) -> (Self::Element, Self::ViewState) { fn build(&self, ctx: &mut ViewCtx) -> (Self::Element, Self::ViewState) {
ctx.with_leaf_action_widget(|ctx| { ctx.with_leaf_action_widget(|ctx| ctx.new_pod(widget::ProgressBar::new(self.progress)))
ctx.new_pod(masonry::widget::ProgressBar::new(self.progress))
})
} }
fn rebuild( fn rebuild(

View File

@ -27,6 +27,7 @@ pub fn inline_prose(content: impl Into<ArcStr>) -> Prose {
prose(content).line_break_mode(LineBreaking::Overflow) prose(content).line_break_mode(LineBreaking::Overflow)
} }
#[must_use = "View values do nothing unless provided to Xilem."]
pub struct Prose { pub struct Prose {
content: ArcStr, content: ArcStr,
@ -109,7 +110,7 @@ impl<State, Action> View<State, Action, ViewCtx> for Prose {
_id_path: &[ViewId], _id_path: &[ViewId],
message: DynMessage, message: DynMessage,
_app_state: &mut State, _app_state: &mut State,
) -> crate::MessageResult<Action> { ) -> MessageResult<Action> {
tracing::error!("Message arrived in Prose::message, but Prose doesn't consume any messages, this is a bug"); tracing::error!("Message arrived in Prose::message, but Prose doesn't consume any messages, this is a bug");
MessageResult::Stale(message) MessageResult::Stale(message)
} }

View File

@ -30,6 +30,7 @@ where
} }
} }
#[must_use = "View values do nothing unless provided to Xilem."]
pub struct SizedBox<V, State, Action = ()> { pub struct SizedBox<V, State, Action = ()> {
inner: V, inner: V,
width: Option<f64>, width: Option<f64>,

View File

@ -38,6 +38,7 @@ pub fn spinner() -> Spinner {
/// The [`View`] created by [`spinner`]. /// The [`View`] created by [`spinner`].
/// ///
/// See `spinner`'s docs for more details. /// See `spinner`'s docs for more details.
#[must_use = "View values do nothing unless provided to Xilem."]
pub struct Spinner { pub struct Spinner {
color: Option<Color>, color: Option<Color>,
} }

View File

@ -33,7 +33,7 @@ where
{ {
const { const {
assert!( assert!(
core::mem::size_of::<F>() == 0, size_of::<F>() == 0,
"`task` will not be ran again when its captured variables are updated.\n\ "`task` will not be ran again when its captured variables are updated.\n\
To ignore this warning, use `task_raw`." To ignore this warning, use `task_raw`."
); );

View File

@ -28,6 +28,7 @@ where
} }
} }
#[must_use = "View values do nothing unless provided to Xilem."]
pub struct Textbox<State, Action> { pub struct Textbox<State, Action> {
contents: String, contents: String,
on_changed: Callback<State, Action>, on_changed: Callback<State, Action>,
@ -72,7 +73,7 @@ impl<State: 'static, Action: 'static> View<State, Action, ViewCtx> for Textbox<S
fn build(&self, ctx: &mut ViewCtx) -> (Self::Element, Self::ViewState) { fn build(&self, ctx: &mut ViewCtx) -> (Self::Element, Self::ViewState) {
ctx.with_leaf_action_widget(|ctx| { ctx.with_leaf_action_widget(|ctx| {
ctx.new_pod( ctx.new_pod(
masonry::widget::Textbox::new(self.contents.clone()) widget::Textbox::new(self.contents.clone())
.with_text_brush(self.text_brush.clone()) .with_text_brush(self.text_brush.clone())
.with_text_alignment(self.alignment), .with_text_alignment(self.alignment),
) )

View File

@ -22,6 +22,7 @@ pub fn variable_label(label: impl Into<ArcStr>) -> VariableLabel {
} }
} }
#[must_use = "View values do nothing unless provided to Xilem."]
pub struct VariableLabel { pub struct VariableLabel {
label: ArcStr, label: ArcStr,
@ -149,7 +150,7 @@ impl<State, Action> View<State, Action, ViewCtx> for VariableLabel {
_id_path: &[ViewId], _id_path: &[ViewId],
message: DynMessage, message: DynMessage,
_app_state: &mut State, _app_state: &mut State,
) -> crate::MessageResult<Action> { ) -> MessageResult<Action> {
tracing::error!("Message arrived in Label::message, but Label doesn't consume any messages, this is a bug"); tracing::error!("Message arrived in Label::message, but Label doesn't consume any messages, this is a bug");
MessageResult::Stale(message) MessageResult::Stale(message)
} }

View File

@ -39,7 +39,7 @@ where
{ {
const { const {
assert!( assert!(
core::mem::size_of::<F>() == 0, size_of::<F>() == 0,
"`worker` will not be ran again when its captured variables are updated.\n\ "`worker` will not be ran again when its captured variables are updated.\n\
To ignore this warning, use `worker_raw`. To ignore this warning, use `worker_raw`.
To provide an updating value to this task, use the " To provide an updating value to this task, use the "

View File

@ -7,6 +7,7 @@ use crate::{MessageResult, Mut, View, ViewId, ViewMarker, ViewPathTracker};
/// A view that wraps a child view and modifies the state that callbacks have access to. /// A view that wraps a child view and modifies the state that callbacks have access to.
#[derive(Debug)] #[derive(Debug)]
#[must_use = "View values do nothing unless provided to Xilem."]
pub struct Adapt< pub struct Adapt<
ParentState, ParentState,
ParentAction, ParentAction,

View File

@ -21,6 +21,7 @@ pub fn fork<Active, Alongside>(
/// The view for [`fork`]. /// The view for [`fork`].
#[derive(Debug)] #[derive(Debug)]
#[must_use = "View values do nothing unless provided to Xilem."]
pub struct Fork<Active, Alongside> { pub struct Fork<Active, Alongside> {
active_view: Active, active_view: Active,
alongside_view: Alongside, alongside_view: Alongside,

View File

@ -8,6 +8,7 @@ use crate::{Mut, View, ViewId, ViewMarker, ViewPathTracker};
/// A view that maps a child [`View<State,ChildAction,_>`] to [`View<State,ParentAction,_>`] while providing mutable access to `State` in the map function. /// A view that maps a child [`View<State,ChildAction,_>`] to [`View<State,ParentAction,_>`] while providing mutable access to `State` in the map function.
/// ///
/// This is very similar to the Elm architecture, where the parent view can update state based on the action message from the child view /// This is very similar to the Elm architecture, where the parent view can update state based on the action message from the child view
#[must_use = "View values do nothing unless provided to Xilem."]
pub struct MapAction< pub struct MapAction<
V, V,
State, State,

View File

@ -8,6 +8,7 @@ use crate::{MessageResult, Mut, View, ViewId, ViewMarker, ViewPathTracker};
/// The View for [`map_state`] and [`lens`]. /// The View for [`map_state`] and [`lens`].
/// ///
/// See their documentation for more context. /// See their documentation for more context.
#[must_use = "View values do nothing unless provided to Xilem."]
pub struct MapState<V, F, ParentState, ChildState, Action, Context, Message> { pub struct MapState<V, F, ParentState, ChildState, Action, Context, Message> {
map_state: F, map_state: F,
child: V, child: V,

View File

@ -10,6 +10,7 @@ use crate::{MessageResult, Mut, View, ViewId, ViewMarker, ViewPathTracker};
/// ///
/// The story of Memoization in Xilem is still being worked out, /// The story of Memoization in Xilem is still being worked out,
/// so the details of this view might change. /// so the details of this view might change.
#[must_use = "View values do nothing unless provided to Xilem."]
pub struct Memoize<Data, InitView, State, Action, Context, Message> { pub struct Memoize<Data, InitView, State, Action, Context, Message> {
data: Data, data: Data,
init_view: InitView, init_view: InitView,

View File

@ -23,6 +23,7 @@ pub trait PhantomElementCtx: ViewPathTracker {
/// A [`View`] which can be one of nine inner view types. /// A [`View`] which can be one of nine inner view types.
#[allow(missing_docs)] // On variants #[allow(missing_docs)] // On variants
#[derive(Debug)] #[derive(Debug)]
#[must_use = "View values do nothing unless provided to Xilem."]
pub enum OneOf<A = (), B = (), C = (), D = (), E = (), F = (), G = (), H = (), I = ()> { pub enum OneOf<A = (), B = (), C = (), D = (), E = (), F = (), G = (), H = (), I = ()> {
A(A), A(A),
B(B), B(B),

View File

@ -71,6 +71,7 @@ where
/// The view type for [`run_once`]. /// The view type for [`run_once`].
/// ///
/// This is a [`NoElement`] view. /// This is a [`NoElement`] view.
#[must_use = "View values do nothing unless provided to Xilem."]
pub struct RunOnce<F> { pub struct RunOnce<F> {
once: F, once: F,
} }