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