Skip to content

Commit 851be5e

Browse files
committed
Add better hints support
1 parent a096511 commit 851be5e

File tree

4 files changed

+129
-167
lines changed

4 files changed

+129
-167
lines changed

src/hint_set.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
const WILDCARD: &'static str = "-";
2+
3+
#[derive(Debug)]
4+
pub struct HintSet<'a> {
5+
values: Vec<&'a [String]>,
6+
}
7+
8+
impl<'a> HintSet<'a> {
9+
pub fn new(values: Vec<&'a [String]>) -> Self {
10+
HintSet { values }
11+
}
12+
13+
pub fn sub_hints(&self, key: &str) -> Self {
14+
Self::new(
15+
self.values
16+
.iter()
17+
.filter(|values| {
18+
let first = values.first().map(String::as_str);
19+
first == Some(WILDCARD) || first == Some(key)
20+
})
21+
.map(|values| &values[1..])
22+
.collect(),
23+
)
24+
}
25+
26+
pub fn is_active(&self) -> bool {
27+
self.values.iter().any(|values| values.is_empty())
28+
}
29+
30+
pub fn peek_active(&self) -> Option<&str> {
31+
self.values
32+
.iter()
33+
.find(|values| values.len() == 1)
34+
.and_then(|values| values.first().map(String::as_str))
35+
}
36+
}

src/hints.rs

Lines changed: 0 additions & 149 deletions
This file was deleted.

src/lib.rs

Lines changed: 88 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,36 @@
1-
mod hints;
1+
mod hint_set;
22

3-
pub use hints::Hints;
3+
pub use hint_set::HintSet;
4+
5+
#[derive(Debug)]
6+
pub struct Hints<'a> {
7+
values: HintSet<'a>,
8+
discriminator: HintSet<'a>,
9+
}
10+
11+
impl<'a> Hints<'a> {
12+
pub fn new(values: HintSet<'a>, discriminator: HintSet<'a>) -> Self {
13+
Hints {
14+
values,
15+
discriminator,
16+
}
17+
}
18+
19+
fn sub_hints(&self, key: &str) -> Self {
20+
Self::new(
21+
self.values.sub_hints(key),
22+
self.discriminator.sub_hints(key),
23+
)
24+
}
25+
26+
fn is_values_active(&self) -> bool {
27+
self.values.is_active()
28+
}
29+
30+
fn peek_active_discriminator(&self) -> Option<&str> {
31+
self.discriminator.peek_active()
32+
}
33+
}
434

535
use chrono::DateTime;
636
use jtd::form::{self, TypeValue};
@@ -69,26 +99,42 @@ impl InferredSchema {
6999

70100
InferredSchema::Array(Box::new(sub_infer))
71101
}
72-
(InferredSchema::Unknown, Value::Object(obj)) => {
102+
(InferredSchema::Unknown, Value::Object(mut obj)) => {
73103
if hints.is_values_active() {
74104
let mut sub_infer = InferredSchema::Unknown;
75105
for (k, v) in obj {
76106
sub_infer = sub_infer.infer(v, &hints.sub_hints(&k));
77107
}
78108

79-
InferredSchema::Values(Box::new(sub_infer))
80-
} else {
81-
let mut props = HashMap::new();
82-
for (k, v) in obj {
83-
let sub_infer = InferredSchema::Unknown.infer(v, &hints.sub_hints(&k));
84-
props.insert(k, sub_infer);
85-
}
109+
return InferredSchema::Values(Box::new(sub_infer));
110+
}
111+
112+
if let Some(discriminator) = hints.peek_active_discriminator() {
113+
if let Some(Value::String(mapping_key)) = obj.remove(discriminator) {
114+
let infer_rest = InferredSchema::Unknown.infer(Value::Object(obj), hints);
86115

87-
InferredSchema::Properties {
88-
required: props,
89-
optional: HashMap::new(),
116+
dbg!("infer rest", &discriminator, &infer_rest);
117+
118+
let mut mapping = HashMap::new();
119+
mapping.insert(mapping_key.to_owned(), infer_rest);
120+
121+
return InferredSchema::Discriminator {
122+
discriminator: discriminator.to_owned(),
123+
mapping,
124+
};
90125
}
91126
}
127+
128+
let mut props = HashMap::new();
129+
for (k, v) in obj {
130+
let sub_infer = InferredSchema::Unknown.infer(v, &hints.sub_hints(&k));
131+
props.insert(k, sub_infer);
132+
}
133+
134+
InferredSchema::Properties {
135+
required: props,
136+
optional: HashMap::new(),
137+
}
92138
}
93139
(InferredSchema::Any, _) => InferredSchema::Any,
94140
(InferredSchema::Bool, Value::Bool(_)) => InferredSchema::Bool,
@@ -198,7 +244,35 @@ impl InferredSchema {
198244

199245
return InferredSchema::Values(Box::new(sub_infer));
200246
}
201-
_ => unimplemented!(),
247+
(InferredSchema::Values(_), _) => InferredSchema::Any,
248+
(
249+
InferredSchema::Discriminator {
250+
discriminator,
251+
mut mapping,
252+
},
253+
Value::Object(mut obj),
254+
) => {
255+
let mapping_key = obj.remove(&discriminator);
256+
if let Some(Value::String(mapping_key_str)) = mapping_key {
257+
if !mapping.contains_key(&mapping_key_str) {
258+
mapping.insert(mapping_key_str.clone(), InferredSchema::Unknown);
259+
}
260+
261+
let sub_infer = mapping
262+
.remove(&mapping_key_str)
263+
.unwrap()
264+
.infer(Value::Object(obj), hints);
265+
mapping.insert(mapping_key_str, sub_infer);
266+
267+
InferredSchema::Discriminator {
268+
discriminator,
269+
mapping,
270+
}
271+
} else {
272+
InferredSchema::Any
273+
}
274+
}
275+
(InferredSchema::Discriminator { .. }, _) => InferredSchema::Any,
202276
}
203277
}
204278

src/main.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use clap::{App, AppSettings, Arg};
22
use failure::Error;
3-
use jtd_infer::{Hints, InferredSchema};
3+
use jtd_infer::{HintSet, Hints, InferredSchema};
44
use serde_json::Deserializer;
55
use std::fs::File;
66
use std::io::stdin;
@@ -50,10 +50,11 @@ fn main() -> Result<(), Error> {
5050
.map(parse_json_pointer)
5151
.collect();
5252

53-
let value_hint_slices = values_hints.iter().map(|p| &p[..]).collect();
54-
let discriminator_hint_slices = discriminator_hints.iter().map(|p| &p[..]).collect();
53+
let hints = Hints::new(
54+
HintSet::new(values_hints.iter().map(|p| &p[..]).collect()),
55+
HintSet::new(discriminator_hints.iter().map(|p| &p[..]).collect()),
56+
);
5557

56-
let hints = Hints::new(value_hint_slices, discriminator_hint_slices);
5758
let mut inference = InferredSchema::Unknown;
5859

5960
let stream = Deserializer::from_reader(reader);

0 commit comments

Comments
 (0)