Struct Qcow2

Source
pub struct Qcow2<S: Storage + 'static, F: WrappedFormat<S> + 'static = FormatAccess<S>> {
    metadata: Arc<S>,
    writable: bool,
    storage_set: bool,
    storage: Option<S>,
    backing_set: bool,
    backing: Option<F>,
    storage_open_options: StorageOpenOptions,
    header: Arc<Header>,
    l1_table: RwLock<L1Table>,
    l2_cache: AsyncLruCache<HostCluster, L2Table, L2CacheBackend<S>>,
    allocator: Option<Mutex<Allocator<S>>>,
}
Expand description

Access qcow2 images.

Allows access to qcow2 images (v2 and v3), referencing the following objects:

  • Metadata storage object: The image file itself
  • Data file (storage object): May be the image file itself, or an external data file
  • Backing image WrappedFormat<S>: A backing disk image in any format

Fields§

§metadata: Arc<S>

Image file (which contains the qcow2 metadata).

§writable: bool

Whether this image may be modified.

§storage_set: bool

Whether the user explicitly assigned a data file storage object (or None).

§storage: Option<S>

Data file storage object; will use metadata if None.

§backing_set: bool

Whether the user explicitly assigned a backing file (or None).

§backing: Option<F>

Backing image.

§storage_open_options: StorageOpenOptions

Base options to be used for implicitly opened storage objects.

§header: Arc<Header>

Qcow2 header.

§l1_table: RwLock<L1Table>

L1 table.

§l2_cache: AsyncLruCache<HostCluster, L2Table, L2CacheBackend<S>>

L2 table cache.

§allocator: Option<Mutex<Allocator<S>>>

Allocates clusters.

Is None for read-only images.

Implementations§

Source§

impl<S: Storage + 'static, F: WrappedFormat<S> + 'static> Qcow2<S, F>

Source

async fn allocator(&self) -> Result<MutexGuard<'_, Allocator<S>>>

Return the central allocator instance.

Returns an error for read-only images.

Source

pub(super) async fn allocate_meta_cluster(&self) -> Result<HostCluster>

Allocate one metadata cluster.

Metadata clusters are allocated exclusively in the metadata (image) file.

Source

pub(super) async fn allocate_meta_clusters( &self, count: ClusterCount, ) -> Result<HostCluster>

Allocate multiple continuous metadata clusters.

Useful e.g. for the L1 table or refcount table.

Source

pub(super) async fn allocate_data_cluster( &self, guest_cluster: GuestCluster, ) -> Result<HostCluster>

Allocate one data clusters for the given guest cluster.

Without an external data file, data clusters are allocated in the image file, just like metadata clusters.

With an external data file, data clusters aren’t really allocated, but just put there at the same offset as their guest offset. Their refcount is not tracked by the qcow2 metadata structures (which only cover the metadata (image) file).

Source

pub(super) async fn allocate_data_cluster_at( &self, guest_cluster: GuestCluster, mandatory_host_cluster: Option<HostCluster>, ) -> Result<Option<HostCluster>>

Allocate the data cluster with the given index.

Without a mandatory_host_cluster given, this is the same as Qcow2::allocate_data_cluster().

With a mandatory_host_cluster given, try to allocate that cluster. If that is not possible because it is already allocated, return Ok(None).

Source

pub(super) async fn free_meta_clusters( &self, cluster: HostCluster, count: ClusterCount, )

Free metadata clusters (i.e. decrement their refcount).

Best-effort operation. On error, the given clusters may be leaked, but no errors are ever returned (because there is no good way to handle such errors anyway).

Source

pub(super) async fn free_data_clusters( &self, cluster: HostCluster, count: ClusterCount, )

Free data clusters (i.e. decrement their refcount).

Best-effort operation. On error, the given clusters may be leaked, but no errors are ever returned (because there is no good way to handle such errors anyway).

Source§

impl<S: Storage + 'static, F: WrappedFormat<S> + 'static> Qcow2<S, F>

Source

pub(super) async fn read_compressed_cluster( &self, buf: &mut [u8], compressed_offset: HostOffset, compressed_length: u64, ) -> Result<()>

Read one compressed cluster.

Read the compressed data at compressed_offset of length compressed_length (which must be the values from the L2 compressed cluster descriptor) into a bounce buffer, then decompress it into buf (which must have a length of exactly one cluster).

Source§

impl<S: Storage, F: WrappedFormat<S>> Qcow2<S, F>

Source

pub(super) async fn cow_cluster( &self, cluster: GuestCluster, mandatory_host_cluster: Option<HostCluster>, partial_skip_cow: Option<Range<usize>>, l2_table: &mut L2TableWriteGuard<'_>, leaked_allocations: &mut Vec<(HostCluster, ClusterCount)>, ) -> Result<Option<HostCluster>>

Do copy-on-write for the given guest cluster, if necessary.

If the given guest cluster is backed by an allocated copied data cluster, return that cluster, so it can just be written into.

Otherwise, allocate a new data cluster and copy the previously visible cluster contents there:

  • For non-copied data clusters, copy the cluster contents.
  • For zero clusters, write zeroes.
  • For unallocated clusters, copy data from the backing file (if any, zeroes otherwise).
  • For compressed clusters, decompress the data and write it into the new cluster.

Return the new cluster, if any was allocated, or the old cluster in case it was already safe to write to. I.e., the returned cluster is where data for cluster may be written to.

cluster is the guest cluster to COW.

mandatory_host_cluster may specify the cluster that must be used for the new allocation, or that an existing data cluster allocation must match. If it does not match, or that cluster is already allocated and cannot be used, return Ok(None).

partial_skip_cow may give an in-cluster range that is supposed to be overwritten immediately anyway, i.e. that need not be copied.

l2_table is the L2 table for offset.

If a previously existing allocation is replaced, the old one will be put into leaked_allocations. The caller must free it.

Source

fn get_cow_range( &self, partial_skip_cow: Option<Range<usize>>, alignment: usize, ) -> Option<Range<usize>>

Calculate what range of a cluster we need to COW.

Given potentially a range to skip, calculate what we should COW. The range will only be taken into account if it is at one end of the cluster, to always yield a continuous range to COW (one without a hole in the middle).

The returned range is also aligned to alignment if possible.

Source

async fn cow_copy_storage( &self, from: &S, from_cluster: HostCluster, to_cluster: HostCluster, partial_skip_cow: Option<Range<usize>>, ) -> Result<()>

Copy data from one data file cluster to another.

Used for COW on non-copied data clusters.

Source

async fn cow_copy_format( &self, from: &F, from_offset: u64, to_cluster: HostCluster, partial_skip_cow: Option<Range<usize>>, ) -> Result<()>

Copy data from another image into our data file.

Used for COW on clusters served by a backing image.

Source

async fn cow_zero( &self, to_cluster: HostCluster, partial_skip_cow: Option<Range<usize>>, ) -> Result<()>

Fill the given cluster with zeroes.

Used for COW on zero clusters.

Source

async fn cow_compressed( &self, compressed_offset: HostOffset, compressed_length: u64, to_cluster: HostCluster, ) -> Result<()>

Decompress a cluster into the target cluster.

Used for COW on compressed clusters.

Source§

impl<S: Storage, F: WrappedFormat<S>> Qcow2<S, F>

Source

pub(super) async fn do_readv_special( &self, bufv: IoVectorMut<'_>, offset: GuestOffset, ) -> Result<()>

Read the special range at offset.

Currently, the only special range we have are compressed clusters.

Source§

impl<S: Storage, F: WrappedFormat<S>> Qcow2<S, F>

Source

pub(super) async fn do_get_mapping( &self, offset: GuestOffset, max_length: u64, ) -> Result<(ShallowMapping<'_, S>, u64)>

Get the given range’s mapping information.

Underlying implementation for Qcow2::get_mapping().

Source

pub(super) async fn do_get_mapping_with_l2( &self, offset: GuestOffset, max_length: u64, l2_table: &L2Table, ) -> Result<(ShallowMapping<'_, S>, u64)>

Get the given range’s mapping information, when we already have the L2 table.

Source

pub(super) async fn do_ensure_data_mapping( &self, offset: GuestOffset, length: u64, overwrite: bool, ) -> Result<(&S, u64, u64)>

Make the given range be mapped by data clusters.

Underlying implementation for Qcow2::ensure_data_mapping().

Source

pub(super) async fn ensure_fixed_mapping( &self, offset: GuestOffset, length: u64, mapping: FixedMapping, ) -> Result<(GuestOffset, u64)>

Make the given range be mapped by a fixed kind of clusters.

Allows zeroing or discarding clusters. mapping says which kind of mapping to create.

Return the offset of the first affected cluster, and the byte length affected (may be 0).

Source

pub(super) async fn get_l2( &self, offset: GuestOffset, writable: bool, ) -> Result<Option<Arc<L2Table>>>

Get the L2 table referenced by the given L1 table index, if any.

writable says whether the L2 table should be modifiable.

If the L1 table index does not point to any L2 table, or the existing entry is not modifiable but writable is true, return Ok(None).

Source

pub(super) async fn ensure_l2( &self, offset: GuestOffset, ) -> Result<Arc<L2Table>>

Get a L2 table for the given L1 table index.

If there already is an L2 table at that index, return it. Otherwise, create one and hook it up.

Source

pub(super) async fn grow_l1_table<'a>( &self, l1_locked: RwLockWriteGuard<'a, L1Table>, at_least_index: usize, ) -> Result<RwLockWriteGuard<'a, L1Table>>

Create a new L1 table covering at least at_least_index.

Create a new L1 table of the required size with all the entries of the previous L1 table.

Source

async fn ensure_data_mapping_no_cleanup( &self, offset: GuestOffset, full_length: u64, overwrite: bool, l2_table: L2TableWriteGuard<'_>, leaked_allocations: &mut Vec<(HostCluster, ClusterCount)>, ) -> Result<(u64, u64)>

Inner implementation for Qcow2::do_ensure_data_mapping().

Does not do any clean-up: The L2 table will probably be modified, but not written to disk. Any existing allocations that have been removed from it (and are thus leaked) are entered into leaked_allocations, but not freed.

The caller must do both, ensuring it is done both in case of success and in case of error.

Source

async fn ensure_fixed_mapping_no_cleanup( &self, first_cluster: GuestCluster, count: ClusterCount, mapping: FixedMapping, l2_table: L2TableWriteGuard<'_>, leaked_allocations: &mut Vec<(HostCluster, ClusterCount)>, ) -> Result<ClusterCount>

Inner implementation for Qcow2::ensure_fixed_mapping().

Does not do any clean-up: The L2 table will probably be modified, but not written to disk. Any existing allocations that have been removed from it (and are thus leaked) are entered into leaked_allocations, but not freed.

The caller must do both, ensuring it is done both in case of success and in case of error.

Allows zeroing or discarding clusters. mapping says which kind of mapping to create.

Source§

impl<S: Storage + 'static, F: WrappedFormat<S> + 'static> Qcow2<S, F>

Source

pub(super) async fn preallocate_zero( &self, offset: u64, length: u64, ) -> Result<()>

Make the given range zero.

Source

pub(super) async fn preallocate( &self, offset: u64, length: u64, storage_prealloc_mode: PreallocateMode, ) -> Result<()>

Preallocate the given range as data clusters.

Does not write data beyond trying to ensure storage_prealloc_mode for the underlying clusters.

Source

pub(super) async fn preallocate_write_data( &self, offset: u64, length: u64, ) -> Result<()>

Write zeroes to the given range.

Source§

impl<S: Storage + 'static, F: WrappedFormat<S> + 'static> Qcow2<S, F>

Source

pub fn open_image_sync(metadata: S, writable: bool) -> Result<Self>

Synchronous wrapper around Qcow2::open_image().

Runs the async function in an ephemeral tokio runtime.

Source

pub fn open_path_sync<P: AsRef<Path>>(path: P, writable: bool) -> Result<Self>

Synchronous wrapper around Qcow2::open_path().

Runs the async function in an ephemeral tokio runtime.

Source

pub fn open_implicit_dependencies_sync(&mut self) -> Result<()>

Synchronous wrapper around Qcow2::open_implicit_dependencies().

Runs the async function in an ephemeral tokio runtime.

Source§

impl<S: Storage + 'static, F: WrappedFormat<S> + 'static> Qcow2<S, F>

Source

pub fn builder(image: S) -> Qcow2OpenBuilder<S, F>

Create a new FormatDriverBuilder instance for the given image.

Source

pub fn builder_path<P: AsRef<Path>>(image_path: P) -> Qcow2OpenBuilder<S, F>

Create a new FormatDriverBuilder instance for an image under the given path.

Source

pub fn create_builder(image: S) -> Qcow2CreateBuilder<S, F>

Create a new FormatCreateBuilder instance to format the given file.

Source

async fn do_open( metadata: S, writable: bool, storage_open_options: StorageOpenOptions, ) -> Result<Self>

Internal implementation for opening a qcow2 image.

Does not open external dependencies.

Source

pub async fn open_image(metadata: S, writable: bool) -> Result<Self>

Opens a qcow2 file.

metadata is the file containing the qcow2 metadata. If writable is not set, no modifications are permitted.

This will not open any other storage objects needed, i.e. no backing image, no external data file. If you want to handle those manually, check whether an external data file is needed via Qcow2::requires_external_data_file(), and, if necessary, assign one via Qcow2::set_data_file(); and assign a backing image via Qcow2::set_backing().

If you want to use the implicit references given in the image header, use Qcow2::open_implicit_dependencies().

Source

pub async fn open_path<P: AsRef<Path>>(path: P, writable: bool) -> Result<Self>

Open a qcow2 file at the given path.

Open the file as a storage object via Storage::open(), with write access if specified, then pass that object to Qcow2::open_image().

This will not open any other storage objects needed, i.e. no backing image, no external data file. If you want to handle those manually, check whether an external data file is needed via Qcow2::requires_external_data_file(), and, if necessary, assign one via Qcow2::set_data_file(); and assign a backing image via Qcow2::set_backing().

If you want to use the implicit references given in the image header, use Qcow2::open_implicit_dependencies().

Source

pub fn requires_external_data_file(&self) -> bool

Does this qcow2 image require an external data file?

Conversely, if this is false, this image must not use an external data file.

Source

pub fn implicit_external_data_file(&self) -> Option<&String>

External data file filename given in the image header.

Note that even if an image requires an external data file, the header may not contain its filename. In this case, an external data file must be set explicitly via Qcow2::set_data_file().

Source

pub fn implicit_backing_file(&self) -> Option<&String>

Backing image filename given in the image header.

Source

pub fn implicit_backing_format(&self) -> Option<&String>

Backing image format given in the image header.

If this is None, the backing image’s format should be probed. Note that this may be dangerous if guests have write access to the backing file: Given a raw image, a guest can write a qcow2 header into it, resulting in the image being opened as qcow2 the next time, allowing the guest to read arbitrary files (e.g. by setting them as backing files).

Source

pub fn set_data_file(&mut self, file: Option<S>)

Assign the data file.

None means using the same data storage for both metadata and data, which should be used if Qcow2::requires_external_data_file() is false.

Source

pub fn set_backing(&mut self, backing: Option<F>)

Assign a backing image.

None means no backing image, i.e. reading from unallocated areas will produce zeroes.

Source

fn storage(&self) -> &S

Get the data storage object.

If we have an external data file, return that. Otherwise, return the image (metadata) file.

Source

async fn open_implicit_data_file<G: ImplicitOpenGate<S>>( &self, gate: &mut G, ) -> Result<Option<S>>

Return the image’s implicit data file (as given in the image header).

Source

async fn open_raw_backing_file<G: ImplicitOpenGate<S>>( &self, file: S, gate: &mut G, ) -> Result<F>

Wrap file in the Raw format. Helper for Qcow2::implicit_backing_file().

Source

async fn open_qcow2_backing_file<G: ImplicitOpenGate<S>>( &self, file: S, gate: &mut G, ) -> Result<F>

Wrap file in the Qcow2 format. Helper for Qcow2::implicit_backing_file().

Source

async fn open_implicit_backing_file<G: ImplicitOpenGate<S>>( &self, gate: &mut G, ) -> Result<Option<F>>

Return the image’s implicit backing image (as given in the image header).

Anything opened will be passed through gate.

Source

pub async fn open_implicit_dependencies_gated<G: ImplicitOpenGate<S>>( &mut self, gate: G, ) -> Result<()>

Open all implicit dependencies.

Qcow2 images have dependencies:

  • The metadata file, which is the image file itself.
  • The data file, which may be the same as the metadata file, or may be an external data file.
  • A backing disk image in any format.

All of this can be set explicitly:

But the image header can also provide “default” references to the data file and a backing image, which we call implicit dependencies. This function opens all such implicit dependencies if they have not been overridden with prior calls to Qcow2::set_data_file() or Qcow2::set_backing(), respectively.

Any image or file is opened through gate.

Source

pub async fn open_implicit_dependencies(&mut self) -> Result<()>

Open all implicit dependencies, ungated.

Same as Qcow2::open_implicit_dependencies_gated, but does not perform any gating on implicitly opened images/files.

See the cautionary notes on PermissiveImplicitOpenGate on FormatDriverInstance::probe() on why this may be dangerous.

Source

fn need_writable(&self) -> Result<()>

Require write access, i.e. return an error for read-only images.

Source

fn check_disk_bounds<D: Display>( &self, length: u64, offset: u64, req: D, ) -> Result<()>

Check whether length + offset is within the disk size.

Trait Implementations§

Source§

impl<S: Storage + 'static, F: WrappedFormat<S>> Debug for Qcow2<S, F>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<S: Storage + 'static, F: WrappedFormat<S>> Display for Qcow2<S, F>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<S: Storage, F: WrappedFormat<S>> FormatDriverInstance for Qcow2<S, F>

Source§

type Storage = S

Type of storage used.
Source§

fn format(&self) -> Format

Return which format this is.
Source§

unsafe fn probe<'life0, 'async_trait>( metadata: &'life0 S, ) -> Pin<Box<dyn Future<Output = Result<bool>> + 'async_trait>>
where Self: Sized + 'async_trait, 'life0: 'async_trait,

Check whether storage has this format. Read more
Source§

fn size(&self) -> u64

Size of the disk represented by this image.
Source§

fn zero_granularity(&self) -> Option<u64>

Granularity on which blocks can be marked as zero. Read more
Source§

fn collect_storage_dependencies(&self) -> Vec<&S>

Recursively collect all storage objects associated with this image. Read more
Source§

fn writable(&self) -> bool

Return whether this image may be modified. Read more
Source§

fn get_mapping<'a, 'async_trait>( &'a self, offset: u64, max_length: u64, ) -> Pin<Box<dyn Future<Output = Result<(ShallowMapping<'a, S>, u64)>> + 'async_trait>>
where Self: 'async_trait, 'a: 'async_trait,

Return the mapping at offset. Read more
Source§

fn ensure_data_mapping<'a, 'async_trait>( &'a self, offset: u64, length: u64, overwrite: bool, ) -> Pin<Box<dyn Future<Output = Result<(&'a S, u64, u64)>> + 'async_trait>>
where Self: 'async_trait, 'a: 'async_trait,

Ensure that offset is directly mapped to some storage object, up to a length of length. Read more
Source§

fn ensure_zero_mapping<'life0, 'async_trait>( &'life0 self, offset: u64, length: u64, ) -> Pin<Box<dyn Future<Output = Result<(u64, u64)>> + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Ensure that the given range is efficiently mapped as zeroes. Read more
Source§

fn discard_to_zero<'life0, 'async_trait>( &'life0 mut self, offset: u64, length: u64, ) -> Pin<Box<dyn Future<Output = Result<(u64, u64)>> + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Discard the given range, ensure it is read back as zeroes. Read more
Source§

fn discard_to_any<'life0, 'async_trait>( &'life0 mut self, offset: u64, length: u64, ) -> Pin<Box<dyn Future<Output = Result<(u64, u64)>> + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Discard the given range. Read more
Source§

fn discard_to_backing<'life0, 'async_trait>( &'life0 mut self, offset: u64, length: u64, ) -> Pin<Box<dyn Future<Output = Result<(u64, u64)>> + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Discard the given range, such that the backing image becomes visible. Read more
Source§

fn readv_special<'life0, 'life1, 'async_trait>( &'life0 self, bufv: IoVectorMut<'life1>, offset: u64, ) -> Pin<Box<dyn Future<Output = Result<()>> + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Read data from a ShallowMapping::Special area.
Source§

fn flush<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = Result<()>> + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Flush internal buffers. Read more
Source§

fn sync<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = Result<()>> + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Sync data already written to the storage hardware. Read more
Source§

unsafe fn invalidate_cache<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = Result<()>> + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Drop internal buffers. Read more
Source§

fn resize_grow<'life0, 'async_trait>( &'life0 self, new_size: u64, prealloc_mode: PreallocateMode, ) -> Pin<Box<dyn Future<Output = Result<()>> + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Resize to the given size, which must be greater than the current size. Read more
Source§

fn resize_shrink<'life0, 'async_trait>( &'life0 mut self, new_size: u64, ) -> Pin<Box<dyn Future<Output = Result<()>> + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Truncate to the given size, which must be smaller than the current size. Read more

Auto Trait Implementations§

§

impl<S, F = FormatAccess<S>> !Freeze for Qcow2<S, F>

§

impl<S, F = FormatAccess<S>> !RefUnwindSafe for Qcow2<S, F>

§

impl<S, F> Send for Qcow2<S, F>

§

impl<S, F> Sync for Qcow2<S, F>

§

impl<S, F> Unpin for Qcow2<S, F>
where S: Unpin, F: Unpin,

§

impl<S, F = FormatAccess<S>> !UnwindSafe for Qcow2<S, F>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more