Skip to content

Commit c19f7c6

Browse files
committed
Add Display impls for type, name, variable
1 parent 1d212ba commit c19f7c6

File tree

5 files changed

+210
-6
lines changed

5 files changed

+210
-6
lines changed

src/types/name.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! Contains names.
22
33
use crate::types::{PrimitiveType, ToTyped, Type, Typed};
4+
use std::fmt::{Display, Formatter};
45
use std::ops::Deref;
56

67
/// A name.
@@ -56,3 +57,20 @@ impl<'a> Deref for Name<'a> {
5657
&self.0
5758
}
5859
}
60+
61+
impl<'a> Display for Name<'a> {
62+
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
63+
write!(f, "{}", self.0)
64+
}
65+
}
66+
67+
#[cfg(test)]
68+
mod tests {
69+
use super::*;
70+
71+
#[test]
72+
fn it_works() {
73+
let name = Name::new("x");
74+
assert_eq!(format!("{name}"), "x");
75+
}
76+
}

src/types/type.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! Contains types.
22
33
use crate::types::Name;
4+
use std::fmt::{Display, Formatter};
45
use std::ops::Deref;
56

67
/// The `object` type.
@@ -30,6 +31,14 @@ impl<'a> Type<'a> {
3031
/// The predefined type `number`.
3132
pub const NUMBER: Type<'a> = Type::Exactly(TYPE_NUMBER);
3233

34+
pub fn new_exactly<S: Into<PrimitiveType<'a>>>(t: S) -> Self {
35+
Self::Exactly(t.into())
36+
}
37+
38+
pub fn new_either<T: IntoIterator<Item = P>, P: Into<PrimitiveType<'a>>>(iter: T) -> Self {
39+
Self::EitherOf(iter.into_iter().map(|x| x.into()).collect())
40+
}
41+
3342
pub fn len(&self) -> usize {
3443
match self {
3544
Type::Exactly(_) => 1,
@@ -102,3 +111,38 @@ impl<'a> Deref for PrimitiveType<'a> {
102111
&self.0
103112
}
104113
}
114+
115+
impl<'a> Display for Type<'a> {
116+
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
117+
match self {
118+
Type::Exactly(x) => write!(f, "{}", x),
119+
Type::EitherOf(xs) => {
120+
let xs: Vec<_> = xs.iter().map(|p| p.to_string()).collect();
121+
write!(f, "(either {})", xs.join(" "))
122+
}
123+
}
124+
}
125+
}
126+
127+
impl<'a> Display for PrimitiveType<'a> {
128+
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
129+
write!(f, "{}", self.0)
130+
}
131+
}
132+
133+
#[cfg(test)]
134+
mod tests {
135+
use super::*;
136+
137+
#[test]
138+
fn simple_works() {
139+
let t = Type::new_exactly("location");
140+
assert_eq!(format!("{t}"), "location");
141+
}
142+
143+
#[test]
144+
fn either_works() {
145+
let t = Type::new_either(["location", "memory"]);
146+
assert_eq!(format!("{t}"), "(either location memory)");
147+
}
148+
}

src/types/typed.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ impl<'a, O> Typed<'a, O> {
1616
Self::new(value, Type::OBJECT)
1717
}
1818

19-
pub const fn value_ref(&self) -> &O {
19+
pub const fn value(&self) -> &O {
2020
&self.0
2121
}
2222

23-
pub const fn type_ref(&self) -> &Type<'a> {
23+
pub const fn type_name(&self) -> &Type<'a> {
2424
&self.1
2525
}
2626
}
@@ -69,6 +69,6 @@ impl<'a, O> Deref for Typed<'a, O> {
6969
type Target = O;
7070

7171
fn deref(&self) -> &Self::Target {
72-
self.value_ref()
72+
self.value()
7373
}
7474
}

src/types/typed_list.rs

Lines changed: 122 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
use crate::types::Typed;
1+
use crate::types::{Type, Typed};
2+
use std::fmt::{Display, Formatter};
23
use std::ops::Deref;
34

45
/// A list of typed elements.
@@ -12,8 +13,8 @@ use std::ops::Deref;
1213
/// ]);
1314
///
1415
/// 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"));
1718
/// ```
1819
#[derive(Debug, Default, Clone, Eq, PartialEq)]
1920
pub struct TypedList<'a, T>(Vec<Typed<'a, T>>);
@@ -70,3 +71,121 @@ impl<'a, T> IntoIterator for TypedList<'a, T> {
7071
self.0.into_iter()
7172
}
7273
}
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+
}

src/types/variable.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
11
//! Contains variables.
22
33
use crate::types::{Name, PrimitiveType, ToTyped, Type, Typed};
4+
use std::fmt::{Display, Formatter};
45
use std::ops::Deref;
56

67
/// A variable name.
78
#[derive(Debug, Clone, Eq, PartialEq, Hash, Default)]
89
pub struct Variable<'a>(Name<'a>);
910

1011
impl<'a> Variable<'a> {
12+
#[inline(always)]
13+
pub fn new<N: Into<Name<'a>>>(name: N) -> Self {
14+
Self(name.into())
15+
}
16+
1117
#[inline(always)]
1218
pub const fn from_str(name: &'a str) -> Self {
1319
Self(Name::new(name))
@@ -67,3 +73,20 @@ impl<'a> Deref for Variable<'a> {
6773
&self.0
6874
}
6975
}
76+
77+
impl<'a> Display for Variable<'a> {
78+
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
79+
write!(f, "?{}", self.0)
80+
}
81+
}
82+
83+
#[cfg(test)]
84+
mod tests {
85+
use super::*;
86+
87+
#[test]
88+
fn it_works() {
89+
let var = Variable::from_str("x");
90+
assert_eq!(format!("{var}"), "?x");
91+
}
92+
}

0 commit comments

Comments
 (0)