erlang_term/term/
improper_list.rs1use 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}