1use iref::IriBuf;
2
3use super::BindingRef;
4use super::Context;
5use super::Key;
6use crate::{Container, Direction, LenientLangTag, LenientLangTagBuf, Nullable, Term, Type};
7use std::cmp::Ordering;
8use std::collections::HashMap;
9use std::fmt;
10use std::hash::Hash;
11
12#[derive(Clone, PartialEq, Eq)]
13pub enum TypeSelection<T = IriBuf> {
14 Reverse,
15 Any,
16 Type(Type<T>),
17}
18
19impl<T: fmt::Debug> fmt::Debug for TypeSelection<T> {
20 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
21 match self {
22 TypeSelection::Reverse => write!(f, "Reverse"),
23 TypeSelection::Any => write!(f, "Any"),
24 TypeSelection::Type(ty) => write!(f, "Type({ty:?})"),
25 }
26 }
27}
28
29struct InverseType<T> {
30 reverse: Option<Key>,
31 any: Option<Key>,
32 map: HashMap<Type<T>, Key>,
33}
34
35impl<T> InverseType<T> {
36 fn select(&self, selection: TypeSelection<T>) -> Option<&Key>
37 where
38 T: Hash + Eq,
39 {
40 match selection {
41 TypeSelection::Reverse => self.reverse.as_ref(),
42 TypeSelection::Any => self.any.as_ref(),
43 TypeSelection::Type(ty) => self.map.get(&ty),
44 }
45 }
46
47 fn set_any(&mut self, term: &Key) {
48 if self.any.is_none() {
49 self.any = Some(term.clone())
50 }
51 }
52
53 fn set_none(&mut self, term: &Key)
54 where
55 T: Clone + Hash + Eq,
56 {
57 self.set(&Type::None, term)
58 }
59
60 fn set(&mut self, ty: &Type<T>, term: &Key)
61 where
62 T: Clone + Hash + Eq,
63 {
64 if !self.map.contains_key(ty) {
65 self.map.insert(ty.clone(), term.clone());
66 }
67 }
68}
69
70type LangDir = Nullable<(Option<LenientLangTagBuf>, Option<Direction>)>;
71
72struct InverseLang {
73 any: Option<Key>,
74 map: HashMap<LangDir, Key>,
75}
76
77#[derive(Clone, Copy, PartialEq, Eq, Debug)]
78pub enum LangSelection<'a> {
79 Any,
80 Lang(Nullable<(Option<&'a LenientLangTag>, Option<Direction>)>),
81}
82
83impl InverseLang {
84 fn select(&self, selection: LangSelection) -> Option<&Key> {
85 match selection {
86 LangSelection::Any => self.any.as_ref(),
87 LangSelection::Lang(lang_dir) => {
88 let lang_dir = lang_dir.map(|(l, d)| (l.map(|l| l.to_owned()), d));
89 self.map.get(&lang_dir)
90 }
91 }
92 }
93
94 fn set_any(&mut self, term: &Key) {
95 if self.any.is_none() {
96 self.any = Some(term.clone())
97 }
98 }
99
100 fn set_none(&mut self, term: &Key) {
101 self.set(Nullable::Some((None, None)), term)
102 }
103
104 fn set(
105 &mut self,
106 lang_dir: Nullable<(Option<&LenientLangTag>, Option<Direction>)>,
107 term: &Key,
108 ) {
109 let lang_dir = lang_dir.map(|(l, d)| (l.map(|l| l.to_owned()), d));
110 self.map.entry(lang_dir).or_insert_with(|| term.clone());
111 }
112}
113
114struct InverseContainer<T> {
115 language: InverseLang,
116 typ: InverseType<T>,
117 any: Any,
118}
119
120struct Any {
121 none: Key,
122}
123
124impl<T> InverseContainer<T> {
125 pub fn new(term: &Key) -> InverseContainer<T> {
126 InverseContainer {
127 language: InverseLang {
128 any: None,
129 map: HashMap::new(),
130 },
131 typ: InverseType {
132 reverse: None,
133 any: None,
134 map: HashMap::new(),
135 },
136 any: Any { none: term.clone() },
137 }
138 }
139}
140
141pub struct InverseDefinition<T> {
142 map: HashMap<Container, InverseContainer<T>>,
143}
144
145impl<T> InverseDefinition<T> {
146 fn new() -> InverseDefinition<T> {
147 InverseDefinition {
148 map: HashMap::new(),
149 }
150 }
151
152 fn get(&self, container: &Container) -> Option<&InverseContainer<T>> {
153 self.map.get(container)
154 }
155
156 fn contains(&self, container: &Container) -> bool {
157 self.map.contains_key(container)
158 }
159
160 fn reference_mut<F: FnOnce() -> InverseContainer<T>>(
161 &mut self,
162 container: &Container,
163 insert: F,
164 ) -> &mut InverseContainer<T> {
165 if !self.contains(container) {
166 self.map.insert(*container, insert());
167 }
168 self.map.get_mut(container).unwrap()
169 }
170
171 pub fn select(&self, containers: &[Container], selection: &Selection<T>) -> Option<&Key>
172 where
173 T: Clone + Hash + Eq,
174 {
175 for container in containers {
176 if let Some(type_lang_map) = self.get(container) {
177 match selection {
178 Selection::Any => return Some(&type_lang_map.any.none),
179 Selection::Type(preferred_values) => {
180 for item in preferred_values {
181 if let Some(term) = type_lang_map.typ.select(item.clone()) {
182 return Some(term);
183 }
184 }
185 }
186 Selection::Lang(preferred_values) => {
187 for item in preferred_values {
188 if let Some(term) = type_lang_map.language.select(*item) {
189 return Some(term);
190 }
191 }
192 }
193 }
194 }
195 }
196
197 None
198 }
199}
200
201pub struct InverseContext<T, B> {
203 map: HashMap<Term<T, B>, InverseDefinition<T>>,
204}
205
206pub enum Selection<'a, T> {
207 Any,
208 Type(Vec<TypeSelection<T>>),
209 Lang(Vec<LangSelection<'a>>),
210}
211
212impl<'a, T: fmt::Debug> fmt::Debug for Selection<'a, T> {
213 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
214 match self {
215 Selection::Any => write!(f, "Any"),
216 Selection::Type(s) => write!(f, "Type({s:?})"),
217 Selection::Lang(s) => write!(f, "Lang({s:?})"),
218 }
219 }
220}
221
222impl<T, B> InverseContext<T, B> {
223 pub fn new() -> Self {
224 InverseContext {
225 map: HashMap::new(),
226 }
227 }
228}
229
230impl<T: Hash + Eq, B: Hash + Eq> InverseContext<T, B> {
231 pub fn contains(&self, term: &Term<T, B>) -> bool {
232 self.map.contains_key(term)
233 }
234
235 pub fn insert(&mut self, term: Term<T, B>, value: InverseDefinition<T>) {
236 self.map.insert(term, value);
237 }
238
239 pub fn get(&self, term: &Term<T, B>) -> Option<&InverseDefinition<T>> {
240 self.map.get(term)
241 }
242
243 pub fn get_mut(&mut self, term: &Term<T, B>) -> Option<&mut InverseDefinition<T>> {
244 self.map.get_mut(term)
245 }
246
247 fn reference_mut<F: FnOnce() -> InverseDefinition<T>>(
248 &mut self,
249 term: &Term<T, B>,
250 insert: F,
251 ) -> &mut InverseDefinition<T>
252 where
253 T: Clone,
254 B: Clone,
255 {
256 if !self.contains(term) {
257 self.insert(term.clone(), insert());
258 }
259 self.map.get_mut(term).unwrap()
260 }
261
262 pub fn select(
263 &self,
264 var: &Term<T, B>,
265 containers: &[Container],
266 selection: &Selection<T>,
267 ) -> Option<&Key>
268 where
269 T: Clone,
270 {
271 match self.get(var) {
272 Some(container_map) => container_map.select(containers, selection),
273 None => None,
274 }
275 }
276}
277
278impl<T, B> Default for InverseContext<T, B> {
279 fn default() -> Self {
280 Self::new()
281 }
282}
283
284impl<'a, T: Clone + Hash + Eq, B: Clone + Hash + Eq> From<&'a Context<T, B>>
285 for InverseContext<T, B>
286{
287 fn from(context: &'a Context<T, B>) -> Self {
288 let mut result = InverseContext::new();
289
290 let mut definitions: Vec<_> = context.definitions().iter().collect();
291 definitions.sort_by(|a, b| {
292 let a = a.term().as_str();
293 let b = b.term().as_str();
294 let ord = a.len().cmp(&b.len());
295 if ord == Ordering::Equal {
296 a.cmp(b)
297 } else {
298 ord
299 }
300 });
301
302 for binding in definitions {
303 if let BindingRef::Normal(term, term_definition) = binding {
304 if let Some(var) = term_definition.value.as_ref() {
305 let container = &term_definition.container;
306 let container_map = result.reference_mut(var, InverseDefinition::new);
307 let type_lang_map =
308 container_map.reference_mut(container, || InverseContainer::new(term));
309
310 let type_map = &mut type_lang_map.typ;
311 let lang_map = &mut type_lang_map.language;
312
313 if term_definition.reverse_property {
314 if type_map.reverse.is_none() {
316 type_map.reverse = Some(term.clone())
317 }
318 } else {
319 match &term_definition.typ {
320 Some(Type::None) => {
321 type_map.set_any(term);
323 lang_map.set_any(term);
324 }
325 Some(typ) => {
326 type_map.set(typ, term)
328 }
329 None => {
330 match (&term_definition.language, &term_definition.direction) {
331 (Some(language), Some(direction)) => {
332 match (language, direction) {
335 (
336 Nullable::Some(language),
337 Nullable::Some(direction),
338 ) => lang_map.set(
339 Nullable::Some((
340 Some(language.as_lenient_lang_tag_ref()),
341 Some(*direction),
342 )),
343 term,
344 ),
345 (Nullable::Some(language), Nullable::Null) => lang_map
346 .set(
347 Nullable::Some((
348 Some(language.as_lenient_lang_tag_ref()),
349 None,
350 )),
351 term,
352 ),
353 (Nullable::Null, Nullable::Some(direction)) => lang_map
354 .set(
355 Nullable::Some((None, Some(*direction))),
356 term,
357 ),
358 (Nullable::Null, Nullable::Null) => {
359 lang_map.set(Nullable::Null, term)
360 }
361 }
362 }
363 (Some(language), None) => {
364 match language {
367 Nullable::Some(language) => lang_map.set(
368 Nullable::Some((
369 Some(language.as_lenient_lang_tag_ref()),
370 None,
371 )),
372 term,
373 ),
374 Nullable::Null => lang_map.set(Nullable::Null, term),
375 }
376 }
377 (None, Some(direction)) => {
378 match direction {
381 Nullable::Some(direction) => lang_map.set(
382 Nullable::Some((None, Some(*direction))),
383 term,
384 ),
385 Nullable::Null => {
386 lang_map.set(Nullable::Some((None, None)), term)
387 }
388 }
389 }
390 (None, None) => {
391 lang_map.set(
392 Nullable::Some((
393 context.default_language(),
394 context.default_base_direction(),
395 )),
396 term,
397 );
398 lang_map.set_none(term);
399 type_map.set_none(term);
400 }
401 }
402 }
403 }
404 }
405 }
406 }
407 }
408
409 result
410 }
411}