Skip to main content

energyml_storage/
lib.rs

1//! Reading EnergyML data stores behind one abstraction: an EPC file today, an
2//! ETP v1.2 dataspace later.
3//!
4//! # The shape, in one paragraph
5//!
6//! [`EnergymlStorage`] is the mother trait, and it is drawn after the **ETP
7//! protocol**, not after a zip file - addressing by URI, plural operations,
8//! partial responses. An EPC fits inside that shape (a file *is* a dataspace);
9//! the reverse would not have been true. [`EpcStore`] implements it, and also
10//! carries a complete **synchronous** API so that an application which only
11//! reads local files never has to write `async`. The reasoning is in
12//! ADR-0002.
13//!
14//! ```no_run
15//! use std::sync::Arc;
16//! use energyml_core::registry::Registry;
17//! use energyml_storage::EpcStore;
18//!
19//! let mut registry = Registry::new();
20//! // energyml_resqml_2_0_1::register(&mut registry); - the application chooses
21//! // which versions it knows: nothing is hard-wired here.
22//!
23//! let store = EpcStore::open("model.epc", Arc::new(registry))?;
24//! for summary in store.resources() {
25//!     let header = store.header(&summary.uri)?;
26//!     println!("{} - {}", header.summary.qualified_type, header.display_name());
27//! }
28//! # Ok::<(), energyml_storage::Error>(())
29//! ```
30//!
31//! # Three levels, and a listing needs all three
32//!
33//! | Level | Call | What it opens |
34//! |---|---|---|
35//! | identity | [`EpcStore::resources`] | the package index only |
36//! | citation | [`EpcStore::header`] | the first bytes of the part |
37//! | object | [`EpcStore::get_object`] | the whole part |
38//!
39//! An interface listing a two-gigabyte EPC lives at level 2, and getting there
40//! cheaply is the point of the split.
41//!
42//! # Tolerant, and never silent
43//!
44//! Real packages break the specification. This reader accepts what it can and
45//! records every departure as a [`Diagnostic`] - the same rule the code
46//! generator follows for the schema constructs it cannot map: *nothing is lost
47//! in silence*.
48//!
49//! # Writing
50//!
51//! An open package is **modifiable**: [`EpcStore::edit`] hands out a borrow and
52//! marks the object, [`EpcStore::put`] and [`EpcStore::remove`] add and delete,
53//! and nothing touches the archive until [`EpcStore::save`]. Saving does not
54//! patch the old package, it **rebuilds** one - `[Content_Types].xml`, every
55//! `.rels` in both directions, `docProps/core.xml` - because a description that
56//! no longer matches is worse than none. Transactions are one more layer of the
57//! same in-memory stack, so a rollback really undoes.
58//!
59//! # External arrays
60//!
61//! An object points at its numbers; it does not hold them. [`EpcStore`] finds
62//! every pointer, in both the spellings EnergyML uses, and reads them through
63//! an [`ArrayBackend`]. HDF5 is one, behind the **optional `hdf5` feature** -
64//! without it an EPC is still read, edited and written, and only reading an
65//! array fails, saying which capability is missing rather than pretending the
66//! data is absent. A WebAssembly application supplies its own backend over
67//! h5wasm and nothing here changes.
68
69#![forbid(unsafe_code)]
70#![warn(missing_docs)]
71
72pub mod array;
73pub mod backend;
74pub mod capabilities;
75pub mod changes;
76pub mod context;
77/// The rules every implementation of the storage traits is held to, played by
78/// each implementation's tests (design note `deux-sources-un-contrat.md` ยง4).
79#[cfg(feature = "contract")]
80pub mod contract;
81/// The rules of objects contained by value (WITSML containers), played on a
82/// WITSML model written from the ETP 1.2 specification and the XSD.
83#[cfg(feature = "contract")]
84pub mod contract_witsml;
85pub mod dataspaces;
86pub mod epc;
87pub mod error;
88pub mod extract;
89pub mod graph;
90#[cfg(feature = "hdf5")]
91pub mod hdf5;
92/// Bringing part of another package into the open one: a quote, then the writing.
93pub mod import;
94/// The kind of an edge, primary or secondary, and what each answer rests on.
95pub mod kinds;
96pub mod raw;
97/// Changing what a part declares itself to be, without parsing what it holds.
98pub mod relabel;
99pub mod rename;
100pub mod resource;
101pub mod search;
102pub mod storage;
103pub mod window;
104pub mod write;
105
106pub use array::{
107    ArrayBuffer, ArrayData, ArrayLocation, ArrayMetadata, ArrayValues, NoProxies, ProxyResolver, ProxyTarget,
108    Resolution,
109};
110pub use backend::{ArrayBackend, Backends, Candidate, ExternalFiles, Origin};
111pub use capabilities::{Capabilities, EdgeKindCoverage, StoreTimes};
112pub use changes::EnergymlChanges;
113pub use context::{Context, DeletedFilter, DeletedResource, Found, Navigable, Scope};
114pub use dataspaces::EnergymlDataspaces;
115pub use epc::overlay::SavePolicy;
116pub use epc::{EpcStore, SaveOptions, Unreadable};
117pub use error::{Diagnostic, Error, ExternalDataReason, Result, Severity};
118pub use graph::{Edge, EdgeKind, RefIssue, RefIssueKind};
119pub use kinds::{Judged, KindBasis, KindRules, StandardRules};
120pub use raw::{RawFormat, RawObject};
121pub use rename::{Applied as Renamed, FileMove, Rename};
122pub use resource::{ActiveStatus, CustomValue, Dataspace, ObjectHeader, ObjectSummary, Relationship};
123pub use storage::{Contents, EnergymlStorage, LocalPackage};
124pub use write::{EnergymlWriter, Put, Transaction, TransactionRequest};