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