@@ -51,18 +51,28 @@ pub enum AssetState {
5151 Commissioned {
5252 /// The ID of the asset
5353 id : AssetID ,
54+ /// The ID of the agent that owns the asset
55+ agent_id : AgentID ,
5456 } ,
5557 /// The asset has been decommissioned
5658 Decommissioned {
5759 /// The ID of the asset
5860 id : AssetID ,
61+ /// The ID of the agent that owned the asset
62+ agent_id : AgentID ,
5963 /// The year the asset was decommissioned
6064 decommission_year : u32 ,
6165 } ,
6266 /// The asset is planned for commissioning in the future
63- Future ,
67+ Future {
68+ /// The ID of the agent that will own the asset
69+ agent_id : AgentID ,
70+ } ,
6471 /// The asset has been selected for investment, but not yet confirmed
65- Selected ,
72+ Selected {
73+ /// The ID of the agent that would own the asset
74+ agent_id : AgentID ,
75+ } ,
6676 /// The asset is a candidate for investment but has not yet been selected by an agent
6777 Candidate ,
6878}
@@ -72,8 +82,6 @@ pub enum AssetState {
7282pub struct Asset {
7383 /// The status of the asset
7484 state : AssetState ,
75- /// The ID of the agent that owns the asset
76- agent_id : AgentID ,
7785 /// The [`Process`] that this asset corresponds to
7886 process : Rc < Process > ,
7987 /// Activity limits for this asset
@@ -93,15 +101,13 @@ pub struct Asset {
93101impl Asset {
94102 /// Create a new candidate asset
95103 pub fn new_candidate (
96- agent_id : AgentID ,
97104 process : Rc < Process > ,
98105 region_id : RegionID ,
99106 capacity : Capacity ,
100107 commission_year : u32 ,
101108 ) -> Result < Self > {
102109 Self :: new_with_state (
103110 AssetState :: Candidate ,
104- agent_id,
105111 process,
106112 region_id,
107113 capacity,
@@ -129,8 +135,7 @@ impl Asset {
129135 ) -> Result < Self > {
130136 check_capacity_valid_for_asset ( capacity) ?;
131137 Self :: new_with_state (
132- AssetState :: Future ,
133- agent_id,
138+ AssetState :: Future { agent_id } ,
134139 process,
135140 region_id,
136141 capacity,
@@ -151,8 +156,7 @@ impl Asset {
151156 commission_year : u32 ,
152157 ) -> Result < Self > {
153158 Self :: new_with_state (
154- AssetState :: Selected ,
155- agent_id,
159+ AssetState :: Selected { agent_id } ,
156160 process,
157161 region_id,
158162 capacity,
@@ -163,7 +167,6 @@ impl Asset {
163167 /// Private helper to create an asset with the given state
164168 fn new_with_state (
165169 state : AssetState ,
166- agent_id : AgentID ,
167170 process : Rc < Process > ,
168171 region_id : RegionID ,
169172 capacity : Capacity ,
@@ -214,7 +217,6 @@ impl Asset {
214217
215218 Ok ( Self {
216219 state,
217- agent_id,
218220 process,
219221 activity_limits,
220222 flows,
@@ -360,8 +362,14 @@ impl Asset {
360362 }
361363
362364 /// Get the agent ID for this asset
363- pub fn agent_id ( & self ) -> & AgentID {
364- & self . agent_id
365+ pub fn agent_id ( & self ) -> Option < & AgentID > {
366+ match & self . state {
367+ AssetState :: Commissioned { agent_id, .. }
368+ | AssetState :: Decommissioned { agent_id, .. }
369+ | AssetState :: Future { agent_id }
370+ | AssetState :: Selected { agent_id } => Some ( agent_id) ,
371+ AssetState :: Candidate => None ,
372+ }
365373 }
366374
367375 /// Get the capacity for this asset
@@ -391,20 +399,21 @@ impl Asset {
391399
392400 /// Decommission this asset
393401 fn decommission ( & mut self , decommission_year : u32 , reason : & str ) {
394- let id = match & self . state {
395- AssetState :: Commissioned { id } => * id,
402+ let ( id , agent_id ) = match & self . state {
403+ AssetState :: Commissioned { id, agent_id } => ( * id, agent_id . clone ( ) ) ,
396404 _ => panic ! ( "Cannot decommission an asset that hasn't been commissioned" ) ,
397405 } ;
398406 debug ! (
399407 "Decommissioning '{}' asset (ID: {}) for agent '{}' (reason: {})" ,
400408 self . process_id( ) ,
401409 id,
402- self . agent_id,
410+ agent_id,
403411 reason
404412 ) ;
405413
406414 self . state = AssetState :: Decommissioned {
407415 id,
416+ agent_id,
408417 decommission_year,
409418 } ;
410419 }
@@ -419,29 +428,31 @@ impl Asset {
419428 /// * `id` - The ID to give the newly commissioned asset
420429 /// * `reason` - The reason for commissioning (included in log)
421430 fn commission ( & mut self , id : AssetID , reason : & str ) {
422- assert ! (
423- matches!( self . state, AssetState :: Future | AssetState :: Selected ) ,
424- "Assets with state {} cannot be commissioned" ,
425- self . state
426- ) ;
431+ let agent_id = match & self . state {
432+ AssetState :: Future { agent_id } | AssetState :: Selected { agent_id } => agent_id,
433+ state => panic ! ( "Assets with state {state} cannot be commissioned" ) ,
434+ } ;
427435 debug ! (
428436 "Commissioning '{}' asset (ID: {}) for agent '{}' (reason: {})" ,
429437 self . process_id( ) ,
430438 id,
431- self . agent_id,
439+ agent_id,
432440 reason
433441 ) ;
434- self . state = AssetState :: Commissioned { id } ;
442+ self . state = AssetState :: Commissioned {
443+ id,
444+ agent_id : agent_id. clone ( ) ,
445+ } ;
435446 }
436447
437448 /// Select a Candidate asset for investment, converting it to a Selected state
438- pub fn select_candidate_for_investment ( & mut self ) {
449+ pub fn select_candidate_for_investment ( & mut self , agent_id : AgentID ) {
439450 assert ! (
440451 self . state == AssetState :: Candidate ,
441452 "select_candidate_for_investment can only be called on Candidate assets"
442453 ) ;
443454 check_capacity_valid_for_asset ( self . capacity ) . unwrap ( ) ;
444- self . state = AssetState :: Selected ;
455+ self . state = AssetState :: Selected { agent_id } ;
445456 }
446457}
447458
@@ -546,8 +557,8 @@ impl Eq for AssetRef {}
546557impl Hash for AssetRef {
547558 /// Hash an asset according to its state:
548559 /// - Commissioned assets are hashed based on their ID alone
549- /// - Candidate and Selected assets are hashed based on `state `, `process_id `, `region_id`,
550- /// `commission_year` and `agent_id `
560+ /// - Selected assets are hashed based on `process_id `, `region_id `, `commission_year` and `agent_id`
561+ /// - Candidate assets are hashed based on `process_id`, `region_id` and `commission_year `
551562 /// - Future and Decommissioned assets cannot currently be hashed
552563 fn hash < H : Hasher > ( & self , state : & mut H ) {
553564 match & self . 0 . state {
@@ -556,14 +567,15 @@ impl Hash for AssetRef {
556567 // asset
557568 id. hash ( state) ;
558569 }
559- AssetState :: Candidate | AssetState :: Selected => {
560- self . 0 . state . hash ( state) ;
570+ AssetState :: Candidate | AssetState :: Selected { .. } => {
571+ // Hashed based on process_id, region_id, commission_year and (for Selected assets)
572+ // agent_id
561573 self . 0 . process . id . hash ( state) ;
562574 self . 0 . region_id . hash ( state) ;
563575 self . 0 . commission_year . hash ( state) ;
564- self . 0 . agent_id . hash ( state) ;
576+ self . 0 . agent_id ( ) . hash ( state) ;
565577 }
566- AssetState :: Future | AssetState :: Decommissioned { .. } => {
578+ AssetState :: Future { .. } | AssetState :: Decommissioned { .. } => {
567579 // We shouldn't currently need to hash Future or Decommissioned assets
568580 unimplemented ! ( "Cannot hash Future or Decommissioned assets" ) ;
569581 }
@@ -747,7 +759,7 @@ impl AssetPool {
747759 // then commission them
748760 let assets = assets. into_iter ( ) . map ( |mut asset| match & asset. state {
749761 AssetState :: Commissioned { .. } => asset,
750- AssetState :: Selected => {
762+ AssetState :: Selected { .. } => {
751763 asset
752764 . make_mut ( )
753765 . commission ( AssetID ( self . next_id ) , "selected" ) ;
@@ -777,7 +789,7 @@ where
777789{
778790 /// Filter assets by the agent that owns them
779791 fn filter_agent ( self , agent_id : & ' a AgentID ) -> impl Iterator < Item = & ' a AssetRef > + ' a {
780- self . filter ( move |asset| asset. agent_id ( ) == agent_id)
792+ self . filter ( move |asset| asset. agent_id ( ) == Some ( agent_id) )
781793 }
782794
783795 /// Iterate over assets that have the given commodity as a primary output
@@ -813,8 +825,7 @@ mod tests {
813825 use super :: * ;
814826 use crate :: commodity:: { Commodity , CommodityID , CommodityType } ;
815827 use crate :: fixture:: {
816- agent_id, assert_error, asset, commodity_id, process, process_parameter_map, region_id,
817- time_slice,
828+ assert_error, asset, commodity_id, process, process_parameter_map, region_id, time_slice,
818829 } ;
819830 use crate :: process:: {
820831 FlowType , Process , ProcessActivityLimitsMap , ProcessFlow , ProcessFlowsMap , ProcessID ,
@@ -836,7 +847,6 @@ mod tests {
836847
837848 #[ rstest]
838849 fn test_get_input_cost_from_prices (
839- agent_id : AgentID ,
840850 region_id : RegionID ,
841851 commodity_id : CommodityID ,
842852 mut process_parameter_map : ProcessParameterMap ,
@@ -892,8 +902,7 @@ mod tests {
892902 } ) ;
893903
894904 // Create asset
895- let asset = Asset :: new_candidate ( agent_id, process, region_id. clone ( ) , Capacity ( 1.0 ) , 2020 )
896- . unwrap ( ) ;
905+ let asset = Asset :: new_candidate ( process, region_id. clone ( ) , Capacity ( 1.0 ) , 2020 ) . unwrap ( ) ;
897906
898907 // Set input prices
899908 let mut input_prices = HashMap :: new ( ) ;
@@ -1213,11 +1222,11 @@ mod tests {
12131222 assert_eq ! ( asset_pool. active[ original_count + 1 ] . id( ) , Some ( AssetID ( 3 ) ) ) ;
12141223 assert_eq ! (
12151224 asset_pool. active[ original_count] . agent_id( ) ,
1216- & "agent2" . into( )
1225+ Some ( & "agent2" . into( ) )
12171226 ) ;
12181227 assert_eq ! (
12191228 asset_pool. active[ original_count + 1 ] . agent_id( ) ,
1220- & "agent3" . into( )
1229+ Some ( & "agent3" . into( ) )
12211230 ) ;
12221231 }
12231232
@@ -1250,7 +1259,7 @@ mod tests {
12501259 asset_pool
12511260 . active
12521261 . iter( )
1253- . any( |a| a. agent_id( ) == & "agent_new" . into( ) )
1262+ . any( |a| a. agent_id( ) == Some ( & "agent_new" . into( ) ) )
12541263 ) ;
12551264 }
12561265
@@ -1428,13 +1437,13 @@ mod tests {
14281437 }
14291438
14301439 #[ rstest]
1431- fn test_asset_state_transitions ( agent_id : AgentID , process : Process , region_id : RegionID ) {
1440+ fn test_asset_state_transitions ( process : Process ) {
14321441 // Test successful commissioning of Future asset
1433- let process = Rc :: new ( process) ;
1442+ let process_rc = Rc :: new ( process) ;
14341443 let mut asset1 = Asset :: new_future (
1435- agent_id . clone ( ) ,
1436- Rc :: clone ( & process ) ,
1437- region_id . clone ( ) ,
1444+ "agent1" . into ( ) ,
1445+ Rc :: clone ( & process_rc ) ,
1446+ "GBR" . into ( ) ,
14381447 Capacity ( 1.0 ) ,
14391448 2020 ,
14401449 )
@@ -1444,8 +1453,14 @@ mod tests {
14441453 assert_eq ! ( asset1. id( ) , Some ( AssetID ( 1 ) ) ) ;
14451454
14461455 // Test successful commissioning of Selected asset
1447- let mut asset2 =
1448- Asset :: new_selected ( agent_id, process, region_id, Capacity ( 1.0 ) , 2020 ) . unwrap ( ) ;
1456+ let mut asset2 = Asset :: new_selected (
1457+ "agent1" . into ( ) ,
1458+ Rc :: clone ( & process_rc) ,
1459+ "GBR" . into ( ) ,
1460+ Capacity ( 1.0 ) ,
1461+ 2020 ,
1462+ )
1463+ . unwrap ( ) ;
14491464 asset2. commission ( AssetID ( 2 ) , "" ) ;
14501465 assert ! ( asset2. is_commissioned( ) ) ;
14511466 assert_eq ! ( asset2. id( ) , Some ( AssetID ( 2 ) ) ) ;
@@ -1458,17 +1473,17 @@ mod tests {
14581473
14591474 #[ rstest]
14601475 #[ should_panic( expected = "Assets with state Candidate cannot be commissioned" ) ]
1461- fn test_commission_wrong_states ( agent_id : AgentID , process : Process , region_id : RegionID ) {
1476+ fn test_commission_wrong_states ( process : Process ) {
14621477 let mut asset =
1463- Asset :: new_candidate ( agent_id , process. into ( ) , region_id , Capacity ( 1.0 ) , 2020 ) . unwrap ( ) ;
1478+ Asset :: new_candidate ( process. into ( ) , "GBR" . into ( ) , Capacity ( 1.0 ) , 2020 ) . unwrap ( ) ;
14641479 asset. commission ( AssetID ( 1 ) , "" ) ;
14651480 }
14661481
14671482 #[ rstest]
14681483 #[ should_panic( expected = "Cannot decommission an asset that hasn't been commissioned" ) ]
1469- fn test_decommission_wrong_state ( agent_id : AgentID , process : Process , region_id : RegionID ) {
1484+ fn test_decommission_wrong_state ( process : Process ) {
14701485 let mut asset =
1471- Asset :: new_candidate ( agent_id , process. into ( ) , region_id , Capacity ( 1.0 ) , 2020 ) . unwrap ( ) ;
1486+ Asset :: new_candidate ( process. into ( ) , "GBR" . into ( ) , Capacity ( 1.0 ) , 2020 ) . unwrap ( ) ;
14721487 asset. decommission ( 2025 , "" ) ;
14731488 }
14741489}
0 commit comments