diff --git a/.clippy.toml b/.clippy.toml index d23c5c6306ef..c6cef69a447b 100644 --- a/.clippy.toml +++ b/.clippy.toml @@ -9,6 +9,14 @@ path = "std::collections::HashSet" reason = """the standard library hasher is secure by default, but not very fast. use ahash::HashSet instead.""" +[[disallowed-types]] +path = "ahash::AHashMap" +reason = """use ahash::HashMap instead.""" + +[[disallowed-types]] +path = "ahash::AHashSet" +reason = """use ahash::HashSet instead.""" + # Banned in #2600, presumably so that poisoning won't need to be user-handled [[disallowed-types]] path = "std::sync::RwLock" diff --git a/src/chain/store/base_fee.rs b/src/chain/store/base_fee.rs index 6e618f324db3..534bc2e0a9b7 100644 --- a/src/chain/store/base_fee.rs +++ b/src/chain/store/base_fee.rs @@ -3,10 +3,10 @@ use crate::blocks::Tipset; use crate::message::MessageReadWrite; +use crate::prelude::*; use crate::shim::clock::ChainEpoch; use crate::shim::econ::{BLOCK_GAS_LIMIT, TokenAmount}; -use ahash::{HashSet, HashSetExt}; -use fvm_ipld_blockstore::Blockstore; +use ahash::HashSet; use super::weighted_quick_select::weighted_quick_select; diff --git a/src/db/blockstore_with_write_buffer.rs b/src/db/blockstore_with_write_buffer.rs index 2f050ef383bb..afb4b99acf60 100644 --- a/src/db/blockstore_with_write_buffer.rs +++ b/src/db/blockstore_with_write_buffer.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0, MIT use crate::prelude::*; -use ahash::{HashMap, HashMapExt}; +use ahash::HashMap; use parking_lot::RwLock; pub struct BlockstoreWithWriteBuffer { diff --git a/src/interpreter/vm.rs b/src/interpreter/vm.rs index 38c372734672..3e86a5c13f72 100644 --- a/src/interpreter/vm.rs +++ b/src/interpreter/vm.rs @@ -1,8 +1,6 @@ // Copyright 2019-2026 ChainSafe Systems // SPDX-License-Identifier: Apache-2.0, MIT -use std::sync::Arc; - use crate::blocks::Tipset; use crate::chain::block_messages; use crate::chain::index::ChainIndex; @@ -24,7 +22,7 @@ use crate::shim::{ state_tree::ActorState, version::NetworkVersion, }; -use ahash::{HashMap, HashMapExt, HashSet}; +use ahash::{HashMap, HashSet}; use anyhow::bail; use fvm_ipld_encoding::{RawBytes, to_vec}; use fvm_shared2::clock::ChainEpoch; diff --git a/src/lib.rs b/src/lib.rs index 90e8f24c2b47..5bfb5eb06a37 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -80,6 +80,7 @@ mod prelude { db::Blockstore, utils::{ShallowClone, get_size::CidWrapper}, }; + pub use ahash::{HashMapExt as _, HashSetExt as _}; pub use anyhow::Context as _; pub use cid::Cid; pub use itertools::Itertools as _; diff --git a/src/libp2p_bitswap/request_manager.rs b/src/libp2p_bitswap/request_manager.rs index 5b84b8ea5f07..10604a190b34 100644 --- a/src/libp2p_bitswap/request_manager.rs +++ b/src/libp2p_bitswap/request_manager.rs @@ -4,14 +4,11 @@ //! Request manager implementation that is optimized for `filecoin` network //! usage -use std::{ - sync::Arc, - time::{Duration, Instant}, -}; +use std::time::{Duration, Instant}; use crate::cid_collections::CidHashMap; use crate::prelude::*; -use ahash::{HashSet, HashSetExt}; +use ahash::HashSet; use flume::TryRecvError; use futures::StreamExt; use libp2p::PeerId; diff --git a/src/message_pool/msgpool/republish.rs b/src/message_pool/msgpool/republish.rs index 7dd8fb92d249..651bc8245973 100644 --- a/src/message_pool/msgpool/republish.rs +++ b/src/message_pool/msgpool/republish.rs @@ -12,10 +12,9 @@ use crate::message_pool::{ provider::Provider, utils::get_base_fee_lower_bound, }; -use crate::prelude::ShallowClone; +use crate::prelude::*; use crate::shim::address::Address; -use ahash::{HashMap, HashMapExt, HashSet}; -use cid::Cid; +use ahash::{HashMap, HashSet}; use parking_lot::RwLock as SyncRwLock; const REPUB_TRIGGER_CAPACITY: usize = 1; diff --git a/src/message_pool/msgpool/selection.rs b/src/message_pool/msgpool/selection.rs index 180a8e475f07..66b8b6a345e7 100644 --- a/src/message_pool/msgpool/selection.rs +++ b/src/message_pool/msgpool/selection.rs @@ -23,7 +23,7 @@ use crate::shim::crypto::{Signature, SignatureType}; use crate::shim::{address::Address, econ::TokenAmount}; use crate::state_manager::IdToAddressCache; use crate::utils::cache::SizeTrackingCache; -use ahash::{HashMap, HashMapExt}; +use ahash::HashMap; use anyhow::{bail, ensure}; use rand::prelude::SliceRandom; use tracing::{debug, error, warn}; diff --git a/src/rpc/auth_layer.rs b/src/rpc/auth_layer.rs index 280354d96ca6..a52c0aa572a5 100644 --- a/src/rpc/auth_layer.rs +++ b/src/rpc/auth_layer.rs @@ -5,7 +5,7 @@ use crate::auth::{JWT_IDENTIFIER, verify_token}; use crate::key_management::KeyStore; use crate::prelude::*; use crate::rpc::{CANCEL_METHOD_NAME, Permission, RpcMethod as _, chain}; -use ahash::{HashMap, HashMapExt as _}; +use ahash::HashMap; use futures::future::Either; use http::{ HeaderMap, diff --git a/src/rpc/methods/eth.rs b/src/rpc/methods/eth.rs index 2a647c6fa8c4..1367d04b855c 100644 --- a/src/rpc/methods/eth.rs +++ b/src/rpc/methods/eth.rs @@ -61,7 +61,7 @@ use crate::utils::encoding::from_slice_with_fallback; use crate::utils::get_size::big_int_heap_size_helper; use crate::utils::misc::env::env_or_default; use crate::utils::multihash::prelude::*; -use ahash::HashSet; +use ahash::{HashMap, HashSet}; use anyhow::{Error, Result, anyhow, bail, ensure}; use enumflags2::{BitFlags, make_bitflags}; use filter::{ParsedFilter, ParsedFilterTipsets}; @@ -3168,8 +3168,6 @@ fn eth_filter_logs_from_events( ctx: &Ctx, events: &[CollectedEvent], ) -> anyhow::Result> { - use ahash::AHashMap as HashMap; - let chain_id = ctx.state_manager.chain_config().eth_chain_id; let mut tx_hash_by_msg: HashMap = HashMap::new(); let mut block_hash_by_tipset: HashMap = HashMap::new(); diff --git a/src/rpc/methods/eth/filter/event.rs b/src/rpc/methods/eth/filter/event.rs index 45b49ee2732a..605ba069c949 100644 --- a/src/rpc/methods/eth/filter/event.rs +++ b/src/rpc/methods/eth/filter/event.rs @@ -1,16 +1,15 @@ // Copyright 2019-2026 ChainSafe Systems // SPDX-License-Identifier: Apache-2.0, MIT -use crate::rpc::Arc; +use crate::prelude::*; use crate::rpc::eth::filter::{ActorEventBlock, ParsedFilter, ParsedFilterTipsets}; use crate::rpc::eth::{CollectedEvent, FilterID, filter::Filter}; use crate::shim::address::Address; -use ahash::AHashMap as HashMap; -use anyhow::{Context, Result}; +use ahash::HashMap; +use anyhow::Result; use parking_lot::RwLock; use std::any::Any; -#[allow(dead_code)] #[derive(Debug, PartialEq)] pub struct EventFilter { // Unique id used to identify the filter diff --git a/src/rpc/methods/eth/filter/mempool.rs b/src/rpc/methods/eth/filter/mempool.rs index 1c2e11c75d28..885979814432 100644 --- a/src/rpc/methods/eth/filter/mempool.rs +++ b/src/rpc/methods/eth/filter/mempool.rs @@ -1,11 +1,11 @@ // Copyright 2019-2026 ChainSafe Systems // SPDX-License-Identifier: Apache-2.0, MIT -use crate::rpc::Arc; +use crate::prelude::*; use crate::rpc::eth::{FilterID, filter::Filter, filter::FilterManager}; use crate::shim::fvm_shared_latest::clock::ChainEpoch; -use ahash::AHashMap as HashMap; -use anyhow::{Context, Result}; +use ahash::HashMap; +use anyhow::Result; use parking_lot::RwLock; use std::any::Any; diff --git a/src/rpc/methods/eth/filter/mod.rs b/src/rpc/methods/eth/filter/mod.rs index ce7fed6e4dbd..b97a14bf7a36 100644 --- a/src/rpc/methods/eth/filter/mod.rs +++ b/src/rpc/methods/eth/filter/mod.rs @@ -45,7 +45,7 @@ use crate::state_manager::StateManager; use crate::state_manager::{ExecutedMessage, ExecutedTipset}; use crate::utils::misc::env::env_or_default; use crate::utils::task::AbortHandles; -use ahash::AHashMap as HashMap; +use ahash::HashMap; use anyhow::{Error, anyhow, bail, ensure}; use futures::{TryStreamExt as _, stream::FuturesOrdered}; use fvm_ipld_encoding::IPLD_RAW; @@ -538,7 +538,7 @@ impl EthFilterSpec { ParsedFilterTipsets::Range(RangeInclusive::new(min, max)) }; - let addresses: Vec<_> = if let Some(ref address_list) = self.address { + let addresses = if let Some(ref address_list) = self.address { address_list .iter() .map(|ea| { @@ -547,13 +547,13 @@ impl EthFilterSpec { }) .collect::, _>>()? } else { - vec![] + Default::default() }; let keys = if let Some(topics) = &self.topics { keys_to_keys_with_codec(parse_eth_topics(topics)?) } else { - HashMap::new() + Default::default() }; Ok(ParsedFilter { @@ -751,8 +751,8 @@ impl ParsedFilter { pub fn new_with_tipset(tipsets: ParsedFilterTipsets) -> Self { ParsedFilter { tipsets, - addresses: vec![], - keys: HashMap::new(), + addresses: Default::default(), + keys: Default::default(), msg_cid: None, } } @@ -760,8 +760,8 @@ impl ParsedFilter { pub fn new_with_tipset_and_msg(tipsets: ParsedFilterTipsets, msg_cid: Option) -> Self { ParsedFilter { tipsets, - addresses: vec![], - keys: HashMap::new(), + addresses: Default::default(), + keys: Default::default(), msg_cid, } } @@ -782,7 +782,7 @@ impl ParsedFilter { ParsedFilterTipsets::Range(RangeInclusive::new(min, max)) }; - let addresses: Vec<_> = filter.addresses.iter().map(|addr| addr.0).collect(); + let addresses = filter.addresses.iter().map(|addr| addr.0).collect_vec(); let mut keys: HashMap> = Default::default(); for (k, v) in filter.fields.into_iter() { @@ -854,13 +854,11 @@ impl Matcher for EventFilter { #[cfg(test)] mod tests { - use ahash::AHashMap; + use super::*; + use crate::rpc::eth::{EthAddress, EthFilterSpec, EthTopicSpec}; use base64::{Engine, prelude::BASE64_STANDARD}; use fvm_ipld_encoding::DAG_CBOR; use fvm_shared4::event::Flags; - - use super::*; - use crate::rpc::eth::{EthAddress, EthFilterSpec, EthTopicSpec}; use std::str::FromStr; #[test] @@ -1546,7 +1544,7 @@ mod tests { let empty_filter = ParsedFilter { tipsets: ParsedFilterTipsets::Range(0..=0), - addresses: vec![], + addresses: Default::default(), keys: Default::default(), msg_cid: None, }; @@ -1648,14 +1646,14 @@ mod tests { let empty_filter = ParsedFilter { tipsets: ParsedFilterTipsets::Range(0..=0), - addresses: vec![], + addresses: Default::default(), keys: Default::default(), msg_cid: None, }; assert!(empty_filter.matches(&addr0, &entries0).unwrap()); - let mut keys: AHashMap> = Default::default(); + let mut keys: HashMap> = Default::default(); keys.insert( "t1".into(), vec![ActorEventBlock { @@ -1668,14 +1666,14 @@ mod tests { let filter1 = ParsedFilter { tipsets: ParsedFilterTipsets::Range(0..=0), - addresses: vec![], + addresses: Default::default(), keys, msg_cid: None, }; assert!(filter1.matches(&addr0, &entries0).unwrap()); - let mut keys: AHashMap> = Default::default(); + let mut keys: HashMap> = Default::default(); keys.insert( "t1".into(), vec![ActorEventBlock { @@ -1688,14 +1686,14 @@ mod tests { let filter2 = ParsedFilter { tipsets: ParsedFilterTipsets::Range(0..=0), - addresses: vec![], + addresses: Default::default(), keys, msg_cid: None, }; assert!(!filter2.matches(&addr0, &entries0).unwrap()); - let mut keys: AHashMap> = Default::default(); + let mut keys: HashMap> = Default::default(); keys.insert( "t1".into(), vec![ActorEventBlock { @@ -1708,14 +1706,14 @@ mod tests { let filter2 = ParsedFilter { tipsets: ParsedFilterTipsets::Range(0..=0), - addresses: vec![], + addresses: Default::default(), keys, msg_cid: None, }; assert!(!filter2.matches(&addr0, &entries0).unwrap()); - let mut keys: AHashMap> = Default::default(); + let mut keys: HashMap> = Default::default(); keys.insert( "t1".into(), vec![ActorEventBlock { @@ -1737,7 +1735,7 @@ mod tests { let filter3 = ParsedFilter { tipsets: ParsedFilterTipsets::Range(0..=0), - addresses: vec![], + addresses: Default::default(), keys, msg_cid: None, }; diff --git a/src/rpc/methods/eth/filter/store.rs b/src/rpc/methods/eth/filter/store.rs index 5ff3e2c30d77..fca935bc9f84 100644 --- a/src/rpc/methods/eth/filter/store.rs +++ b/src/rpc/methods/eth/filter/store.rs @@ -1,9 +1,9 @@ // Copyright 2019-2026 ChainSafe Systems // SPDX-License-Identifier: Apache-2.0, MIT -use crate::rpc::Arc; +use crate::prelude::*; use crate::rpc::eth::FilterID; -use ahash::AHashMap as HashMap; +use ahash::HashMap; use anyhow::Result; use anyhow::anyhow; use parking_lot::RwLock; diff --git a/src/rpc/methods/eth/filter/tipset.rs b/src/rpc/methods/eth/filter/tipset.rs index c65e0d2d3a8f..4a2e5d51c2a3 100644 --- a/src/rpc/methods/eth/filter/tipset.rs +++ b/src/rpc/methods/eth/filter/tipset.rs @@ -1,11 +1,11 @@ // Copyright 2019-2026 ChainSafe Systems // SPDX-License-Identifier: Apache-2.0, MIT -use crate::rpc::Arc; +use crate::prelude::*; use crate::rpc::eth::{FilterID, filter::Filter, filter::FilterManager}; use crate::shim::fvm_shared_latest::clock::ChainEpoch; -use ahash::AHashMap as HashMap; -use anyhow::{Context, Result}; +use ahash::HashMap; +use anyhow::Result; use parking_lot::RwLock; use std::any::Any; diff --git a/src/rpc/methods/eth/trace/geth.rs b/src/rpc/methods/eth/trace/geth.rs index 3b31ad6536df..01b0991f65b3 100644 --- a/src/rpc/methods/eth/trace/geth.rs +++ b/src/rpc/methods/eth/trace/geth.rs @@ -20,13 +20,13 @@ use super::types::{ }; use super::utils::{ZERO_HASH, trace_to_address, u256_to_eth_hash}; use crate::eth::EAMMethod; +use crate::prelude::*; use crate::rpc::state::ExecutionTrace; use crate::shim::actors::is_evm_actor; use crate::shim::address::Address; use crate::shim::state_tree::{ActorState, StateTree}; use ahash::{HashMap, HashSet}; use fil_actor_evm_state::evm_shared::v17::uints::U256; -use fvm_ipld_blockstore::Blockstore; use num::FromPrimitive as _; use std::collections::BTreeMap; @@ -267,7 +267,6 @@ mod tests { use super::super::types::{PreStateConfig, PreStateFrame}; use super::*; use crate::rpc::eth::{EthBigInt, EthUint64}; - use ahash::HashSetExt as _; use num::BigInt; #[test] diff --git a/src/rpc/methods/eth/trace/state_diff.rs b/src/rpc/methods/eth/trace/state_diff.rs index 1033c67e5cde..3eefb669e5b7 100644 --- a/src/rpc/methods/eth/trace/state_diff.rs +++ b/src/rpc/methods/eth/trace/state_diff.rs @@ -11,12 +11,11 @@ use super::super::types::{EthAddress, EthHash}; use super::super::utils::ActorStateEthExt as _; use super::types::{AccountDiff, ChangedType, Delta, StateDiff}; use super::utils::{ZERO_HASH, u256_to_eth_hash}; +use crate::prelude::*; use crate::shim::actors::{EVMActorStateLoad as _, evm, is_evm_actor}; use crate::shim::state_tree::{ActorState, StateTree}; use ahash::{HashMap, HashSet}; -use anyhow::Context as _; use fil_actor_evm_state::evm_shared::v17::uints::U256; -use fvm_ipld_blockstore::Blockstore; use fvm_ipld_kamt::{AsHashedKey, Config as KamtConfig, HashedKey, Kamt}; use std::borrow::Cow; use std::collections::BTreeMap; @@ -278,9 +277,7 @@ mod tests { use crate::rpc::eth::types::EthBytes; use crate::shim::address::Address as FilecoinAddress; use crate::shim::state_tree::StateTreeVersion; - use ahash::HashSetExt as _; use num::BigInt; - use std::sync::Arc; #[test] fn test_build_state_diff_empty_touched_addresses() { diff --git a/src/rpc/methods/eth/utils.rs b/src/rpc/methods/eth/utils.rs index 8e2a1c252753..2e21100fc989 100644 --- a/src/rpc/methods/eth/utils.rs +++ b/src/rpc/methods/eth/utils.rs @@ -2,18 +2,18 @@ // SPDX-License-Identifier: Apache-2.0, MIT use super::types::{EthAddress, EthBytes}; +use crate::prelude::*; use crate::rpc::state::{MessageTrace, ReturnTrace}; use crate::shim::actors::{EVMActorStateLoad as _, evm, is_evm_actor}; use crate::shim::address::Address as FilecoinAddress; use crate::shim::fvm_shared_latest::IDENTITY_HASH; use crate::shim::state_tree::{ActorState, StateTree}; -use ahash::{HashMap, HashMapExt}; +use ahash::HashMap; use crate::rpc::eth::{EVM_WORD_LENGTH, EthUint64}; -use anyhow::{Context as _, Result, bail}; +use anyhow::{Result, bail}; use cbor4ii::core::Value; use cbor4ii::core::dec::Decode as _; -use fvm_ipld_blockstore::Blockstore; use fvm_ipld_encoding::{CBOR, DAG_CBOR, IPLD_RAW, RawBytes}; use serde::de; use std::sync::LazyLock; diff --git a/src/rpc/methods/mpool.rs b/src/rpc/methods/mpool.rs index 7ff6a30b5789..cebd11d72d16 100644 --- a/src/rpc/methods/mpool.rs +++ b/src/rpc/methods/mpool.rs @@ -4,6 +4,7 @@ use super::gas::estimate_message_gas; use crate::lotus_json::{LotusJson, NotNullVec, lotus_json_with_self}; use crate::message::SignedMessage; +use crate::prelude::*; use crate::rpc::error::ServerError; use crate::rpc::types::{ApiTipsetKey, MessageSendSpec}; use crate::rpc::{ApiPaths, Ctx, Permission, RpcMethod}; @@ -12,8 +13,7 @@ use crate::shim::{ message::Message, percent::Percent, }; -use ahash::{HashSet, HashSetExt as _}; -use cid::Cid; +use ahash::HashSet; use enumflags2::BitFlags; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; diff --git a/src/rpc/methods/state.rs b/src/rpc/methods/state.rs index 1a3f45b0181a..236119e6ff62 100644 --- a/src/rpc/methods/state.rs +++ b/src/rpc/methods/state.rs @@ -51,7 +51,7 @@ use crate::{ beacon::BeaconEntry, rpc::{ApiPaths, Ctx, Permission, RpcMethod, ServerError, types::*}, }; -use ahash::{HashMap, HashMapExt, HashSet}; +use ahash::{HashMap, HashSet}; use anyhow::Result; use enumflags2::{BitFlags, make_bitflags}; use fil_actor_miner_state::v10::{qa_power_for_weight, qa_power_max}; diff --git a/src/rpc/registry/actors_reg.rs b/src/rpc/registry/actors_reg.rs index fb81de3269ad..04023fa30cff 100644 --- a/src/rpc/registry/actors_reg.rs +++ b/src/rpc/registry/actors_reg.rs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0, MIT use crate::lotus_json::HasLotusJson; use crate::networks::ACTOR_BUNDLES_METADATA; +use crate::prelude::*; use crate::shim::actors::{ AccountActorStateLoad, CronActorStateLoad, DataCapActorStateLoad, EVMActorStateLoad, InitActorStateLoad, MarketActorStateLoad, MinerActorStateLoad, MultisigActorStateLoad, @@ -10,11 +11,9 @@ use crate::shim::actors::{ paymentchannel, power, reward, system, verifreg, }; use crate::shim::machine::BuiltinActor; -use ahash::{HashMap, HashMapExt}; -use anyhow::{Context, Result, anyhow}; -use cid::Cid; +use ahash::HashMap; +use anyhow::{Result, anyhow}; use fil_actors_shared::actor_versions::ActorVersion; -use fvm_ipld_blockstore::Blockstore; use serde_json::Value; use std::sync::LazyLock; diff --git a/src/rpc/registry/methods_reg.rs b/src/rpc/registry/methods_reg.rs index d96c759482ba..169d11ea629d 100644 --- a/src/rpc/registry/methods_reg.rs +++ b/src/rpc/registry/methods_reg.rs @@ -2,12 +2,12 @@ // SPDX-License-Identifier: Apache-2.0, MIT use crate::lotus_json::HasLotusJson; +use crate::prelude::*; use crate::rpc::registry::actors_reg::{ACTOR_REGISTRY, ActorRegistry}; use crate::shim::machine::BuiltinActor; use crate::shim::message::MethodNum; -use ahash::{HashMap, HashMapExt}; -use anyhow::{Context, Result, bail}; -use cid::Cid; +use ahash::HashMap; +use anyhow::{Result, bail}; use fil_actors_shared::v11::runtime::builtins::Type; use serde::de::DeserializeOwned; use serde_json::Value; diff --git a/src/state_manager/message_search.rs b/src/state_manager/message_search.rs index c8231a80c093..5f06615ccb2e 100644 --- a/src/state_manager/message_search.rs +++ b/src/state_manager/message_search.rs @@ -4,8 +4,7 @@ use super::*; use crate::blocks::TipsetKey; use crate::message::MessageRead as _; -use ahash::{HashMap, HashMapExt as _}; -use anyhow::Context as _; +use ahash::HashMap; use futures::{FutureExt, channel::oneshot, select}; use tokio::sync::{RwLock, broadcast::error::RecvError}; use tracing::warn; diff --git a/src/tool/subcommands/api_cmd/report.rs b/src/tool/subcommands/api_cmd/report.rs index e7a8a38e110c..f40cf987151a 100644 --- a/src/tool/subcommands/api_cmd/report.rs +++ b/src/tool/subcommands/api_cmd/report.rs @@ -2,12 +2,11 @@ // SPDX-License-Identifier: Apache-2.0, MIT use super::ReportMode; -use crate::rpc; -use crate::rpc::{FilterList, Permission}; +use crate::prelude::*; +use crate::rpc::{self, FilterList, Permission}; use crate::tool::subcommands::api_cmd::api_compare_tests::TestSummary; -use ahash::{HashMap, HashMapExt, HashSet, HashSetExt}; +use ahash::{HashMap, HashSet}; use chrono::{DateTime, Utc}; -use itertools::Itertools; use serde::{Deserialize, Serialize}; use serde_with::{DisplayFromStr, DurationMilliSeconds, DurationSeconds, serde_as}; use similar::{ChangeTag, TextDiff};