erlang_term/term/
improper_list.rs

1use crate::Term;
2
3#[derive(Debug, Clone, PartialEq)]
4#[cfg_attr(feature = "serde_impl", derive(Serialize, Deserialize))]
5pub struct ImproperList {
6    head: Vec<Term>,
7    tail: Option<Term>,
8}
9
10impl ImproperList {
11    pub fn new() -> ImproperList {
12        ImproperList::from_list(Vec::new())
13    }
14
15    pub fn from_list(head: Vec<Term>) -> ImproperList {
16        ImproperList { head, tail: None }
17    }
18
19    pub fn from_parts(head: Vec<Term>, tail: Term) -> ImproperList {
20        ImproperList {
21            head,
22            tail: Some(tail),
23        }
24    }
25
26    pub fn set_tail(&mut self, term: Term) {
27        if term.is_list() {
28            self.head.extend(term.as_list().unwrap());
29        } else {
30            self.tail = Some(term)
31        }
32    }
33
34    pub fn put_tail(mut self, tail: Term) -> Self {
35        self.set_tail(tail);
36        self
37    }
38
39    pub fn get_tail(&self) -> Option<&Term> {
40        self.tail.as_ref()
41    }
42
43    pub fn get_mut_tail(&mut self) -> Option<&mut Term> {
44        self.tail.as_mut()
45    }
46}
47
48impl std::ops::Deref for ImproperList {
49    type Target = Vec<Term>;
50
51    fn deref(&self) -> &Self::Target {
52        &self.head
53    }
54}
55
56impl std::ops::DerefMut for ImproperList {
57    fn deref_mut(&mut self) -> &mut Vec<Term> {
58        &mut self.head
59    }
60}
61
62#[test]
63fn extend_list() {
64    let list = ImproperList::from_list(vec![Term::Int(123), Term::Int(124), Term::Int(125)]);
65
66    let new_list = list.put_tail(Term::List(vec![
67        Term::Int(256),
68        Term::Int(257),
69        Term::Int(258),
70    ]));
71    let expected = ImproperList::from_list(vec![
72        Term::Int(123),
73        Term::Int(124),
74        Term::Int(125),
75        Term::Int(256),
76        Term::Int(257),
77        Term::Int(258),
78    ]);
79
80    assert_eq!(new_list, expected);
81}
82
83#[test]
84fn deref() {
85    let list = ImproperList::from_list(vec![Term::Int(123), Term::Int(124), Term::Int(125)]);
86
87    assert_eq!(Some(&Term::Int(124)), list.get(1))
88}
89
90#[test]
91fn deref_mut() {
92    let mut list = ImproperList::from_list(vec![Term::Int(123), Term::Int(124), Term::Int(125)]);
93
94    list.push(Term::Int(555));
95    assert_eq!(Some(&Term::Int(555)), list.last())
96}
97
98#[test]
99fn get_tail() {
100    let list = ImproperList::from_list(vec![Term::Int(123), Term::Int(124), Term::Int(125)]);
101    assert_eq!(None, list.get_tail());
102
103    let list = ImproperList::from_parts(
104        vec![Term::Int(123), Term::Int(124), Term::Int(125)],
105        Term::Int(999),
106    );
107    assert_eq!(Some(&Term::Int(999)), list.get_tail());
108}
109
110#[test]
111fn get_mut_tail() {
112    let mut expected = std::collections::HashMap::new();
113    expected.insert(Term::from(String::from("test")), Term::Int(16));
114
115    let mut list = ImproperList::from_parts(
116        vec![Term::Int(123), Term::Int(124), Term::Int(125)],
117        Term::Map(Default::default()),
118    );
119
120    if let Some(tail) = list.get_mut_tail() {
121        match tail {
122            Term::Map(map) => {
123                map.insert(Term::from(String::from("test")), Term::Int(16));
124            }
125            _ => unreachable!(),
126        }
127    }
128
129    assert_eq!(Some(&Term::Map(expected)), list.get_tail());
130}