edifact_mapper/data_dir.rs
1//! Data directory configuration for locating DataBundle files on disk.
2
3use std::path::{Path, PathBuf};
4
5/// Configures where the [`Mapper`](crate::Mapper) looks for `DataBundle` files.
6///
7/// Bundle files follow the naming convention `edifact-data-{FV}.bin`
8/// (e.g., `edifact-data-FV2504.bin`).
9///
10/// # Resolution order for [`DataDir::auto`]
11///
12/// 1. `$EDIFACT_DATA_DIR` environment variable (if set)
13/// 2. `$HOME/.edifact/data` (Unix) or `%USERPROFILE%\.edifact\data` (Windows)
14/// 3. `./data` (current working directory fallback)
15#[derive(Debug, Clone)]
16pub struct DataDir {
17 path: PathBuf,
18 eager_fvs: Vec<String>,
19 allow_other_release: bool,
20}
21
22impl DataDir {
23 /// Auto-detect the data directory from the environment.
24 ///
25 /// See [struct-level docs](DataDir) for resolution order.
26 pub fn auto() -> Self {
27 let path = if let Ok(env_dir) = std::env::var("EDIFACT_DATA_DIR") {
28 PathBuf::from(env_dir)
29 } else if let Some(home) = home_dir() {
30 home.join(".edifact").join("data")
31 } else {
32 PathBuf::from("data")
33 };
34 Self {
35 path,
36 eager_fvs: vec![],
37 allow_other_release: false,
38 }
39 }
40
41 /// Use an explicit path for the data directory.
42 pub fn path<P: AsRef<Path>>(path: P) -> Self {
43 Self {
44 path: path.as_ref().to_path_buf(),
45 eager_fvs: vec![],
46 allow_other_release: false,
47 }
48 }
49
50 /// Mark format versions to be eagerly loaded when the [`Mapper`](crate::Mapper)
51 /// is created (rather than lazy-loaded on first access).
52 pub fn eager(mut self, fvs: &[&str]) -> Self {
53 self.eager_fvs = fvs.iter().map(|s| s.to_string()).collect();
54 self
55 }
56
57 /// Load a bundle even when it was produced by a different release.
58 ///
59 /// Off by default. A crate and a bundle from different releases is the
60 /// pairing that goes wrong: the format check passes, the bundle loads, and
61 /// the mappings inside are from another era — which shows up as a smaller
62 /// message rather than an error (issue #158).
63 ///
64 /// Turn it on only when the mismatch is deliberate and you have some other
65 /// way of knowing the two belong together.
66 pub fn allow_bundle_from_other_release(mut self, allow: bool) -> Self {
67 self.allow_other_release = allow;
68 self
69 }
70
71 /// Whether a bundle from another release may be loaded.
72 pub fn allows_bundle_from_other_release(&self) -> bool {
73 self.allow_other_release
74 }
75
76 /// The resolved data directory path.
77 pub fn data_path(&self) -> &Path {
78 &self.path
79 }
80
81 /// Format versions that should be eagerly loaded.
82 pub fn eager_fvs(&self) -> &[String] {
83 &self.eager_fvs
84 }
85
86 /// Path to the bundle file for a specific format version.
87 pub fn bundle_path(&self, fv: &str) -> PathBuf {
88 self.path.join(format!("edifact-data-{fv}.bin"))
89 }
90}
91
92fn home_dir() -> Option<PathBuf> {
93 std::env::var("HOME")
94 .or_else(|_| std::env::var("USERPROFILE"))
95 .ok()
96 .map(PathBuf::from)
97}