1use std::collections::{HashMap, HashSet};
17use std::fmt;
18use std::future::Future;
19use std::pin::Pin;
20use std::sync::atomic::{AtomicBool, Ordering};
21use std::sync::{Arc, Mutex};
22
23use fml_check::definitions::type_url;
24use fml_check::{Definitions, Kind, Lookup, Type, Types};
25use fml_model::model::{
26 Dependent, Group, Parameter, ParameterValue, Rule, Source, StructureMap, Target,
27};
28use fml_model::{SOURCE_ELEMENT_EXTENSION, TARGET_ELEMENT_EXTENSION};
29use serde_json::{Value, json};
30
31use crate::expressions::{Expressions, Item, bind_variables, path_start_names};
32use crate::ids::{IdGenerator, RandomIds};
33use crate::terminology::{ConceptMapResolver, NoConceptMaps, TranslateService, translate};
34use crate::trace::{Phase, Trace, TraceEvent, TraceStatus, TraceVariable};
35use crate::tree::{NodeId, Tree};
36use crate::{datetime, transforms};
37
38type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + 'a>>;
39
40#[derive(Debug, Clone, PartialEq, Eq)]
42pub struct Error {
43 pub kind: ErrorKind,
44 pub message: String,
45 pub map: Option<String>,
47 pub position: Option<String>,
49 pub trace: Option<Box<Trace>>,
51}
52
53#[derive(Debug, Clone, Copy, PartialEq, Eq)]
55pub enum ErrorKind {
56 Failed,
58 Limit,
60 Cancelled,
62}
63
64impl Error {
65 fn new(message: impl Into<String>) -> Self {
66 Self {
67 kind: ErrorKind::Failed,
68 message: message.into(),
69 map: None,
70 position: None,
71 trace: None,
72 }
73 }
74
75 fn limit(message: impl Into<String>) -> Self {
76 Self {
77 kind: ErrorKind::Limit,
78 ..Self::new(message)
79 }
80 }
81
82 fn at(mut self, map: &StructureMap, position: &str) -> Self {
84 if self.position.is_none() {
85 self.map = map.url.clone();
86 self.position = Some(position.to_owned());
87 }
88 self
89 }
90
91 fn in_rule(rule: &Rule, message: impl fmt::Display) -> Self {
92 match &rule.name {
93 Some(name) => Self::new(format!("rule `{name}`: {message}")),
94 None => Self::new(message.to_string()),
95 }
96 }
97}
98
99impl fmt::Display for Error {
100 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101 f.write_str(&self.message)
102 }
103}
104
105impl std::error::Error for Error {}
106
107type Result<T> = std::result::Result<T, Error>;
108
109pub trait MapResolver {
111 fn resolve(&self, url: &str) -> Vec<Arc<StructureMap>>;
112}
113
114#[derive(Debug, Default, Clone, Copy)]
116pub struct NoMaps;
117
118impl MapResolver for NoMaps {
119 fn resolve(&self, _url: &str) -> Vec<Arc<StructureMap>> {
120 Vec::new()
121 }
122}
123
124#[derive(Debug, Default, Clone)]
126pub struct MapSet {
127 maps: Vec<Arc<StructureMap>>,
128}
129
130impl MapSet {
131 pub fn new() -> Self {
132 Self::default()
133 }
134
135 pub fn add(&mut self, map: StructureMap) {
136 self.maps.push(Arc::new(map));
137 }
138}
139
140impl MapResolver for MapSet {
141 fn resolve(&self, url: &str) -> Vec<Arc<StructureMap>> {
142 self.maps
143 .iter()
144 .filter(|map| {
145 map.url
146 .as_deref()
147 .is_some_and(|candidate| match url.split_once('*') {
148 Some((prefix, suffix)) => {
149 candidate.len() >= prefix.len() + suffix.len()
150 && candidate.starts_with(prefix)
151 && candidate.ends_with(suffix)
152 }
153 None => candidate == url,
154 })
155 })
156 .cloned()
157 .collect()
158 }
159}
160
161#[derive(Debug, Clone, Copy, PartialEq, Eq)]
164pub struct Limits {
165 pub max_depth: usize,
167 pub max_rules: u64,
169 pub max_values: usize,
171 pub max_trace_events: usize,
173 pub max_trace_bytes: usize,
175}
176
177impl Default for Limits {
178 fn default() -> Self {
179 Self {
180 max_depth: 512,
181 max_rules: 20_000_000,
182 max_values: 2_000_000,
183 max_trace_events: 10_000,
184 max_trace_bytes: 8 * 1024 * 1024,
185 }
186 }
187}
188
189#[derive(Debug, Clone, PartialEq)]
191pub struct Transformed {
192 pub target: Value,
194 pub log: Vec<String>,
196 pub warnings: Vec<String>,
199 pub produced: Vec<Value>,
202 pub trace: Option<Trace>,
204}
205
206pub struct Engine<'a, X> {
208 definitions: &'a dyn Definitions,
209 expressions: X,
210 maps: &'a dyn MapResolver,
211 concept_maps: &'a dyn ConceptMapResolver,
212 translator: Option<&'a dyn TranslateService>,
214 ids: &'a dyn IdGenerator,
215 limits: Limits,
216 cancel: Option<&'a AtomicBool>,
217 trace: bool,
218 lenient_translations: bool,
222 template_versions: bool,
225 groups: Mutex<GroupCache>,
228}
229
230type TypedTarget = (Type, Option<String>);
232
233#[derive(Default)]
237struct GroupCache {
238 by_name: HashMap<(String, String), Found>,
239 by_types: HashMap<(String, String, String), Option<GroupRef>>,
240 default_target: HashMap<(String, String), Option<TypedTarget>>,
241}
242
243#[derive(Debug, Clone, Copy, PartialEq, Eq)]
244enum Mode {
245 Input,
246 Output,
247 Shared,
248}
249
250#[derive(Debug, Clone, Default)]
252struct Vars {
253 entries: Vec<(Mode, String, NodeId)>,
254}
255
256impl Vars {
257 fn add(&mut self, mode: Mode, name: &str, node: NodeId) {
258 self.entries.push((mode, name.to_owned(), node));
259 }
260
261 fn get(&self, mode: Mode, name: &str) -> Option<NodeId> {
262 self.entries
263 .iter()
264 .rev()
265 .find(|(m, n, _)| *m == mode && n == name)
266 .map(|(_, _, node)| *node)
267 }
268
269 fn value(&self, name: &str) -> Option<NodeId> {
271 self.get(Mode::Input, name)
272 .or_else(|| self.get(Mode::Output, name))
273 }
274
275 fn names(&self) -> impl Iterator<Item = &str> {
276 self.entries
277 .iter()
278 .filter(|(mode, _, _)| *mode != Mode::Shared)
279 .map(|(_, name, _)| name.as_str())
280 }
281}
282
283#[derive(Clone)]
285enum Found {
286 One(GroupRef),
287 None,
288 Several(Vec<String>),
290}
291
292#[derive(Clone)]
294struct GroupRef {
295 map: Arc<StructureMap>,
296 index: usize,
297}
298
299impl GroupRef {
300 fn group(&self) -> &Group {
301 &self.map.group[self.index]
302 }
303}
304
305#[derive(Default)]
307struct Run {
308 tree: Tree,
309 log: Vec<String>,
310 warnings: Vec<String>,
311 depth: usize,
312 trace: Option<Vec<TraceEvent>>,
314 trace_depth: usize,
315 produced: Vec<NodeId>,
317 constants: HashMap<(String, String), Vec<NodeId>>,
319 evaluating: HashSet<(String, String)>,
321 rules: u64,
323 trace_bytes: usize,
325 trace_truncated: Option<String>,
327 single: HashSet<(NodeId, String, usize)>,
329 order: HashMap<(NodeId, String), TargetOrder>,
331}
332
333#[derive(Default)]
335struct TargetOrder {
336 first: Option<usize>,
337 first_count: usize,
338 last: Option<usize>,
339 last_values: Vec<NodeId>,
340}
341const CORE: &str = "http://hl7.org/fhir/StructureDefinition/";
342
343impl<'a, X: Expressions> Engine<'a, X> {
344 pub fn new(definitions: &'a dyn Definitions, expressions: X) -> Self {
345 Self {
346 definitions,
347 expressions,
348 maps: &NoMaps,
349 concept_maps: &NoConceptMaps,
350 translator: None,
351 ids: &RandomIds,
352 limits: Limits::default(),
353 cancel: None,
354 trace: false,
355 template_versions: true,
356 lenient_translations: false,
357 groups: Mutex::new(GroupCache::default()),
358 }
359 }
360
361 fn cache(&self) -> std::sync::MutexGuard<'_, GroupCache> {
362 self.groups.lock().unwrap_or_else(|e| e.into_inner())
363 }
364
365 pub fn with_trace(mut self, trace: bool) -> Self {
367 self.trace = trace;
368 self
369 }
370
371 pub fn with_concept_maps(mut self, concept_maps: &'a dyn ConceptMapResolver) -> Self {
373 self.concept_maps = concept_maps;
374 self
375 }
376
377 pub fn with_translator(mut self, translator: &'a dyn TranslateService) -> Self {
380 self.translator = Some(translator);
381 self
382 }
383
384 pub fn with_limits(mut self, limits: Limits) -> Self {
386 self.limits = limits;
387 self
388 }
389
390 pub fn with_cancellation(mut self, cancel: &'a AtomicBool) -> Self {
393 self.cancel = Some(cancel);
394 self
395 }
396
397 pub fn with_template_versions(mut self, versions: bool) -> Self {
402 self.template_versions = versions;
403 self
404 }
405
406 pub fn with_lenient_translations(mut self, lenient: bool) -> Self {
411 self.lenient_translations = lenient;
412 self
413 }
414
415 pub fn with_ids(mut self, ids: &'a dyn IdGenerator) -> Self {
417 self.ids = ids;
418 self
419 }
420
421 pub fn with_maps(mut self, maps: &'a dyn MapResolver) -> Self {
423 self.maps = maps;
424 self
425 }
426
427 fn types(&self) -> Types<'a> {
428 Types::new(self.definitions)
429 }
430
431 pub async fn transform(&self, map: &StructureMap, source: &Value) -> Result<Transformed> {
434 self.run(map, source, None).await
435 }
436
437 pub async fn transform_into(
439 &self,
440 map: &StructureMap,
441 source: &Value,
442 target: &Value,
443 ) -> Result<Transformed> {
444 self.run(map, source, Some(target)).await
445 }
446
447 async fn run(
448 &self,
449 map: &StructureMap,
450 source: &Value,
451 target: Option<&Value>,
452 ) -> Result<Transformed> {
453 let map = Arc::new(map.clone());
454 let group = map
455 .group
456 .first()
457 .ok_or_else(|| Error::new("the map has no groups"))?;
458 let input = |mode: &str| group.input.iter().find(|input| input.mode == mode);
459 let source_input =
460 input("source").ok_or_else(|| Error::new("the first group has no source"))?;
461 let target_input =
462 input("target").ok_or_else(|| Error::new("the first group has no target"))?;
463
464 let mut run = Run {
465 trace: self.trace.then(Vec::new),
466 ..Run::default()
467 };
468 let types = self.types();
469 let source_type = self.input_type(&map, source_input.type_name.as_deref());
470 let source_node = run.tree.load(source, source_type, &types);
471 if run.trace.is_some() {
472 let root_name = match run.tree.ty(source_node) {
476 Type::Node { structure, path }
477 if path.is_empty() && structure.kind == Kind::Logical =>
478 {
479 structure.name.clone()
480 }
481 _ => run
482 .tree
483 .fhir_type(source_node)
484 .unwrap_or_else(|| "%resource".to_owned()),
485 };
486 run.tree.record_paths(source_node, &root_name);
487 }
488 let target_type = self.input_type(&map, target_input.type_name.as_deref());
489 let target_node = match target {
490 Some(target) => run.tree.load(target, target_type, &types),
491 None => {
492 if matches!(target_type, Type::Unknown) {
493 return Err(Error::new(format!(
494 "cannot create the target: type `{}` is not known",
495 target_input.type_name.as_deref().unwrap_or("?")
496 )));
497 }
498 run.tree.create(target_type, None)
499 }
500 };
501 let mut vars = Vars::default();
502 vars.add(Mode::Input, &source_input.name, source_node);
503 vars.add(Mode::Output, &target_input.name, target_node);
504 let entry = GroupRef {
505 map: map.clone(),
506 index: 0,
507 };
508 if let Err(mut error) = self.execute_group(&mut run, entry, vars, true).await {
509 let truncated = run.trace_truncated.take();
510 error.trace = run.trace.take().map(|events| {
511 Box::new(Trace {
512 status: match truncated {
513 Some(_) => TraceStatus::Truncated,
514 None => TraceStatus::Stopped,
515 },
516 note: truncated,
517 events,
518 })
519 });
520 return Err(error);
521 }
522 let in_target = run.tree.reachable(target_node);
523 let produced = run
524 .produced
525 .iter()
526 .filter(|node| !in_target.contains(node))
527 .map(|&node| run.tree.to_json(node))
528 .collect();
529 Ok(Transformed {
530 target: run.tree.to_json(target_node),
531 log: run.log,
532 warnings: run.warnings,
533 produced,
534 trace: run.trace.map(|events| Trace {
535 status: match run.trace_truncated {
536 Some(_) => TraceStatus::Truncated,
537 None => TraceStatus::Complete,
538 },
539 note: run.trace_truncated,
540 events,
541 }),
542 })
543 }
544
545 fn input_type(&self, map: &StructureMap, name: Option<&str>) -> Type {
547 let Some(name) = name else {
548 return Type::Unknown;
549 };
550 self.types().structure(&self.type_name_url(map, name, CORE))
551 }
552
553 fn type_name_url(&self, map: &StructureMap, name: &str, context: &str) -> String {
554 if let Some(structure) = map
555 .structure
556 .iter()
557 .find(|s| s.alias.as_deref() == Some(name))
558 {
559 return structure.url.clone();
560 }
561 type_url(name, context)
562 }
563
564 fn execute_group<'r>(
567 &'r self,
568 run: &'r mut Run,
569 group: GroupRef,
570 vars: Vars,
571 at_root: bool,
572 ) -> BoxFuture<'r, Result<()>> {
573 Box::pin(async move {
574 run.depth += 1;
575 if run.depth > self.limits.max_depth {
576 return Err(Error::limit(format!(
577 "groups nest more than {} deep; is a group calling itself without end?",
578 self.limits.max_depth
579 )));
580 }
581 let map = group.map.clone();
582 let definition = group.group();
583 let position = format!("StructureMap.group[{}]", group.index);
584 self.record(run, Phase::Enter, &map, &position, &vars, Vec::new());
585 if let Some(extends) = &definition.extends {
586 let base = self.group_by_name(&map, extends)?;
587 self.execute_group(run, base, vars.clone(), false).await?;
588 }
589 let mut vars = vars;
590 for (index, rule) in definition.rule.iter().enumerate() {
591 let rule_position = format!("{position}.rule[{index}]");
592 self.execute_rule(run, &group, rule, &rule_position, &mut vars, at_root)
593 .await?;
594 }
595 self.record(run, Phase::Exit, &map, &position, &vars, Vec::new());
596 run.depth -= 1;
597 Ok(())
598 })
599 }
600
601 fn group_by_name(&self, map: &Arc<StructureMap>, name: &str) -> Result<GroupRef> {
603 if let Some(index) = map.group.iter().position(|g| g.name == name) {
604 return Ok(GroupRef {
605 map: map.clone(),
606 index,
607 });
608 }
609 let key = (imports_key(map), name.to_owned());
610 let cached = self.cache().by_name.get(&key).cloned();
611 let found = match cached {
612 Some(found) => found,
613 None => {
614 let found = self.find_imported_group_by_name(map, name);
615 self.cache().by_name.insert(key, found.clone());
616 found
617 }
618 };
619 match found {
620 Found::One(group) => Ok(group),
621 Found::None => Err(Error::new(format!(
622 "no group `{name}` in {} or the maps it imports",
623 map.url.as_deref().unwrap_or("the map")
624 ))),
625 Found::Several(urls) => Err(Error::new(format!(
626 "group `{name}` is in several imported maps ({}); a group name must be unique",
627 urls.join(", ")
628 ))),
629 }
630 }
631
632 fn find_imported_group_by_name(&self, map: &Arc<StructureMap>, name: &str) -> Found {
635 let mut found: Vec<GroupRef> = Vec::new();
636 for import in &map.import {
637 for imported in self.maps.resolve(import) {
638 if imported.url == map.url || found.iter().any(|g| g.map.url == imported.url) {
639 continue;
640 }
641 if let Some(index) = imported.group.iter().position(|g| g.name == name) {
642 found.push(GroupRef {
643 map: imported.clone(),
644 index,
645 });
646 }
647 }
648 }
649 match found.len() {
650 0 => Found::None,
651 1 => Found::One(found.remove(0)),
652 _ => Found::Several(
653 found
654 .iter()
655 .map(|g| g.map.url.clone().unwrap_or_default())
656 .collect(),
657 ),
658 }
659 }
660
661 fn group_by_types(
664 &self,
665 map: &Arc<StructureMap>,
666 source: Option<&str>,
667 target: Option<&str>,
668 ) -> Option<GroupRef> {
669 let (source, target) = (source?, target?);
670 if let Some(index) = self.default_group_index(map, source, target) {
671 return Some(GroupRef {
672 map: map.clone(),
673 index,
674 });
675 }
676 let key = (imports_key(map), source.to_owned(), target.to_owned());
677 if let Some(found) = self.cache().by_types.get(&key) {
678 return found.clone();
679 }
680 let found = self.find_imported_group_by_types(map, source, target);
681 self.cache().by_types.insert(key, found.clone());
682 found
683 }
684
685 fn default_group_index(&self, map: &StructureMap, source: &str, target: &str) -> Option<usize> {
687 map.group.iter().position(|group| {
688 group.type_mode.is_some()
689 && matches!(group.input.as_slice(), [s, t]
690 if s.mode == "source" && t.mode == "target"
691 && self.stated_type_is(map, s.type_name.as_deref(), source)
692 && !self.is_template_profile(map, s.type_name.as_deref())
693 && self.stated_type_is(map, t.type_name.as_deref(), target))
694 })
695 }
696
697 fn is_template_profile(&self, map: &StructureMap, stated: Option<&str>) -> bool {
700 stated.is_some_and(|stated| {
701 !self
702 .definitions
703 .templates(&self.type_name_url(map, stated, CORE))
704 .is_empty()
705 })
706 }
707
708 fn find_imported_group_by_types(
709 &self,
710 map: &Arc<StructureMap>,
711 source: &str,
712 target: &str,
713 ) -> Option<GroupRef> {
714 for import in &map.import {
715 for imported in self.maps.resolve(import) {
716 if imported.url == map.url {
717 continue;
718 }
719 if let Some(index) = self.default_group_index(&imported, source, target) {
720 return Some(GroupRef {
721 map: imported,
722 index,
723 });
724 }
725 }
726 }
727 None
728 }
729
730 fn stated_type_name(&self, map: &StructureMap, stated: &str) -> String {
733 map.structure
734 .iter()
735 .find(|s| s.alias.as_deref() == Some(stated))
736 .and_then(|s| self.definitions.structure(&s.url))
737 .map_or_else(|| stated.to_owned(), |s| s.type_name.clone())
738 }
739
740 fn has_stated_type(&self, run: &Run, map: &StructureMap, node: NodeId, stated: &str) -> bool {
744 let wanted = self.stated_type_name(map, stated);
745 let same = run.tree.fhir_type(node).as_deref() == Some(wanted.as_str())
746 || matches!(run.tree.ty(node), Type::Node { structure, path }
747 if path.is_empty()
748 && structure.kind == Kind::Logical
749 && (structure.name == wanted || structure.url == wanted));
750 same && self.has_templates_of(run, map, node, stated)
751 }
752
753 fn has_templates_of(&self, run: &Run, map: &StructureMap, node: NodeId, stated: &str) -> bool {
756 let url = self.type_name_url(map, stated, CORE);
757 let templates = self.definitions.templates(&url);
758 if templates.is_empty() {
759 return true;
760 }
761 run.tree.children(node, "templateId").into_iter().any(|id| {
762 let text = |name: &str| {
763 run.tree
764 .children(id, name)
765 .first()
766 .and_then(|&n| run.tree.text(n))
767 };
768 let (root, extension) = (text("root"), text("extension"));
769 root.is_some_and(|root| {
770 templates.iter().any(|t| {
771 if self.template_versions {
772 t.matches(&root, extension.as_deref())
773 } else {
774 t.root == root
775 }
776 })
777 })
778 })
779 }
780
781 fn group_by_template(
785 &self,
786 run: &Run,
787 map: &Arc<StructureMap>,
788 source: NodeId,
789 target: Option<&str>,
790 ) -> Option<GroupRef> {
791 let target = target?;
792 let fits = |owner: &StructureMap, group: &Group| -> bool {
793 group.type_mode.is_some()
794 && matches!(group.input.as_slice(), [s, t]
795 if s.mode == "source" && t.mode == "target"
796 && s.type_name.as_deref().is_some_and(|stated| {
797 !self.definitions.templates(&self.type_name_url(owner, stated, CORE)).is_empty()
798 && self.has_stated_type(run, owner, source, stated)
799 })
800 && self.stated_type_is(owner, t.type_name.as_deref(), target))
801 };
802 if let Some(index) = map.group.iter().position(|g| fits(map, g)) {
803 return Some(GroupRef {
804 map: map.clone(),
805 index,
806 });
807 }
808 for import in &map.import {
809 for imported in self.maps.resolve(import) {
810 if imported.url == map.url {
811 continue;
812 }
813 if let Some(index) = imported.group.iter().position(|g| fits(&imported, g)) {
814 return Some(GroupRef {
815 map: imported,
816 index,
817 });
818 }
819 }
820 }
821 None
822 }
823
824 fn stated_type_is(&self, map: &StructureMap, stated: Option<&str>, actual: &str) -> bool {
825 let Some(stated) = stated else { return false };
826 if stated == actual {
827 return true;
828 }
829 let url = self.type_name_url(map, stated, CORE);
830 self.definitions
831 .structure(&url)
832 .is_some_and(|s| s.type_name == actual)
833 }
834
835 fn execute_rule<'r>(
838 &'r self,
839 run: &'r mut Run,
840 group: &'r GroupRef,
841 rule: &'r Rule,
842 position: &'r str,
843 vars: &'r mut Vars,
844 at_root: bool,
845 ) -> BoxFuture<'r, Result<()>> {
846 Box::pin(async move {
847 self.check_limits(run)?;
848 self.record(run, Phase::Enter, &group.map, position, vars, Vec::new());
849 let mut bindings = vec![vars.clone()];
850 for (index, source) in rule.source.iter().enumerate() {
851 let logged = run.log.len();
852 let mut next = Vec::new();
853 for binding in &bindings {
854 next.extend(
855 self.process_source(run, group, rule, source, binding)
856 .await
857 .map_err(|e| {
858 e.at(&group.map, &format!("{position}.source[{index}]"))
859 })?,
860 );
861 }
862 bindings = next;
863 if run.trace.is_some() {
864 let messages = run.log[logged..].to_vec();
865 let shown = bindings.first().cloned().unwrap_or_else(|| vars.clone());
866 let step = format!("{position}.source[{index}]");
867 self.record(run, Phase::Step, &group.map, &step, &shown, messages);
868 }
869 }
870 let source_variable = match rule.source.as_slice() {
871 [single] => single.variable.as_deref(),
872 _ => None,
873 };
874 for mut binding in bindings {
875 for (index, target) in rule.target.iter().enumerate() {
876 self.process_target(
877 run,
878 group,
879 rule,
880 target,
881 &mut binding,
882 vars,
883 source_variable,
884 at_root,
885 )
886 .await
887 .map_err(|e| e.at(&group.map, &format!("{position}.target[{index}]")))?;
888 if run.trace.is_some() {
889 let step = format!("{position}.target[{index}]");
890 self.record(run, Phase::Step, &group.map, &step, &binding, Vec::new());
891 }
892 }
893 for dependent in &rule.dependent {
895 self.execute_dependency(run, group, rule, dependent, &binding)
896 .await
897 .map_err(|e| e.at(&group.map, position))?;
898 }
899 for (index, child) in rule.rule.iter().enumerate() {
900 let child_position = format!("{position}.rule[{index}]");
901 self.execute_rule(run, group, child, &child_position, &mut binding, false)
902 .await?;
903 }
904 if rule.dependent.is_empty()
905 && rule.rule.is_empty()
906 && let Some((source, target)) = simple_copy(rule)
907 {
908 self.default_copy(run, group, rule, source, target, &binding)
909 .await
910 .map_err(|e| e.at(&group.map, position))?;
911 }
912 }
913 self.record(run, Phase::Exit, &group.map, position, vars, Vec::new());
914 Ok(())
915 })
916 }
917
918 fn check_limits(&self, run: &mut Run) -> Result<()> {
920 if self
921 .cancel
922 .is_some_and(|cancel| cancel.load(Ordering::Relaxed))
923 {
924 return Err(Error {
925 kind: ErrorKind::Cancelled,
926 ..Error::new("the transform was cancelled")
927 });
928 }
929 run.rules += 1;
930 if run.rules > self.limits.max_rules {
931 return Err(Error::limit(format!(
932 "the transform ran more than {} rules",
933 self.limits.max_rules
934 )));
935 }
936 if run.tree.len() > self.limits.max_values {
937 return Err(Error::limit(format!(
938 "the transform created more than {} values",
939 self.limits.max_values
940 )));
941 }
942 Ok(())
943 }
944
945 fn record(
947 &self,
948 run: &mut Run,
949 phase: Phase,
950 map: &StructureMap,
951 position: &str,
952 vars: &Vars,
953 messages: Vec<String>,
954 ) {
955 if run.trace.is_none() {
956 return;
957 }
958 if phase == Phase::Exit {
959 run.trace_depth = run.trace_depth.saturating_sub(1);
960 }
961 if run.trace_truncated.is_some() {
962 if phase == Phase::Enter {
963 run.trace_depth += 1;
964 }
965 return;
966 }
967 let mut seen = HashSet::new();
968 let mut variables: Vec<TraceVariable> = vars
969 .entries
970 .iter()
971 .rev()
972 .filter(|(mode, name, _)| *mode != Mode::Shared && seen.insert(name.clone()))
973 .map(|(mode, name, node)| TraceVariable {
974 name: name.clone(),
975 context_type: match mode {
976 Mode::Input => "input",
977 _ => "output",
978 }
979 .to_owned(),
980 value: run.tree.to_json(*node),
981 data_type: self.item(run, *node).type_name,
982 path: run.tree.path(*node).map(str::to_owned),
983 })
984 .collect();
985 variables.reverse();
986 let event = TraceEvent {
987 phase,
988 depth: run.trace_depth,
989 source: map.url.clone(),
990 position: position.to_owned(),
991 variables,
992 messages,
993 };
994 if run.trace_truncated.is_none() {
995 let size = event.approximate_size();
996 let count = run.trace.as_ref().map_or(0, Vec::len);
997 if count >= self.limits.max_trace_events {
998 run.trace_truncated = Some(format!(
999 "the trace keeps its first {} events",
1000 self.limits.max_trace_events
1001 ));
1002 } else if run.trace_bytes + size > self.limits.max_trace_bytes {
1003 run.trace_truncated = Some(format!(
1004 "the trace keeps its first {count} events, about {} bytes",
1005 run.trace_bytes
1006 ));
1007 } else if let Some(events) = &mut run.trace {
1008 run.trace_bytes += size;
1009 events.push(event);
1010 }
1011 }
1012 if phase == Phase::Enter {
1013 run.trace_depth += 1;
1014 }
1015 }
1016
1017 async fn default_copy(
1020 &self,
1021 run: &mut Run,
1022 group: &GroupRef,
1023 rule: &Rule,
1024 source: &str,
1025 target: &str,
1026 vars: &Vars,
1027 ) -> Result<()> {
1028 let source = vars
1029 .get(Mode::Input, source)
1030 .ok_or_else(|| Error::in_rule(rule, format!("no source variable `{source}`")))?;
1031 let target = vars
1032 .get(Mode::Output, target)
1033 .ok_or_else(|| Error::in_rule(rule, format!("no target variable `{target}`")))?;
1034 let source_type = run.tree.fhir_type(source);
1035 let target_type = run.tree.fhir_type(target);
1036 let chosen = self
1037 .group_by_template(run, &group.map, source, target_type.as_deref())
1038 .or_else(|| {
1039 self.group_by_types(&group.map, source_type.as_deref(), target_type.as_deref())
1040 });
1041 if let Some(default) = chosen {
1042 let inputs = &default.group().input;
1043 let mut call = Vars::default();
1044 call.add(Mode::Input, &inputs[0].name, source);
1045 call.add(Mode::Output, &inputs[1].name, target);
1046 return self.execute_group(run, default, call, false).await;
1047 }
1048 if source_type == target_type || target_type.is_none() {
1049 run.tree.assign(target, source);
1050 return Ok(());
1051 }
1052 Err(Error::in_rule(
1053 rule,
1054 format!(
1055 "no default group maps {} to {}",
1056 source_type.as_deref().unwrap_or("?"),
1057 target_type.as_deref().unwrap_or("?")
1058 ),
1059 ))
1060 }
1061
1062 async fn execute_dependency(
1063 &self,
1064 run: &mut Run,
1065 group: &GroupRef,
1066 rule: &Rule,
1067 dependent: &Dependent,
1068 vars: &Vars,
1069 ) -> Result<()> {
1070 let callee = self.group_by_name(&group.map, &dependent.name)?;
1071 let inputs = &callee.group().input;
1072 if inputs.len() != dependent.parameter.len() {
1073 return Err(Error::in_rule(
1074 rule,
1075 format!(
1076 "group `{}` takes {} arguments, the call passes {}",
1077 dependent.name,
1078 inputs.len(),
1079 dependent.parameter.len()
1080 ),
1081 ));
1082 }
1083 let mut call = Vars::default();
1084 for (input, parameter) in inputs.iter().zip(&dependent.parameter) {
1085 let name = parameter_name(parameter);
1086 let (mode, node) = if input.mode == "source" {
1087 let node = match ¶meter.value {
1090 ParameterValue::Id(name) => vars.value(name),
1091 ParameterValue::String(text) => vars
1092 .value(text)
1093 .or_else(|| Some(self.string(run, text.clone(), "string"))),
1094 ParameterValue::Boolean(b) => {
1095 Some(self.literal(run, Value::Bool(*b), "boolean"))
1096 }
1097 ParameterValue::Integer(n) => {
1098 Some(self.literal(run, Value::from(*n), "integer"))
1099 }
1100 ParameterValue::Decimal(n) => {
1101 Some(self.literal(run, Value::Number(n.clone()), "decimal"))
1102 }
1103 ParameterValue::Date(text) => Some(self.string(run, text.clone(), "date")),
1104 ParameterValue::Time(text) => Some(self.string(run, text.clone(), "time")),
1105 ParameterValue::DateTime(text) => {
1106 Some(self.string(run, text.clone(), "dateTime"))
1107 }
1108 };
1109 (Mode::Input, node)
1110 } else {
1111 (Mode::Output, vars.get(Mode::Output, &name))
1112 };
1113 let node = node.ok_or_else(|| {
1114 Error::in_rule(
1115 rule,
1116 format!(
1117 "`{}` passes `{name}` as {} `{}`, but it has no value",
1118 dependent.name, input.mode, input.name
1119 ),
1120 )
1121 })?;
1122 call.add(mode, &input.name, node);
1123 }
1124 self.execute_group(run, callee, call, false).await
1125 }
1126
1127 async fn process_source(
1130 &self,
1131 run: &mut Run,
1132 group: &GroupRef,
1133 rule: &Rule,
1134 source: &Source,
1135 vars: &Vars,
1136 ) -> Result<Vec<Vars>> {
1137 let context = vars.get(Mode::Input, &source.context).ok_or_else(|| {
1138 Error::in_rule(
1139 rule,
1140 format!("unknown source variable `{}`", source.context),
1141 )
1142 })?;
1143 let mut items = vec![context];
1144 for element in element_path(
1145 source.element.as_deref(),
1146 &source.extension,
1147 SOURCE_ELEMENT_EXTENSION,
1148 ) {
1149 items = items
1150 .iter()
1151 .flat_map(|&item| run.tree.children(item, &element))
1152 .collect();
1153 }
1154 check_cardinality(rule, source, items.len())?;
1155 if let Some(type_name) = &source.type_name {
1157 items.retain(|&item| self.has_stated_type(run, &group.map, item, type_name));
1158 }
1159 if items.is_empty()
1160 && let Some(default) = &source.default_value
1161 {
1162 items = self.evaluate(run, group, default, None, vars).await?;
1163 }
1164 let with_item = |item: NodeId| {
1165 let mut bound = vars.clone();
1166 if let Some(variable) = &source.variable {
1167 bound.add(Mode::Input, variable, item);
1168 }
1169 bound
1170 };
1171 if let Some(condition) = &source.condition {
1172 let mut kept = Vec::with_capacity(items.len());
1173 for item in items {
1174 if self
1175 .evaluate_boolean(run, group, condition, Some(item), &with_item(item))
1176 .await?
1177 {
1178 kept.push(item);
1179 }
1180 }
1181 items = kept;
1182 }
1183 if let Some(check) = &source.check {
1184 for &item in &items {
1185 if !self
1186 .evaluate_boolean(run, group, check, Some(item), &with_item(item))
1187 .await?
1188 {
1189 return Err(Error::in_rule(rule, format!("check `{check}` failed")));
1190 }
1191 }
1192 }
1193 if let Some(log) = &source.log_message {
1194 let mut messages = Vec::new();
1195 for &item in &items {
1196 let values = self
1197 .evaluate(run, group, log, Some(item), &with_item(item))
1198 .await?;
1199 messages.extend(values.into_iter().filter_map(|v| run.tree.text(v)));
1200 }
1201 if !messages.is_empty() {
1202 run.log.push(messages.join(","));
1203 }
1204 }
1205 match source.list_mode.as_deref() {
1206 _ if items.is_empty() => {}
1207 Some("first") => items.truncate(1),
1208 Some("not_first") => {
1209 items.remove(0);
1210 }
1211 Some("last") => items = vec![*items.last().unwrap()],
1212 Some("not_last") => {
1213 items.pop();
1214 }
1215 Some("only_one") if items.len() > 1 => {
1216 return Err(Error::in_rule(
1217 rule,
1218 format!("`{}` has more than one item", source.context),
1219 ));
1220 }
1221 _ => {}
1222 }
1223 Ok(items.into_iter().map(with_item).collect())
1224 }
1225
1226 #[allow(clippy::too_many_arguments)]
1229 async fn process_target(
1230 &self,
1231 run: &mut Run,
1232 group: &GroupRef,
1233 rule: &Rule,
1234 target: &Target,
1235 vars: &mut Vars,
1236 shared: &mut Vars,
1237 source_variable: Option<&str>,
1238 at_root: bool,
1239 ) -> Result<()> {
1240 let types = self.types();
1241 let elements = element_path(
1242 target.element.as_deref(),
1243 &target.extension,
1244 TARGET_ELEMENT_EXTENSION,
1245 );
1246 let element = elements.last().cloned();
1247 let mut destination = match &target.context {
1248 Some(context) => Some(vars.get(Mode::Output, context).ok_or_else(|| {
1249 Error::in_rule(rule, format!("unknown target variable `{context}`"))
1250 })?),
1251 None => None,
1252 };
1253 let sharing = target.list_mode.iter().any(|m| m == "share");
1254 let mut value = match (&target.transform, sharing, &target.list_rule_id) {
1255 (None, true, Some(id)) => shared.get(Mode::Shared, id),
1256 _ => None,
1257 };
1258 if let Some(dest) = destination
1259 && value.is_none()
1260 {
1261 let mut dest = dest;
1262 for intermediate in elements.iter().take(elements.len().saturating_sub(1)) {
1263 dest = run
1264 .tree
1265 .make_property(dest, intermediate, &types)
1266 .map_err(|e| Error::in_rule(rule, e))?;
1267 }
1268 destination = Some(dest);
1269 }
1270 if target.transform.is_some() {
1271 let produced = if target.transform.as_deref() == Some("evaluate") {
1272 let values = self
1273 .evaluate_transform(run, group, rule, target, vars)
1274 .await?;
1275 if values.len() > 1 {
1276 self.check_several(
1277 run,
1278 rule,
1279 target,
1280 destination,
1281 element.as_deref(),
1282 values.len(),
1283 )?;
1284 }
1285 values
1286 } else {
1287 self.run_transform(
1288 run,
1289 group,
1290 rule,
1291 target,
1292 vars,
1293 destination,
1294 element.as_deref(),
1295 source_variable,
1296 at_root,
1297 )
1298 .await?
1299 .into_iter()
1300 .collect()
1301 };
1302 if let Some(dest) = destination {
1303 for &item in &produced {
1304 match &element {
1305 Some(element) => {
1306 run.tree
1307 .set_property(dest, element, item, &types)
1308 .map_err(|e| Error::in_rule(rule, e))?;
1309 order_target(run, rule, target, dest, element, item)?;
1310 }
1311 None => run.tree.assign(dest, item),
1312 }
1313 }
1314 }
1315 value = produced.last().copied();
1316 } else if let (Some(dest), None) = (destination, value) {
1317 value = Some(match &element {
1318 Some(element) => {
1319 let created = run
1320 .tree
1321 .make_property(dest, element, &types)
1322 .map_err(|e| Error::in_rule(rule, e))?;
1323 if let (true, Some(id)) = (sharing, &target.list_rule_id) {
1324 shared.add(Mode::Shared, id, created);
1326 vars.add(Mode::Shared, id, created);
1327 }
1328 order_target(run, rule, target, dest, element, created)?;
1329 created
1330 }
1331 None => dest,
1332 });
1333 }
1334 if let (Some(variable), Some(value)) = (&target.variable, value) {
1335 vars.add(Mode::Output, variable, value);
1336 }
1337 Ok(())
1338 }
1339
1340 async fn evaluate_transform(
1342 &self,
1343 run: &mut Run,
1344 group: &GroupRef,
1345 rule: &Rule,
1346 target: &Target,
1347 vars: &Vars,
1348 ) -> Result<Vec<NodeId>> {
1349 let parameters = &target.parameter;
1350 let expression = match parameters.last().map(|p| &p.value) {
1351 Some(ParameterValue::String(expression)) => expression,
1352 _ => return Err(Error::in_rule(rule, "evaluate needs an expression")),
1353 };
1354 let focus = match parameters.as_slice() {
1355 [context, _] => Some(self.parameter_node(run, group, context, vars).await?),
1356 _ => None,
1357 };
1358 self.evaluate(run, group, expression, focus, vars).await
1359 }
1360
1361 fn check_several(
1364 &self,
1365 run: &Run,
1366 rule: &Rule,
1367 target: &Target,
1368 destination: Option<NodeId>,
1369 element: Option<&str>,
1370 count: usize,
1371 ) -> Result<()> {
1372 let fail = |message: String| Err(Error::in_rule(rule, message));
1373 let (Some(dest), Some(element)) = (destination, element) else {
1374 return fail(format!(
1375 "evaluate gave {count} values where one was expected"
1376 ));
1377 };
1378 let owner = run.tree.ty(dest).display();
1379 match self.types().lookup(run.tree.ty(dest), element) {
1380 Lookup::Found(found) if found.element.array => {}
1381 Lookup::Found(_) => {
1382 return fail(format!(
1383 "evaluate gave {count} values, but `{owner}.{element}` does not repeat"
1384 ));
1385 }
1386 _ => {
1387 return fail(format!(
1388 "evaluate gave {count} values, and whether `{owner}.{element}` repeats is not known"
1389 ));
1390 }
1391 }
1392 if let Some(variable) = &target.variable {
1393 return fail(format!(
1394 "evaluate gave {count} values; variable `{variable}` can only name one"
1395 ));
1396 }
1397 Ok(())
1398 }
1399
1400 #[allow(clippy::too_many_arguments)]
1401 async fn run_transform(
1402 &self,
1403 run: &mut Run,
1404 group: &GroupRef,
1405 rule: &Rule,
1406 target: &Target,
1407 vars: &Vars,
1408 destination: Option<NodeId>,
1409 element: Option<&str>,
1410 source_variable: Option<&str>,
1411 _at_root: bool,
1412 ) -> Result<Option<NodeId>> {
1413 let transform = target.transform.as_deref().unwrap_or("copy");
1414 let parameters = &target.parameter;
1415 let fail = |message: String| Error::in_rule(rule, message);
1416 let types = self.types();
1417 match transform {
1418 "create" => {
1419 let ty = match parameters.first() {
1420 Some(parameter) => {
1421 let name = self.parameter_text(run, group, parameter, vars).await?;
1422 let context = destination
1423 .and_then(|d| run.tree.ty(d).structure().map(|s| s.url.clone()))
1424 .unwrap_or_else(|| CORE.to_owned());
1425 let of_element = match (destination, element) {
1428 (Some(d), Some(element)) => match types.lookup(run.tree.ty(d), element)
1429 {
1430 Lookup::Found(found) => types.named_type(&found, &name),
1431 _ => Type::Unknown,
1432 },
1433 _ => Type::Unknown,
1434 };
1435 let ty = match of_element {
1436 Type::Unknown => {
1437 types.structure(&self.type_name_url(&group.map, &name, &context))
1438 }
1439 known => known,
1440 };
1441 (ty, Some(name))
1442 }
1443 None => self
1444 .implied_type(run, group, destination, element, source_variable, vars)
1445 .map_err(fail)?,
1446 };
1447 let created = run.tree.create(ty.0, ty.1);
1448 if destination.is_none() && run.tree.ty(created).is_resource() {
1450 run.produced.push(created);
1451 }
1452 Ok(Some(created))
1453 }
1454 "copy" => {
1455 let parameter = parameters
1456 .first()
1457 .ok_or_else(|| fail("copy needs a value".into()))?;
1458 let node = self.parameter_node(run, group, parameter, vars).await?;
1459 Ok(Some(run.tree.deep_copy(node)))
1460 }
1461 "truncate" => {
1462 let text = self.argument_text(run, group, parameters, 0, vars).await?;
1463 let length = self.argument_text(run, group, parameters, 1, vars).await?;
1464 let length: usize = length
1465 .trim()
1466 .parse()
1467 .map_err(|_| fail(format!("truncate needs a length, not `{length}`")))?;
1468 let truncated = text.chars().take(length).collect();
1469 Ok(Some(self.string(run, truncated, "string")))
1470 }
1471 "cast" => {
1472 let source = self
1473 .parameter_node(
1474 run,
1475 group,
1476 parameters
1477 .first()
1478 .ok_or_else(|| fail("cast needs a value".into()))?,
1479 vars,
1480 )
1481 .await?;
1482 let type_name = if parameters.len() > 1 {
1483 transforms::cast_type(
1484 &self.argument_text(run, group, parameters, 1, vars).await?,
1485 )
1486 } else {
1487 self.implied_type(run, group, destination, element, None, vars)
1489 .ok()
1490 .and_then(|(_, name)| name)
1491 .ok_or_else(|| fail("cast needs a type: cast(value, 'type')".into()))?
1492 };
1493 if !run.tree.is_primitive(source) {
1494 return match run.tree.fhir_type(source) {
1496 Some(own) if own == type_name => Ok(Some(run.tree.deep_copy(source))),
1497 own => Err(fail(format!(
1498 "cannot cast a {} to {type_name}",
1499 own.as_deref().unwrap_or("complex value")
1500 ))),
1501 };
1502 }
1503 let text = run.tree.text(source).unwrap_or_default();
1504 let value = transforms::cast(&text, &type_name).map_err(fail)?;
1505 let ty = types.structure(&type_url(&type_name, CORE));
1506 Ok(Some(run.tree.primitive(value, ty, Some(type_name))))
1507 }
1508 "append" => {
1509 let mut text = String::new();
1510 for index in 0..parameters.len() {
1511 text.push_str(
1512 &self
1513 .argument_text(run, group, parameters, index, vars)
1514 .await?,
1515 );
1516 }
1517 Ok(Some(self.string(run, text, "string")))
1518 }
1519 "translate" => self.translate(run, group, rule, parameters, vars).await,
1520 "reference" | "pointer" => {
1521 let parameter = parameters
1522 .first()
1523 .ok_or_else(|| fail(format!("{transform} needs a resource")))?;
1524 let resource = self.parameter_node(run, group, parameter, vars).await?;
1525 let resource_type = run
1526 .tree
1527 .fhir_type(resource)
1528 .filter(|_| {
1529 run.tree.ty(resource).is_resource() || !run.tree.is_primitive(resource)
1530 })
1531 .ok_or_else(|| fail(format!("{transform} needs a resource")))?;
1532 let id = match run
1533 .tree
1534 .children(resource, "id")
1535 .first()
1536 .and_then(|&id| run.tree.text(id))
1537 {
1538 Some(id) => id,
1539 None => {
1540 let id = self.ids.uuid();
1541 run.tree
1542 .set_text(resource, "id", &id, &types)
1543 .map_err(fail)?;
1544 id
1545 }
1546 };
1547 Ok(Some(if transform == "reference" {
1548 self.string(run, format!("{resource_type}/{id}"), "string")
1549 } else {
1550 self.string(run, format!("urn:uuid:{id}"), "uri")
1551 }))
1552 }
1553 "uuid" => Ok(Some(self.string(run, self.ids.uuid(), "id"))),
1554 "toDateTime" | "toDate" | "toTime" => {
1555 let text = self.argument_text(run, group, parameters, 0, vars).await?;
1556 let format = match parameters.get(1) {
1557 Some(_) => Some(self.argument_text(run, group, parameters, 1, vars).await?),
1558 None => None,
1559 };
1560 let (value, type_name) = match transform {
1561 "toDateTime" => (datetime::to_date_time(&text, format.as_deref()), "dateTime"),
1562 "toDate" => (datetime::to_date(&text, format.as_deref()), "date"),
1563 _ => (datetime::to_time(&text, format.as_deref()), "time"),
1564 };
1565 Ok(Some(self.string(run, value.map_err(fail)?, type_name)))
1566 }
1567 "unixToDateTime" | "unixToDate" | "unixToTime" => {
1568 let text = self.argument_text(run, group, parameters, 0, vars).await?;
1569 let millis: i64 = text.trim().parse().map_err(|_| {
1570 fail(format!("`{text}` is not a Unix timestamp in milliseconds"))
1571 })?;
1572 let timezone = match parameters.get(1) {
1573 Some(_) => Some(self.argument_text(run, group, parameters, 1, vars).await?),
1574 None => None,
1575 };
1576 let (value, type_name) = match transform {
1577 "unixToDateTime" => (
1578 datetime::unix_to_date_time(millis, timezone.as_deref()),
1579 "dateTime",
1580 ),
1581 "unixToDate" => (datetime::unix_to_date(millis, timezone.as_deref()), "date"),
1582 _ => (datetime::unix_to_time(millis, timezone.as_deref()), "time"),
1583 };
1584 Ok(Some(self.string(run, value.map_err(fail)?, type_name)))
1585 }
1586 "escape" => {
1587 let text = self.argument_text(run, group, parameters, 0, vars).await?;
1588 let (from, to) = match parameters.len() {
1589 3 => (
1590 self.argument_text(run, group, parameters, 1, vars).await?,
1591 self.argument_text(run, group, parameters, 2, vars).await?,
1592 ),
1593 _ => (
1594 "none".to_owned(),
1595 self.argument_text(run, group, parameters, 1, vars).await?,
1596 ),
1597 };
1598 let escaped = datetime::escape(&text, &from, &to).map_err(fail)?;
1599 Ok(Some(self.string(run, escaped, "string")))
1600 }
1601 "cc" | "c" | "id" | "cp" | "qty" => {
1602 let mut arguments = Vec::with_capacity(parameters.len());
1603 for index in 0..parameters.len() {
1604 arguments.push(
1605 self.argument_text(run, group, parameters, index, vars)
1606 .await?,
1607 );
1608 }
1609 let (json, type_name) = match transform {
1610 "cc" => (transforms::codeable_concept(&arguments), "CodeableConcept"),
1611 "c" => match arguments.as_slice() {
1612 [system, code, rest @ ..] => {
1613 (transforms::coding(system, code, rest.first()), "Coding")
1614 }
1615 _ => return Err(fail("c needs a system and a code".into())),
1616 },
1617 "id" => (transforms::identifier(&arguments), "Identifier"),
1618 "cp" => (transforms::contact_point(&arguments), "ContactPoint"),
1619 _ => (transforms::quantity(&arguments).map_err(fail)?, "Quantity"),
1620 };
1621 let context = destination
1622 .and_then(|d| run.tree.ty(d).structure().map(|s| s.url.clone()))
1623 .unwrap_or_else(|| CORE.to_owned());
1624 let ty = types.structure(&type_url(type_name, &context));
1625 let node = run.tree.load(&json, ty, &types);
1626 Ok(Some(node))
1627 }
1628 other => Err(fail(format!("the {other} transform is not supported"))),
1629 }
1630 }
1631
1632 fn implied_type(
1635 &self,
1636 run: &Run,
1637 group: &GroupRef,
1638 destination: Option<NodeId>,
1639 element: Option<&str>,
1640 source_variable: Option<&str>,
1641 vars: &Vars,
1642 ) -> std::result::Result<(Type, Option<String>), String> {
1643 let types = self.types();
1644 if let (Some(dest), Some(element)) = (destination, element)
1645 && let Lookup::Found(found) = types.lookup(run.tree.ty(dest), element)
1646 && let [single] = found.element.types.as_slice()
1647 && single != "Resource"
1648 && single != "*"
1649 {
1650 return Ok((types.element_type(&found, None), Some(single.clone())));
1651 }
1652 if let Some(source) = source_variable.and_then(|s| vars.get(Mode::Input, s)) {
1653 if let Some(source_type) = run.tree.fhir_type(source)
1656 && let Some(produced) = self.default_target_type(group, &source_type)
1657 {
1658 return Ok(produced);
1659 }
1660 return Ok((run.tree.ty(source).clone(), run.tree.fhir_type(source)));
1661 }
1662 Err("cannot tell what type to create: name it, as in create('Type')".into())
1663 }
1664
1665 fn default_target_type(&self, group: &GroupRef, source_type: &str) -> Option<TypedTarget> {
1668 if let Some(found) = self.default_target_in(&group.map, source_type) {
1669 return Some(found);
1670 }
1671 let key = (imports_key(&group.map), source_type.to_owned());
1672 if let Some(found) = self.cache().default_target.get(&key) {
1673 return found.clone();
1674 }
1675 let found = self.find_default_target_type(group, source_type);
1676 self.cache().default_target.insert(key, found.clone());
1677 found
1678 }
1679
1680 fn default_target_in(&self, map: &StructureMap, source_type: &str) -> Option<TypedTarget> {
1682 map.group.iter().find_map(|candidate| {
1683 if candidate.type_mode.as_deref() != Some("type-and-types") {
1684 return None;
1685 }
1686 let [source, target] = candidate.input.as_slice() else {
1687 return None;
1688 };
1689 if source.mode != "source"
1690 || target.mode != "target"
1691 || !self.stated_type_is(map, source.type_name.as_deref(), source_type)
1692 {
1693 return None;
1694 }
1695 let stated = target.type_name.as_deref()?;
1696 let ty = self
1697 .types()
1698 .structure(&self.type_name_url(map, stated, CORE));
1699 let name = ty.fhir_type().unwrap_or_else(|| stated.to_owned());
1700 Some((ty, Some(name)))
1701 })
1702 }
1703
1704 fn find_default_target_type(&self, group: &GroupRef, source_type: &str) -> Option<TypedTarget> {
1705 group.map.import.iter().find_map(|import| {
1706 self.maps
1707 .resolve(import)
1708 .iter()
1709 .filter(|imported| imported.url != group.map.url)
1710 .find_map(|imported| self.default_target_in(imported, source_type))
1711 })
1712 }
1713
1714 async fn translate(
1717 &self,
1718 run: &mut Run,
1719 group: &GroupRef,
1720 rule: &Rule,
1721 parameters: &[Parameter],
1722 vars: &Vars,
1723 ) -> Result<Option<NodeId>> {
1724 let fail = |message: String| Error::in_rule(rule, message);
1725 let source = self
1726 .parameter_node(
1727 run,
1728 group,
1729 parameters
1730 .first()
1731 .ok_or_else(|| fail("translate needs a value".into()))?,
1732 vars,
1733 )
1734 .await?;
1735 let map_url = self.argument_text(run, group, parameters, 1, vars).await?;
1736 let output = self.argument_text(run, group, parameters, 2, vars).await?;
1737 let concept_map = match map_url.strip_prefix('#') {
1738 Some(id) => Some(
1739 group
1740 .map
1741 .contained
1742 .iter()
1743 .find(|r| r["resourceType"] == "ConceptMap" && r["id"] == id)
1744 .cloned()
1745 .map(Arc::new)
1746 .ok_or_else(|| fail(format!("no contained ConceptMap `{id}`")))?,
1747 ),
1748 None => self.concept_maps.resolve(&map_url),
1749 };
1750 if concept_map.is_none() && self.translator.is_none() {
1751 return Err(fail(format!("ConceptMap `{map_url}` not found")));
1752 }
1753 let codes = self.codes_of(run, source);
1754 let mut translation = None;
1755 let mut reported = false;
1756 for (system, code) in &codes {
1757 let found = match (&concept_map, self.translator) {
1758 (Some(concept_map), _) => translate(concept_map, system.as_deref(), code),
1759 (None, Some(translator)) => {
1760 translator
1761 .translate(&map_url, system.as_deref(), code)
1762 .await
1763 }
1764 (None, None) => unreachable!("checked above"),
1765 };
1766 let found = match found {
1767 Ok(found) => found,
1768 Err(e) if self.lenient_translations => {
1771 let rule_name = rule.name.as_deref().unwrap_or("?");
1772 run.warnings
1773 .push(format!("rule `{rule_name}`: {e} in `{map_url}`; left out"));
1774 reported = true;
1775 None
1776 }
1777 Err(e) => return Err(fail(format!("{e} in `{map_url}`"))),
1778 };
1779 if let Some(found) = found {
1780 translation = Some(found);
1781 break;
1782 }
1783 }
1784 let Some(translation) = translation else {
1785 if reported {
1786 return Ok(None);
1787 }
1788 let shown: Vec<&str> = codes.iter().map(|(_, c)| c.as_str()).collect();
1789 let rule_name = rule.name.as_deref().unwrap_or("?");
1790 run.warnings.push(format!(
1791 "rule `{rule_name}`: `{}` has no translation in `{map_url}`; left out",
1792 shown.join(", ")
1793 ));
1794 return Ok(None);
1795 };
1796
1797 let types = self.types();
1798 let mut coding = serde_json::Map::new();
1799 if let Some(system) = &translation.system {
1800 coding.insert("system".into(), system.clone().into());
1801 }
1802 if let Some(code) = &translation.code {
1803 coding.insert("code".into(), code.clone().into());
1804 }
1805 if let Some(display) = &translation.display {
1806 coding.insert("display".into(), display.clone().into());
1807 }
1808 let text = |value: &Option<String>| value.clone().map_or(Value::Null, Value::String);
1809 let (json, type_name) = match output.as_str() {
1810 "code" => (text(&translation.code), "code"),
1811 "system" => (text(&translation.system), "uri"),
1812 "display" => (text(&translation.display), "string"),
1813 "Coding" => (Value::Object(coding), "Coding"),
1814 "CodeableConcept" => (
1815 json!({ "coding": [Value::Object(coding)] }),
1816 "CodeableConcept",
1817 ),
1818 other => return Err(fail(format!("unknown translate output `{other}`"))),
1819 };
1820 let ty = types.structure(&type_url(type_name, CORE));
1821 Ok(Some(if json.is_object() {
1822 run.tree.load(&json, ty, &types)
1823 } else {
1824 run.tree.primitive(json, ty, Some(type_name.to_owned()))
1825 }))
1826 }
1827
1828 fn codes_of(&self, run: &Run, node: NodeId) -> Vec<(Option<String>, String)> {
1830 let text = |id: NodeId, name: &str| {
1831 run.tree
1832 .children(id, name)
1833 .first()
1834 .and_then(|&child| run.tree.text(child))
1835 };
1836 if run.tree.is_primitive(node) {
1837 return run
1838 .tree
1839 .text(node)
1840 .map(|code| (None, code))
1841 .into_iter()
1842 .collect();
1843 }
1844 let codings = run.tree.children(node, "coding");
1845 let codings = if codings.is_empty() {
1846 vec![node]
1847 } else {
1848 codings
1849 };
1850 codings
1851 .into_iter()
1852 .filter_map(|coding| Some((text(coding, "system"), text(coding, "code")?)))
1853 .collect()
1854 }
1855
1856 async fn parameter_node(
1860 &self,
1861 run: &mut Run,
1862 group: &GroupRef,
1863 parameter: &Parameter,
1864 vars: &Vars,
1865 ) -> Result<NodeId> {
1866 let types = self.types();
1867 let (value, type_name) = match ¶meter.value {
1868 ParameterValue::Id(name) => return self.variable(run, group, name, vars).await,
1869 ParameterValue::String(v) => (Value::String(v.clone()), "string"),
1870 ParameterValue::Boolean(v) => (Value::Bool(*v), "boolean"),
1871 ParameterValue::Integer(v) => (Value::from(*v), "integer"),
1872 ParameterValue::Decimal(v) => (Value::Number(v.clone()), "decimal"),
1873 ParameterValue::Date(v) => (Value::String(v.clone()), "date"),
1874 ParameterValue::Time(v) => (Value::String(v.clone()), "time"),
1875 ParameterValue::DateTime(v) => (Value::String(v.clone()), "dateTime"),
1876 };
1877 let ty = types.structure(&type_url(type_name, CORE));
1878 Ok(run.tree.primitive(value, ty, Some(type_name.to_owned())))
1879 }
1880
1881 async fn variable(
1883 &self,
1884 run: &mut Run,
1885 group: &GroupRef,
1886 name: &str,
1887 vars: &Vars,
1888 ) -> Result<NodeId> {
1889 if let Some(node) = vars.value(name) {
1890 return Ok(node);
1891 }
1892 if let Some((variable, path)) = name.split_once('.')
1894 && let Some(mut node) = vars.value(variable)
1895 {
1896 for segment in path.split('.') {
1897 node = *run
1898 .tree
1899 .children(node, segment)
1900 .first()
1901 .ok_or_else(|| Error::new(format!("`{name}` has no value")))?;
1902 }
1903 return Ok(node);
1904 }
1905 let values = self.constant(run, group, name).await?;
1906 match values.as_slice() {
1907 [single] => Ok(*single),
1908 [] => Err(Error::new(format!("unknown variable `{name}`"))),
1909 _ => Err(Error::new(format!("constant `{name}` has several values"))),
1910 }
1911 }
1912
1913 async fn parameter_text(
1914 &self,
1915 run: &mut Run,
1916 group: &GroupRef,
1917 parameter: &Parameter,
1918 vars: &Vars,
1919 ) -> Result<String> {
1920 if let ParameterValue::String(text) = ¶meter.value {
1921 return Ok(text.clone());
1922 }
1923 let node = self.parameter_node(run, group, parameter, vars).await?;
1924 Ok(run.tree.text(node).unwrap_or_default())
1925 }
1926
1927 async fn argument_text(
1928 &self,
1929 run: &mut Run,
1930 group: &GroupRef,
1931 parameters: &[Parameter],
1932 index: usize,
1933 vars: &Vars,
1934 ) -> Result<String> {
1935 let parameter = parameters
1936 .get(index)
1937 .ok_or_else(|| Error::new(format!("missing argument {}", index + 1)))?;
1938 self.parameter_text(run, group, parameter, vars).await
1939 }
1940
1941 fn literal(&self, run: &mut Run, value: Value, type_name: &str) -> NodeId {
1942 let ty = self.types().structure(&type_url(type_name, CORE));
1943 run.tree.primitive(value, ty, Some(type_name.to_owned()))
1944 }
1945
1946 fn string(&self, run: &mut Run, text: String, type_name: &str) -> NodeId {
1947 let ty = self.types().structure(&type_url(type_name, CORE));
1948 run.tree
1949 .primitive(Value::String(text), ty, Some(type_name.to_owned()))
1950 }
1951
1952 fn constant<'r>(
1956 &'r self,
1957 run: &'r mut Run,
1958 group: &'r GroupRef,
1959 name: &'r str,
1960 ) -> BoxFuture<'r, Result<Vec<NodeId>>> {
1961 Box::pin(async move {
1962 let key = (group.map.url.clone().unwrap_or_default(), name.to_owned());
1963 if let Some(values) = run.constants.get(&key) {
1964 return Ok(values.clone());
1965 }
1966 let Some(constant) = group.map.constants.iter().find(|c| c.name == name) else {
1967 return Ok(Vec::new());
1968 };
1969 if !run.evaluating.insert(key.clone()) {
1970 return Err(Error::new(format!("constant `{name}` refers to itself")));
1971 }
1972 let values = self
1973 .evaluate(run, group, &constant.value, None, &Vars::default())
1974 .await;
1975 run.evaluating.remove(&key);
1976 let values = values?;
1977 run.constants.insert(key, values.clone());
1978 Ok(values)
1979 })
1980 }
1981
1982 fn evaluate<'r>(
1983 &'r self,
1984 run: &'r mut Run,
1985 group: &'r GroupRef,
1986 expression: &'r str,
1987 focus: Option<NodeId>,
1988 vars: &'r Vars,
1989 ) -> BoxFuture<'r, Result<Vec<NodeId>>> {
1990 Box::pin(async move {
1991 let referenced = path_start_names(expression);
1994 let mut names: HashSet<String> = vars
1995 .names()
1996 .filter(|name| referenced.contains(*name))
1997 .map(str::to_owned)
1998 .collect();
1999 let mut variables = Vec::new();
2000 for name in &names {
2001 if let Some(node) = vars.value(name) {
2002 variables.push((name.clone(), self.item(run, node)));
2003 }
2004 }
2005 for constant in &group.map.constants {
2006 if names.contains(&constant.name) || expression == constant.value {
2007 continue;
2008 }
2009 if referenced.contains(&constant.name) {
2010 let values = self.constant(run, group, &constant.name).await?;
2011 if let [value] = values.as_slice() {
2012 variables.push((constant.name.clone(), self.item(run, *value)));
2013 names.insert(constant.name.clone());
2014 }
2015 }
2016 }
2017 let bound = bind_variables(expression, &names);
2018 let focus = focus.map(|node| self.item(run, node));
2019 let results = self
2020 .expressions
2021 .evaluate(&bound, focus.as_ref(), &variables)
2022 .await
2023 .map_err(|e| Error::new(format!("`{expression}`: {e}")))?;
2024 let types = self.types();
2025 Ok(results
2026 .into_iter()
2027 .map(|item| {
2028 let ty = item
2029 .type_name
2030 .as_deref()
2031 .map(|t| types.structure(&type_url(t, CORE)))
2032 .unwrap_or(Type::Unknown);
2033 if item.json.is_object() {
2034 run.tree.load(&item.json, ty, &types)
2035 } else {
2036 run.tree.primitive(item.json, ty, item.type_name)
2037 }
2038 })
2039 .collect())
2040 })
2041 }
2042
2043 async fn evaluate_boolean(
2044 &self,
2045 run: &mut Run,
2046 group: &GroupRef,
2047 expression: &str,
2048 focus: Option<NodeId>,
2049 vars: &Vars,
2050 ) -> Result<bool> {
2051 let values = self.evaluate(run, group, expression, focus, vars).await?;
2052 Ok(match values.as_slice() {
2053 [] => false,
2054 [single] => run.tree.value(*single) != Some(&Value::Bool(false)),
2055 _ => true,
2056 })
2057 }
2058
2059 fn item(&self, run: &Run, node: NodeId) -> Item {
2062 let type_name = match run.tree.ty(node) {
2063 backbone @ Type::Node { path, .. } if !path.is_empty() => Some(backbone.display()),
2064 _ => run.tree.fhir_type(node),
2065 };
2066 Item {
2067 json: run.tree.to_json(node),
2068 type_name,
2069 }
2070 }
2071}
2072
2073fn element_path(
2076 element: Option<&str>,
2077 extensions: &[fml_model::model::Extension],
2078 url: &str,
2079) -> Vec<String> {
2080 element
2081 .map(str::to_owned)
2082 .into_iter()
2083 .chain(
2084 extensions
2085 .iter()
2086 .filter(|e| e.url == url)
2087 .filter_map(|e| e.value_string.clone()),
2088 )
2089 .collect()
2090}
2091
2092fn order_target(
2096 run: &mut Run,
2097 rule: &Rule,
2098 target: &Target,
2099 dest: NodeId,
2100 element: &str,
2101 value: NodeId,
2102) -> Result<()> {
2103 let identity = std::ptr::from_ref(target) as usize;
2104 let mode = target
2105 .list_mode
2106 .iter()
2107 .find(|mode| matches!(mode.as_str(), "first" | "last" | "single"))
2108 .map(String::as_str);
2109 if mode == Some("single") && !run.single.insert((dest, element.to_owned(), identity)) {
2110 return Err(Error::in_rule(
2111 rule,
2112 format!("target `{element}` is `single`, but the rule makes more than one"),
2113 ));
2114 }
2115 let key = (dest, element.to_owned());
2116 let order = match (mode, run.order.contains_key(&key)) {
2117 (Some("first" | "last"), _) | (_, true) => run.order.entry(key).or_default(),
2118 _ => return Ok(()),
2119 };
2120 match mode {
2121 Some("first") => {
2122 if order.first.is_some_and(|first| first != identity) {
2123 return Err(Error::in_rule(
2124 rule,
2125 format!("two rules put their values `first` in `{element}`"),
2126 ));
2127 }
2128 order.first = Some(identity);
2129 let at = order.first_count;
2130 order.first_count += 1;
2131 run.tree.move_value(dest, element, value, Some(at));
2132 }
2133 Some("last") => {
2134 if order.last.is_some_and(|last| last != identity) {
2135 return Err(Error::in_rule(
2136 rule,
2137 format!("two rules put their values `last` in `{element}`"),
2138 ));
2139 }
2140 order.last = Some(identity);
2141 order.last_values.push(value);
2142 }
2143 _ => {}
2144 }
2145 let last_values = order.last_values.clone();
2146 for last in last_values {
2147 run.tree.move_value(dest, element, last, None);
2148 }
2149 Ok(())
2150}
2151
2152fn check_cardinality(rule: &Rule, source: &Source, count: usize) -> Result<()> {
2154 let below = source
2155 .min
2156 .is_some_and(|min| i64::try_from(count).is_ok_and(|count| count < min));
2157 let above = source
2158 .max
2159 .as_deref()
2160 .and_then(|max| max.parse::<usize>().ok())
2161 .is_some_and(|max| count > max);
2162 if below || above {
2163 let path = std::iter::once(source.context.as_str())
2164 .chain(source.element.as_deref())
2165 .collect::<Vec<_>>()
2166 .join(".");
2167 return Err(Error::in_rule(
2168 rule,
2169 format!(
2170 "`{path}` has {count} values, outside {}..{}",
2171 source.min.unwrap_or(0),
2172 source.max.as_deref().unwrap_or("*")
2173 ),
2174 ));
2175 }
2176 Ok(())
2177}
2178
2179fn imports_key(map: &StructureMap) -> String {
2181 let mut key = map.url.clone().unwrap_or_default();
2182 for import in &map.import {
2183 key.push('\n');
2184 key.push_str(import);
2185 }
2186 key
2187}
2188
2189fn parameter_name(parameter: &Parameter) -> String {
2191 match ¶meter.value {
2192 ParameterValue::Id(name) | ParameterValue::String(name) => name.clone(),
2193 other => format!("{other:?}"),
2194 }
2195}
2196
2197fn simple_copy(rule: &Rule) -> Option<(&str, &str)> {
2199 let ([source], [target]) = (rule.source.as_slice(), rule.target.as_slice()) else {
2200 return None;
2201 };
2202 (target.transform.as_deref() == Some("create") && target.parameter.is_empty()).then_some(())?;
2203 Some((source.variable.as_deref()?, target.variable.as_deref()?))
2204}