diff options
Diffstat (limited to 'ecs/src/lib.rs')
-rw-r--r-- | ecs/src/lib.rs | 639 |
1 files changed, 295 insertions, 344 deletions
diff --git a/ecs/src/lib.rs b/ecs/src/lib.rs index 3caaa6b..e9494a7 100644 --- a/ecs/src/lib.rs +++ b/ecs/src/lib.rs @@ -1,9 +1,9 @@ #![deny(clippy::all, clippy::pedantic)] -use std::any::{type_name, TypeId}; -use std::cell::RefCell; +use std::any::{type_name, Any, TypeId}; use std::fmt::Debug; use std::mem::ManuallyDrop; +use std::rc::Rc; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; @@ -12,26 +12,31 @@ use hashbrown::HashMap; use crate::actions::Action; use crate::component::storage::archetype::EntityComponent as ArchetypeEntityComponent; use crate::component::storage::Storage as ComponentStorage; -use crate::component::{Component, Sequence as ComponentSequence}; -use crate::entity::CREATE_STATIC_ENTITIES; -use crate::event::component::Kind as ComponentEventKind; +use crate::component::{ + Component, + IntoParts as IntoComponentParts, + Parts as ComponentParts, + Sequence as ComponentSequence, +}; +use crate::entity::{Declaration as EntityDeclaration, Handle as EntityHandle}; +use crate::event::{Emitted as EmittedEvent, NewEvents, Submitter as EventSubmitter}; use crate::extension::{Collector as ExtensionCollector, Extension}; -use crate::lock::{Lock, WriteGuard}; +use crate::lock::Lock; +use crate::pair::{ChildOf, DependsOn, Pair, Wildcard}; use crate::phase::{Phase, START as START_PHASE}; use crate::query::flexible::Query as FlexibleQuery; use crate::query::term::Without; use crate::query::{ - Iter as QueryIter, TermWithFieldTuple as QueryTermWithFieldTuple, TermWithoutFieldTuple as QueryTermWithoutFieldTuple, Terms as QueryTerms, TermsBuilderInterface, + MAX_TERM_CNT as QUERY_MAX_TERM_CNT, }; -use crate::relationship::{ChildOf, DependsOn, Relationship}; -use crate::sole::Sole; +use crate::sole::{Single, Sole}; use crate::stats::Stats; -use crate::system::{System, SystemComponent}; -use crate::type_name::TypeName; +use crate::system::observer::{Observer, WrapperComponent as ObserverWrapperComponent}; +use crate::system::{Callbacks, Metadata as SystemMetadata, System, SystemComponent}; use crate::uid::{Kind as UidKind, Uid}; pub mod actions; @@ -39,20 +44,17 @@ pub mod component; pub mod entity; pub mod event; pub mod extension; -pub mod lock; +pub mod pair; pub mod phase; pub mod query; -pub mod relationship; pub mod sole; pub mod stats; pub mod system; pub mod tuple; -pub mod type_name; pub mod uid; pub mod util; -#[doc(hidden)] -pub mod private; +mod lock; pub use ecs_macros::{Component, Sole}; @@ -77,56 +79,48 @@ impl World is_first_tick: AtomicBool::new(false), }; - world.add_sole(Stats::default()).ok(); + crate::phase::spawn_entities(&mut world); - for create_static_entity in CREATE_STATIC_ENTITIES { - create_static_entity(&world); - } + world.add_sole(Stats::default()).ok(); world } - /// Creates a new entity with the given components. - /// - /// # Panics - /// Will panic if mutable internal lock cannot be acquired. + /// Creates a entity with the given components. A new unique [`Uid`] will be generated + /// for this entity. pub fn create_entity<Comps>(&mut self, components: Comps) -> Uid where Comps: ComponentSequence, { let entity_uid = Uid::new_unique(UidKind::Entity); - self.create_entity_with_uid(components, entity_uid); + self.create_entity_with_uid(entity_uid, components); entity_uid } + /// Creates a entity with the given components. The entity will have the specified + /// [`Uid`]. #[tracing::instrument(skip_all)] - #[doc(hidden)] - pub fn create_entity_with_uid<Comps>(&self, components: Comps, entity_uid: Uid) + pub fn create_entity_with_uid<Comps>(&mut self, entity_uid: Uid, components: Comps) where Comps: ComponentSequence, { - debug_assert_eq!(entity_uid.kind(), UidKind::Entity); - - { - let mut component_storage_lock = self.lock_component_storage_rw(); - - if let Err(err) = component_storage_lock.create_entity(entity_uid) { - tracing::warn!("Failed to create entity: {err}"); - return; - }; + self.create_ent(entity_uid, components.into_parts_array()); + } - Self::add_entity_components( - entity_uid, - components.into_array(), - &mut component_storage_lock, - ); - } + pub fn add_component(&mut self, entity_id: Uid, component_parts: ComponentParts) + { + Self::add_entity_components( + entity_id, + [component_parts], + &mut self.data.component_storage, + ); + } - for added_event_id in Comps::added_event_ids() { - self.emit_event_by_id(added_event_id); - } + pub fn create_declared_entity(&mut self, entity_decl: &EntityDeclaration) + { + entity_decl.create(self); } /// Adds a globally shared singleton value. @@ -140,35 +134,45 @@ impl World self.data.sole_storage.insert(sole) } - pub fn register_system<'this, SystemImpl>( + pub fn register_observer<'this, SystemImpl, ObserverT>( &'this mut self, - phase_euid: Uid, - system: impl System<'this, SystemImpl>, - ) + observer: ObserverT, + ) where + ObserverT: Observer<'this, SystemImpl>, { - self.create_entity(( - SystemComponent { system: system.into_type_erased() }, - Relationship::<DependsOn, Phase>::new(phase_euid), - )); + let (wrapper_comp, mut system_callbacks) = observer.finish_observer(); + + let ent_id = Uid::new_unique(UidKind::Entity); + + self.create_ent( + ent_id, + [wrapper_comp.into_parts()].into_iter().chain( + ObserverT::observed_events() + .into_iter() + .map(IntoComponentParts::into_parts), + ), + ); + + system_callbacks.on_created(self, SystemMetadata { ent_id }); } - pub fn register_observer_system<'this, SystemImpl, Event>( + pub fn register_system<'this, SystemImpl>( &'this mut self, + phase_euid: Uid, system: impl System<'this, SystemImpl>, - event: Event, - ) where - Event: Component, + ) { - self.create_entity::<(SystemComponent, Event)>(( - SystemComponent { system: system.into_type_erased() }, - event, + let (type_erased_system, mut system_callbacks) = system.finish(); + + let system_ent_id = self.create_entity(( + SystemComponent { system: type_erased_system }, + Pair::new::<DependsOn>(phase_euid), )); + + system_callbacks.on_created(self, SystemMetadata { ent_id: system_ent_id }); } /// Adds a extensions. - /// - /// # Panics - /// Will panic if mutable internal lock cannot be acquired. pub fn add_extension(&mut self, extension: impl Extension) { let extension_collector = ExtensionCollector::new(self); @@ -176,7 +180,9 @@ impl World extension.collect(extension_collector); } - pub fn query<FieldTerms, FieldlessTerms>(&self) -> Query<FieldTerms, FieldlessTerms> + pub fn query<FieldTerms, FieldlessTerms>( + &self, + ) -> Query<'_, FieldTerms, FieldlessTerms> where FieldTerms: QueryTermWithFieldTuple, FieldlessTerms: QueryTermWithoutFieldTuple, @@ -184,19 +190,42 @@ impl World Query::new(self) } - pub fn flexible_query<'terms>( + pub fn flexible_query<const MAX_TERM_CNT: usize>( &self, - terms: QueryTerms<'terms>, - ) -> FlexibleQuery<'_, 'terms> + terms: QueryTerms<MAX_TERM_CNT>, + ) -> FlexibleQuery<'_, MAX_TERM_CNT> { FlexibleQuery::new(self, terms) } + pub fn get_entity(&self, entity_id: Uid) -> Option<EntityHandle<'_>> + { + let archetype = self + .data + .component_storage + .get_entity_archetype(entity_id)?; + + let Some(entity) = archetype.get_entity_by_id(entity_id) else { + unreachable!("Should exist since archetype was found by entity id"); + }; + + Some(EntityHandle::new(archetype, entity, self)) + } + + pub fn get_sole<SoleT: Sole>(&self) -> Option<Single<'_, SoleT>> + { + Some(Single::new(self.data.sole_storage.get::<SoleT>()?)) + } + + pub fn event_submitter(&self) -> EventSubmitter<'_> + { + EventSubmitter::new(self) + } + /// Performs a single tick. - /// /// # Panics - /// Will panic if a internal lock cannot be acquired. - pub fn step(&self) -> StepResult + /// Will panic if mutable internal lock cannot be acquired. + pub fn step(&mut self) -> StepResult { if self.stop.load(Ordering::Relaxed) { return StepResult::Stop; @@ -212,8 +241,9 @@ impl World self.perform_phases(); - self.lock_component_storage_rw() - .create_imaginary_archetypes(); + self.emit_new_events(); + + self.data.component_storage.create_imaginary_archetypes(); self.perform_queued_actions(); @@ -221,17 +251,9 @@ impl World return StepResult::Stop; } - let mut stats_lock = self - .data - .sole_storage - .get::<Stats>() - .expect("No stats sole found") - .write_nonblock() - .expect("Failed to aquire read-write stats sole lock"); - - let stats = stats_lock - .downcast_mut::<Stats>() - .expect("Casting stats sole to Stats type failed"); + let Some(mut stats) = self.get_sole::<Stats>() else { + unreachable!(); // Reason: is added in World::new + }; stats.current_tick += 1; @@ -239,10 +261,7 @@ impl World } /// Starts a loop which calls [`Self::step`] until the world is stopped. - /// - /// # Panics - /// Will panic if a internal lock cannot be acquired. - pub fn start_loop(&self) + pub fn start_loop(&mut self) { while let StepResult::Continue = self.step() {} } @@ -260,13 +279,7 @@ impl World VizoxideArchetypeGraphParams, }; - let component_storage_lock = self - .data - .component_storage - .read_nonblock() - .expect("Failed to acquire read-only component storage lock"); - - component_storage_lock.create_vizoxide_archetype_graph( + self.data.component_storage.create_vizoxide_archetype_graph( name, VizoxideArchetypeGraphParams { create_node_name: |archetype, _| { @@ -275,7 +288,7 @@ impl World archetype .component_ids_sorted() .into_iter() - .map(|comp_id| comp_id.id().to_string()) + .map(|comp_id| comp_id.to_string()) .collect::<Vec<_>>() .join(", ") )) @@ -300,161 +313,151 @@ impl World ) } - fn query_and_run_systems(&self, phase_euid: Uid) + #[tracing::instrument(skip_all)] + fn create_ent( + &mut self, + entity_uid: Uid, + components: impl IntoIterator<Item = ComponentParts>, + ) { - let system_comps_query = - self.query::<(&SystemComponent, &Relationship<DependsOn, Phase>), ()>(); + debug_assert_eq!(entity_uid.kind(), UidKind::Entity); + + if let Err(err) = self.data.component_storage.create_entity(entity_uid) { + tracing::warn!("Failed to create entity: {err}"); + return; + } - let system_iter = system_comps_query.iter().filter(|(_, phase_rel)| { - phase_rel - .target_uids() - .any(|target_uid| target_uid == phase_euid) - }); + Self::add_entity_components( + entity_uid, + components, + &mut self.data.component_storage, + ); + } + + fn query_and_run_systems(&self, phase_euid: Uid) + { + let system_query = Query::<(&SystemComponent,)>::from_flexible_query( + self.flexible_query( + QueryTerms::<QUERY_MAX_TERM_CNT>::builder() + .with_required([ + SystemComponent::id(), + Pair::new::<DependsOn>(phase_euid).id(), + ]) + .build(), + ), + ); - for (system_component, _) in system_iter { + for (system_ent_id, (system_component,)) in system_query.iter_with_euids() { // SAFETY: The world lives long enough unsafe { - system_component.system.run(self); + system_component + .system + .run(self, SystemMetadata { ent_id: system_ent_id }); } } } fn perform_child_phases(&self, parent_phase_euid: Uid) { - let phase_query = self.query::<(&Phase, &Relationship<ChildOf, Phase>), ()>(); - - for (child_phase_euid, (_, phase_rel)) in phase_query.iter_with_euids() { - if !phase_rel - .target_uids() - .any(|phase_euid| phase_euid == parent_phase_euid) - { - continue; - } + let phase_query = self.flexible_query( + QueryTerms::<2>::builder() + .with_required([ + Phase::id(), + Pair::new::<ChildOf>(parent_phase_euid).id(), + ]) + .build(), + ); - self.query_and_run_systems(child_phase_euid); - self.perform_child_phases(child_phase_euid); + for child_phase_entity in &phase_query { + self.query_and_run_systems(child_phase_entity.uid()); + self.perform_child_phases(child_phase_entity.uid()); } } fn perform_phases(&self) { - let phase_query = - self.query::<(&Phase,), (Without<Relationship<ChildOf, Phase>>,)>(); + let phase_query = self.query::<(&Phase,), (Without<Pair<ChildOf, Wildcard>>,)>(); - for (phase_euid, (_,)) in phase_query.iter_with_euids() { - if phase_euid == *START_PHASE { + for (phase_entity_id, _) in phase_query.iter_with_euids() { + if phase_entity_id == *START_PHASE { continue; } - self.query_and_run_systems(phase_euid); - self.perform_child_phases(phase_euid); + self.query_and_run_systems(phase_entity_id); + self.perform_child_phases(phase_entity_id); } } - #[tracing::instrument(skip_all)] - fn perform_queued_actions(&self) + fn emit_new_events(&self) { - let mut active_action_queue = match *self.data.action_queue.active_queue.borrow() - { - ActiveActionQueue::A => &self.data.action_queue.queue_a, - ActiveActionQueue::B => &self.data.action_queue.queue_b, - } - .write_nonblock() - .unwrap_or_else(|err| { - panic!( - "Failed to take read-write action queue lock {:?}: {err}", - self.data.action_queue.active_queue + let new_events = self + .data + .new_events + .write_nonblock() + .expect("Failed to acquire read-write lock to new events") + .take(); + + for (event_id, event_matches) in new_events { + self.emit_event_observers( + event_id, + &EmittedEvent { + event: event_id, + match_ids: &event_matches.match_ids, + }, ); - }); + } + } - let mut has_swapped_active_queue = false; + #[tracing::instrument(skip_all)] + fn perform_queued_actions(&mut self) + { + let mut action_queue_lock = self + .data + .action_queue + .queue + .write_nonblock() + .unwrap_or_else(|err| { + panic!("Failed to take read-write action queue lock: {err}",); + }); - for action in active_action_queue.drain(..) { + for action in action_queue_lock.drain(..) { match action { - Action::Spawn(components, component_added_event_ids) => { - { - let mut component_storage_lock = self.lock_component_storage_rw(); - - let new_entity_uid = Uid::new_unique(UidKind::Entity); - - if let Err(err) = - component_storage_lock.create_entity(new_entity_uid) - { - tracing::warn!("Failed to create entity: {err}"); - continue; - }; - - Self::add_entity_components( - new_entity_uid, - components, - &mut component_storage_lock, - ); - } + Action::Spawn(components) => { + let new_entity_uid = Uid::new_unique(UidKind::Entity); - if !has_swapped_active_queue { - self.swap_event_queue(&mut has_swapped_active_queue); + if let Err(err) = + self.data.component_storage.create_entity(new_entity_uid) + { + tracing::warn!("Failed to create entity: {err}"); + continue; } - for comp_added_event_id in component_added_event_ids.ids { - self.emit_event_by_id(comp_added_event_id); - } + Self::add_entity_components( + new_entity_uid, + components, + &mut self.data.component_storage, + ); } Action::Despawn(entity_uid) => { - self.despawn_entity(entity_uid, &mut has_swapped_active_queue); - } - Action::AddComponents( - entity_uid, - components, - component_added_event_ids, - ) => { + if let Err(err) = + self.data.component_storage.remove_entity(entity_uid) { - let mut component_storage_lock = self.lock_component_storage_rw(); - - Self::add_entity_components( - entity_uid, - components, - &mut component_storage_lock, - ); - } - - if !has_swapped_active_queue { - self.swap_event_queue(&mut has_swapped_active_queue); - } - - // TODO: Fix that events are emitted for components that haven't been - // added because a error occurred (for example, the entity already has - // the component) - for comp_added_event_id in component_added_event_ids.ids { - self.emit_event_by_id(comp_added_event_id); + tracing::error!("Failed to despawn entity: {err}"); } } - Action::RemoveComponents( - entity_uid, - components_metadata, - component_removed_event_ids, - ) => { - { - let mut component_storage_lock = self.lock_component_storage_rw(); - - Self::remove_entity_components( - entity_uid, - components_metadata - .iter() - .map(|comp_metadata| comp_metadata.id), - &mut component_storage_lock, - ); - } - - if !has_swapped_active_queue { - self.swap_event_queue(&mut has_swapped_active_queue); - } - - // TODO: Fix that events are emitted for components that haven't been - // removed because a error occurred (for example, the entity does not - // have the component) - for comp_removed_event_id in component_removed_event_ids.ids { - self.emit_event_by_id(comp_removed_event_id); - } + Action::AddComponents(entity_uid, components) => { + Self::add_entity_components( + entity_uid, + components, + &mut self.data.component_storage, + ); + } + Action::RemoveComponents(entity_uid, component_ids) => { + Self::remove_entity_components( + entity_uid, + component_ids, + &mut self.data.component_storage, + ); } Action::Stop => { self.stop.store(true, Ordering::Relaxed); @@ -463,113 +466,81 @@ impl World } } - #[tracing::instrument(skip_all)] - fn despawn_entity(&self, entity_uid: Uid, has_swapped_active_queue: &mut bool) - { - let mut component_storage_lock = self.lock_component_storage_rw(); - - let removed_entity = match component_storage_lock.remove_entity(entity_uid) { - Ok(components) => components, - Err(err) => { - tracing::error!("Failed to despawn entity: {err}"); - return; - } - }; - - let component_removed_event_uids = removed_entity - .components() - .iter() - .map(|component| { - component - .component() - .read_nonblock() - .unwrap_or_else(|_| { - panic!( - "Failed to acquire read-only {} component lock", - component.name() - ) - }) - .get_event_uid(ComponentEventKind::Removed) - }) - .collect::<Vec<_>>(); - - drop(component_storage_lock); - - if !*has_swapped_active_queue { - self.swap_event_queue(has_swapped_active_queue); - } - - for comp_removed_event_id in component_removed_event_uids { - self.emit_event_by_id(comp_removed_event_id); - } - } - fn add_entity_components( entity_uid: Uid, - components: impl IntoIterator<Item = (Uid, Box<dyn Component>)>, + components: impl IntoIterator<Item = ComponentParts>, component_storage: &mut ComponentStorage, - ) + ) -> Vec<Uid> { - for (component_id, component) in components { - if let Err(err) = component_storage - .add_entity_component(entity_uid, (component_id, component)) - { + let component_iter = components.into_iter(); + + let mut added_component_ids = + Vec::<Uid>::with_capacity(component_iter.size_hint().0); + + for component_parts in component_iter { + let comp_id = component_parts.id(); + + if let Err(err) = component_storage.add_entity_component( + entity_uid, + (comp_id, component_parts.name(), component_parts.into_data()), + ) { tracing::error!("Failed to add component to entity: {err}"); + continue; } + + added_component_ids.push(comp_id); } + + added_component_ids } fn remove_entity_components( entity_uid: Uid, component_ids: impl IntoIterator<Item = Uid>, component_storage: &mut ComponentStorage, - ) + ) -> Vec<Uid> { - for component_id in component_ids { + let component_id_iter = component_ids.into_iter(); + + let mut removed_component_ids = + Vec::<Uid>::with_capacity(component_id_iter.size_hint().0); + + for component_id in component_id_iter { if let Err(err) = component_storage.remove_entity_component(entity_uid, component_id) { tracing::error!("Failed to remove component to entity: {err}"); + continue; } + + removed_component_ids.push(component_id); } + + removed_component_ids } - fn emit_event_by_id(&self, event_id: Uid) + fn emit_event_observers(&self, event_id: Uid, emitted_event: &EmittedEvent<'_>) { - let mut query_required_ids = [SystemComponent::id(), event_id]; - - let query = self.flexible_query( - QueryTerms::builder() - .with_required_ids(&mut query_required_ids) - .build(), + assert_eq!(event_id.kind(), UidKind::Pair); + + let query = Query::<(&ObserverWrapperComponent,)>::from_flexible_query( + self.flexible_query( + QueryTerms::<QUERY_MAX_TERM_CNT>::builder() + .with_required([ObserverWrapperComponent::id(), event_id]) + .build(), + ), ); - for (system,) in QueryIter::<(&SystemComponent,), _>::new(self, query.iter()) { + for (observer_ent_id, (observer,)) in query.iter_with_euids() { unsafe { - system.system.run(self); + observer.run( + self, + SystemMetadata { ent_id: observer_ent_id }, + emitted_event.clone(), + ); } } } - - fn swap_event_queue(&self, has_swapped_active_queue: &mut bool) - { - let mut active_queue = self.data.action_queue.active_queue.borrow_mut(); - - *active_queue = match *active_queue { - ActiveActionQueue::A => ActiveActionQueue::B, - ActiveActionQueue::B => ActiveActionQueue::A, - }; - - *has_swapped_active_queue = true; - } - - fn lock_component_storage_rw(&self) -> WriteGuard<'_, ComponentStorage> - { - self.data - .component_storage - .write_nonblock() - .expect("Failed to acquire read-write component storage lock") - } } impl Default for World @@ -593,70 +564,64 @@ pub enum StepResult #[derive(Debug, Default)] pub struct WorldData { - component_storage: Arc<Lock<ComponentStorage>>, + component_storage: ComponentStorage, sole_storage: SoleStorage, - action_queue: Arc<ActionQueue>, + action_queue: Rc<ActionQueue>, + new_events: Lock<NewEvents>, } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct EntityComponentRef<'a> { - comp: &'a ArchetypeEntityComponent, + component_id: Uid, + component: &'a ArchetypeEntityComponent, + entity_id: Uid, } impl<'a> EntityComponentRef<'a> { - pub fn component(&self) -> &'a Lock<Box<dyn Component>> + fn component(&self) -> &'a Lock<Box<dyn Any>> { - self.comp.component() + self.component.component() } - fn new(comp: &'a ArchetypeEntityComponent) -> Self + #[must_use] + pub fn id(&self) -> Uid { - Self { comp } + self.component_id } -} -#[derive(Debug, Default, Clone, Copy)] -enum ActiveActionQueue -{ - #[default] - A, - B, + #[must_use] + pub fn entity_id(&self) -> Uid + { + self.entity_id + } + + fn new(component_id: Uid, comp: &'a ArchetypeEntityComponent, entity_id: Uid) + -> Self + { + Self { + component_id, + component: comp, + entity_id, + } + } } #[derive(Debug, Default)] struct ActionQueue { - queue_a: Lock<Vec<Action>>, - queue_b: Lock<Vec<Action>>, - active_queue: RefCell<ActiveActionQueue>, + queue: Lock<Vec<Action>>, } impl ActionQueue { fn push(&self, action: Action) { - match *self.active_queue.borrow() { - ActiveActionQueue::A => self - .queue_a - .write_nonblock() - .expect("Failed to aquire read-write action queue A lock") - .push(action), - ActiveActionQueue::B => self - .queue_b - .write_nonblock() - .expect("Failed to aquire read-write action queue A lock") - .push(action), - } - } -} - -impl TypeName for ActionQueue -{ - fn type_name(&self) -> &'static str - { - type_name::<Self>() + self.queue + .write_nonblock() + .expect("Failed to aquire read-write lock to action queue") + .push(action); } } @@ -701,7 +666,7 @@ impl SoleStorage self.storage.insert( sole_type_id, ManuallyDrop::new(StoredSole { - sole: Arc::new(Lock::new(Box::new(sole))), + sole: Arc::new(Lock::new(Box::new(sole), type_name::<SoleT>())), drop_last, }), ); @@ -718,18 +683,9 @@ impl Drop for SoleStorage for sole in self.storage.values_mut() { if sole.drop_last { - tracing::trace!( - "Sole {} pushed to dropping last queue", - sole.sole.read_nonblock().unwrap().type_name() - ); - soles_to_drop_last.push(sole); continue; } - tracing::trace!( - "Dropping sole {}", - sole.sole.read_nonblock().unwrap().type_name() - ); unsafe { ManuallyDrop::drop(sole); @@ -737,11 +693,6 @@ impl Drop for SoleStorage } for sole in &mut soles_to_drop_last { - tracing::trace!( - "Dropping sole {} last", - sole.sole.read_nonblock().unwrap().type_name() - ); - unsafe { ManuallyDrop::drop(sole); } |