From: Ian Jackson Date: Sun, 14 Feb 2021 16:02:35 +0000 (+0000) Subject: xdata: fix downcasting to actually work X-Git-Tag: otter-0.4.0~501 X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=commitdiff_plain;h=24e31045965054f1f5012d2638f1545907313944;p=otter.git xdata: fix downcasting to actually work Urgh, this involved a lot of flail before I found (i) downcast-rs (ii) the conditional lifetime bug. Signed-off-by: Ian Jackson --- diff --git a/src/gamestate.rs b/src/gamestate.rs index 00cb748c..d7a872c0 100644 --- a/src/gamestate.rs +++ b/src/gamestate.rs @@ -101,11 +101,14 @@ pub struct CommittedLogEntry { // ---------- piece trait, and rendering ---------- #[typetag::serde(tag="type")] -pub trait PieceXData: Any + Debug + Send + 'static { +pub trait PieceXData: Downcast + Debug + Send + 'static { fn default() -> Box where Self: Default { - Box::new(::default()) + let k = Box::new(::default()); + dbg!(&k); + k } } +impl_downcast!(PieceXData); #[typetag::serde] pub trait Outline: Send + Debug { @@ -286,22 +289,43 @@ impl PieceState { } pub trait PieceXDataExt { - fn get(&self) -> Result, IE>; + fn get(&self) -> Result, IE>; fn get_mut(&mut self) -> Result<&mut T, IE>; } + +fn xdata_unexpected(got: &dyn PieceXData) + -> InternalError { + internal_logic_error(format!( + "\n\ + piece xdata unexpectedly: {:?}\n\ + expected something like: Some({:?})\n", + &got, ::default(), + )) +} + impl PieceXDataExt for PieceXDataState { #[throws(IE)] - fn get(&self) -> Option<&T> { - let m = format!("piece xdata unexpectedly {:?}", &self); + fn get(&self) -> Option<&T> where T: Default { let xdata = if let Some(xdata) = &self { xdata } else { return None }; - Some(Any::downcast_ref(xdata).ok_or_else(|| internal_logic_error(m))?) + let xdata: &dyn PieceXData = xdata.as_ref(); + if let Some(y) = xdata.downcast_ref::() { Some(y) } + else { throw!(xdata_unexpected::(xdata)) } } - #[throws(IE)] - fn get_mut(&mut self) -> &mut T { - let m = format!("piece xdata unexpectedly {:?}", &self); + fn get_mut(&mut self) -> Result<&mut T, IE> { let xdata = self.get_or_insert_with(|| ::default()); - Any::downcast_mut(xdata).ok_or_else(|| internal_logic_error(m))? + let xdata: &mut dyn PieceXData = xdata.as_mut(); + let keep: *mut dyn PieceXData = xdata; + if let Some(y) = xdata.downcast_mut::() { return Ok(y) } + + // Erroneous borrowck error with early returns + // https://github.com/rust-lang/rust/issues/58910 + // https://github.com/rust-lang/rust/issues/51545 + // Safety: the `xdata` borrow that was passed to `downcast_mut` + // is no longer present in this branch, so now we have only `keep` + // and the things `keep` was borrowed from. + let xdata: &dyn PieceXData = unsafe { keep.as_ref().unwrap() }; + Err(xdata_unexpected::(xdata)) } } diff --git a/src/imports.rs b/src/imports.rs index 2146afa3..2154cd74 100644 --- a/src/imports.rs +++ b/src/imports.rs @@ -48,6 +48,7 @@ pub use arrayvec::ArrayVec; pub use boolinator::Boolinator as _; pub use delegate::delegate; pub use derive_more::*; +pub use downcast_rs::{impl_downcast, Downcast}; pub use either::{Either, Left, Right}; pub use enum_map::{Enum, EnumMap}; pub use fehler::{throw, throws};