Skip to content

Commit ee017c0

Browse files
committed
Put AssetCapacity in submodule
1 parent af4f10d commit ee017c0

2 files changed

Lines changed: 219 additions & 206 deletions

File tree

src/asset.rs

Lines changed: 3 additions & 206 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,11 @@ use std::cell::Cell;
2020
use std::cmp::Ordering;
2121
use std::hash::{Hash, Hasher};
2222
use std::iter;
23-
use std::ops::{Add, Deref, RangeInclusive, Sub};
23+
use std::ops::{Deref, RangeInclusive};
2424
use std::rc::Rc;
2525

26+
mod capacity;
27+
pub use capacity::AssetCapacity;
2628
mod pool;
2729
pub use pool::AssetPool;
2830

@@ -117,155 +119,6 @@ pub enum AssetState {
117119
Candidate,
118120
}
119121

120-
/// Capacity of an asset, which may be continuous or a discrete number of indivisible units
121-
#[derive(Clone, PartialEq, Copy, Debug)]
122-
pub enum AssetCapacity {
123-
/// Continuous capacity
124-
Continuous(Capacity),
125-
/// Discrete capacity represented by a number of indivisible units
126-
/// Stores: (number of units, unit size)
127-
Discrete(u32, Capacity),
128-
}
129-
130-
impl Add for AssetCapacity {
131-
type Output = Self;
132-
133-
// Add two AssetCapacity values together
134-
fn add(self, rhs: AssetCapacity) -> Self {
135-
match (self, rhs) {
136-
(AssetCapacity::Continuous(cap1), AssetCapacity::Continuous(cap2)) => {
137-
AssetCapacity::Continuous(cap1 + cap2)
138-
}
139-
(AssetCapacity::Discrete(units1, size1), AssetCapacity::Discrete(units2, size2)) => {
140-
Self::check_same_unit_size(size1, size2);
141-
AssetCapacity::Discrete(units1 + units2, size1)
142-
}
143-
_ => panic!("Cannot add different types of AssetCapacity ({self:?} and {rhs:?})"),
144-
}
145-
}
146-
}
147-
148-
impl Sub for AssetCapacity {
149-
type Output = Self;
150-
151-
// Subtract rhs from self, ensuring that the result is non-negative
152-
fn sub(self, rhs: AssetCapacity) -> Self {
153-
match (self, rhs) {
154-
(AssetCapacity::Continuous(cap1), AssetCapacity::Continuous(cap2)) => {
155-
AssetCapacity::Continuous((cap1 - cap2).max(Capacity(0.0)))
156-
}
157-
(AssetCapacity::Discrete(units1, size1), AssetCapacity::Discrete(units2, size2)) => {
158-
Self::check_same_unit_size(size1, size2);
159-
AssetCapacity::Discrete(units1 - units2.min(units1), size1)
160-
}
161-
_ => panic!("Cannot subtract different types of AssetCapacity ({self:?} and {rhs:?})"),
162-
}
163-
}
164-
}
165-
166-
impl Eq for AssetCapacity {}
167-
168-
impl PartialOrd for AssetCapacity {
169-
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
170-
Some(self.cmp(other))
171-
}
172-
}
173-
174-
impl Ord for AssetCapacity {
175-
fn cmp(&self, other: &Self) -> Ordering {
176-
match (self, other) {
177-
(AssetCapacity::Continuous(a), AssetCapacity::Continuous(b)) => a.total_cmp(b),
178-
(AssetCapacity::Discrete(units1, size1), AssetCapacity::Discrete(units2, size2)) => {
179-
Self::check_same_unit_size(*size1, *size2);
180-
units1.cmp(units2)
181-
}
182-
_ => panic!("Cannot compare different types of AssetCapacity ({self:?} and {other:?})"),
183-
}
184-
}
185-
}
186-
187-
impl AssetCapacity {
188-
/// Validates that two discrete capacities have the same unit size.
189-
fn check_same_unit_size(size1: Capacity, size2: Capacity) {
190-
assert_eq!(
191-
size1, size2,
192-
"Can't perform operation on capacities with different unit sizes ({size1} and {size2})",
193-
);
194-
}
195-
196-
/// Create an `AssetCapacity` from a total capacity and optional unit size
197-
///
198-
/// If a unit size is provided, the capacity is represented as a discrete number of units,
199-
/// calculated as the ceiling of (capacity / `unit_size`). If no unit size is provided, the
200-
/// capacity is represented as continuous.
201-
pub fn from_capacity(capacity: Capacity, unit_size: Option<Capacity>) -> Self {
202-
#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
203-
match unit_size {
204-
Some(size) => {
205-
let num_units = (capacity / size).value().ceil() as u32;
206-
AssetCapacity::Discrete(num_units, size)
207-
}
208-
None => AssetCapacity::Continuous(capacity),
209-
}
210-
}
211-
212-
/// Create an `AssetCapacity` from a total capacity and optional unit size
213-
///
214-
/// If a unit size is provided, the capacity is represented as a discrete number of units,
215-
/// calculated as the floor of (capacity / `unit_size`). If no unit size is provided, the
216-
/// capacity is represented as continuous.
217-
pub fn from_capacity_floor(capacity: Capacity, unit_size: Option<Capacity>) -> Self {
218-
#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
219-
match unit_size {
220-
Some(size) => {
221-
let num_units = (capacity / size).value().floor() as u32;
222-
AssetCapacity::Discrete(num_units, size)
223-
}
224-
None => AssetCapacity::Continuous(capacity),
225-
}
226-
}
227-
228-
/// Returns the total capacity represented by this `AssetCapacity`.
229-
pub fn total_capacity(&self) -> Capacity {
230-
match self {
231-
AssetCapacity::Continuous(cap) => *cap,
232-
AssetCapacity::Discrete(units, size) => *size * Dimensionless(*units as f64),
233-
}
234-
}
235-
236-
/// Returns the number of units if this is a discrete capacity, or `None` if continuous.
237-
pub fn n_units(&self) -> Option<u32> {
238-
match self {
239-
AssetCapacity::Continuous(_) => None,
240-
AssetCapacity::Discrete(units, _) => Some(*units),
241-
}
242-
}
243-
244-
/// Asserts that both capacities are the same type (both continuous or both discrete).
245-
pub fn assert_same_type(&self, other: AssetCapacity) {
246-
assert!(
247-
matches!(self, AssetCapacity::Continuous(_))
248-
== matches!(other, AssetCapacity::Continuous(_)),
249-
"Cannot change capacity type"
250-
);
251-
}
252-
253-
/// Applies a limit factor to the capacity, scaling it accordingly.
254-
///
255-
/// For discrete capacities, the number of units is scaled by the limit factor and rounded up to
256-
/// the nearest integer.
257-
pub fn apply_limit_factor(self, limit_factor: Dimensionless) -> Self {
258-
#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
259-
match self {
260-
AssetCapacity::Continuous(cap) => AssetCapacity::Continuous(cap * limit_factor),
261-
AssetCapacity::Discrete(units, size) => {
262-
let new_units = (units as f64 * limit_factor.value()).ceil() as u32;
263-
AssetCapacity::Discrete(new_units, size)
264-
}
265-
}
266-
}
267-
}
268-
269122
/// An asset controlled by an agent.
270123
#[derive(Clone, PartialEq)]
271124
pub struct Asset {
@@ -1388,62 +1241,6 @@ mod tests {
13881241
use rstest::{fixture, rstest};
13891242
use std::rc::Rc;
13901243

1391-
#[rstest]
1392-
#[case::exact_multiple(Capacity(12.0), Some(Capacity(4.0)), Some(3), Capacity(12.0))]
1393-
#[case::rounded_up(Capacity(11.0), Some(Capacity(4.0)), Some(3), Capacity(12.0))]
1394-
#[case::unit_size_greater_than_capacity(
1395-
Capacity(3.0),
1396-
Some(Capacity(4.0)),
1397-
Some(1),
1398-
Capacity(4.0)
1399-
)]
1400-
#[case::continuous(Capacity(5.5), None, None, Capacity(5.5))]
1401-
fn from_capacity(
1402-
#[case] capacity: Capacity,
1403-
#[case] unit_size: Option<Capacity>,
1404-
#[case] expected_n: Option<u32>,
1405-
#[case] expected_total: Capacity,
1406-
) {
1407-
let got = AssetCapacity::from_capacity(capacity, unit_size);
1408-
assert_eq!(got.n_units(), expected_n);
1409-
assert_eq!(got.total_capacity(), expected_total);
1410-
}
1411-
1412-
#[rstest]
1413-
#[case::exact_multiple(Capacity(12.0), Some(Capacity(4.0)), Some(3), Capacity(12.0))]
1414-
#[case::rounded_down(Capacity(11.0), Some(Capacity(4.0)), Some(2), Capacity(8.0))]
1415-
#[case::unit_size_greater_than_capacity(
1416-
Capacity(3.0),
1417-
Some(Capacity(4.0)),
1418-
Some(0),
1419-
Capacity(0.0)
1420-
)]
1421-
#[case::continuous(Capacity(5.5), None, None, Capacity(5.5))]
1422-
fn from_capacity_floor(
1423-
#[case] capacity: Capacity,
1424-
#[case] unit_size: Option<Capacity>,
1425-
#[case] expected_n: Option<u32>,
1426-
#[case] expected_total: Capacity,
1427-
) {
1428-
let got = AssetCapacity::from_capacity_floor(capacity, unit_size);
1429-
assert_eq!(got.n_units(), expected_n);
1430-
assert_eq!(got.total_capacity(), expected_total);
1431-
}
1432-
1433-
#[rstest]
1434-
#[case::round_up(3u32, Capacity(4.0), Dimensionless(0.5), 2u32)]
1435-
#[case::exact(3u32, Capacity(4.0), Dimensionless(0.33), 1u32)]
1436-
fn apply_limit_factor(
1437-
#[case] start_units: u32,
1438-
#[case] unit_size: Capacity,
1439-
#[case] factor: Dimensionless,
1440-
#[case] expected_units: u32,
1441-
) {
1442-
let orig = AssetCapacity::Discrete(start_units, unit_size);
1443-
let got = orig.apply_limit_factor(factor);
1444-
assert_eq!(got, AssetCapacity::Discrete(expected_units, unit_size));
1445-
}
1446-
14471244
#[rstest]
14481245
fn get_input_cost_from_prices_works(
14491246
region_id: RegionID,

0 commit comments

Comments
 (0)