1use std::{fmt, marker};
2
3use crate::{
4 Path, Root,
5 gltf::Get,
6 validation::{self, Validate},
7};
8
9pub struct StringIndex<T>(String, marker::PhantomData<fn() -> T>);
10
11impl<T> StringIndex<T> {
12 pub fn new(value: String) -> Self {
14 StringIndex(value, std::marker::PhantomData)
15 }
16
17 pub fn value(&self) -> &str {
19 &self.0
20 }
21}
22
23impl<T> serde::Serialize for StringIndex<T> {
24 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
25 where
26 S: ::serde::Serializer,
27 {
28 serializer.serialize_str(self.value())
29 }
30}
31
32impl<'de, T> serde::Deserialize<'de> for StringIndex<T> {
33 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
34 where
35 D: serde::Deserializer<'de>,
36 {
37 struct Visitor<T>(marker::PhantomData<T>);
38 impl<T> serde::de::Visitor<'_> for Visitor<T> {
39 type Value = StringIndex<T>;
40
41 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
42 formatter.write_str("index into child of root")
43 }
44
45 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
46 where
47 E: serde::de::Error,
48 {
49 Ok(StringIndex::new(v.to_string()))
50 }
51
52 fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
53 where
54 E: serde::de::Error,
55 {
56 Ok(StringIndex::new(v))
57 }
58 }
59 deserializer.deserialize_str(Visitor::<T>(marker::PhantomData))
60 }
61}
62
63impl<T> Ord for StringIndex<T> {
64 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
65 self.0.cmp(&other.0)
66 }
67}
68impl<T> PartialOrd for StringIndex<T> {
69 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
70 Some(self.cmp(other))
71 }
72}
73
74impl<T> Eq for StringIndex<T> {}
75impl<T> PartialEq for StringIndex<T> {
76 fn eq(&self, other: &Self) -> bool {
77 self.0 == other.0
78 }
79}
80
81impl<T> std::hash::Hash for StringIndex<T> {
82 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
83 self.0.hash(state);
84 }
85}
86
87impl<T> fmt::Debug for StringIndex<T> {
88 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
89 write!(f, "{}", self.0)
90 }
91}
92
93impl<T> fmt::Display for StringIndex<T> {
94 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
95 write!(f, "{}", self.0)
96 }
97}
98
99impl<T> Clone for StringIndex<T> {
100 fn clone(&self) -> Self {
101 Self::new(self.0.clone())
102 }
103}
104
105impl<T> Validate for StringIndex<T>
106where
107 Root: Get<T>,
108{
109 fn validate<P, R>(&self, root: &Root, path: P, report: &mut R)
110 where
111 P: Fn() -> Path,
112 R: FnMut(&dyn Fn() -> Path, validation::Error),
113 {
114 if root.get(self.clone()).is_none() {
115 report(&path, validation::Error::IndexNotFound);
116 }
117 }
118}