hledger_parser/component/
price.rs1use chumsky::prelude::*;
2
3use crate::component::amount::{amount, Amount};
4use crate::component::whitespace::whitespace;
5use crate::state::State;
6
7#[allow(clippy::module_name_repetitions)]
8#[derive(Clone, Debug, PartialEq)]
9pub enum AmountPrice {
10 Unit(Amount),
11 Total(Amount),
12}
13
14#[allow(clippy::module_name_repetitions)]
15pub fn amount_price<'a>(
16) -> impl Parser<'a, &'a str, AmountPrice, extra::Full<Rich<'a, char>, State, ()>> {
17 just("@")
18 .repeated()
19 .at_least(1)
20 .at_most(2)
21 .collect::<Vec<_>>()
22 .then_ignore(whitespace().repeated())
23 .then(amount())
24 .map(|(price_type, price)| {
25 if price_type.len() == 1 {
26 AmountPrice::Unit(price)
27 } else {
28 AmountPrice::Total(price)
29 }
30 })
31}
32
33#[cfg(test)]
34mod tests {
35 use rust_decimal::Decimal;
36
37 use super::*;
38
39 #[test]
40 fn total_price() {
41 let result = amount_price()
42 .then_ignore(end())
43 .parse("@@ $1.35")
44 .into_result();
45 assert_eq!(
46 result,
47 Ok(AmountPrice::Total(Amount {
48 commodity: String::from("$"),
49 quantity: Decimal::new(135, 2)
50 }))
51 );
52 }
53
54 #[test]
55 fn unit_price() {
56 let result = amount_price()
57 .then_ignore(end())
58 .parse("@ $1.35")
59 .into_result();
60 assert_eq!(
61 result,
62 Ok(AmountPrice::Unit(Amount {
63 commodity: String::from("$"),
64 quantity: Decimal::new(135, 2),
65 }))
66 );
67 }
68}