Skip to main content

imago/
lib.rs

1// #![feature(async_drop)] -- enable with async-drop
2#![cfg_attr(all(doc, nightly), feature(doc_cfg))] // expect nightly for doc
3#![warn(missing_docs)]
4#![warn(clippy::missing_docs_in_private_items)]
5
6//! Provides access to VM image formats.
7//!
8//! Simple example (requires the `sync` feature):
9//! ```no_run
10//! # #[cfg(feature = "sync")]
11//! # let _ = || -> Result<(), std::io::Error> {
12//! use imago::file::File;
13//! use imago::qcow2::Qcow2;
14//! use imago::{FormatAccess, FormatDriverBuilder, PermissiveImplicitOpenGate};
15//!
16//! let qcow2 =
17//!     Qcow2::<File>::builder_path("image.qcow2").open(PermissiveImplicitOpenGate::default())?;
18//!
19//! let qcow2 = FormatAccess::new(qcow2);
20//!
21//! let mut buf = vec![0u8; 512];
22//! qcow2.read(&mut buf, 0)?;
23//! # Ok(())
24//! # };
25//! ```
26//!
27//! Another example, using the native async interface instead of sync wrapper functions, explicitly
28//! overriding the implicit references contained in qcow2 files, and showcasing using different
29//! types of storage (specifically normal files and null storage):
30//! ```no_run
31//! # #[cfg(feature = "async")]
32//! # let _ = async {
33//! use imago::file::File;
34//! use imago::null::Null;
35//! use imago::qcow2::Qcow2;
36//! use imago::raw::Raw;
37//! use imago::{
38//!     DenyImplicitOpenGate, DynStorage, FormatAccess, FormatDriverBuilder,
39//!     PermissiveImplicitOpenGate, Storage, StorageOpenOptions,
40//! };
41//! use std::sync::Arc;
42//!
43//! // Produce qcow2 instance with arbitrary (and potentially mixed) storage instances
44//! // (By using `Box<dyn DynStorage>` as the `Storage` type.)
45//!
46//! let backing_storage: Box<dyn DynStorage> = Box::new(Null::new(0));
47//! let backing = Raw::builder(backing_storage)
48//!     .open(DenyImplicitOpenGate::default())
49//!     .await?;
50//! let backing = Arc::new(FormatAccess::new(backing));
51//!
52//! // `Box<dyn DynStorage>::open()` defaults to using the `imago::file::File` driver, so we can
53//! // use paths with `Box<dyn DynStorage>`, too.
54//! // Despite explicitly setting a backing image, we still need `PermissiveImplicitOpenGate`
55//! // instead of `DenyImplicitOpenGate`, because `builder_path()` will need to implicitly open
56//! // that storage object.  Passing an explicitly opened storage object via `builder()` would
57//! // remedy that.
58//! let qcow2 = Qcow2::builder_path("image.qcow2")
59//!     .storage_open_options(StorageOpenOptions::new().direct(true))
60//!     .write(true)
61//!     .backing(Some(Arc::clone(&backing)))
62//!     .open(PermissiveImplicitOpenGate::default())
63//!     .await?;
64//!
65//! let qcow2 = FormatAccess::new(qcow2);
66//!
67//! let mut buf = vec![0u8; 512];
68//! qcow2.read(&mut buf, 0).await?;
69//!
70//! qcow2.flush().await?;
71//! # Ok::<(), std::io::Error>(())
72//! # };
73//! ```
74//!
75//! # Flushing
76//!
77//! In async mode, given that `AsyncDrop` is not stable yet (and probably will not be stable for a
78//! long time), callers must ensure that images are properly flushed before dropping them, i.e.
79//! call `.flush().await` on any image that is not read-only.
80//!
81//! (The synchronous wrapper `SyncFormatAccess` does perform a synchronous flush in its `Drop`
82//! implementation.)
83//!
84//! In sync mode, [`FormatAccess`] implements `Drop` and flushes automatically.
85//!
86//! # Features
87//!
88//! - `async` *(default)*: Build with `async` support, which requires `tokio` (for async locking),
89//!   `async-trait`, and `futures`.
90//!
91//! - `sync`: Build as a fully synchronous library, with no `async`, no `tokio` dependency.  All
92//!   I/O methods become plain `fn`.  Enable via
93//!   `imago = { default-features = false, features = ["sync"] }`.
94//!   Incompatible with `sync-wrappers`.
95//!
96//! - `sync-wrappers`: Provide synchronous wrappers for the native `async` interface.  Note that
97//!   these build a `tokio` runtime in which they run the `async` functions, so prefer using `sync`
98//!   instead, which provides native synchronous methods without the `tokio` overhead.
99//!   Incompatible with `sync`, and planned to be deprecated in the future.
100//!
101//! - `vm-memory`: Provide conversion functions
102//!   [`IoVector::from_volatile_slice`](io_buffers::IoVector::from_volatile_slice) and
103//!   [`IoVectorMut::from_volatile_slice`](io_buffers::IoVectorMut::from_volatile_slice) to convert
104//!   the vm-memory crate’s `[VolatileSlice]` arrays into imago’s native I/O vectors.
105
106#[cfg(not(any(feature = "async", feature = "sync")))]
107compile_error!("Either the `async` feature (included in defaults) or `sync` must be enabled!");
108
109#[cfg(all(feature = "sync-wrappers", feature = "sync"))]
110compile_error!("The `sync` feature conflicts with `sync-wrappers`. Consider using `sync` alone.");
111
112#[cfg(all(feature = "async", feature = "sync"))]
113compile_error!(
114    "The `async` and `sync` features are mutually exclusive. \
115    `async` is in defaults, so use `--no-default-features --features=sync` for sync mode."
116);
117
118pub mod annotated;
119mod async_lru_cache;
120pub mod file;
121pub mod format;
122pub mod io_buffers;
123mod macros;
124mod misc_helpers;
125pub mod null;
126pub mod qcow2;
127pub mod raw;
128pub mod storage;
129mod sync_primitives;
130pub mod vmdk;
131
132pub use format::access::{FormatAccess, Mapping};
133pub use format::builder::{FormatCreateBuilder, FormatDriverBuilder};
134pub use format::drivers::ShallowMapping;
135pub use format::gate::{DenyImplicitOpenGate, PermissiveImplicitOpenGate};
136#[cfg(feature = "sync-wrappers")]
137pub use format::sync_wrappers::SyncFormatAccess;
138pub use storage::ext::StorageExt;
139pub use storage::{DynStorage, Storage, StorageCreateOptions, StorageOpenOptions};