use super::drivers::FormatDriverInstance;
use super::gate::ImplicitOpenGate;
use super::wrapped::WrappedFormat;
use super::{Format, PreallocateMode};
use crate::misc_helpers::ResultErrorContext;
use crate::qcow2::Qcow2OpenBuilder;
use crate::raw::RawOpenBuilder;
use crate::vmdk::VmdkOpenBuilder;
use crate::{Storage, StorageOpenOptions};
use std::io;
use std::path::{Path, PathBuf};
pub trait FormatDriverBuilder<S: Storage + 'static>: Sized {
type Format: FormatDriverInstance<Storage = S>;
const FORMAT: Format;
fn new(image: S) -> Self;
fn new_path<P: AsRef<Path>>(path: P) -> Self;
fn write(self, writable: bool) -> Self;
fn storage_open_options(self, options: StorageOpenOptions) -> Self;
#[allow(async_fn_in_trait)] async fn open<G: ImplicitOpenGate<S>>(self, gate: G) -> io::Result<Self::Format>;
#[cfg(feature = "sync-wrappers")]
fn open_sync<G: ImplicitOpenGate<S>>(self, gate: G) -> io::Result<Self::Format> {
tokio::runtime::Builder::new_current_thread()
.build()?
.block_on(self.open(gate))
}
fn get_image_path(&self) -> Option<PathBuf>;
fn get_writable(&self) -> bool;
fn get_storage_open_options(&self) -> Option<&StorageOpenOptions>;
}
pub trait FormatCreateBuilder<S: Storage + 'static>: Sized {
const FORMAT: Format;
type DriverBuilder: FormatDriverBuilder<S>;
fn new(image: S) -> Self;
fn size(self, size: u64) -> Self;
fn preallocate(self, prealloc_mode: PreallocateMode) -> Self;
#[allow(async_fn_in_trait)] async fn create(self) -> io::Result<()>;
#[allow(async_fn_in_trait)] async fn create_open<G: ImplicitOpenGate<S>, F: FnOnce(S) -> io::Result<Self::DriverBuilder>>(
self,
open_gate: G,
open_builder_fn: F,
) -> io::Result<<Self::DriverBuilder as FormatDriverBuilder<S>>::Format>;
fn get_size(&self) -> u64;
fn get_preallocate(&self) -> PreallocateMode;
}
pub struct FormatDriverBuilderBase<S: Storage> {
image: StorageOrPath<S>,
writable: bool,
storage_opts: Option<StorageOpenOptions>,
}
pub struct FormatCreateBuilderBase<S: Storage> {
image: S,
size: u64,
prealloc_mode: PreallocateMode,
}
impl<S: Storage + 'static> FormatDriverBuilderBase<S> {
fn do_new(image: StorageOrPath<S>) -> Self {
FormatDriverBuilderBase {
image,
writable: false,
storage_opts: None,
}
}
pub fn new(image: S) -> Self {
Self::do_new(StorageOrPath::Storage(image))
}
pub fn new_path<P: AsRef<Path>>(path: P) -> Self {
Self::do_new(StorageOrPath::Path(path.as_ref().to_path_buf()))
}
pub fn set_write(&mut self, writable: bool) {
self.writable = writable;
}
pub fn set_storage_open_options(&mut self, options: StorageOpenOptions) {
self.storage_opts = Some(options);
}
pub fn get_image_path(&self) -> Option<PathBuf> {
match &self.image {
StorageOrPath::Storage(s) => s.get_filename(),
StorageOrPath::Path(p) => Some(p.clone()),
}
}
pub fn get_writable(&self) -> bool {
self.writable
}
pub fn get_storage_opts(&self) -> Option<&StorageOpenOptions> {
self.storage_opts.as_ref()
}
pub fn make_storage_opts(&self) -> StorageOpenOptions {
self.storage_opts
.as_ref()
.cloned()
.unwrap_or(StorageOpenOptions::new())
.write(self.writable)
}
pub async fn open_image<G: ImplicitOpenGate<S>>(self, gate: &mut G) -> io::Result<S> {
let opts = self.make_storage_opts();
self.image.open_storage(opts, gate).await
}
}
impl<S: Storage> FormatCreateBuilderBase<S> {
pub fn new(image: S) -> Self {
FormatCreateBuilderBase {
image,
size: 0,
prealloc_mode: PreallocateMode::None,
}
}
pub fn set_size(&mut self, size: u64) {
self.size = size;
}
pub fn set_preallocate(&mut self, prealloc_mode: PreallocateMode) {
self.prealloc_mode = prealloc_mode;
}
pub fn get_size(&self) -> u64 {
self.size
}
pub fn get_preallocate(&self) -> PreallocateMode {
self.prealloc_mode
}
pub fn get_image(self) -> S {
self.image
}
pub fn get_image_ref(&self) -> &S {
&self.image
}
}
pub(crate) enum StorageOrPath<S: Storage> {
Storage(S),
Path(PathBuf),
}
impl<S: Storage + 'static> StorageOrPath<S> {
pub async fn open_storage<G: ImplicitOpenGate<S>>(
self,
opts: StorageOpenOptions,
gate: &mut G,
) -> io::Result<S> {
match self {
StorageOrPath::Storage(s) => Ok(s),
StorageOrPath::Path(p) => gate
.open_storage(opts.filename(&p))
.await
.err_context(|| p.to_string_lossy()),
}
}
}
pub(crate) enum FormatOrBuilder<S: Storage + 'static, F: WrappedFormat<S>> {
Format(F),
Qcow2Builder(Box<Qcow2OpenBuilder<S>>),
RawBuilder(Box<RawOpenBuilder<S>>),
VmdkBuilder(Box<VmdkOpenBuilder<S>>),
}
impl<S: Storage + 'static, F: WrappedFormat<S> + 'static> FormatOrBuilder<S, F> {
pub fn new_builder<P: AsRef<Path>>(format: Format, path: P) -> Self {
match format {
Format::Qcow2 => Self::Qcow2Builder(Box::new(Qcow2OpenBuilder::new_path(path))),
Format::Raw => Self::RawBuilder(Box::new(RawOpenBuilder::new_path(path))),
Format::Vmdk => Self::VmdkBuilder(Box::new(VmdkOpenBuilder::new_path(path))),
}
}
pub async fn open_format<G: ImplicitOpenGate<S>>(
self,
opts: StorageOpenOptions,
gate: &mut G,
) -> io::Result<F> {
let f = match self {
FormatOrBuilder::Format(f) => return Ok(f),
FormatOrBuilder::Qcow2Builder(b) => {
let b = b.storage_open_options(opts);
gate.open_format(b).await?
}
FormatOrBuilder::RawBuilder(b) => {
let b = b.storage_open_options(opts);
gate.open_format(b).await?
}
FormatOrBuilder::VmdkBuilder(b) => {
let b = b.storage_open_options(opts);
gate.open_format(b).await?
}
};
Ok(F::wrap(f))
}
}