Fix `missing_debug_implementations` in Xilem Core (#739)

This also updates to use `core::error::Error` now that it is stable.
This commit is contained in:
Daniel McNab 2024-11-11 16:51:27 +00:00 committed by GitHub
parent 23f04ca370
commit 5c61ac195b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 119 additions and 36 deletions

View File

@ -52,8 +52,12 @@ impl RawProxy for MasonryProxy {
}
}
}
fn dyn_debug(&self) -> &dyn std::fmt::Debug {
self
}
}
#[derive(Debug)]
pub struct MasonryProxy(pub(crate) EventLoopProxy);
impl MasonryProxy {

View File

@ -166,6 +166,7 @@ where
/// The state used by [`AnyView`].
#[doc(hidden)]
#[allow(unnameable_types)] // reason: Implementation detail, public because of trait visibility rules
#[derive(Debug)]
pub struct AnyViewState {
inner_state: Box<dyn Any>,
/// The generation is the value which is shown

View File

@ -3,7 +3,7 @@
use alloc::boxed::Box;
use alloc::sync::Arc;
use core::fmt::Display;
use core::fmt::{Debug, Display};
use core::marker::PhantomData;
use crate::{DynMessage, Message, NoElement, View, ViewId, ViewPathTracker};
@ -47,9 +47,18 @@ pub trait RawProxy<Message = DynMessage>: Send + Sync + 'static {
//
// e.g. an `Option<Arc<dyn FnMut(ProxyError, ProxyMessageId?)>>`?
fn send_message(&self, path: Arc<[ViewId]>, message: Message) -> Result<(), ProxyError>;
/// Get the debug formatter for this proxy type.
fn dyn_debug(&self) -> &dyn Debug;
}
impl<Message: 'static> Debug for dyn RawProxy<Message> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.dyn_debug().fmt(f)
}
}
/// A way to send a message of an expected type to a specific view.
#[derive(Debug)]
pub struct MessageProxy<M: Message> {
proxy: Arc<dyn RawProxy<DynMessage>>,
path: Arc<[ViewId]>,
@ -109,10 +118,8 @@ pub enum ProxyError {
///
/// This likely requires async error handling to happen.
ViewExpired(DynMessage, Arc<[ViewId]>),
#[allow(missing_docs)]
Other(&'static str),
// TODO: When core::error::Error is stabilised
// Other(Box<dyn core::error::Error + Send>),
/// An error specific to the driver being used.
Other(Box<dyn core::error::Error + Send>),
}
// Is it fine to use thiserror in this crate?
@ -123,17 +130,16 @@ impl Display for ProxyError {
ProxyError::ViewExpired(_, _) => {
f.write_fmt(format_args!("the corresponding view is no longer present"))
}
ProxyError::Other(inner) => inner.fmt(f),
ProxyError::Other(inner) => Display::fmt(inner, f),
}
}
}
// impl std::error::Error for ProxyError {
// fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
// match self {
// ProxyError::Other(inner) => inner.source(),
// _ => None,
// }
// }
// }
impl core::error::Error for ProxyError {
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
match self {
ProxyError::Other(inner) => inner.source(),
_ => None,
}
}
}

View File

@ -38,6 +38,7 @@
use crate::{run_once, View, ViewPathTracker};
/// A type used for documentation
#[derive(Debug)]
pub enum Fake {}
impl ViewPathTracker for Fake {
@ -63,6 +64,7 @@ pub trait DocsView<State, Action = ()>: View<State, Action, Fake> {}
impl<V, State, Action> DocsView<State, Action> for V where V: View<State, Action, Fake> {}
/// A state type usable in a component
#[derive(Debug)]
pub struct State;
/// A minimal component.

View File

@ -87,6 +87,7 @@ where
/// correct `State` and `Action` types), as they do not need to actually add an element to the sequence.
///
/// These views can also as the `alongside_view` in [`fork`](crate::fork).
#[derive(Debug)]
pub struct NoElement;
impl ViewElement for NoElement {

View File

@ -24,7 +24,6 @@
#![warn(clippy::print_stdout, clippy::print_stderr)]
// TODO: Remove any items listed as "Deferred"
#![deny(clippy::trivially_copy_pass_by_ref)]
#![expect(missing_debug_implementations, reason = "Deferred: Noisy")]
#![expect(unused_qualifications, reason = "Deferred: Noisy")]
#![expect(single_use_lifetimes, reason = "Deferred: Noisy")]
#![expect(clippy::exhaustive_enums, reason = "Deferred: Noisy")]

View File

@ -11,7 +11,7 @@ use core::ops::Deref;
/// The possible outcomes from a [`View::message`]
///
/// [`View::message`]: crate::View::message
#[derive(Default)]
#[derive(Default, Debug)]
pub enum MessageResult<Action, Message = DynMessage> {
/// An action for a parent message handler to use
///

View File

@ -197,6 +197,7 @@ where
/// The state used to implement `ViewSequence` for `Option<impl ViewSequence>`
#[allow(unnameable_types)] // reason: Implementation detail, public because of trait visibility rules
#[derive(Debug)]
pub struct OptionSeqState<InnerState> {
/// The current state.
///
@ -341,6 +342,7 @@ where
// This is managed in [`create_generational_view_id`] and [`view_id_to_index_generation`]
#[doc(hidden)]
#[allow(unnameable_types)] // reason: Implementation detail, public because of trait visibility rules
#[derive(Debug)]
pub struct VecViewState<InnerState> {
inner_states: Vec<InnerState>,

View File

@ -206,6 +206,7 @@ where
}
#[allow(unnameable_types)] // reason: Implementation detail, public because of trait visibility rules
#[derive(Debug)]
pub struct RcState<ViewState> {
view_state: ViewState,
/// This is a flag that is set, when an inner view signifies that it requires a rebuild (via [`MessageResult::RequestRebuild`]).

View File

@ -6,6 +6,7 @@ use core::marker::PhantomData;
use crate::{MessageResult, Mut, View, ViewId, ViewMarker, ViewPathTracker};
/// A view that wraps a child view and modifies the state that callbacks have access to.
#[derive(Debug)]
pub struct Adapt<
ParentState,
ParentAction,
@ -37,6 +38,7 @@ pub struct Adapt<
///
/// The closure passed to [`Adapt`] should call this thunk with the child's
/// app state.
#[derive(Debug)]
pub struct AdaptThunk<'a, ChildState, ChildAction, Context, ChildView, Message>
where
Context: ViewPathTracker,

View File

@ -20,6 +20,7 @@ pub fn fork<Active, Alongside>(
}
/// The view for [`fork`].
#[derive(Debug)]
pub struct Fork<Active, Alongside> {
active_view: Active,
alongside_view: Alongside,

View File

@ -1,23 +1,38 @@
// Copyright 2024 the Xilem Authors
// SPDX-License-Identifier: Apache-2.0
use core::marker::PhantomData;
use core::{fmt::Debug, marker::PhantomData};
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.
///
/// 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
pub struct MapAction<
V,
State,
ParentAction,
ChildAction,
V,
Context,
Message,
// This default only exists for documentation purposes.
F = fn(&mut State, ChildAction) -> ParentAction,
> {
map_fn: F,
child: V,
phantom: PhantomData<fn() -> (State, ParentAction, ChildAction)>,
phantom: PhantomData<fn() -> (State, ParentAction, ChildAction, Context, Message)>,
}
impl<V, State, ParentAction, ChildAction, Context, Message, F> Debug
for MapAction<V, State, ParentAction, ChildAction, Context, Message, F>
where
V: Debug,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("MapAction")
.field("child", &self.child)
.finish_non_exhaustive()
}
}
/// A view that maps a child [`View<State,ChildAction,_>`] to [`View<State,ParentAction,_>`] while providing mutable access to `State` in the map function.
@ -52,7 +67,7 @@ pub struct MapAction<
pub fn map_action<State, ParentAction, ChildAction, Context: ViewPathTracker, Message, V, F>(
view: V,
map_fn: F,
) -> MapAction<State, ParentAction, ChildAction, V, F>
) -> MapAction<V, State, ParentAction, ChildAction, Context, Message, F>
where
State: 'static,
ParentAction: 'static,
@ -67,19 +82,21 @@ where
}
}
impl<State, ParentAction, ChildAction, V, F> ViewMarker
for MapAction<State, ParentAction, ChildAction, V, F>
impl<V, State, ParentAction, ChildAction, F, Context, Message> ViewMarker
for MapAction<V, State, ParentAction, ChildAction, Context, Message, F>
{
}
impl<State, ParentAction, ChildAction, Context: ViewPathTracker, Message, V, F>
impl<V, State, ParentAction, ChildAction, Context, Message, F>
View<State, ParentAction, Context, Message>
for MapAction<State, ParentAction, ChildAction, V, F>
for MapAction<V, State, ParentAction, ChildAction, Context, Message, F>
where
V: View<State, ChildAction, Context, Message>,
State: 'static,
ParentAction: 'static,
ChildAction: 'static,
V: View<State, ChildAction, Context, Message>,
F: Fn(&mut State, ChildAction) -> ParentAction + 'static,
Context: ViewPathTracker + 'static,
Message: 'static,
{
type ViewState = V::ViewState;
type Element = V::Element;

View File

@ -1,7 +1,7 @@
// Copyright 2024 the Xilem Authors
// SPDX-License-Identifier: Apache-2.0
use core::marker::PhantomData;
use core::{fmt::Debug, marker::PhantomData};
use crate::{MessageResult, Mut, View, ViewId, ViewMarker, ViewPathTracker};
@ -14,6 +14,18 @@ pub struct MapState<V, F, ParentState, ChildState, Action, Context, Message> {
phantom: PhantomData<fn(ParentState) -> (ChildState, Action, Context, Message)>,
}
impl<V, F, ParentState, ChildState, Action, Context, Message> Debug
for MapState<V, F, ParentState, ChildState, Action, Context, Message>
where
V: Debug,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("MapAction")
.field("child", &self.child)
.finish_non_exhaustive()
}
}
/// A view that "extracts" state from a [`View<ParentState,_,_>`] to [`View<ChildState,_,_>`].
/// This allows modularization of views based on their state.
///

View File

@ -1,8 +1,8 @@
// Copyright 2024 the Xilem Authors
// SPDX-License-Identifier: Apache-2.0
use core::marker::PhantomData;
use core::mem::size_of;
use core::{fmt::Debug, marker::PhantomData};
use crate::{MessageResult, Mut, View, ViewId, ViewMarker, ViewPathTracker};
@ -10,10 +10,22 @@ use crate::{MessageResult, Mut, View, ViewId, ViewMarker, ViewPathTracker};
///
/// The story of Memoization in Xilem is still being worked out,
/// so the details of this view might change.
pub struct Memoize<Data, InitView, State, Action> {
pub struct Memoize<Data, InitView, State, Action, Context, Message> {
data: Data,
init_view: InitView,
phantom: PhantomData<fn() -> (State, Action)>,
phantom: PhantomData<fn() -> (State, Action, Context, Message)>,
}
impl<Data, InitView, State, Action, Context, Message> Debug
for Memoize<Data, InitView, State, Action, Context, Message>
where
Data: Debug,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("Memoize")
.field("data", &self.data)
.finish_non_exhaustive()
}
}
const NON_CAPTURING_CLOSURE: &str = "
@ -41,7 +53,7 @@ It's not possible in Rust currently to check whether the (content of the) callba
pub fn memoize<State, Action, Context, Message, Data, V, InitView>(
data: Data,
init_view: InitView,
) -> Memoize<Data, InitView, State, Action>
) -> Memoize<Data, InitView, State, Action, Context, Message>
where
Data: PartialEq + 'static,
InitView: Fn(&Data) -> V + 'static,
@ -59,19 +71,24 @@ where
}
#[allow(unnameable_types)] // reason: Implementation detail, public because of trait visibility rules
#[derive(Debug)]
pub struct MemoizeState<V, VState> {
view: V,
view_state: VState,
dirty: bool,
}
impl<Data, ViewFn, State, Action> ViewMarker for Memoize<Data, ViewFn, State, Action> {}
impl<Data, ViewFn, State, Action, Context, Message> ViewMarker
for Memoize<Data, ViewFn, State, Action, Context, Message>
{
}
impl<State, Action, Context, Data, V, ViewFn, Message> View<State, Action, Context, Message>
for Memoize<Data, ViewFn, State, Action>
for Memoize<Data, ViewFn, State, Action, Context, Message>
where
State: 'static,
Action: 'static,
Context: ViewPathTracker,
Context: ViewPathTracker + 'static,
Message: 'static,
Data: PartialEq + 'static,
V: View<State, Action, Context, Message>,
ViewFn: Fn(&Data) -> V + 'static,
@ -140,6 +157,12 @@ pub struct Frozen<InitView, State, Action> {
phantom: PhantomData<fn() -> (State, Action)>,
}
impl<InitView, State, Action> Debug for Frozen<InitView, State, Action> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("Frozen").finish_non_exhaustive()
}
}
/// This view can be used, when the view returned by `init_view` doesn't access the `State`, other than in event callbacks
/// It only evaluates the `init_view` once, when it's being created.
///

View File

@ -22,6 +22,7 @@ pub trait PhantomElementCtx: ViewPathTracker {
/// A [`View`] which can be one of nine inner view types.
#[allow(missing_docs)] // On variants
#[derive(Debug)]
pub enum OneOf<A = (), B = (), C = (), D = (), E = (), F = (), G = (), H = (), I = ()> {
A(A),
B(B),
@ -552,6 +553,7 @@ mod hidden {
use crate::{View, ViewMarker};
#[allow(unnameable_types)] // reason: Implementation detail, public because of trait visibility rules
#[derive(Debug)]
pub enum Never {}
impl ViewMarker for Never {}
@ -592,6 +594,7 @@ mod hidden {
}
/// The state used to implement `View` for `OneOfN`
#[allow(unnameable_types)] // reason: Implementation detail, public because of trait visibility rules
#[derive(Debug)]
pub struct OneOfState<A, B, C, D, E, F, G, H, I> {
/// The current state of the inner view or view sequence.
pub(super) inner_state: super::OneOf<A, B, C, D, E, F, G, H, I>,

View File

@ -75,6 +75,12 @@ pub struct RunOnce<F> {
once: F,
}
impl<F> Debug for RunOnce<F> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("RunOnce").finish_non_exhaustive()
}
}
impl<F> ViewMarker for RunOnce<F> {}
impl<F, State, Action, Context, Message> View<State, Action, Context, Message> for RunOnce<F>
where

View File

@ -218,7 +218,10 @@ pub trait DomView<State, Action = ()>:
}
/// See [`map_action`](`core::map_action`)
fn map_action<ParentAction, F>(self, f: F) -> MapAction<State, ParentAction, Action, Self, F>
fn map_action<ParentAction, F>(
self,
f: F,
) -> MapAction<Self, State, ParentAction, Action, ViewCtx, DynMessage, F>
where
State: 'static,
ParentAction: 'static,