Decouple some dependencies (#3886)
# Objective Reduce from scratch build time. ## Solution Reduce the size of the critical path by removing dependencies between crates where not necessary. For `cargo check --no-default-features` this reduced build time from ~51s to ~45s. For some commits I am not completely sure if the tradeoff between build time reduction and convenience caused by the commit is acceptable. If not, I can drop them.
This commit is contained in:
parent
f1aae380ab
commit
ddce22b614
@ -1,4 +1,3 @@
|
|||||||
use bevy_macro_utils::BevyManifest;
|
|
||||||
use proc_macro::{Span, TokenStream};
|
use proc_macro::{Span, TokenStream};
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
use syn::{parse_macro_input, Data, DeriveInput};
|
use syn::{parse_macro_input, Data, DeriveInput};
|
||||||
@ -14,8 +13,6 @@ pub fn derive_enum_variant_meta(input: TokenStream) -> TokenStream {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let bevy_util_path = BevyManifest::default().get_path(crate::modules::BEVY_UTILS);
|
|
||||||
|
|
||||||
let generics = ast.generics;
|
let generics = ast.generics;
|
||||||
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
|
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
|
||||||
|
|
||||||
@ -25,13 +22,13 @@ pub fn derive_enum_variant_meta(input: TokenStream) -> TokenStream {
|
|||||||
let indices = 0..names.len();
|
let indices = 0..names.len();
|
||||||
|
|
||||||
TokenStream::from(quote! {
|
TokenStream::from(quote! {
|
||||||
impl #impl_generics #bevy_util_path::EnumVariantMeta for #struct_name #ty_generics #where_clause {
|
impl #impl_generics #struct_name #ty_generics #where_clause {
|
||||||
fn enum_variant_index(&self) -> usize {
|
pub fn enum_variant_index(&self) -> usize {
|
||||||
match self {
|
match self {
|
||||||
#(#struct_name::#idents {..} => #indices,)*
|
#(#struct_name::#idents {..} => #indices,)*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn enum_variant_name(&self) -> &'static str {
|
pub fn enum_variant_name(&self) -> &'static str {
|
||||||
static variants: &[&str] = &[
|
static variants: &[&str] = &[
|
||||||
#(#names,)*
|
#(#names,)*
|
||||||
];
|
];
|
||||||
|
|||||||
@ -4,7 +4,6 @@ mod app_plugin;
|
|||||||
mod bevy_main;
|
mod bevy_main;
|
||||||
mod derefs;
|
mod derefs;
|
||||||
mod enum_variant_meta;
|
mod enum_variant_meta;
|
||||||
mod modules;
|
|
||||||
|
|
||||||
use bevy_macro_utils::{derive_label, BevyManifest};
|
use bevy_macro_utils::{derive_label, BevyManifest};
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
|
|||||||
@ -1 +0,0 @@
|
|||||||
pub const BEVY_UTILS: &str = "bevy_utils";
|
|
||||||
@ -22,7 +22,6 @@ bevy_ecs_macros = { path = "macros", version = "0.8.0-dev" }
|
|||||||
async-channel = "1.4"
|
async-channel = "1.4"
|
||||||
fixedbitset = "0.4"
|
fixedbitset = "0.4"
|
||||||
fxhash = "0.2"
|
fxhash = "0.2"
|
||||||
thiserror = "1.0"
|
|
||||||
downcast-rs = "1.2"
|
downcast-rs = "1.2"
|
||||||
serde = "1"
|
serde = "1"
|
||||||
|
|
||||||
|
|||||||
@ -1,13 +1,24 @@
|
|||||||
use crate::entity::Entity;
|
use crate::entity::Entity;
|
||||||
use bevy_utils::{Entry, HashMap};
|
use bevy_utils::{Entry, HashMap};
|
||||||
use thiserror::Error;
|
use std::fmt;
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Debug)]
|
||||||
pub enum MapEntitiesError {
|
pub enum MapEntitiesError {
|
||||||
#[error("the given entity does not exist in the map")]
|
|
||||||
EntityNotFound(Entity),
|
EntityNotFound(Entity),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for MapEntitiesError {}
|
||||||
|
|
||||||
|
impl fmt::Display for MapEntitiesError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
MapEntitiesError::EntityNotFound(_) => {
|
||||||
|
write!(f, "the given entity does not exist in the map")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait MapEntities {
|
pub trait MapEntities {
|
||||||
fn map_entities(&mut self, entity_map: &EntityMap) -> Result<(), MapEntitiesError>;
|
fn map_entities(&mut self, entity_map: &EntityMap) -> Result<(), MapEntitiesError>;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,7 +12,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use bevy_tasks::TaskPool;
|
use bevy_tasks::TaskPool;
|
||||||
use fixedbitset::FixedBitSet;
|
use fixedbitset::FixedBitSet;
|
||||||
use thiserror::Error;
|
use std::fmt;
|
||||||
|
|
||||||
/// Provides scoped access to a [`World`] state according to a given [`WorldQuery`] and query filter.
|
/// Provides scoped access to a [`World`] state according to a given [`WorldQuery`] and query filter.
|
||||||
pub struct QueryState<Q: WorldQuery, F: WorldQuery = ()>
|
pub struct QueryState<Q: WorldQuery, F: WorldQuery = ()>
|
||||||
@ -936,16 +936,29 @@ where
|
|||||||
|
|
||||||
/// An error that occurs when retrieving a specific [`Entity`]'s query result.
|
/// An error that occurs when retrieving a specific [`Entity`]'s query result.
|
||||||
// TODO: return the type_name as part of this error
|
// TODO: return the type_name as part of this error
|
||||||
#[derive(Error, Debug, PartialEq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||||
pub enum QueryEntityError {
|
pub enum QueryEntityError {
|
||||||
#[error("The given entity does not have the requested component.")]
|
|
||||||
QueryDoesNotMatch(Entity),
|
QueryDoesNotMatch(Entity),
|
||||||
#[error("The requested entity does not exist.")]
|
|
||||||
NoSuchEntity(Entity),
|
NoSuchEntity(Entity),
|
||||||
#[error("The entity was requested mutably more than once.")]
|
|
||||||
AliasedMutability(Entity),
|
AliasedMutability(Entity),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for QueryEntityError {}
|
||||||
|
|
||||||
|
impl fmt::Display for QueryEntityError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
QueryEntityError::QueryDoesNotMatch(_) => {
|
||||||
|
write!(f, "The given entity does not have the requested component.")
|
||||||
|
}
|
||||||
|
QueryEntityError::NoSuchEntity(_) => write!(f, "The requested entity does not exist."),
|
||||||
|
QueryEntityError::AliasedMutability(_) => {
|
||||||
|
write!(f, "The entity was requested mutably more than once.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{prelude::*, query::QueryEntityError};
|
use crate::{prelude::*, query::QueryEntityError};
|
||||||
|
|||||||
@ -5,8 +5,11 @@ use crate::{
|
|||||||
},
|
},
|
||||||
system::{In, IntoChainSystem, Local, Res, ResMut},
|
system::{In, IntoChainSystem, Local, Res, ResMut},
|
||||||
};
|
};
|
||||||
use std::{any::TypeId, fmt::Debug, hash::Hash};
|
use std::{
|
||||||
use thiserror::Error;
|
any::TypeId,
|
||||||
|
fmt::{self, Debug},
|
||||||
|
hash::Hash,
|
||||||
|
};
|
||||||
|
|
||||||
pub trait StateData: Send + Sync + Clone + Eq + Debug + Hash + 'static {}
|
pub trait StateData: Send + Sync + Clone + Eq + Debug + Hash + 'static {}
|
||||||
impl<T> StateData for T where T: Send + Sync + Clone + Eq + Debug + Hash + 'static {}
|
impl<T> StateData for T where T: Send + Sync + Clone + Eq + Debug + Hash + 'static {}
|
||||||
@ -399,16 +402,32 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug)]
|
||||||
pub enum StateError {
|
pub enum StateError {
|
||||||
#[error("Attempted to change the state to the current state.")]
|
|
||||||
AlreadyInState,
|
AlreadyInState,
|
||||||
#[error("Attempted to queue a state change, but there was already a state queued.")]
|
|
||||||
StateAlreadyQueued,
|
StateAlreadyQueued,
|
||||||
#[error("Attempted to queue a pop, but there is nothing to pop.")]
|
|
||||||
StackEmpty,
|
StackEmpty,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for StateError {}
|
||||||
|
|
||||||
|
impl fmt::Display for StateError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
StateError::AlreadyInState => {
|
||||||
|
write!(f, "Attempted to change the state to the current state.")
|
||||||
|
}
|
||||||
|
StateError::StateAlreadyQueued => write!(
|
||||||
|
f,
|
||||||
|
"Attempted to queue a state change, but there was already a state queued."
|
||||||
|
),
|
||||||
|
StateError::StackEmpty => {
|
||||||
|
write!(f, "Attempted to queue a pop, but there is nothing to pop.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn should_run_adapter<T: StateData>(In(cmp_result): In<bool>, state: Res<State<T>>) -> ShouldRun {
|
fn should_run_adapter<T: StateData>(In(cmp_result): In<bool>, state: Res<State<T>>) -> ShouldRun {
|
||||||
if state.end_next_loop {
|
if state.end_next_loop {
|
||||||
return ShouldRun::No;
|
return ShouldRun::No;
|
||||||
|
|||||||
@ -9,7 +9,6 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use bevy_tasks::TaskPool;
|
use bevy_tasks::TaskPool;
|
||||||
use std::{any::TypeId, fmt::Debug};
|
use std::{any::TypeId, fmt::Debug};
|
||||||
use thiserror::Error;
|
|
||||||
|
|
||||||
/// Provides scoped access to components in a [`World`].
|
/// Provides scoped access to components in a [`World`].
|
||||||
///
|
///
|
||||||
@ -1157,28 +1156,61 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// An error that occurs when retrieving a specific [`Entity`]'s component from a [`Query`]
|
/// An error that occurs when retrieving a specific [`Entity`]'s component from a [`Query`]
|
||||||
#[derive(Error, Debug)]
|
#[derive(Debug)]
|
||||||
pub enum QueryComponentError {
|
pub enum QueryComponentError {
|
||||||
#[error("This query does not have read access to the requested component.")]
|
|
||||||
MissingReadAccess,
|
MissingReadAccess,
|
||||||
#[error("This query does not have write access to the requested component.")]
|
|
||||||
MissingWriteAccess,
|
MissingWriteAccess,
|
||||||
#[error("The given entity does not have the requested component.")]
|
|
||||||
MissingComponent,
|
MissingComponent,
|
||||||
#[error("The requested entity does not exist.")]
|
|
||||||
NoSuchEntity,
|
NoSuchEntity,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for QueryComponentError {}
|
||||||
|
|
||||||
|
impl std::fmt::Display for QueryComponentError {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
QueryComponentError::MissingReadAccess => {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"This query does not have read access to the requested component."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
QueryComponentError::MissingWriteAccess => {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"This query does not have write access to the requested component."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
QueryComponentError::MissingComponent => {
|
||||||
|
write!(f, "The given entity does not have the requested component.")
|
||||||
|
}
|
||||||
|
QueryComponentError::NoSuchEntity => {
|
||||||
|
write!(f, "The requested entity does not exist.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// An error that occurs when evaluating a [`Query`] as a single expected resulted via
|
/// An error that occurs when evaluating a [`Query`] as a single expected resulted via
|
||||||
/// [`Query::single`] or [`Query::single_mut`].
|
/// [`Query::single`] or [`Query::single_mut`].
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug)]
|
||||||
pub enum QuerySingleError {
|
pub enum QuerySingleError {
|
||||||
#[error("No entities fit the query {0}")]
|
|
||||||
NoEntities(&'static str),
|
NoEntities(&'static str),
|
||||||
#[error("Multiple entities fit the query {0}!")]
|
|
||||||
MultipleEntities(&'static str),
|
MultipleEntities(&'static str),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for QuerySingleError {}
|
||||||
|
|
||||||
|
impl std::fmt::Display for QuerySingleError {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
QuerySingleError::NoEntities(query) => write!(f, "No entities fit the query {}", query),
|
||||||
|
QuerySingleError::MultipleEntities(query) => {
|
||||||
|
write!(f, "Multiple entities fit the query {}!", query)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
impl<'w, 's, Q: WorldQuery, F: WorldQuery> Query<'w, 's, Q, F>
|
impl<'w, 's, Q: WorldQuery, F: WorldQuery> Query<'w, 's, Q, F>
|
||||||
where
|
where
|
||||||
F::Fetch: FilterFetch,
|
F::Fetch: FilterFetch,
|
||||||
|
|||||||
@ -9,6 +9,6 @@ license = "MIT OR Apache-2.0"
|
|||||||
keywords = ["bevy"]
|
keywords = ["bevy"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cargo-manifest = "0.2.6"
|
toml = "0.5.8"
|
||||||
syn = "1.0"
|
syn = "1.0"
|
||||||
quote = "1.0"
|
quote = "1.0"
|
||||||
|
|||||||
@ -8,13 +8,13 @@ pub use attrs::*;
|
|||||||
pub use shape::*;
|
pub use shape::*;
|
||||||
pub use symbol::*;
|
pub use symbol::*;
|
||||||
|
|
||||||
use cargo_manifest::{DepsSet, Manifest};
|
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
use std::{env, path::PathBuf};
|
use std::{env, path::PathBuf};
|
||||||
|
use toml::{map::Map, Value};
|
||||||
|
|
||||||
pub struct BevyManifest {
|
pub struct BevyManifest {
|
||||||
manifest: Manifest,
|
manifest: Map<String, Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for BevyManifest {
|
impl Default for BevyManifest {
|
||||||
@ -24,7 +24,8 @@ impl Default for BevyManifest {
|
|||||||
.map(PathBuf::from)
|
.map(PathBuf::from)
|
||||||
.map(|mut path| {
|
.map(|mut path| {
|
||||||
path.push("Cargo.toml");
|
path.push("Cargo.toml");
|
||||||
Manifest::from_path(path).unwrap()
|
let manifest = std::fs::read_to_string(path).unwrap();
|
||||||
|
toml::from_str(&manifest).unwrap()
|
||||||
})
|
})
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
}
|
}
|
||||||
@ -36,13 +37,24 @@ impl BevyManifest {
|
|||||||
const BEVY: &str = "bevy";
|
const BEVY: &str = "bevy";
|
||||||
const BEVY_INTERNAL: &str = "bevy_internal";
|
const BEVY_INTERNAL: &str = "bevy_internal";
|
||||||
|
|
||||||
let find_in_deps = |deps: &DepsSet| -> Option<syn::Path> {
|
fn dep_package(dep: &Value) -> Option<&str> {
|
||||||
|
if dep.as_str().is_some() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
dep.as_table()
|
||||||
|
.unwrap()
|
||||||
|
.get("package")
|
||||||
|
.map(|name| name.as_str().unwrap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let find_in_deps = |deps: &Map<String, Value>| -> Option<syn::Path> {
|
||||||
let package = if let Some(dep) = deps.get(name) {
|
let package = if let Some(dep) = deps.get(name) {
|
||||||
return Some(Self::parse_str(dep.package().unwrap_or(name)));
|
return Some(Self::parse_str(dep_package(dep).unwrap_or(name)));
|
||||||
} else if let Some(dep) = deps.get(BEVY) {
|
} else if let Some(dep) = deps.get(BEVY) {
|
||||||
dep.package().unwrap_or(BEVY)
|
dep_package(dep).unwrap_or(BEVY)
|
||||||
} else if let Some(dep) = deps.get(BEVY_INTERNAL) {
|
} else if let Some(dep) = deps.get(BEVY_INTERNAL) {
|
||||||
dep.package().unwrap_or(BEVY_INTERNAL)
|
dep_package(dep).unwrap_or(BEVY_INTERNAL)
|
||||||
} else {
|
} else {
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
@ -54,8 +66,14 @@ impl BevyManifest {
|
|||||||
Some(path)
|
Some(path)
|
||||||
};
|
};
|
||||||
|
|
||||||
let deps = self.manifest.dependencies.as_ref();
|
let deps = self
|
||||||
let deps_dev = self.manifest.dev_dependencies.as_ref();
|
.manifest
|
||||||
|
.get("dependencies")
|
||||||
|
.map(|deps| deps.as_table().unwrap());
|
||||||
|
let deps_dev = self
|
||||||
|
.manifest
|
||||||
|
.get("dev-dependencies")
|
||||||
|
.map(|deps| deps.as_table().unwrap());
|
||||||
|
|
||||||
deps.and_then(find_in_deps)
|
deps.and_then(find_in_deps)
|
||||||
.or_else(|| deps_dev.and_then(find_in_deps))
|
.or_else(|| deps_dev.and_then(find_in_deps))
|
||||||
|
|||||||
@ -17,4 +17,4 @@ bevy_macro_utils = { path = "../../bevy_macro_utils", version = "0.8.0-dev" }
|
|||||||
syn = { version = "1.0", features = ["full"] }
|
syn = { version = "1.0", features = ["full"] }
|
||||||
proc-macro2 = "1.0"
|
proc-macro2 = "1.0"
|
||||||
quote = "1.0"
|
quote = "1.0"
|
||||||
uuid = { version = "0.8", features = ["v4", "serde"] }
|
uuid = { version = "0.8", features = ["v4"] }
|
||||||
|
|||||||
@ -25,7 +25,6 @@
|
|||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
use crate::mesh::VertexAttributeValues;
|
use crate::mesh::VertexAttributeValues;
|
||||||
use bevy_utils::EnumVariantMeta;
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Error)]
|
#[derive(Debug, Clone, Error)]
|
||||||
|
|||||||
@ -9,10 +9,11 @@ use crate::{
|
|||||||
renderer::RenderDevice,
|
renderer::RenderDevice,
|
||||||
};
|
};
|
||||||
use bevy_core::cast_slice;
|
use bevy_core::cast_slice;
|
||||||
|
use bevy_derive::EnumVariantMeta;
|
||||||
use bevy_ecs::system::{lifetimeless::SRes, SystemParamItem};
|
use bevy_ecs::system::{lifetimeless::SRes, SystemParamItem};
|
||||||
use bevy_math::*;
|
use bevy_math::*;
|
||||||
use bevy_reflect::TypeUuid;
|
use bevy_reflect::TypeUuid;
|
||||||
use bevy_utils::{EnumVariantMeta, Hashed};
|
use bevy_utils::Hashed;
|
||||||
use std::{collections::BTreeMap, hash::Hash};
|
use std::{collections::BTreeMap, hash::Hash};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use wgpu::{
|
use wgpu::{
|
||||||
|
|||||||
@ -9,9 +9,8 @@ license = "MIT OR Apache-2.0"
|
|||||||
keywords = ["bevy"]
|
keywords = ["bevy"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bevy_derive = { path = "../bevy_derive", version = "0.8.0-dev" }
|
|
||||||
ahash = "0.7.0"
|
ahash = "0.7.0"
|
||||||
tracing = { version = "0.1" }
|
tracing = { version = "0.1", default-features = false, features = ["std"] }
|
||||||
instant = { version = "0.1", features = ["wasm-bindgen"] }
|
instant = { version = "0.1", features = ["wasm-bindgen"] }
|
||||||
uuid = { version = "0.8", features = ["v4", "serde"] }
|
uuid = { version = "0.8", features = ["v4", "serde"] }
|
||||||
hashbrown = { version = "0.11", features = ["serde"] }
|
hashbrown = { version = "0.11", features = ["serde"] }
|
||||||
|
|||||||
@ -1,6 +0,0 @@
|
|||||||
pub use bevy_derive::EnumVariantMeta;
|
|
||||||
|
|
||||||
pub trait EnumVariantMeta {
|
|
||||||
fn enum_variant_index(&self) -> usize;
|
|
||||||
fn enum_variant_name(&self) -> &'static str;
|
|
||||||
}
|
|
||||||
@ -6,12 +6,10 @@ pub mod futures;
|
|||||||
pub mod label;
|
pub mod label;
|
||||||
|
|
||||||
mod default;
|
mod default;
|
||||||
mod enum_variant_meta;
|
|
||||||
mod float_ord;
|
mod float_ord;
|
||||||
|
|
||||||
pub use ahash::AHasher;
|
pub use ahash::AHasher;
|
||||||
pub use default::default;
|
pub use default::default;
|
||||||
pub use enum_variant_meta::*;
|
|
||||||
pub use float_ord::*;
|
pub use float_ord::*;
|
||||||
pub use hashbrown;
|
pub use hashbrown;
|
||||||
pub use instant::{Duration, Instant};
|
pub use instant::{Duration, Instant};
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user