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, 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 groups: Mutex<GroupCache>,
221}
222
223type TypedTarget = (Type, Option<String>);
225
226#[derive(Default)]
230struct GroupCache {
231 by_name: HashMap<(String, String), Found>,
232 by_types: HashMap<(String, String, String), Option<GroupRef>>,
233 default_target: HashMap<(String, String), Option<TypedTarget>>,
234}
235
236#[derive(Debug, Clone, Copy, PartialEq, Eq)]
237enum Mode {
238 Input,
239 Output,
240 Shared,
241}
242
243#[derive(Debug, Clone, Default)]
245struct Vars {
246 entries: Vec<(Mode, String, NodeId)>,
247}
248
249impl Vars {
250 fn add(&mut self, mode: Mode, name: &str, node: NodeId) {
251 self.entries.push((mode, name.to_owned(), node));
252 }
253
254 fn get(&self, mode: Mode, name: &str) -> Option<NodeId> {
255 self.entries
256 .iter()
257 .rev()
258 .find(|(m, n, _)| *m == mode && n == name)
259 .map(|(_, _, node)| *node)
260 }
261
262 fn value(&self, name: &str) -> Option<NodeId> {
264 self.get(Mode::Input, name)
265 .or_else(|| self.get(Mode::Output, name))
266 }
267
268 fn names(&self) -> impl Iterator<Item = &str> {
269 self.entries
270 .iter()
271 .filter(|(mode, _, _)| *mode != Mode::Shared)
272 .map(|(_, name, _)| name.as_str())
273 }
274}
275
276#[derive(Clone)]
278enum Found {
279 One(GroupRef),
280 None,
281 Several(Vec<String>),
283}
284
285#[derive(Clone)]
287struct GroupRef {
288 map: Arc<StructureMap>,
289 index: usize,
290}
291
292impl GroupRef {
293 fn group(&self) -> &Group {
294 &self.map.group[self.index]
295 }
296}
297
298#[derive(Default)]
300struct Run {
301 tree: Tree,
302 log: Vec<String>,
303 warnings: Vec<String>,
304 depth: usize,
305 trace: Option<Vec<TraceEvent>>,
307 trace_depth: usize,
308 produced: Vec<NodeId>,
310 constants: HashMap<(String, String), Vec<NodeId>>,
312 evaluating: HashSet<(String, String)>,
314 rules: u64,
316 trace_bytes: usize,
318 trace_truncated: Option<String>,
320 single: HashSet<(NodeId, String, usize)>,
322 order: HashMap<(NodeId, String), TargetOrder>,
324}
325
326#[derive(Default)]
328struct TargetOrder {
329 first: Option<usize>,
330 first_count: usize,
331 last: Option<usize>,
332 last_values: Vec<NodeId>,
333}
334const CORE: &str = "http://hl7.org/fhir/StructureDefinition/";
335
336impl<'a, X: Expressions> Engine<'a, X> {
337 pub fn new(definitions: &'a dyn Definitions, expressions: X) -> Self {
338 Self {
339 definitions,
340 expressions,
341 maps: &NoMaps,
342 concept_maps: &NoConceptMaps,
343 translator: None,
344 ids: &RandomIds,
345 limits: Limits::default(),
346 cancel: None,
347 trace: false,
348 groups: Mutex::new(GroupCache::default()),
349 }
350 }
351
352 fn cache(&self) -> std::sync::MutexGuard<'_, GroupCache> {
353 self.groups.lock().unwrap_or_else(|e| e.into_inner())
354 }
355
356 pub fn with_trace(mut self, trace: bool) -> Self {
358 self.trace = trace;
359 self
360 }
361
362 pub fn with_concept_maps(mut self, concept_maps: &'a dyn ConceptMapResolver) -> Self {
364 self.concept_maps = concept_maps;
365 self
366 }
367
368 pub fn with_translator(mut self, translator: &'a dyn TranslateService) -> Self {
371 self.translator = Some(translator);
372 self
373 }
374
375 pub fn with_limits(mut self, limits: Limits) -> Self {
377 self.limits = limits;
378 self
379 }
380
381 pub fn with_cancellation(mut self, cancel: &'a AtomicBool) -> Self {
384 self.cancel = Some(cancel);
385 self
386 }
387
388 pub fn with_ids(mut self, ids: &'a dyn IdGenerator) -> Self {
390 self.ids = ids;
391 self
392 }
393
394 pub fn with_maps(mut self, maps: &'a dyn MapResolver) -> Self {
396 self.maps = maps;
397 self
398 }
399
400 fn types(&self) -> Types<'a> {
401 Types::new(self.definitions)
402 }
403
404 pub async fn transform(&self, map: &StructureMap, source: &Value) -> Result<Transformed> {
407 self.run(map, source, None).await
408 }
409
410 pub async fn transform_into(
412 &self,
413 map: &StructureMap,
414 source: &Value,
415 target: &Value,
416 ) -> Result<Transformed> {
417 self.run(map, source, Some(target)).await
418 }
419
420 async fn run(
421 &self,
422 map: &StructureMap,
423 source: &Value,
424 target: Option<&Value>,
425 ) -> Result<Transformed> {
426 let map = Arc::new(map.clone());
427 let group = map
428 .group
429 .first()
430 .ok_or_else(|| Error::new("the map has no groups"))?;
431 let input = |mode: &str| group.input.iter().find(|input| input.mode == mode);
432 let source_input =
433 input("source").ok_or_else(|| Error::new("the first group has no source"))?;
434 let target_input =
435 input("target").ok_or_else(|| Error::new("the first group has no target"))?;
436
437 let mut run = Run {
438 trace: self.trace.then(Vec::new),
439 ..Run::default()
440 };
441 let types = self.types();
442 let source_type = self.input_type(&map, source_input.type_name.as_deref());
443 let source_node = run.tree.load(source, source_type, &types);
444 if run.trace.is_some() {
445 let root_name = run
447 .tree
448 .fhir_type(source_node)
449 .unwrap_or_else(|| "%resource".to_owned());
450 run.tree.record_paths(source_node, &root_name);
451 }
452 let target_type = self.input_type(&map, target_input.type_name.as_deref());
453 let target_node = match target {
454 Some(target) => run.tree.load(target, target_type, &types),
455 None => {
456 if matches!(target_type, Type::Unknown) {
457 return Err(Error::new(format!(
458 "cannot create the target: type `{}` is not known",
459 target_input.type_name.as_deref().unwrap_or("?")
460 )));
461 }
462 run.tree.create(target_type, None)
463 }
464 };
465 let mut vars = Vars::default();
466 vars.add(Mode::Input, &source_input.name, source_node);
467 vars.add(Mode::Output, &target_input.name, target_node);
468 let entry = GroupRef {
469 map: map.clone(),
470 index: 0,
471 };
472 if let Err(mut error) = self.execute_group(&mut run, entry, vars, true).await {
473 let truncated = run.trace_truncated.take();
474 error.trace = run.trace.take().map(|events| {
475 Box::new(Trace {
476 status: match truncated {
477 Some(_) => TraceStatus::Truncated,
478 None => TraceStatus::Stopped,
479 },
480 note: truncated,
481 events,
482 })
483 });
484 return Err(error);
485 }
486 let in_target = run.tree.reachable(target_node);
487 let produced = run
488 .produced
489 .iter()
490 .filter(|node| !in_target.contains(node))
491 .map(|&node| run.tree.to_json(node))
492 .collect();
493 Ok(Transformed {
494 target: run.tree.to_json(target_node),
495 log: run.log,
496 warnings: run.warnings,
497 produced,
498 trace: run.trace.map(|events| Trace {
499 status: match run.trace_truncated {
500 Some(_) => TraceStatus::Truncated,
501 None => TraceStatus::Complete,
502 },
503 note: run.trace_truncated,
504 events,
505 }),
506 })
507 }
508
509 fn input_type(&self, map: &StructureMap, name: Option<&str>) -> Type {
511 let Some(name) = name else {
512 return Type::Unknown;
513 };
514 self.types().structure(&self.type_name_url(map, name, CORE))
515 }
516
517 fn type_name_url(&self, map: &StructureMap, name: &str, context: &str) -> String {
518 if let Some(structure) = map
519 .structure
520 .iter()
521 .find(|s| s.alias.as_deref() == Some(name))
522 {
523 return structure.url.clone();
524 }
525 type_url(name, context)
526 }
527
528 fn execute_group<'r>(
531 &'r self,
532 run: &'r mut Run,
533 group: GroupRef,
534 vars: Vars,
535 at_root: bool,
536 ) -> BoxFuture<'r, Result<()>> {
537 Box::pin(async move {
538 run.depth += 1;
539 if run.depth > self.limits.max_depth {
540 return Err(Error::limit(format!(
541 "groups nest more than {} deep; is a group calling itself without end?",
542 self.limits.max_depth
543 )));
544 }
545 let map = group.map.clone();
546 let definition = group.group();
547 let position = format!("StructureMap.group[{}]", group.index);
548 self.record(run, Phase::Enter, &map, &position, &vars, Vec::new());
549 if let Some(extends) = &definition.extends {
550 let base = self.group_by_name(&map, extends)?;
551 self.execute_group(run, base, vars.clone(), false).await?;
552 }
553 let mut vars = vars;
554 for (index, rule) in definition.rule.iter().enumerate() {
555 let rule_position = format!("{position}.rule[{index}]");
556 self.execute_rule(run, &group, rule, &rule_position, &mut vars, at_root)
557 .await?;
558 }
559 self.record(run, Phase::Exit, &map, &position, &vars, Vec::new());
560 run.depth -= 1;
561 Ok(())
562 })
563 }
564
565 fn group_by_name(&self, map: &Arc<StructureMap>, name: &str) -> Result<GroupRef> {
567 if let Some(index) = map.group.iter().position(|g| g.name == name) {
568 return Ok(GroupRef {
569 map: map.clone(),
570 index,
571 });
572 }
573 let key = (imports_key(map), name.to_owned());
574 let cached = self.cache().by_name.get(&key).cloned();
575 let found = match cached {
576 Some(found) => found,
577 None => {
578 let found = self.find_imported_group_by_name(map, name);
579 self.cache().by_name.insert(key, found.clone());
580 found
581 }
582 };
583 match found {
584 Found::One(group) => Ok(group),
585 Found::None => Err(Error::new(format!(
586 "no group `{name}` in {} or the maps it imports",
587 map.url.as_deref().unwrap_or("the map")
588 ))),
589 Found::Several(urls) => Err(Error::new(format!(
590 "group `{name}` is in several imported maps ({}); a group name must be unique",
591 urls.join(", ")
592 ))),
593 }
594 }
595
596 fn find_imported_group_by_name(&self, map: &Arc<StructureMap>, name: &str) -> Found {
599 let mut found: Vec<GroupRef> = Vec::new();
600 for import in &map.import {
601 for imported in self.maps.resolve(import) {
602 if imported.url == map.url || found.iter().any(|g| g.map.url == imported.url) {
603 continue;
604 }
605 if let Some(index) = imported.group.iter().position(|g| g.name == name) {
606 found.push(GroupRef {
607 map: imported.clone(),
608 index,
609 });
610 }
611 }
612 }
613 match found.len() {
614 0 => Found::None,
615 1 => Found::One(found.remove(0)),
616 _ => Found::Several(
617 found
618 .iter()
619 .map(|g| g.map.url.clone().unwrap_or_default())
620 .collect(),
621 ),
622 }
623 }
624
625 fn group_by_types(
628 &self,
629 map: &Arc<StructureMap>,
630 source: Option<&str>,
631 target: Option<&str>,
632 ) -> Option<GroupRef> {
633 let (source, target) = (source?, target?);
634 if let Some(index) = self.default_group_index(map, source, target) {
635 return Some(GroupRef {
636 map: map.clone(),
637 index,
638 });
639 }
640 let key = (imports_key(map), source.to_owned(), target.to_owned());
641 if let Some(found) = self.cache().by_types.get(&key) {
642 return found.clone();
643 }
644 let found = self.find_imported_group_by_types(map, source, target);
645 self.cache().by_types.insert(key, found.clone());
646 found
647 }
648
649 fn default_group_index(&self, map: &StructureMap, source: &str, target: &str) -> Option<usize> {
651 map.group.iter().position(|group| {
652 group.type_mode.is_some()
653 && matches!(group.input.as_slice(), [s, t]
654 if s.mode == "source" && t.mode == "target"
655 && self.stated_type_is(map, s.type_name.as_deref(), source)
656 && self.stated_type_is(map, t.type_name.as_deref(), target))
657 })
658 }
659
660 fn find_imported_group_by_types(
661 &self,
662 map: &Arc<StructureMap>,
663 source: &str,
664 target: &str,
665 ) -> Option<GroupRef> {
666 for import in &map.import {
667 for imported in self.maps.resolve(import) {
668 if imported.url == map.url {
669 continue;
670 }
671 if let Some(index) = self.default_group_index(&imported, source, target) {
672 return Some(GroupRef {
673 map: imported,
674 index,
675 });
676 }
677 }
678 }
679 None
680 }
681
682 fn stated_type_name(&self, map: &StructureMap, stated: &str) -> String {
685 map.structure
686 .iter()
687 .find(|s| s.alias.as_deref() == Some(stated))
688 .and_then(|s| self.definitions.structure(&s.url))
689 .map_or_else(|| stated.to_owned(), |s| s.type_name.clone())
690 }
691
692 fn stated_type_is(&self, map: &StructureMap, stated: Option<&str>, actual: &str) -> bool {
693 let Some(stated) = stated else { return false };
694 if stated == actual {
695 return true;
696 }
697 let url = self.type_name_url(map, stated, CORE);
698 self.definitions
699 .structure(&url)
700 .is_some_and(|s| s.type_name == actual)
701 }
702
703 fn execute_rule<'r>(
706 &'r self,
707 run: &'r mut Run,
708 group: &'r GroupRef,
709 rule: &'r Rule,
710 position: &'r str,
711 vars: &'r mut Vars,
712 at_root: bool,
713 ) -> BoxFuture<'r, Result<()>> {
714 Box::pin(async move {
715 self.check_limits(run)?;
716 self.record(run, Phase::Enter, &group.map, position, vars, Vec::new());
717 let mut bindings = vec![vars.clone()];
718 for (index, source) in rule.source.iter().enumerate() {
719 let logged = run.log.len();
720 let mut next = Vec::new();
721 for binding in &bindings {
722 next.extend(
723 self.process_source(run, group, rule, source, binding)
724 .await
725 .map_err(|e| {
726 e.at(&group.map, &format!("{position}.source[{index}]"))
727 })?,
728 );
729 }
730 bindings = next;
731 if run.trace.is_some() {
732 let messages = run.log[logged..].to_vec();
733 let shown = bindings.first().cloned().unwrap_or_else(|| vars.clone());
734 let step = format!("{position}.source[{index}]");
735 self.record(run, Phase::Step, &group.map, &step, &shown, messages);
736 }
737 }
738 let source_variable = match rule.source.as_slice() {
739 [single] => single.variable.as_deref(),
740 _ => None,
741 };
742 for mut binding in bindings {
743 for (index, target) in rule.target.iter().enumerate() {
744 self.process_target(
745 run,
746 group,
747 rule,
748 target,
749 &mut binding,
750 vars,
751 source_variable,
752 at_root,
753 )
754 .await
755 .map_err(|e| e.at(&group.map, &format!("{position}.target[{index}]")))?;
756 if run.trace.is_some() {
757 let step = format!("{position}.target[{index}]");
758 self.record(run, Phase::Step, &group.map, &step, &binding, Vec::new());
759 }
760 }
761 for dependent in &rule.dependent {
763 self.execute_dependency(run, group, rule, dependent, &binding)
764 .await
765 .map_err(|e| e.at(&group.map, position))?;
766 }
767 for (index, child) in rule.rule.iter().enumerate() {
768 let child_position = format!("{position}.rule[{index}]");
769 self.execute_rule(run, group, child, &child_position, &mut binding, false)
770 .await?;
771 }
772 if rule.dependent.is_empty()
773 && rule.rule.is_empty()
774 && let Some((source, target)) = simple_copy(rule)
775 {
776 self.default_copy(run, group, rule, source, target, &binding)
777 .await
778 .map_err(|e| e.at(&group.map, position))?;
779 }
780 }
781 self.record(run, Phase::Exit, &group.map, position, vars, Vec::new());
782 Ok(())
783 })
784 }
785
786 fn check_limits(&self, run: &mut Run) -> Result<()> {
788 if self
789 .cancel
790 .is_some_and(|cancel| cancel.load(Ordering::Relaxed))
791 {
792 return Err(Error {
793 kind: ErrorKind::Cancelled,
794 ..Error::new("the transform was cancelled")
795 });
796 }
797 run.rules += 1;
798 if run.rules > self.limits.max_rules {
799 return Err(Error::limit(format!(
800 "the transform ran more than {} rules",
801 self.limits.max_rules
802 )));
803 }
804 if run.tree.len() > self.limits.max_values {
805 return Err(Error::limit(format!(
806 "the transform created more than {} values",
807 self.limits.max_values
808 )));
809 }
810 Ok(())
811 }
812
813 fn record(
815 &self,
816 run: &mut Run,
817 phase: Phase,
818 map: &StructureMap,
819 position: &str,
820 vars: &Vars,
821 messages: Vec<String>,
822 ) {
823 if run.trace.is_none() {
824 return;
825 }
826 if phase == Phase::Exit {
827 run.trace_depth = run.trace_depth.saturating_sub(1);
828 }
829 if run.trace_truncated.is_some() {
830 if phase == Phase::Enter {
831 run.trace_depth += 1;
832 }
833 return;
834 }
835 let mut seen = HashSet::new();
836 let mut variables: Vec<TraceVariable> = vars
837 .entries
838 .iter()
839 .rev()
840 .filter(|(mode, name, _)| *mode != Mode::Shared && seen.insert(name.clone()))
841 .map(|(mode, name, node)| TraceVariable {
842 name: name.clone(),
843 context_type: match mode {
844 Mode::Input => "input",
845 _ => "output",
846 }
847 .to_owned(),
848 value: run.tree.to_json(*node),
849 data_type: self.item(run, *node).type_name,
850 path: run.tree.path(*node).map(str::to_owned),
851 })
852 .collect();
853 variables.reverse();
854 let event = TraceEvent {
855 phase,
856 depth: run.trace_depth,
857 source: map.url.clone(),
858 position: position.to_owned(),
859 variables,
860 messages,
861 };
862 if run.trace_truncated.is_none() {
863 let size = event.approximate_size();
864 let count = run.trace.as_ref().map_or(0, Vec::len);
865 if count >= self.limits.max_trace_events {
866 run.trace_truncated = Some(format!(
867 "the trace keeps its first {} events",
868 self.limits.max_trace_events
869 ));
870 } else if run.trace_bytes + size > self.limits.max_trace_bytes {
871 run.trace_truncated = Some(format!(
872 "the trace keeps its first {count} events, about {} bytes",
873 run.trace_bytes
874 ));
875 } else if let Some(events) = &mut run.trace {
876 run.trace_bytes += size;
877 events.push(event);
878 }
879 }
880 if phase == Phase::Enter {
881 run.trace_depth += 1;
882 }
883 }
884
885 async fn default_copy(
888 &self,
889 run: &mut Run,
890 group: &GroupRef,
891 rule: &Rule,
892 source: &str,
893 target: &str,
894 vars: &Vars,
895 ) -> Result<()> {
896 let source = vars
897 .get(Mode::Input, source)
898 .ok_or_else(|| Error::in_rule(rule, format!("no source variable `{source}`")))?;
899 let target = vars
900 .get(Mode::Output, target)
901 .ok_or_else(|| Error::in_rule(rule, format!("no target variable `{target}`")))?;
902 let source_type = run.tree.fhir_type(source);
903 let target_type = run.tree.fhir_type(target);
904 if let Some(default) =
905 self.group_by_types(&group.map, source_type.as_deref(), target_type.as_deref())
906 {
907 let inputs = &default.group().input;
908 let mut call = Vars::default();
909 call.add(Mode::Input, &inputs[0].name, source);
910 call.add(Mode::Output, &inputs[1].name, target);
911 return self.execute_group(run, default, call, false).await;
912 }
913 if source_type == target_type || target_type.is_none() {
914 run.tree.assign(target, source);
915 return Ok(());
916 }
917 Err(Error::in_rule(
918 rule,
919 format!(
920 "no default group maps {} to {}",
921 source_type.as_deref().unwrap_or("?"),
922 target_type.as_deref().unwrap_or("?")
923 ),
924 ))
925 }
926
927 async fn execute_dependency(
928 &self,
929 run: &mut Run,
930 group: &GroupRef,
931 rule: &Rule,
932 dependent: &Dependent,
933 vars: &Vars,
934 ) -> Result<()> {
935 let callee = self.group_by_name(&group.map, &dependent.name)?;
936 let inputs = &callee.group().input;
937 if inputs.len() != dependent.parameter.len() {
938 return Err(Error::in_rule(
939 rule,
940 format!(
941 "group `{}` takes {} arguments, the call passes {}",
942 dependent.name,
943 inputs.len(),
944 dependent.parameter.len()
945 ),
946 ));
947 }
948 let mut call = Vars::default();
949 for (input, parameter) in inputs.iter().zip(&dependent.parameter) {
950 let name = parameter_name(parameter);
951 let (mode, node) = if input.mode == "source" {
952 (Mode::Input, vars.value(&name))
953 } else {
954 (Mode::Output, vars.get(Mode::Output, &name))
955 };
956 let node = node.ok_or_else(|| {
957 Error::in_rule(
958 rule,
959 format!(
960 "`{}` passes `{name}` as {} `{}`, but it has no value",
961 dependent.name, input.mode, input.name
962 ),
963 )
964 })?;
965 call.add(mode, &input.name, node);
966 }
967 self.execute_group(run, callee, call, false).await
968 }
969
970 async fn process_source(
973 &self,
974 run: &mut Run,
975 group: &GroupRef,
976 rule: &Rule,
977 source: &Source,
978 vars: &Vars,
979 ) -> Result<Vec<Vars>> {
980 let context = vars.get(Mode::Input, &source.context).ok_or_else(|| {
981 Error::in_rule(
982 rule,
983 format!("unknown source variable `{}`", source.context),
984 )
985 })?;
986 let mut items = vec![context];
987 for element in element_path(
988 source.element.as_deref(),
989 &source.extension,
990 SOURCE_ELEMENT_EXTENSION,
991 ) {
992 items = items
993 .iter()
994 .flat_map(|&item| run.tree.children(item, &element))
995 .collect();
996 }
997 check_cardinality(rule, source, items.len())?;
998 if let Some(type_name) = &source.type_name {
1000 let wanted = self.stated_type_name(&group.map, type_name);
1001 items.retain(|&item| run.tree.fhir_type(item).as_deref() == Some(wanted.as_str()));
1002 }
1003 if items.is_empty()
1004 && let Some(default) = &source.default_value
1005 {
1006 items = self.evaluate(run, group, default, None, vars).await?;
1007 }
1008 let with_item = |item: NodeId| {
1009 let mut bound = vars.clone();
1010 if let Some(variable) = &source.variable {
1011 bound.add(Mode::Input, variable, item);
1012 }
1013 bound
1014 };
1015 if let Some(condition) = &source.condition {
1016 let mut kept = Vec::with_capacity(items.len());
1017 for item in items {
1018 if self
1019 .evaluate_boolean(run, group, condition, Some(item), &with_item(item))
1020 .await?
1021 {
1022 kept.push(item);
1023 }
1024 }
1025 items = kept;
1026 }
1027 if let Some(check) = &source.check {
1028 for &item in &items {
1029 if !self
1030 .evaluate_boolean(run, group, check, Some(item), &with_item(item))
1031 .await?
1032 {
1033 return Err(Error::in_rule(rule, format!("check `{check}` failed")));
1034 }
1035 }
1036 }
1037 if let Some(log) = &source.log_message {
1038 let mut messages = Vec::new();
1039 for &item in &items {
1040 let values = self
1041 .evaluate(run, group, log, Some(item), &with_item(item))
1042 .await?;
1043 messages.extend(values.into_iter().filter_map(|v| run.tree.text(v)));
1044 }
1045 if !messages.is_empty() {
1046 run.log.push(messages.join(","));
1047 }
1048 }
1049 match source.list_mode.as_deref() {
1050 _ if items.is_empty() => {}
1051 Some("first") => items.truncate(1),
1052 Some("not_first") => {
1053 items.remove(0);
1054 }
1055 Some("last") => items = vec![*items.last().unwrap()],
1056 Some("not_last") => {
1057 items.pop();
1058 }
1059 Some("only_one") if items.len() > 1 => {
1060 return Err(Error::in_rule(
1061 rule,
1062 format!("`{}` has more than one item", source.context),
1063 ));
1064 }
1065 _ => {}
1066 }
1067 Ok(items.into_iter().map(with_item).collect())
1068 }
1069
1070 #[allow(clippy::too_many_arguments)]
1073 async fn process_target(
1074 &self,
1075 run: &mut Run,
1076 group: &GroupRef,
1077 rule: &Rule,
1078 target: &Target,
1079 vars: &mut Vars,
1080 shared: &mut Vars,
1081 source_variable: Option<&str>,
1082 at_root: bool,
1083 ) -> Result<()> {
1084 let types = self.types();
1085 let elements = element_path(
1086 target.element.as_deref(),
1087 &target.extension,
1088 TARGET_ELEMENT_EXTENSION,
1089 );
1090 let element = elements.last().cloned();
1091 let mut destination = match &target.context {
1092 Some(context) => Some(vars.get(Mode::Output, context).ok_or_else(|| {
1093 Error::in_rule(rule, format!("unknown target variable `{context}`"))
1094 })?),
1095 None => None,
1096 };
1097 let sharing = target.list_mode.iter().any(|m| m == "share");
1098 let mut value = match (&target.transform, sharing, &target.list_rule_id) {
1099 (None, true, Some(id)) => shared.get(Mode::Shared, id),
1100 _ => None,
1101 };
1102 if let Some(dest) = destination
1103 && value.is_none()
1104 {
1105 let mut dest = dest;
1106 for intermediate in elements.iter().take(elements.len().saturating_sub(1)) {
1107 dest = run
1108 .tree
1109 .make_property(dest, intermediate, &types)
1110 .map_err(|e| Error::in_rule(rule, e))?;
1111 }
1112 destination = Some(dest);
1113 }
1114 if target.transform.is_some() {
1115 let produced = if target.transform.as_deref() == Some("evaluate") {
1116 let values = self
1117 .evaluate_transform(run, group, rule, target, vars)
1118 .await?;
1119 if values.len() > 1 {
1120 self.check_several(
1121 run,
1122 rule,
1123 target,
1124 destination,
1125 element.as_deref(),
1126 values.len(),
1127 )?;
1128 }
1129 values
1130 } else {
1131 self.run_transform(
1132 run,
1133 group,
1134 rule,
1135 target,
1136 vars,
1137 destination,
1138 element.as_deref(),
1139 source_variable,
1140 at_root,
1141 )
1142 .await?
1143 .into_iter()
1144 .collect()
1145 };
1146 if let Some(dest) = destination {
1147 for &item in &produced {
1148 match &element {
1149 Some(element) => {
1150 run.tree
1151 .set_property(dest, element, item, &types)
1152 .map_err(|e| Error::in_rule(rule, e))?;
1153 order_target(run, rule, target, dest, element, item)?;
1154 }
1155 None => run.tree.assign(dest, item),
1156 }
1157 }
1158 }
1159 value = produced.last().copied();
1160 } else if let (Some(dest), None) = (destination, value) {
1161 value = Some(match &element {
1162 Some(element) => {
1163 let created = run
1164 .tree
1165 .make_property(dest, element, &types)
1166 .map_err(|e| Error::in_rule(rule, e))?;
1167 if let (true, Some(id)) = (sharing, &target.list_rule_id) {
1168 shared.add(Mode::Shared, id, created);
1170 vars.add(Mode::Shared, id, created);
1171 }
1172 order_target(run, rule, target, dest, element, created)?;
1173 created
1174 }
1175 None => dest,
1176 });
1177 }
1178 if let (Some(variable), Some(value)) = (&target.variable, value) {
1179 vars.add(Mode::Output, variable, value);
1180 }
1181 Ok(())
1182 }
1183
1184 async fn evaluate_transform(
1186 &self,
1187 run: &mut Run,
1188 group: &GroupRef,
1189 rule: &Rule,
1190 target: &Target,
1191 vars: &Vars,
1192 ) -> Result<Vec<NodeId>> {
1193 let parameters = &target.parameter;
1194 let expression = match parameters.last().map(|p| &p.value) {
1195 Some(ParameterValue::String(expression)) => expression,
1196 _ => return Err(Error::in_rule(rule, "evaluate needs an expression")),
1197 };
1198 let focus = match parameters.as_slice() {
1199 [context, _] => Some(self.parameter_node(run, group, context, vars).await?),
1200 _ => None,
1201 };
1202 self.evaluate(run, group, expression, focus, vars).await
1203 }
1204
1205 fn check_several(
1208 &self,
1209 run: &Run,
1210 rule: &Rule,
1211 target: &Target,
1212 destination: Option<NodeId>,
1213 element: Option<&str>,
1214 count: usize,
1215 ) -> Result<()> {
1216 let fail = |message: String| Err(Error::in_rule(rule, message));
1217 let (Some(dest), Some(element)) = (destination, element) else {
1218 return fail(format!(
1219 "evaluate gave {count} values where one was expected"
1220 ));
1221 };
1222 let owner = run.tree.ty(dest).display();
1223 match self.types().lookup(run.tree.ty(dest), element) {
1224 Lookup::Found(found) if found.element.array => {}
1225 Lookup::Found(_) => {
1226 return fail(format!(
1227 "evaluate gave {count} values, but `{owner}.{element}` does not repeat"
1228 ));
1229 }
1230 _ => {
1231 return fail(format!(
1232 "evaluate gave {count} values, and whether `{owner}.{element}` repeats is not known"
1233 ));
1234 }
1235 }
1236 if let Some(variable) = &target.variable {
1237 return fail(format!(
1238 "evaluate gave {count} values; variable `{variable}` can only name one"
1239 ));
1240 }
1241 Ok(())
1242 }
1243
1244 #[allow(clippy::too_many_arguments)]
1245 async fn run_transform(
1246 &self,
1247 run: &mut Run,
1248 group: &GroupRef,
1249 rule: &Rule,
1250 target: &Target,
1251 vars: &Vars,
1252 destination: Option<NodeId>,
1253 element: Option<&str>,
1254 source_variable: Option<&str>,
1255 _at_root: bool,
1256 ) -> Result<Option<NodeId>> {
1257 let transform = target.transform.as_deref().unwrap_or("copy");
1258 let parameters = &target.parameter;
1259 let fail = |message: String| Error::in_rule(rule, message);
1260 let types = self.types();
1261 match transform {
1262 "create" => {
1263 let ty = match parameters.first() {
1264 Some(parameter) => {
1265 let name = self.parameter_text(run, group, parameter, vars).await?;
1266 let context = destination
1267 .and_then(|d| run.tree.ty(d).structure().map(|s| s.url.clone()))
1268 .unwrap_or_else(|| CORE.to_owned());
1269 let ty = types.structure(&self.type_name_url(&group.map, &name, &context));
1270 (ty, Some(name))
1271 }
1272 None => self
1273 .implied_type(run, group, destination, element, source_variable, vars)
1274 .map_err(fail)?,
1275 };
1276 let created = run.tree.create(ty.0, ty.1);
1277 if destination.is_none() && run.tree.ty(created).is_resource() {
1279 run.produced.push(created);
1280 }
1281 Ok(Some(created))
1282 }
1283 "copy" => {
1284 let parameter = parameters
1285 .first()
1286 .ok_or_else(|| fail("copy needs a value".into()))?;
1287 let node = self.parameter_node(run, group, parameter, vars).await?;
1288 Ok(Some(run.tree.deep_copy(node)))
1289 }
1290 "truncate" => {
1291 let text = self.argument_text(run, group, parameters, 0, vars).await?;
1292 let length = self.argument_text(run, group, parameters, 1, vars).await?;
1293 let length: usize = length
1294 .trim()
1295 .parse()
1296 .map_err(|_| fail(format!("truncate needs a length, not `{length}`")))?;
1297 let truncated = text.chars().take(length).collect();
1298 Ok(Some(self.string(run, truncated, "string")))
1299 }
1300 "cast" => {
1301 let source = self
1302 .parameter_node(
1303 run,
1304 group,
1305 parameters
1306 .first()
1307 .ok_or_else(|| fail("cast needs a value".into()))?,
1308 vars,
1309 )
1310 .await?;
1311 let type_name = if parameters.len() > 1 {
1312 transforms::cast_type(
1313 &self.argument_text(run, group, parameters, 1, vars).await?,
1314 )
1315 } else {
1316 self.implied_type(run, group, destination, element, None, vars)
1318 .ok()
1319 .and_then(|(_, name)| name)
1320 .ok_or_else(|| fail("cast needs a type: cast(value, 'type')".into()))?
1321 };
1322 if !run.tree.is_primitive(source) {
1323 return match run.tree.fhir_type(source) {
1325 Some(own) if own == type_name => Ok(Some(run.tree.deep_copy(source))),
1326 own => Err(fail(format!(
1327 "cannot cast a {} to {type_name}",
1328 own.as_deref().unwrap_or("complex value")
1329 ))),
1330 };
1331 }
1332 let text = run.tree.text(source).unwrap_or_default();
1333 let value = transforms::cast(&text, &type_name).map_err(fail)?;
1334 let ty = types.structure(&type_url(&type_name, CORE));
1335 Ok(Some(run.tree.primitive(value, ty, Some(type_name))))
1336 }
1337 "append" => {
1338 let mut text = String::new();
1339 for index in 0..parameters.len() {
1340 text.push_str(
1341 &self
1342 .argument_text(run, group, parameters, index, vars)
1343 .await?,
1344 );
1345 }
1346 Ok(Some(self.string(run, text, "string")))
1347 }
1348 "translate" => self.translate(run, group, rule, parameters, vars).await,
1349 "reference" | "pointer" => {
1350 let parameter = parameters
1351 .first()
1352 .ok_or_else(|| fail(format!("{transform} needs a resource")))?;
1353 let resource = self.parameter_node(run, group, parameter, vars).await?;
1354 let resource_type = run
1355 .tree
1356 .fhir_type(resource)
1357 .filter(|_| {
1358 run.tree.ty(resource).is_resource() || !run.tree.is_primitive(resource)
1359 })
1360 .ok_or_else(|| fail(format!("{transform} needs a resource")))?;
1361 let id = match run
1362 .tree
1363 .children(resource, "id")
1364 .first()
1365 .and_then(|&id| run.tree.text(id))
1366 {
1367 Some(id) => id,
1368 None => {
1369 let id = self.ids.uuid();
1370 run.tree
1371 .set_text(resource, "id", &id, &types)
1372 .map_err(fail)?;
1373 id
1374 }
1375 };
1376 Ok(Some(if transform == "reference" {
1377 self.string(run, format!("{resource_type}/{id}"), "string")
1378 } else {
1379 self.string(run, format!("urn:uuid:{id}"), "uri")
1380 }))
1381 }
1382 "uuid" => Ok(Some(self.string(run, self.ids.uuid(), "id"))),
1383 "toDateTime" | "toDate" | "toTime" => {
1384 let text = self.argument_text(run, group, parameters, 0, vars).await?;
1385 let format = match parameters.get(1) {
1386 Some(_) => Some(self.argument_text(run, group, parameters, 1, vars).await?),
1387 None => None,
1388 };
1389 let (value, type_name) = match transform {
1390 "toDateTime" => (datetime::to_date_time(&text, format.as_deref()), "dateTime"),
1391 "toDate" => (datetime::to_date(&text, format.as_deref()), "date"),
1392 _ => (datetime::to_time(&text, format.as_deref()), "time"),
1393 };
1394 Ok(Some(self.string(run, value.map_err(fail)?, type_name)))
1395 }
1396 "unixToDateTime" | "unixToDate" | "unixToTime" => {
1397 let text = self.argument_text(run, group, parameters, 0, vars).await?;
1398 let millis: i64 = text.trim().parse().map_err(|_| {
1399 fail(format!("`{text}` is not a Unix timestamp in milliseconds"))
1400 })?;
1401 let timezone = match parameters.get(1) {
1402 Some(_) => Some(self.argument_text(run, group, parameters, 1, vars).await?),
1403 None => None,
1404 };
1405 let (value, type_name) = match transform {
1406 "unixToDateTime" => (
1407 datetime::unix_to_date_time(millis, timezone.as_deref()),
1408 "dateTime",
1409 ),
1410 "unixToDate" => (datetime::unix_to_date(millis, timezone.as_deref()), "date"),
1411 _ => (datetime::unix_to_time(millis, timezone.as_deref()), "time"),
1412 };
1413 Ok(Some(self.string(run, value.map_err(fail)?, type_name)))
1414 }
1415 "escape" => {
1416 let text = self.argument_text(run, group, parameters, 0, vars).await?;
1417 let (from, to) = match parameters.len() {
1418 3 => (
1419 self.argument_text(run, group, parameters, 1, vars).await?,
1420 self.argument_text(run, group, parameters, 2, vars).await?,
1421 ),
1422 _ => (
1423 "none".to_owned(),
1424 self.argument_text(run, group, parameters, 1, vars).await?,
1425 ),
1426 };
1427 let escaped = datetime::escape(&text, &from, &to).map_err(fail)?;
1428 Ok(Some(self.string(run, escaped, "string")))
1429 }
1430 "cc" | "c" | "id" | "cp" | "qty" => {
1431 let mut arguments = Vec::with_capacity(parameters.len());
1432 for index in 0..parameters.len() {
1433 arguments.push(
1434 self.argument_text(run, group, parameters, index, vars)
1435 .await?,
1436 );
1437 }
1438 let (json, type_name) = match transform {
1439 "cc" => (transforms::codeable_concept(&arguments), "CodeableConcept"),
1440 "c" => match arguments.as_slice() {
1441 [system, code, rest @ ..] => {
1442 (transforms::coding(system, code, rest.first()), "Coding")
1443 }
1444 _ => return Err(fail("c needs a system and a code".into())),
1445 },
1446 "id" => (transforms::identifier(&arguments), "Identifier"),
1447 "cp" => (transforms::contact_point(&arguments), "ContactPoint"),
1448 _ => (transforms::quantity(&arguments).map_err(fail)?, "Quantity"),
1449 };
1450 let context = destination
1451 .and_then(|d| run.tree.ty(d).structure().map(|s| s.url.clone()))
1452 .unwrap_or_else(|| CORE.to_owned());
1453 let ty = types.structure(&type_url(type_name, &context));
1454 let node = run.tree.load(&json, ty, &types);
1455 Ok(Some(node))
1456 }
1457 other => Err(fail(format!("the {other} transform is not supported"))),
1458 }
1459 }
1460
1461 fn implied_type(
1464 &self,
1465 run: &Run,
1466 group: &GroupRef,
1467 destination: Option<NodeId>,
1468 element: Option<&str>,
1469 source_variable: Option<&str>,
1470 vars: &Vars,
1471 ) -> std::result::Result<(Type, Option<String>), String> {
1472 let types = self.types();
1473 if let (Some(dest), Some(element)) = (destination, element)
1474 && let Lookup::Found(found) = types.lookup(run.tree.ty(dest), element)
1475 && let [single] = found.element.types.as_slice()
1476 && single != "Resource"
1477 && single != "*"
1478 {
1479 return Ok((types.element_type(&found, None), Some(single.clone())));
1480 }
1481 if let Some(source) = source_variable.and_then(|s| vars.get(Mode::Input, s)) {
1482 if let Some(source_type) = run.tree.fhir_type(source)
1485 && let Some(produced) = self.default_target_type(group, &source_type)
1486 {
1487 return Ok(produced);
1488 }
1489 return Ok((run.tree.ty(source).clone(), run.tree.fhir_type(source)));
1490 }
1491 Err("cannot tell what type to create: name it, as in create('Type')".into())
1492 }
1493
1494 fn default_target_type(&self, group: &GroupRef, source_type: &str) -> Option<TypedTarget> {
1497 if let Some(found) = self.default_target_in(&group.map, source_type) {
1498 return Some(found);
1499 }
1500 let key = (imports_key(&group.map), source_type.to_owned());
1501 if let Some(found) = self.cache().default_target.get(&key) {
1502 return found.clone();
1503 }
1504 let found = self.find_default_target_type(group, source_type);
1505 self.cache().default_target.insert(key, found.clone());
1506 found
1507 }
1508
1509 fn default_target_in(&self, map: &StructureMap, source_type: &str) -> Option<TypedTarget> {
1511 map.group.iter().find_map(|candidate| {
1512 if candidate.type_mode.as_deref() != Some("type-and-types") {
1513 return None;
1514 }
1515 let [source, target] = candidate.input.as_slice() else {
1516 return None;
1517 };
1518 if source.mode != "source"
1519 || target.mode != "target"
1520 || !self.stated_type_is(map, source.type_name.as_deref(), source_type)
1521 {
1522 return None;
1523 }
1524 let stated = target.type_name.as_deref()?;
1525 let ty = self
1526 .types()
1527 .structure(&self.type_name_url(map, stated, CORE));
1528 let name = ty.fhir_type().unwrap_or_else(|| stated.to_owned());
1529 Some((ty, Some(name)))
1530 })
1531 }
1532
1533 fn find_default_target_type(&self, group: &GroupRef, source_type: &str) -> Option<TypedTarget> {
1534 group.map.import.iter().find_map(|import| {
1535 self.maps
1536 .resolve(import)
1537 .iter()
1538 .filter(|imported| imported.url != group.map.url)
1539 .find_map(|imported| self.default_target_in(imported, source_type))
1540 })
1541 }
1542
1543 async fn translate(
1546 &self,
1547 run: &mut Run,
1548 group: &GroupRef,
1549 rule: &Rule,
1550 parameters: &[Parameter],
1551 vars: &Vars,
1552 ) -> Result<Option<NodeId>> {
1553 let fail = |message: String| Error::in_rule(rule, message);
1554 let source = self
1555 .parameter_node(
1556 run,
1557 group,
1558 parameters
1559 .first()
1560 .ok_or_else(|| fail("translate needs a value".into()))?,
1561 vars,
1562 )
1563 .await?;
1564 let map_url = self.argument_text(run, group, parameters, 1, vars).await?;
1565 let output = self.argument_text(run, group, parameters, 2, vars).await?;
1566 let concept_map = match map_url.strip_prefix('#') {
1567 Some(id) => Some(
1568 group
1569 .map
1570 .contained
1571 .iter()
1572 .find(|r| r["resourceType"] == "ConceptMap" && r["id"] == id)
1573 .cloned()
1574 .map(Arc::new)
1575 .ok_or_else(|| fail(format!("no contained ConceptMap `{id}`")))?,
1576 ),
1577 None => self.concept_maps.resolve(&map_url),
1578 };
1579 if concept_map.is_none() && self.translator.is_none() {
1580 return Err(fail(format!("ConceptMap `{map_url}` not found")));
1581 }
1582 let codes = self.codes_of(run, source);
1583 let mut translation = None;
1584 for (system, code) in &codes {
1585 let found = match (&concept_map, self.translator) {
1586 (Some(concept_map), _) => translate(concept_map, system.as_deref(), code),
1587 (None, Some(translator)) => {
1588 translator
1589 .translate(&map_url, system.as_deref(), code)
1590 .await
1591 }
1592 (None, None) => unreachable!("checked above"),
1593 }
1594 .map_err(|e| fail(format!("{e} in `{map_url}`")))?;
1595 if let Some(found) = found {
1596 translation = Some(found);
1597 break;
1598 }
1599 }
1600 let Some(translation) = translation else {
1601 let shown: Vec<&str> = codes.iter().map(|(_, c)| c.as_str()).collect();
1602 let rule_name = rule.name.as_deref().unwrap_or("?");
1603 run.warnings.push(format!(
1604 "rule `{rule_name}`: `{}` has no translation in `{map_url}`; left out",
1605 shown.join(", ")
1606 ));
1607 return Ok(None);
1608 };
1609
1610 let types = self.types();
1611 let mut coding = serde_json::Map::new();
1612 if let Some(system) = &translation.system {
1613 coding.insert("system".into(), system.clone().into());
1614 }
1615 if let Some(code) = &translation.code {
1616 coding.insert("code".into(), code.clone().into());
1617 }
1618 if let Some(display) = &translation.display {
1619 coding.insert("display".into(), display.clone().into());
1620 }
1621 let text = |value: &Option<String>| value.clone().map_or(Value::Null, Value::String);
1622 let (json, type_name) = match output.as_str() {
1623 "code" => (text(&translation.code), "code"),
1624 "system" => (text(&translation.system), "uri"),
1625 "display" => (text(&translation.display), "string"),
1626 "Coding" => (Value::Object(coding), "Coding"),
1627 "CodeableConcept" => (
1628 json!({ "coding": [Value::Object(coding)] }),
1629 "CodeableConcept",
1630 ),
1631 other => return Err(fail(format!("unknown translate output `{other}`"))),
1632 };
1633 let ty = types.structure(&type_url(type_name, CORE));
1634 Ok(Some(if json.is_object() {
1635 run.tree.load(&json, ty, &types)
1636 } else {
1637 run.tree.primitive(json, ty, Some(type_name.to_owned()))
1638 }))
1639 }
1640
1641 fn codes_of(&self, run: &Run, node: NodeId) -> Vec<(Option<String>, String)> {
1643 let text = |id: NodeId, name: &str| {
1644 run.tree
1645 .children(id, name)
1646 .first()
1647 .and_then(|&child| run.tree.text(child))
1648 };
1649 if run.tree.is_primitive(node) {
1650 return run
1651 .tree
1652 .text(node)
1653 .map(|code| (None, code))
1654 .into_iter()
1655 .collect();
1656 }
1657 let codings = run.tree.children(node, "coding");
1658 let codings = if codings.is_empty() {
1659 vec![node]
1660 } else {
1661 codings
1662 };
1663 codings
1664 .into_iter()
1665 .filter_map(|coding| Some((text(coding, "system"), text(coding, "code")?)))
1666 .collect()
1667 }
1668
1669 async fn parameter_node(
1673 &self,
1674 run: &mut Run,
1675 group: &GroupRef,
1676 parameter: &Parameter,
1677 vars: &Vars,
1678 ) -> Result<NodeId> {
1679 let types = self.types();
1680 let (value, type_name) = match ¶meter.value {
1681 ParameterValue::Id(name) => return self.variable(run, group, name, vars).await,
1682 ParameterValue::String(v) => (Value::String(v.clone()), "string"),
1683 ParameterValue::Boolean(v) => (Value::Bool(*v), "boolean"),
1684 ParameterValue::Integer(v) => (Value::from(*v), "integer"),
1685 ParameterValue::Decimal(v) => (Value::Number(v.clone()), "decimal"),
1686 ParameterValue::Date(v) => (Value::String(v.clone()), "date"),
1687 ParameterValue::Time(v) => (Value::String(v.clone()), "time"),
1688 ParameterValue::DateTime(v) => (Value::String(v.clone()), "dateTime"),
1689 };
1690 let ty = types.structure(&type_url(type_name, CORE));
1691 Ok(run.tree.primitive(value, ty, Some(type_name.to_owned())))
1692 }
1693
1694 async fn variable(
1696 &self,
1697 run: &mut Run,
1698 group: &GroupRef,
1699 name: &str,
1700 vars: &Vars,
1701 ) -> Result<NodeId> {
1702 if let Some(node) = vars.value(name) {
1703 return Ok(node);
1704 }
1705 if let Some((variable, path)) = name.split_once('.')
1707 && let Some(mut node) = vars.value(variable)
1708 {
1709 for segment in path.split('.') {
1710 node = *run
1711 .tree
1712 .children(node, segment)
1713 .first()
1714 .ok_or_else(|| Error::new(format!("`{name}` has no value")))?;
1715 }
1716 return Ok(node);
1717 }
1718 let values = self.constant(run, group, name).await?;
1719 match values.as_slice() {
1720 [single] => Ok(*single),
1721 [] => Err(Error::new(format!("unknown variable `{name}`"))),
1722 _ => Err(Error::new(format!("constant `{name}` has several values"))),
1723 }
1724 }
1725
1726 async fn parameter_text(
1727 &self,
1728 run: &mut Run,
1729 group: &GroupRef,
1730 parameter: &Parameter,
1731 vars: &Vars,
1732 ) -> Result<String> {
1733 if let ParameterValue::String(text) = ¶meter.value {
1734 return Ok(text.clone());
1735 }
1736 let node = self.parameter_node(run, group, parameter, vars).await?;
1737 Ok(run.tree.text(node).unwrap_or_default())
1738 }
1739
1740 async fn argument_text(
1741 &self,
1742 run: &mut Run,
1743 group: &GroupRef,
1744 parameters: &[Parameter],
1745 index: usize,
1746 vars: &Vars,
1747 ) -> Result<String> {
1748 let parameter = parameters
1749 .get(index)
1750 .ok_or_else(|| Error::new(format!("missing argument {}", index + 1)))?;
1751 self.parameter_text(run, group, parameter, vars).await
1752 }
1753
1754 fn string(&self, run: &mut Run, text: String, type_name: &str) -> NodeId {
1755 let ty = self.types().structure(&type_url(type_name, CORE));
1756 run.tree
1757 .primitive(Value::String(text), ty, Some(type_name.to_owned()))
1758 }
1759
1760 fn constant<'r>(
1764 &'r self,
1765 run: &'r mut Run,
1766 group: &'r GroupRef,
1767 name: &'r str,
1768 ) -> BoxFuture<'r, Result<Vec<NodeId>>> {
1769 Box::pin(async move {
1770 let key = (group.map.url.clone().unwrap_or_default(), name.to_owned());
1771 if let Some(values) = run.constants.get(&key) {
1772 return Ok(values.clone());
1773 }
1774 let Some(constant) = group.map.constants.iter().find(|c| c.name == name) else {
1775 return Ok(Vec::new());
1776 };
1777 if !run.evaluating.insert(key.clone()) {
1778 return Err(Error::new(format!("constant `{name}` refers to itself")));
1779 }
1780 let values = self
1781 .evaluate(run, group, &constant.value, None, &Vars::default())
1782 .await;
1783 run.evaluating.remove(&key);
1784 let values = values?;
1785 run.constants.insert(key, values.clone());
1786 Ok(values)
1787 })
1788 }
1789
1790 fn evaluate<'r>(
1791 &'r self,
1792 run: &'r mut Run,
1793 group: &'r GroupRef,
1794 expression: &'r str,
1795 focus: Option<NodeId>,
1796 vars: &'r Vars,
1797 ) -> BoxFuture<'r, Result<Vec<NodeId>>> {
1798 Box::pin(async move {
1799 let referenced = path_start_names(expression);
1802 let mut names: HashSet<String> = vars
1803 .names()
1804 .filter(|name| referenced.contains(*name))
1805 .map(str::to_owned)
1806 .collect();
1807 let mut variables = Vec::new();
1808 for name in &names {
1809 if let Some(node) = vars.value(name) {
1810 variables.push((name.clone(), self.item(run, node)));
1811 }
1812 }
1813 for constant in &group.map.constants {
1814 if names.contains(&constant.name) || expression == constant.value {
1815 continue;
1816 }
1817 if referenced.contains(&constant.name) {
1818 let values = self.constant(run, group, &constant.name).await?;
1819 if let [value] = values.as_slice() {
1820 variables.push((constant.name.clone(), self.item(run, *value)));
1821 names.insert(constant.name.clone());
1822 }
1823 }
1824 }
1825 let bound = bind_variables(expression, &names);
1826 let focus = focus.map(|node| self.item(run, node));
1827 let results = self
1828 .expressions
1829 .evaluate(&bound, focus.as_ref(), &variables)
1830 .await
1831 .map_err(|e| Error::new(format!("`{expression}`: {e}")))?;
1832 let types = self.types();
1833 Ok(results
1834 .into_iter()
1835 .map(|item| {
1836 let ty = item
1837 .type_name
1838 .as_deref()
1839 .map(|t| types.structure(&type_url(t, CORE)))
1840 .unwrap_or(Type::Unknown);
1841 if item.json.is_object() {
1842 run.tree.load(&item.json, ty, &types)
1843 } else {
1844 run.tree.primitive(item.json, ty, item.type_name)
1845 }
1846 })
1847 .collect())
1848 })
1849 }
1850
1851 async fn evaluate_boolean(
1852 &self,
1853 run: &mut Run,
1854 group: &GroupRef,
1855 expression: &str,
1856 focus: Option<NodeId>,
1857 vars: &Vars,
1858 ) -> Result<bool> {
1859 let values = self.evaluate(run, group, expression, focus, vars).await?;
1860 Ok(match values.as_slice() {
1861 [] => false,
1862 [single] => run.tree.value(*single) != Some(&Value::Bool(false)),
1863 _ => true,
1864 })
1865 }
1866
1867 fn item(&self, run: &Run, node: NodeId) -> Item {
1870 let type_name = match run.tree.ty(node) {
1871 backbone @ Type::Node { path, .. } if !path.is_empty() => Some(backbone.display()),
1872 _ => run.tree.fhir_type(node),
1873 };
1874 Item {
1875 json: run.tree.to_json(node),
1876 type_name,
1877 }
1878 }
1879}
1880
1881fn element_path(
1884 element: Option<&str>,
1885 extensions: &[fml_model::model::Extension],
1886 url: &str,
1887) -> Vec<String> {
1888 element
1889 .map(str::to_owned)
1890 .into_iter()
1891 .chain(
1892 extensions
1893 .iter()
1894 .filter(|e| e.url == url)
1895 .filter_map(|e| e.value_string.clone()),
1896 )
1897 .collect()
1898}
1899
1900fn order_target(
1904 run: &mut Run,
1905 rule: &Rule,
1906 target: &Target,
1907 dest: NodeId,
1908 element: &str,
1909 value: NodeId,
1910) -> Result<()> {
1911 let identity = std::ptr::from_ref(target) as usize;
1912 let mode = target
1913 .list_mode
1914 .iter()
1915 .find(|mode| matches!(mode.as_str(), "first" | "last" | "single"))
1916 .map(String::as_str);
1917 if mode == Some("single") && !run.single.insert((dest, element.to_owned(), identity)) {
1918 return Err(Error::in_rule(
1919 rule,
1920 format!("target `{element}` is `single`, but the rule makes more than one"),
1921 ));
1922 }
1923 let key = (dest, element.to_owned());
1924 let order = match (mode, run.order.contains_key(&key)) {
1925 (Some("first" | "last"), _) | (_, true) => run.order.entry(key).or_default(),
1926 _ => return Ok(()),
1927 };
1928 match mode {
1929 Some("first") => {
1930 if order.first.is_some_and(|first| first != identity) {
1931 return Err(Error::in_rule(
1932 rule,
1933 format!("two rules put their values `first` in `{element}`"),
1934 ));
1935 }
1936 order.first = Some(identity);
1937 let at = order.first_count;
1938 order.first_count += 1;
1939 run.tree.move_value(dest, element, value, Some(at));
1940 }
1941 Some("last") => {
1942 if order.last.is_some_and(|last| last != identity) {
1943 return Err(Error::in_rule(
1944 rule,
1945 format!("two rules put their values `last` in `{element}`"),
1946 ));
1947 }
1948 order.last = Some(identity);
1949 order.last_values.push(value);
1950 }
1951 _ => {}
1952 }
1953 let last_values = order.last_values.clone();
1954 for last in last_values {
1955 run.tree.move_value(dest, element, last, None);
1956 }
1957 Ok(())
1958}
1959
1960fn check_cardinality(rule: &Rule, source: &Source, count: usize) -> Result<()> {
1962 let below = source
1963 .min
1964 .is_some_and(|min| i64::try_from(count).is_ok_and(|count| count < min));
1965 let above = source
1966 .max
1967 .as_deref()
1968 .and_then(|max| max.parse::<usize>().ok())
1969 .is_some_and(|max| count > max);
1970 if below || above {
1971 let path = std::iter::once(source.context.as_str())
1972 .chain(source.element.as_deref())
1973 .collect::<Vec<_>>()
1974 .join(".");
1975 return Err(Error::in_rule(
1976 rule,
1977 format!(
1978 "`{path}` has {count} values, outside {}..{}",
1979 source.min.unwrap_or(0),
1980 source.max.as_deref().unwrap_or("*")
1981 ),
1982 ));
1983 }
1984 Ok(())
1985}
1986
1987fn imports_key(map: &StructureMap) -> String {
1989 let mut key = map.url.clone().unwrap_or_default();
1990 for import in &map.import {
1991 key.push('\n');
1992 key.push_str(import);
1993 }
1994 key
1995}
1996
1997fn parameter_name(parameter: &Parameter) -> String {
1999 match ¶meter.value {
2000 ParameterValue::Id(name) | ParameterValue::String(name) => name.clone(),
2001 other => format!("{other:?}"),
2002 }
2003}
2004
2005fn simple_copy(rule: &Rule) -> Option<(&str, &str)> {
2007 let ([source], [target]) = (rule.source.as_slice(), rule.target.as_slice()) else {
2008 return None;
2009 };
2010 (target.transform.as_deref() == Some("create") && target.parameter.is_empty()).then_some(())?;
2011 Some((source.variable.as_deref()?, target.variable.as_deref()?))
2012}