Skip to content

Commit 98fbdb9

Browse files
tronicalogoffart
andauthored
doc: Extend Model::as_any() docs with a hint how to debug downcast fa… (slint-ui#8451)
Co-authored-by: Olivier Goffart <[email protected]>
1 parent fd45de2 commit 98fbdb9

File tree

1 file changed

+52
-5
lines changed

1 file changed

+52
-5
lines changed

internal/core/model.rs

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -161,10 +161,10 @@ pub trait Model {
161161
ModelIterator::new(self)
162162
}
163163

164-
/// Return something that can be downcast'ed (typically self)
164+
/// Return something that can be downcast'ed (typically self).
165165
///
166-
/// This is useful to get back to the actual model from a [`ModelRc`] stored
167-
/// in a ItemTree.
166+
/// Use this to retrieve the concrete model from a [`ModelRc`] stored
167+
/// in your tree of UI elements.
168168
///
169169
/// ```
170170
/// # use i_slint_core::model::*;
@@ -175,11 +175,58 @@ pub trait Model {
175175
/// assert_eq!(handle.row_data(3).unwrap(), 4);
176176
/// ```
177177
///
178-
/// Note: the default implementation returns nothing interesting. this method should be
179-
/// implemented by model implementation to return something useful. For example:
178+
/// Note: Custom models must implement this method for the cast to succeed.
179+
/// A valid implementation is to return `self`:
180180
/// ```ignore
181181
/// fn as_any(&self) -> &dyn core::any::Any { self }
182182
/// ```
183+
///
184+
/// ## Troubleshooting
185+
/// A common reason why the dowcast fails at run-time is because of a type-mismatch
186+
/// between the model created and the model downcasted. To debug this at compile time,
187+
/// try matching the model type used for the downcast explicitly at model creation time.
188+
/// In the following example, the downcast fails at run-time:
189+
///
190+
/// ```
191+
/// # use i_slint_core::model::*;
192+
/// # use std::rc::Rc;
193+
/// let model = VecModel::from_slice(&[3i32, 2, 1])
194+
/// .filter(Box::new(|v: &i32| *v >= 2) as Box<dyn Fn(&i32) -> bool>);
195+
/// let model_rc = ModelRc::new(model);
196+
/// assert!(model_rc.as_any()
197+
/// .downcast_ref::<FilterModel<VecModel<i32>, Box<dyn Fn(&i32) -> bool>>>()
198+
/// .is_none());
199+
/// ```
200+
///
201+
/// To debug this, let's make the type explicit. It fails to compile.
202+
///
203+
/// ```compile_fail
204+
/// # use i_slint_core::model::*;
205+
/// # use std::rc::Rc;
206+
/// let model: FilterModel<VecModel<i32>, Box<dyn Fn(&i32) -> bool>>
207+
/// = VecModel::from_slice(&[3i32, 2, 1])
208+
/// .filter(Box::new(|v: &i32| *v >= 2) as Box<dyn Fn(&i32) -> bool>);
209+
/// let model_rc = ModelRc::new(model);
210+
/// assert!(model_rc.as_any()
211+
/// .downcast_ref::<FilterModel<VecModel<i32>, Box<dyn Fn(&i32) -> bool>>>()
212+
/// .is_none());
213+
/// ```
214+
///
215+
/// The compiler tells us that the type of model is not `FilterModel<VecModel<..>>`,
216+
/// but instead `from_slice()` already returns a `ModelRc`, so the correct type to
217+
/// use for the downcast is wrapped in `ModelRc`:
218+
///
219+
/// ```
220+
/// # use i_slint_core::model::*;
221+
/// # use std::rc::Rc;
222+
/// let model: FilterModel<ModelRc<i32>, Box<dyn Fn(&i32) -> bool>>
223+
/// = VecModel::from_slice(&[3i32, 2, 1])
224+
/// .filter(Box::new(|v: &i32| *v >= 2) as Box<dyn Fn(&i32) -> bool>);
225+
/// let model_rc = ModelRc::new(model);
226+
/// assert!(model_rc.as_any()
227+
/// .downcast_ref::<FilterModel<ModelRc<i32>, Box<dyn Fn(&i32) -> bool>>>()
228+
/// .is_some());
229+
/// ```
183230
fn as_any(&self) -> &dyn core::any::Any {
184231
&()
185232
}

0 commit comments

Comments
 (0)