Skip to main content

jsonld_syntax/
direction.rs

1use std::{fmt, str::FromStr};
2
3#[derive(Debug, thiserror::Error)]
4#[error("invalid JSON-LD text direction `{0}`")]
5/// Error raised when a string is neither `ltr` nor `rtl`.
6pub struct InvalidDirection<T>(pub T);
7
8impl<T: ?Sized + ToOwned> InvalidDirection<&T> {
9    /// Converts this `InvalidDirection` into an owned one.
10    #[must_use]
11    pub fn into_owned(self) -> InvalidDirection<T::Owned> {
12        InvalidDirection(self.0.to_owned())
13    }
14}
15
16/// Internationalized string direction.
17///
18/// Specifies the direction used to read a string.
19/// This can be either left-to-right (`"ltr"`) or right-to-left (`"rtl"`).
20#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
21pub enum Direction {
22    /// Left-to-right direction.
23    Ltr,
24
25    /// Right-to-left direction.
26    Rtl,
27}
28
29impl Direction {
30    /// Returns `"ltr"` or `"rtl"`.
31    #[must_use]
32    pub fn as_str(&self) -> &'static str {
33        match self {
34            Direction::Ltr => "ltr",
35            Direction::Rtl => "rtl",
36        }
37    }
38
39    /// Same as [`as_str`](Self::as_str), taking `self` by value.
40    #[must_use]
41    pub fn into_str(self) -> &'static str {
42        self.as_str()
43    }
44}
45
46impl FromStr for Direction {
47    type Err = InvalidDirection<String>;
48
49    fn from_str(s: &str) -> Result<Self, Self::Err> {
50        Self::try_from(s).map_err(InvalidDirection::into_owned)
51    }
52}
53
54impl<'a> TryFrom<&'a str> for Direction {
55    type Error = InvalidDirection<&'a str>;
56
57    /// Converts the strings `"ltr"` and `"rtl"` into a `Direction`.
58    #[inline(always)]
59    fn try_from(name: &'a str) -> Result<Direction, InvalidDirection<&'a str>> {
60        match name {
61            "ltr" => Ok(Direction::Ltr),
62            "rtl" => Ok(Direction::Rtl),
63            _ => Err(InvalidDirection(name)),
64        }
65    }
66}
67
68impl fmt::Display for Direction {
69    #[inline(always)]
70    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
71        match self {
72            Direction::Ltr => write!(f, "ltr"),
73            Direction::Rtl => write!(f, "rtl"),
74        }
75    }
76}
77
78#[cfg(feature = "serde")]
79impl serde::Serialize for Direction {
80    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
81    where
82        S: serde::Serializer,
83    {
84        self.as_str().serialize(serializer)
85    }
86}
87
88#[cfg(feature = "serde")]
89impl<'de> serde::Deserialize<'de> for Direction {
90    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
91    where
92        D: serde::Deserializer<'de>,
93    {
94        struct Visitor;
95
96        impl serde::de::Visitor<'_> for Visitor {
97            type Value = Direction;
98
99            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
100                formatter.write_str("JSON-LD text direction")
101            }
102
103            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
104            where
105                E: serde::de::Error,
106            {
107                v.parse().map_err(|e| E::custom(e))
108            }
109        }
110
111        deserializer.deserialize_str(Visitor)
112    }
113}