1use crate::{ExpandedName, XbrlError};
6use std::{fmt, str::FromStr};
7
8#[derive(Debug, Clone, PartialEq, Eq)]
14pub enum Decimals {
15 Infinite,
17 Finite(i32),
19}
20
21impl FromStr for Decimals {
22 type Err = XbrlError;
23
24 fn from_str(str: &str) -> Result<Self, Self::Err> {
25 if str.eq_ignore_ascii_case("INF") {
26 return Ok(Self::Infinite);
27 }
28 str.parse::<i32>()
29 .map(Self::Finite)
30 .map_err(|_| XbrlError::ParseError {
31 expected: "Decimals",
32 value: str.to_owned(),
33 })
34 }
35}
36
37impl fmt::Display for Decimals {
38 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39 match self {
40 Self::Infinite => f.write_str("INF"),
41 Self::Finite(n) => write!(f, "{n}"),
42 }
43 }
44}
45
46#[derive(Debug, Clone)]
48pub enum Fact {
49 Item(ItemFact),
51 Tuple(TupleFact),
54}
55
56#[derive(Debug, Clone)]
58pub struct ItemFact {
59 concept_name: ExpandedName,
61 id: Option<String>,
63 context_ref: String,
65 unit_ref: Option<String>,
67 value: String,
69 is_nil: bool,
71 decimals: Option<Decimals>,
73 precision: Option<Decimals>,
75}
76
77impl ItemFact {
78 #[allow(clippy::too_many_arguments)]
79 pub fn new(
80 id: Option<String>,
81 concept_name: ExpandedName,
82 context_ref: String,
83 unit_ref: Option<String>,
84 value: String,
85 is_nil: bool,
86 decimals: Option<Decimals>,
87 precision: Option<Decimals>,
88 ) -> Self {
89 Self {
90 id,
91 concept_name,
92 context_ref,
93 unit_ref,
94 value,
95 is_nil,
96 decimals,
97 precision,
98 }
99 }
100
101 pub fn concept_name(&self) -> &ExpandedName {
102 &self.concept_name
103 }
104
105 pub fn id(&self) -> Option<&str> {
106 self.id.as_deref()
107 }
108
109 pub fn set_id(&mut self, id: String) {
110 self.id = Some(id);
111 }
112
113 pub fn context_ref(&self) -> &str {
114 &self.context_ref
115 }
116
117 pub fn unit_ref(&self) -> Option<&str> {
118 self.unit_ref.as_deref()
119 }
120
121 pub fn value(&self) -> &str {
122 &self.value
123 }
124
125 pub fn is_nil(&self) -> bool {
126 self.is_nil
127 }
128
129 pub fn set_value(&mut self, value: String) {
130 self.value = value;
131 }
132
133 pub fn set_nil(&mut self, is_nil: bool) {
134 self.is_nil = is_nil;
135 }
136
137 pub fn decimals(&self) -> Option<&Decimals> {
138 self.decimals.as_ref()
139 }
140
141 pub fn set_decimals(&mut self, decimals: Decimals) {
142 self.decimals = Some(decimals);
143 }
144
145 pub fn precision(&self) -> Option<&Decimals> {
146 self.precision.as_ref()
147 }
148
149 pub fn set_precision(&mut self, precision: Decimals) {
150 self.precision = Some(precision);
151 }
152}
153
154#[derive(Debug, Clone)]
156pub struct TupleFact {
157 id: Option<String>,
159 concept_name: ExpandedName,
162 is_nil: bool,
165 children: Vec<Fact>,
167}
168
169impl TupleFact {
170 pub fn new(concept_name: ExpandedName) -> Self {
171 Self {
172 id: None,
173 concept_name,
174 is_nil: false,
175 children: Vec::new(),
176 }
177 }
178
179 pub fn concept_name(&self) -> &ExpandedName {
180 &self.concept_name
181 }
182
183 pub fn id(&self) -> Option<&str> {
184 self.id.as_deref()
185 }
186
187 pub fn set_id(&mut self, id: String) {
188 self.id = Some(id);
189 }
190
191 pub fn is_nil(&self) -> bool {
192 self.is_nil
193 }
194
195 pub fn set_nil(&mut self, is_nil: bool) {
196 self.is_nil = is_nil;
197 }
198
199 pub fn children(&self) -> &[Fact] {
200 &self.children
201 }
202
203 pub fn children_mut(&mut self) -> &mut Vec<Fact> {
204 &mut self.children
205 }
206
207 pub fn add_child(&mut self, child: Fact) {
208 self.children.push(child);
209 }
210}
211
212impl Fact {
213 pub fn item(
214 concept: ExpandedName,
215 context_ref: String,
216 unit_ref: Option<String>,
217 value: String,
218 ) -> Self {
219 Self::Item(ItemFact::new(
220 None,
221 concept,
222 context_ref,
223 unit_ref,
224 value,
225 false,
226 None,
227 None,
228 ))
229 }
230
231 pub fn tuple(concept_name: ExpandedName) -> Self {
232 Self::Tuple(TupleFact::new(concept_name))
233 }
234
235 pub fn concept_name(&self) -> &ExpandedName {
236 match self {
237 Self::Item(fact) => fact.concept_name(),
238 Self::Tuple(fact) => fact.concept_name(),
239 }
240 }
241
242 pub fn id(&self) -> Option<&str> {
243 match self {
244 Self::Item(fact) => fact.id(),
245 Self::Tuple(fact) => fact.id(),
246 }
247 }
248
249 pub fn as_item(&self) -> Option<&ItemFact> {
250 match self {
251 Self::Item(fact) => Some(fact),
252 Self::Tuple(_) => None,
253 }
254 }
255
256 pub fn as_item_mut(&mut self) -> Option<&mut ItemFact> {
257 match self {
258 Self::Item(fact) => Some(fact),
259 Self::Tuple(_) => None,
260 }
261 }
262
263 pub fn as_tuple(&self) -> Option<&TupleFact> {
264 match self {
265 Self::Item(_) => None,
266 Self::Tuple(fact) => Some(fact),
267 }
268 }
269
270 pub fn as_tuple_mut(&mut self) -> Option<&mut TupleFact> {
271 match self {
272 Self::Item(_) => None,
273 Self::Tuple(fact) => Some(fact),
274 }
275 }
276
277 pub fn walk_items<'a>(&'a self, out: &mut Vec<&'a ItemFact>) {
278 match self {
279 Self::Item(fact) => out.push(fact),
280 Self::Tuple(fact) => {
281 for child in &fact.children {
282 child.walk_items(out);
283 }
284 }
285 }
286 }
287
288 pub fn walk_items_mut<'a>(&'a mut self, out: &mut Vec<&'a mut ItemFact>) {
289 match self {
290 Self::Item(fact) => out.push(fact),
291 Self::Tuple(fact) => {
292 for child in &mut fact.children {
293 child.walk_items_mut(out);
294 }
295 }
296 }
297 }
298
299 pub fn count_items(&self) -> usize {
300 match self {
301 Self::Item(_) => 1,
302 Self::Tuple(tuple_fact) => tuple_fact
303 .children
304 .iter()
305 .map(|fact| fact.count_items())
306 .sum(),
307 }
308 }
309}