1#![cfg_attr(docsrs, feature(doc_cfg))]
3#![cfg_attr(feature = "frozen-abi", feature(min_specialization))]
4#[cfg(feature = "serde")]
5use serde_derive::{Deserialize, Serialize};
6
7#[cfg_attr(feature = "frozen-abi", derive(atlas_frozen_abi_macro::AbiExample))]
8#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
9#[derive(PartialEq, Clone, Debug, Copy)]
10#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
11pub struct Inflation {
12 pub initial: f64,
14
15 pub terminal: f64,
17
18 pub taper: f64,
21
22 pub foundation: f64,
24 pub foundation_term: f64,
26
27 __unused: f64,
29}
30
31const DEFAULT_INITIAL: f64 = 0.08;
32const DEFAULT_TERMINAL: f64 = 0.015;
33const DEFAULT_TAPER: f64 = 0.15;
34const DEFAULT_FOUNDATION: f64 = 0.05;
35const DEFAULT_FOUNDATION_TERM: f64 = 7.0;
36
37impl Default for Inflation {
38 fn default() -> Self {
39 Self {
40 initial: DEFAULT_INITIAL,
41 terminal: DEFAULT_TERMINAL,
42 taper: DEFAULT_TAPER,
43 foundation: DEFAULT_FOUNDATION,
44 foundation_term: DEFAULT_FOUNDATION_TERM,
45 __unused: 0.0,
46 }
47 }
48}
49
50impl Inflation {
51 pub fn new_disabled() -> Self {
52 Self {
53 initial: 0.0,
54 terminal: 0.0,
55 taper: 0.0,
56 foundation: 0.0,
57 foundation_term: 0.0,
58 __unused: 0.0,
59 }
60 }
61
62 pub fn new_fixed(validator: f64) -> Self {
64 Self {
65 initial: validator,
66 terminal: validator,
67 taper: 1.0,
68 foundation: 0.0,
69 foundation_term: 0.0,
70 __unused: 0.0,
71 }
72 }
73
74 pub fn pico() -> Self {
75 Self::new_fixed(0.0001) }
77
78 pub fn full() -> Self {
79 Self {
80 initial: DEFAULT_INITIAL,
81 terminal: DEFAULT_TERMINAL,
82 taper: DEFAULT_TAPER,
83 foundation: 0.0,
84 foundation_term: 0.0,
85 __unused: 0.0,
86 }
87 }
88
89 pub fn total(&self, year: f64) -> f64 {
91 assert!(year >= 0.0);
92 let tapered = self.initial * ((1.0 - self.taper).powf(year));
93
94 if tapered > self.terminal {
95 tapered
96 } else {
97 self.terminal
98 }
99 }
100
101 pub fn validator(&self, year: f64) -> f64 {
103 self.total(year) - self.foundation(year)
104 }
105
106 pub fn foundation(&self, year: f64) -> f64 {
108 if year < self.foundation_term {
109 self.total(year) * self.foundation
110 } else {
111 0.0
112 }
113 }
114}
115
116#[cfg(test)]
117mod tests {
118 use super::*;
119
120 #[test]
121 fn test_inflation_basic() {
122 let inflation = Inflation::default();
123
124 let mut last = inflation.total(0.0);
125
126 for year in &[0.1, 0.5, 1.0, DEFAULT_FOUNDATION_TERM, 100.0] {
127 let total = inflation.total(*year);
128 assert_eq!(
129 total,
130 inflation.validator(*year) + inflation.foundation(*year)
131 );
132 assert!(total < last);
133 assert!(total >= inflation.terminal);
134 last = total;
135 }
136 assert_eq!(last, inflation.terminal);
137 }
138
139 #[test]
140 fn test_inflation_fixed() {
141 let inflation = Inflation::new_fixed(0.001);
142 for year in &[0.1, 0.5, 1.0, DEFAULT_FOUNDATION_TERM, 100.0] {
143 assert_eq!(inflation.total(*year), 0.001);
144 }
145 }
146}