@@ -1243,8 +1243,9 @@ impl ComponentCloneBehavior {
1243
1243
1244
1244
/// A queued component registration.
1245
1245
struct QueuedRegistration {
1246
- registrator : Box < dyn FnOnce ( & mut ComponentsRegistrator , ComponentId ) > ,
1246
+ registrator : Box < dyn FnOnce ( & mut ComponentsRegistrator , ComponentId , ComponentDescriptor ) > ,
1247
1247
id : ComponentId ,
1248
+ descriptor : ComponentDescriptor ,
1248
1249
}
1249
1250
1250
1251
impl QueuedRegistration {
@@ -1255,17 +1256,19 @@ impl QueuedRegistration {
1255
1256
/// [`ComponentId`] must be unique.
1256
1257
unsafe fn new (
1257
1258
id : ComponentId ,
1258
- func : impl FnOnce ( & mut ComponentsRegistrator , ComponentId ) + ' static ,
1259
+ descriptor : ComponentDescriptor ,
1260
+ func : impl FnOnce ( & mut ComponentsRegistrator , ComponentId , ComponentDescriptor ) + ' static ,
1259
1261
) -> Self {
1260
1262
Self {
1261
1263
registrator : Box :: new ( func) ,
1262
1264
id,
1265
+ descriptor,
1263
1266
}
1264
1267
}
1265
1268
1266
1269
/// Performs the registration, returning the now valid [`ComponentId`].
1267
1270
fn register ( self , registrator : & mut ComponentsRegistrator ) -> ComponentId {
1268
- ( self . registrator ) ( registrator, self . id ) ;
1271
+ ( self . registrator ) ( registrator, self . id , self . descriptor ) ;
1269
1272
self . id
1270
1273
}
1271
1274
}
@@ -1362,6 +1365,7 @@ impl ComponentIds {
1362
1365
///
1363
1366
/// As a rule of thumb, if you have mutable access to [`ComponentsRegistrator`], prefer to use that instead.
1364
1367
/// Use this only if you need to know the id of a component but do not need to modify the contents of the world based on that id.
1368
+ #[ derive( Clone , Copy ) ]
1365
1369
pub struct ComponentsQueuedRegistrator < ' w > {
1366
1370
components : & ' w Components ,
1367
1371
ids : & ' w ComponentIds ,
@@ -1394,7 +1398,8 @@ impl<'w> ComponentsQueuedRegistrator<'w> {
1394
1398
unsafe fn force_register_arbitrary_component (
1395
1399
& self ,
1396
1400
type_id : TypeId ,
1397
- func : impl FnOnce ( & mut ComponentsRegistrator , ComponentId ) + ' static ,
1401
+ descriptor : ComponentDescriptor ,
1402
+ func : impl FnOnce ( & mut ComponentsRegistrator , ComponentId , ComponentDescriptor ) + ' static ,
1398
1403
) -> ComponentId {
1399
1404
let id = self . ids . next ( ) ;
1400
1405
self . components
@@ -1405,7 +1410,7 @@ impl<'w> ComponentsQueuedRegistrator<'w> {
1405
1410
. insert (
1406
1411
type_id,
1407
1412
// SAFETY: The id was just generated.
1408
- unsafe { QueuedRegistration :: new ( id, func) } ,
1413
+ unsafe { QueuedRegistration :: new ( id, descriptor , func) } ,
1409
1414
) ;
1410
1415
id
1411
1416
}
@@ -1418,7 +1423,8 @@ impl<'w> ComponentsQueuedRegistrator<'w> {
1418
1423
unsafe fn force_register_arbitrary_resource (
1419
1424
& self ,
1420
1425
type_id : TypeId ,
1421
- func : impl FnOnce ( & mut ComponentsRegistrator , ComponentId ) + ' static ,
1426
+ descriptor : ComponentDescriptor ,
1427
+ func : impl FnOnce ( & mut ComponentsRegistrator , ComponentId , ComponentDescriptor ) + ' static ,
1422
1428
) -> ComponentId {
1423
1429
let id = self . ids . next ( ) ;
1424
1430
self . components
@@ -1429,15 +1435,16 @@ impl<'w> ComponentsQueuedRegistrator<'w> {
1429
1435
. insert (
1430
1436
type_id,
1431
1437
// SAFETY: The id was just generated.
1432
- unsafe { QueuedRegistration :: new ( id, func) } ,
1438
+ unsafe { QueuedRegistration :: new ( id, descriptor , func) } ,
1433
1439
) ;
1434
1440
id
1435
1441
}
1436
1442
1437
1443
/// Queues this function to run as a dynamic registrator.
1438
1444
fn force_register_arbitrary_dynamic (
1439
1445
& self ,
1440
- func : impl FnOnce ( & mut ComponentsRegistrator , ComponentId ) + ' static ,
1446
+ descriptor : ComponentDescriptor ,
1447
+ func : impl FnOnce ( & mut ComponentsRegistrator , ComponentId , ComponentDescriptor ) + ' static ,
1441
1448
) -> ComponentId {
1442
1449
let id = self . ids . next ( ) ;
1443
1450
self . components
@@ -1447,7 +1454,7 @@ impl<'w> ComponentsQueuedRegistrator<'w> {
1447
1454
. dynamic_registrations
1448
1455
. push (
1449
1456
// SAFETY: The id was just generated.
1450
- unsafe { QueuedRegistration :: new ( id, func) } ,
1457
+ unsafe { QueuedRegistration :: new ( id, descriptor , func) } ,
1451
1458
) ;
1452
1459
id
1453
1460
}
@@ -1456,6 +1463,8 @@ impl<'w> ComponentsQueuedRegistrator<'w> {
1456
1463
/// This will reserve an id and queue the registration.
1457
1464
/// These registrations will be carried out at the next opportunity.
1458
1465
///
1466
+ /// If this has already been registered or queued, this returns the previous [`ComponentId`].
1467
+ ///
1459
1468
/// # Note
1460
1469
///
1461
1470
/// Technically speaking, the returned [`ComponentId`] is not valid, but it will become valid later.
@@ -1465,13 +1474,17 @@ impl<'w> ComponentsQueuedRegistrator<'w> {
1465
1474
self . component_id :: < T > ( ) . unwrap_or_else ( || {
1466
1475
// SAFETY: We just checked that this type was not in the queue.
1467
1476
unsafe {
1468
- self . force_register_arbitrary_component ( TypeId :: of :: < T > ( ) , |registrator, id| {
1469
- // SAFETY: We just checked that this is not currently registered or queued, and if it was registered since, this would have been dropped from the queue.
1470
- #[ expect( unused_unsafe, reason = "More precise to specify." ) ]
1471
- unsafe {
1472
- registrator. register_component_unchecked :: < T > ( & mut Vec :: new ( ) , id) ;
1473
- }
1474
- } )
1477
+ self . force_register_arbitrary_component (
1478
+ TypeId :: of :: < T > ( ) ,
1479
+ ComponentDescriptor :: new :: < T > ( ) ,
1480
+ |registrator, id, _descriptor| {
1481
+ // SAFETY: We just checked that this is not currently registered or queued, and if it was registered since, this would have been dropped from the queue.
1482
+ #[ expect( unused_unsafe, reason = "More precise to specify." ) ]
1483
+ unsafe {
1484
+ registrator. register_component_unchecked :: < T > ( & mut Vec :: new ( ) , id) ;
1485
+ }
1486
+ } ,
1487
+ )
1475
1488
}
1476
1489
} )
1477
1490
}
@@ -1489,7 +1502,7 @@ impl<'w> ComponentsQueuedRegistrator<'w> {
1489
1502
& self ,
1490
1503
descriptor : ComponentDescriptor ,
1491
1504
) -> ComponentId {
1492
- self . force_register_arbitrary_dynamic ( |registrator, id| {
1505
+ self . force_register_arbitrary_dynamic ( descriptor , |registrator, id, descriptor | {
1493
1506
// SAFETY: Id uniqueness handled by caller.
1494
1507
unsafe {
1495
1508
registrator. register_component_inner ( id, descriptor) ;
@@ -1501,6 +1514,8 @@ impl<'w> ComponentsQueuedRegistrator<'w> {
1501
1514
/// This will reserve an id and queue the registration.
1502
1515
/// These registrations will be carried out at the next opportunity.
1503
1516
///
1517
+ /// If this has already been registered or queued, this returns the previous [`ComponentId`].
1518
+ ///
1504
1519
/// # Note
1505
1520
///
1506
1521
/// Technically speaking, the returned [`ComponentId`] is not valid, but it will become valid later.
@@ -1511,16 +1526,18 @@ impl<'w> ComponentsQueuedRegistrator<'w> {
1511
1526
self . get_resource_id ( type_id) . unwrap_or_else ( || {
1512
1527
// SAFETY: We just checked that this type was not in the queue.
1513
1528
unsafe {
1514
- self . force_register_arbitrary_resource ( type_id, move |registrator, id| {
1515
- // SAFETY: We just checked that this is not currently registered or queued, and if it was registered since, this would have been dropped from the queue.
1516
- // SAFETY: Id uniqueness handled by caller, and the type_id matches descriptor.
1517
- #[ expect( unused_unsafe, reason = "More precise to specify." ) ]
1518
- unsafe {
1519
- registrator. register_resource_unchecked_with ( type_id, id, || {
1520
- ComponentDescriptor :: new_resource :: < T > ( )
1521
- } ) ;
1522
- }
1523
- } )
1529
+ self . force_register_arbitrary_resource (
1530
+ type_id,
1531
+ ComponentDescriptor :: new_resource :: < T > ( ) ,
1532
+ move |registrator, id, descriptor| {
1533
+ // SAFETY: We just checked that this is not currently registered or queued, and if it was registered since, this would have been dropped from the queue.
1534
+ // SAFETY: Id uniqueness handled by caller, and the type_id matches descriptor.
1535
+ #[ expect( unused_unsafe, reason = "More precise to specify." ) ]
1536
+ unsafe {
1537
+ registrator. register_resource_unchecked ( type_id, id, descriptor) ;
1538
+ }
1539
+ } ,
1540
+ )
1524
1541
}
1525
1542
} )
1526
1543
}
@@ -1529,6 +1546,8 @@ impl<'w> ComponentsQueuedRegistrator<'w> {
1529
1546
/// This will reserve an id and queue the registration.
1530
1547
/// These registrations will be carried out at the next opportunity.
1531
1548
///
1549
+ /// If this has already been registered or queued, this returns the previous [`ComponentId`].
1550
+ ///
1532
1551
/// # Note
1533
1552
///
1534
1553
/// Technically speaking, the returned [`ComponentId`] is not valid, but it will become valid later.
@@ -1539,16 +1558,18 @@ impl<'w> ComponentsQueuedRegistrator<'w> {
1539
1558
self . get_resource_id ( type_id) . unwrap_or_else ( || {
1540
1559
// SAFETY: We just checked that this type was not in the queue.
1541
1560
unsafe {
1542
- self . force_register_arbitrary_resource ( type_id, move |registrator, id| {
1543
- // SAFETY: We just checked that this is not currently registered or queued, and if it was registered since, this would have been dropped from the queue.
1544
- // SAFETY: Id uniqueness handled by caller, and the type_id matches descriptor.
1545
- #[ expect( unused_unsafe, reason = "More precise to specify." ) ]
1546
- unsafe {
1547
- registrator. register_resource_unchecked_with ( type_id, id, || {
1548
- ComponentDescriptor :: new_non_send :: < T > ( StorageType :: default ( ) )
1549
- } ) ;
1550
- }
1551
- } )
1561
+ self . force_register_arbitrary_resource (
1562
+ type_id,
1563
+ ComponentDescriptor :: new_non_send :: < T > ( StorageType :: default ( ) ) ,
1564
+ move |registrator, id, descriptor| {
1565
+ // SAFETY: We just checked that this is not currently registered or queued, and if it was registered since, this would have been dropped from the queue.
1566
+ // SAFETY: Id uniqueness handled by caller, and the type_id matches descriptor.
1567
+ #[ expect( unused_unsafe, reason = "More precise to specify." ) ]
1568
+ unsafe {
1569
+ registrator. register_resource_unchecked ( type_id, id, descriptor) ;
1570
+ }
1571
+ } ,
1572
+ )
1552
1573
}
1553
1574
} )
1554
1575
}
@@ -1566,7 +1587,7 @@ impl<'w> ComponentsQueuedRegistrator<'w> {
1566
1587
& self ,
1567
1588
descriptor : ComponentDescriptor ,
1568
1589
) -> ComponentId {
1569
- self . force_register_arbitrary_dynamic ( |registrator, id| {
1590
+ self . force_register_arbitrary_dynamic ( descriptor , |registrator, id, descriptor | {
1570
1591
// SAFETY: Id uniqueness handled by caller.
1571
1592
unsafe {
1572
1593
registrator. register_component_inner ( id, descriptor) ;
@@ -1870,7 +1891,7 @@ impl<'w> ComponentsRegistrator<'w> {
1870
1891
}
1871
1892
}
1872
1893
1873
- /// Same as [`Components::register_resource_unchecked_with `] but handles safety.
1894
+ /// Same as [`Components::register_resource_unchecked `] but handles safety.
1874
1895
///
1875
1896
/// # Safety
1876
1897
///
@@ -1901,7 +1922,7 @@ impl<'w> ComponentsRegistrator<'w> {
1901
1922
let id = self . ids . next_mut ( ) ;
1902
1923
// SAFETY: The resource is not currently registered, the id is fresh, and the [`ComponentDescriptor`] matches the [`TypeId`]
1903
1924
unsafe {
1904
- self . register_resource_unchecked_with ( type_id, id, descriptor) ;
1925
+ self . register_resource_unchecked ( type_id, id, descriptor ( ) ) ;
1905
1926
}
1906
1927
id
1907
1928
}
@@ -2027,13 +2048,53 @@ impl Components {
2027
2048
self . components . get ( id. 0 ) . and_then ( |info| info. as_ref ( ) )
2028
2049
}
2029
2050
2030
- /// Returns the name associated with the given component, if it is registered.
2031
- /// This will return `None` if the id is not regiserted or is queued.
2051
+ /// Gets the [`ComponentDescriptor`] of the component with this [`ComponentId`] if it is present.
2052
+ /// This will return `None` only if the id is neither regisered nor queued to be registered.
2053
+ ///
2054
+ /// Currently, the [`Cow`] will be [`Cow::Owned`] if and only if the component is queued. It will be [`Cow::Borrowed`] otherwise.
2032
2055
///
2033
2056
/// This will return an incorrect result if `id` did not come from the same world as `self`. It may return `None` or a garbage value.
2034
2057
#[ inline]
2035
- pub fn get_name ( & self , id : ComponentId ) -> Option < & str > {
2036
- self . get_info ( id) . map ( ComponentInfo :: name)
2058
+ pub fn get_descriptor < ' a > ( & ' a self , id : ComponentId ) -> Option < Cow < ' a , ComponentDescriptor > > {
2059
+ self . components
2060
+ . get ( id. 0 )
2061
+ . and_then ( |info| info. as_ref ( ) . map ( |info| Cow :: Borrowed ( & info. descriptor ) ) )
2062
+ . or_else ( || {
2063
+ let queued = self . queued . read ( ) . unwrap_or_else ( PoisonError :: into_inner) ;
2064
+ // first check components, then resources, then dynamic
2065
+ queued
2066
+ . components
2067
+ . values ( )
2068
+ . chain ( queued. resources . values ( ) )
2069
+ . chain ( queued. dynamic_registrations . iter ( ) )
2070
+ . find ( |queued| queued. id == id)
2071
+ . map ( |queued| Cow :: Owned ( queued. descriptor . clone ( ) ) )
2072
+ } )
2073
+ }
2074
+
2075
+ /// Gets the name of the component with this [`ComponentId`] if it is present.
2076
+ /// This will return `None` only if the id is neither regisered nor queued to be registered.
2077
+ ///
2078
+ /// This will return an incorrect result if `id` did not come from the same world as `self`. It may return `None` or a garbage value.
2079
+ #[ inline]
2080
+ pub fn get_name < ' a > ( & ' a self , id : ComponentId ) -> Option < Cow < ' a , str > > {
2081
+ self . components
2082
+ . get ( id. 0 )
2083
+ . and_then ( |info| {
2084
+ info. as_ref ( )
2085
+ . map ( |info| Cow :: Borrowed ( info. descriptor . name ( ) ) )
2086
+ } )
2087
+ . or_else ( || {
2088
+ let queued = self . queued . read ( ) . unwrap_or_else ( PoisonError :: into_inner) ;
2089
+ // first check components, then resources, then dynamic
2090
+ queued
2091
+ . components
2092
+ . values ( )
2093
+ . chain ( queued. resources . values ( ) )
2094
+ . chain ( queued. dynamic_registrations . iter ( ) )
2095
+ . find ( |queued| queued. id == id)
2096
+ . map ( |queued| queued. descriptor . name . clone ( ) )
2097
+ } )
2037
2098
}
2038
2099
2039
2100
/// Gets the metadata associated with the given component.
@@ -2456,15 +2517,15 @@ impl Components {
2456
2517
/// The [`ComponentId`] must be unique.
2457
2518
/// The [`TypeId`] and [`ComponentId`] must not be registered or queued.
2458
2519
#[ inline]
2459
- unsafe fn register_resource_unchecked_with (
2520
+ unsafe fn register_resource_unchecked (
2460
2521
& mut self ,
2461
2522
type_id : TypeId ,
2462
2523
component_id : ComponentId ,
2463
- func : impl FnOnce ( ) -> ComponentDescriptor ,
2524
+ descriptor : ComponentDescriptor ,
2464
2525
) {
2465
2526
// SAFETY: ensured by caller
2466
2527
unsafe {
2467
- self . register_component_inner ( component_id, func ( ) ) ;
2528
+ self . register_component_inner ( component_id, descriptor ) ;
2468
2529
}
2469
2530
let prev = self . resource_indices . insert ( type_id, component_id) ;
2470
2531
debug_assert ! ( prev. is_none( ) ) ;
@@ -2940,13 +3001,13 @@ pub fn enforce_no_required_components_recursion(
2940
3001
"Recursive required components detected: {}\n help: {}" ,
2941
3002
recursion_check_stack
2942
3003
. iter( )
2943
- . map( |id| format!( "{}" , ShortName ( components. get_name( * id) . unwrap( ) ) ) )
3004
+ . map( |id| format!( "{}" , ShortName ( & components. get_name( * id) . unwrap( ) ) ) )
2944
3005
. collect:: <Vec <_>>( )
2945
3006
. join( " → " ) ,
2946
3007
if direct_recursion {
2947
3008
format!(
2948
3009
"Remove require({})." ,
2949
- ShortName ( components. get_name( requiree) . unwrap( ) )
3010
+ ShortName ( & components. get_name( requiree) . unwrap( ) )
2950
3011
)
2951
3012
} else {
2952
3013
"If this is intentional, consider merging the components." . into( )
0 commit comments