1
- use crate :: types:: Typed ;
1
+ use crate :: types:: { Type , Typed } ;
2
+ use std:: fmt:: { Display , Formatter } ;
2
3
use std:: ops:: Deref ;
3
4
4
5
/// A list of typed elements.
@@ -12,8 +13,8 @@ use std::ops::Deref;
12
13
/// ]);
13
14
///
14
15
/// assert_eq!(tl.len(), 2);
15
- /// assert_eq!(tl[0].value_ref (), &Name::from("location"));
16
- /// assert_eq!(tl[1].value_ref (), &Name::from("physob"));
16
+ /// assert_eq!(tl[0].value (), &Name::from("location"));
17
+ /// assert_eq!(tl[1].value (), &Name::from("physob"));
17
18
/// ```
18
19
#[ derive( Debug , Default , Clone , Eq , PartialEq ) ]
19
20
pub struct TypedList < ' a , T > ( Vec < Typed < ' a , T > > ) ;
@@ -70,3 +71,121 @@ impl<'a, T> IntoIterator for TypedList<'a, T> {
70
71
self . 0 . into_iter ( )
71
72
}
72
73
}
74
+
75
+ impl < ' a , T > Display for TypedList < ' a , T >
76
+ where
77
+ T : Display ,
78
+ {
79
+ fn fmt ( & self , f : & mut Formatter < ' _ > ) -> std:: fmt:: Result {
80
+ if self . is_empty ( ) {
81
+ return Ok ( ( ) ) ;
82
+ }
83
+
84
+ let mut stack = Vec :: with_capacity ( self . len ( ) ) ;
85
+ let mut type_required = false ;
86
+ let mut last_type = & Type :: OBJECT ;
87
+
88
+ for item in self . iter ( ) . rev ( ) {
89
+ // The `object` type is the default (for non-fluents) but can only
90
+ // be omitted if it is the last type displayed.
91
+ if !type_required && item. type_name ( ) . eq ( & Type :: OBJECT ) {
92
+ stack. push ( format ! ( "{}" , item. value( ) ) ) ;
93
+ continue ;
94
+ }
95
+
96
+ // The moment a non-`object` type is noticed, we are required to list names.
97
+ type_required = true ;
98
+
99
+ // If the type is identical to the one of the previous iteration,
100
+ // it was already stated (since we are iterating backwards).
101
+ // Therefore, we can skip it.
102
+ if last_type. eq ( item. type_name ( ) ) {
103
+ stack. push ( format ! ( "{}" , item. value( ) ) )
104
+ } else {
105
+ stack. push ( format ! ( "{} - {}" , item. value( ) , item. type_name( ) ) ) ;
106
+ last_type = item. type_name ( ) ;
107
+ }
108
+ }
109
+
110
+ stack = stack. into_iter ( ) . rev ( ) . collect ( ) ;
111
+ write ! ( f, "{}" , stack. join( " " ) )
112
+ }
113
+ }
114
+
115
+ #[ cfg( test) ]
116
+ mod tests {
117
+ use super :: * ;
118
+ use crate :: types:: { Name , ToTyped , Type , Variable } ;
119
+
120
+ #[ test]
121
+ fn object_is_default_works ( ) {
122
+ let name = TypedList :: from_iter ( [ Name :: new ( "x" ) . to_typed ( Type :: OBJECT ) ] ) ;
123
+ assert_eq ! ( format!( "{name}" ) , "x" ) ;
124
+ }
125
+
126
+ #[ test]
127
+ fn multiple_object_works ( ) {
128
+ let name = TypedList :: from_iter ( [
129
+ Name :: new ( "x" ) . to_typed ( Type :: OBJECT ) ,
130
+ Name :: new ( "y" ) . to_typed ( Type :: OBJECT ) ,
131
+ Name :: new ( "z" ) . to_typed ( Type :: OBJECT ) ,
132
+ ] ) ;
133
+ assert_eq ! ( format!( "{name}" ) , "x y z" ) ;
134
+ }
135
+
136
+ #[ test]
137
+ fn simple_works ( ) {
138
+ let name = TypedList :: from_iter ( [ Name :: new ( "x" ) . to_typed ( Type :: new_exactly ( "letter" ) ) ] ) ;
139
+ assert_eq ! ( format!( "{name}" ) , "x - letter" ) ;
140
+ }
141
+
142
+ #[ test]
143
+ fn multiple_same_works ( ) {
144
+ let name = TypedList :: from_iter ( [
145
+ Name :: new ( "x" ) . to_typed ( Type :: new_exactly ( "letter" ) ) ,
146
+ Name :: new ( "y" ) . to_typed ( Type :: new_exactly ( "letter" ) ) ,
147
+ Name :: new ( "z" ) . to_typed ( Type :: new_exactly ( "letter" ) ) ,
148
+ ] ) ;
149
+ assert_eq ! ( format!( "{name}" ) , "x y z - letter" ) ;
150
+ }
151
+
152
+ #[ test]
153
+ fn interleaved_at_end ( ) {
154
+ let name = TypedList :: from_iter ( [
155
+ Name :: new ( "x" ) . to_typed ( Type :: new_exactly ( "letter" ) ) ,
156
+ Name :: new ( "y" ) . to_typed ( Type :: new_exactly ( "letter" ) ) ,
157
+ Name :: new ( "z" ) . to_typed ( Type :: new_exactly ( "car" ) ) ,
158
+ ] ) ;
159
+ assert_eq ! ( format!( "{name}" ) , "x y - letter z - car" ) ;
160
+ }
161
+
162
+ #[ test]
163
+ fn interleaved ( ) {
164
+ let name = TypedList :: from_iter ( [
165
+ Name :: new ( "x" ) . to_typed ( Type :: new_exactly ( "letter" ) ) ,
166
+ Name :: new ( "y" ) . to_typed ( Type :: new_exactly ( "car" ) ) ,
167
+ Name :: new ( "z" ) . to_typed ( Type :: new_exactly ( "letter" ) ) ,
168
+ ] ) ;
169
+ assert_eq ! ( format!( "{name}" ) , "x - letter y - car z - letter" ) ;
170
+ }
171
+
172
+ #[ test]
173
+ fn object_at_end ( ) {
174
+ let name = TypedList :: from_iter ( [
175
+ Name :: new ( "x" ) . to_typed ( Type :: new_exactly ( "letter" ) ) ,
176
+ Name :: new ( "y" ) . to_typed ( Type :: OBJECT ) ,
177
+ Name :: new ( "z" ) . to_typed ( Type :: OBJECT ) ,
178
+ ] ) ;
179
+ assert_eq ! ( format!( "{name}" ) , "x - letter y z" ) ;
180
+ }
181
+
182
+ #[ test]
183
+ fn object_at_start ( ) {
184
+ let name = TypedList :: from_iter ( [
185
+ Variable :: new ( "x" ) . to_typed ( Type :: OBJECT ) ,
186
+ Variable :: new ( "y" ) . to_typed ( Type :: OBJECT ) ,
187
+ Variable :: new ( "z" ) . to_typed ( Type :: new_exactly ( "letter" ) ) ,
188
+ ] ) ;
189
+ assert_eq ! ( format!( "{name}" ) , "?x ?y - object ?z - letter" ) ;
190
+ }
191
+ }
0 commit comments