#![doc = include_str!("../README.md")] #![doc(html_logo_url = "https://raw.githubusercontent.com/al8n/memberlist/main/art/logo_72x72.png")] #![cfg_attr(not(feature = "std"), no_std)] #![forbid(unsafe_code)] #![deny(missing_docs)] // `collapsible_if`: the nested `if cond { if let ... }` form is kept deliberately — // flattening multi-level guards into one long let-chain reads worse here. #![allow(clippy::collapsible_if, clippy::type_complexity, unexpected_cfgs)] #![cfg_attr(docsrs, feature(doc_cfg))] #![cfg_attr(docsrs, allow(unused_attributes))] // Alias `alloc` to the name `std` so genuine-heap `std::` paths compile unchanged // under no_std+alloc (and `#[macro_use]` brings `vec!`/`format!` crate-wide). // Core-resident items are imported from `core::` directly, never via this alias. #[cfg(all(not(feature = "std"), feature = "alloc"))] #[macro_use] extern crate alloc as std; #[cfg(feature = "std")] extern crate std; // The protocol state is intrinsically heap-backed (Vec/Box/String/maps), so a // build with neither capability tier is unsupported. Fail with a clear message // instead of a cascade of "cannot find type `Vec`" errors. #[cfg(not(any(feature = "std", feature = "alloc")))] compile_error!( "memberlist-proto requires the `std` or `alloc` feature (the protocol state needs a heap allocator)" ); #[cfg(any(feature = "quic", feature = "tls", feature = "tcp"))] mod bridge_phase; #[cfg(feature = "quic")] mod quic; #[cfg(feature = "quic")] #[cfg_attr(docsrs, doc(cfg(feature = "quic")))] pub use quic::{ DEFAULT_CATCHUP_INTERVAL, DEFAULT_DIAL_SERVICE_MARGIN, DEFAULT_MAX_PENDING_CONNECTIONS_PER_SOURCE, DEFAULT_MAX_PENDING_INBOUND_TOTAL, DEFAULT_MAX_PENDING_USER_DIALS_PER_PEER, DEFAULT_MAX_QUIC_CONNECTIONS, DEFAULT_MAX_QUIC_INBOUND_STREAMS, DEFAULT_MAX_RELIABLE_PING_EXEMPT_POPS_PER_PASS, DEFAULT_PENDING_SOURCE_PREFIX_V4, DEFAULT_PENDING_SOURCE_PREFIX_V6, DatagramSendStatus, MAX_CATCHUP_INTERVAL, QuicEndpoint, QuicOptions, QuicOptionsError, SourcePrefix, UnreliableTransport, }; #[cfg(all(feature = "quic", feature = "tls"))] #[cfg_attr(docsrs, doc(cfg(all(feature = "quic", feature = "tls"))))] pub use quic::{QuicConfigError, QuicConfigOptions}; #[cfg(feature = "tls")] mod tls; #[cfg(feature = "tls")] #[cfg_attr(docsrs, doc(cfg(feature = "tls")))] pub use streams::TlsEndpoint; #[cfg(feature = "tls")] #[cfg_attr(docsrs, doc(cfg(feature = "tls")))] pub use tls::{ ClientAuthMode, ParseClientAuthModeError, TlsConfigError, TlsConfigOptions, TlsOptions, TlsRecords, }; #[cfg(feature = "tcp")] mod tcp; #[cfg(feature = "tcp")] #[cfg_attr(docsrs, doc(cfg(feature = "tcp")))] pub use streams::TcpEndpoint; #[cfg(feature = "tcp")] #[cfg_attr(docsrs, doc(cfg(feature = "tcp")))] pub use tcp::RawRecords; // The cluster-label record-layer decorator and its options bundle are shared // by every reliable transport (plain TCP via `Labeled`, TLS via // `Labeled`), so they are re-exported whenever any stream // transport is built. `LabelOptionsError` rides alongside for the fallible // label-validating constructors. #[cfg(any(feature = "tls", feature = "tcp"))] #[cfg_attr(docsrs, doc(cfg(any(feature = "tls", feature = "tcp"))))] pub use streams::{LabelOptions, LabelOptionsError, Labeled, Passthrough}; #[cfg(any(feature = "tls", feature = "tcp"))] #[cfg_attr(docsrs, doc(cfg(any(feature = "tls", feature = "tcp"))))] pub mod streams; pub mod ack; pub mod awareness; pub mod broadcast; #[cfg(feature = "cidr")] #[cfg_attr(docsrs, doc(cfg(feature = "cidr")))] pub mod cidr; pub mod config; pub mod delegate; pub mod endpoint; pub mod error; pub mod event; mod mathf; pub mod maybe_owned; pub mod maybe_resolved; pub mod members; pub mod metrics; pub(crate) mod probe; pub mod stream; pub mod suspicion; pub mod time; pub(crate) mod wire; // ── Wire types, codec, and framing ────────────────────────────────────────── pub mod bridge; #[cfg(checksum)] #[cfg_attr( docsrs, doc(cfg(any( feature = "crc32", feature = "xxhash32", feature = "xxhash64", feature = "xxhash3", feature = "murmur3" ))) )] pub mod checksum; pub mod codec; #[cfg(compression)] #[cfg_attr( docsrs, doc(cfg(any( feature = "lz4", feature = "snappy", feature = "zstd", feature = "brotli" ))) )] pub mod compression; pub mod convert; pub mod data; #[cfg(encryption)] #[cfg_attr( docsrs, doc(cfg(any(feature = "aes-gcm", feature = "chacha20poly1305"))) )] pub mod encryption; pub mod framing; pub mod id; pub mod label; pub mod messages; pub mod node; pub mod typed; pub mod wire_type; pub use ack::{AckEntry, AckKind, AckRegistry, AckResolution, ForwardAck}; pub use awareness::Awareness; pub use broadcast::{ Broadcast, BroadcastQueue, BytesBroadcast, MemberlistBroadcast, NoId, UserBroadcasts, }; #[cfg(feature = "cidr")] #[cfg_attr(docsrs, doc(cfg(feature = "cidr")))] pub use cidr::{CidrAnd, CidrPolicy}; pub use config::{DEFAULT_GOSSIP_MTU, EndpointOptions, EndpointTuning}; pub use delegate::{AliveDelegate, MergeDelegate}; pub use endpoint::{Endpoint, Lifecycle, META_MAX_SIZE}; pub use error::{EndpointInitError, Error, SizeExceeded, StreamError, UserDialBacklogFull}; // The RNG vocabulary backing the `Endpoint` type parameter (defaulting // to `SmallRng`), re-exported so a driver can name the trait bound, seed a // `SmallRng`, and inject it without taking its own direct `rand` dependency. pub use event::{ CompoundTransmit, DecodeError, DialIntent, DialRequested, EndpointEvent, Event, NodeConflict, PacketTransmit, PingCompleted, PingFailed, PingId, PushPullKind, PushPullReplyReceived, PushPullRequestReceived, Reliability, ReliablePingAcked, ReliablePingFailed, RemoteStateReceived, SendPushPullResponse, StreamClosed, StreamCommand, StreamErrored, StreamEvent, StreamId, Transmit, UserDataReceived, UserPacket, }; #[cfg(feature = "cidr")] #[cfg_attr(docsrs, doc(cfg(feature = "cidr")))] pub use ipnet::{AddrParseError, IpNet}; pub use maybe_owned::MaybeOwned; pub use maybe_resolved::MaybeResolved; pub use members::{LocalNodeState, Member, Members}; pub use rand::{Rng, SeedableRng, rngs::SmallRng}; pub use stream::{PushPullSnapshot, Stream}; pub use suspicion::{Confirmation, Suspicion}; pub use time::Instant; pub use bridge::{BridgeError, message_from_any, message_to_any}; pub use cheap_clone::CheapClone; #[cfg(checksum)] #[cfg_attr( docsrs, doc(cfg(any( feature = "crc32", feature = "xxhash32", feature = "xxhash64", feature = "xxhash3", feature = "murmur3" ))) )] pub use checksum::{ CHECKSUMED_WRAPPER_OVERHEAD, ChecksumAlgorithm, ChecksumDigest, ChecksumError, ChecksumOptions, ChecksumOutput, decode_checksummed_frame, digest, encode_checksummed_frame, verify, }; pub use codec::{ CodecError, DecodeOptions, EncodeOptions, TrailingData, TruncatedInput, decode_incoming, encode_outgoing, encode_outgoing_compound, parse_message, parse_messages, }; #[cfg(compression)] #[cfg_attr( docsrs, doc(cfg(any( feature = "lz4", feature = "snappy", feature = "zstd", feature = "brotli" ))) )] pub use compression::{ CompressAlgorithm, CompressionError, CompressionOptions, CompressionOutput, OversizeOriginal, UnitLenExceedsMaxInfo, compress, decode_compressed_frame, decompress, encode_compressed_frame, encode_reliable_unit, take_reliable_unit, }; // The encryption-aware reliable-unit codec helpers live in the `compression` // module (present only under a compression backend) AND name `EncryptionOptions` // (present only under an encryption backend), so they exist only when BOTH a // compression and an encryption backend are built in. #[cfg(all(compression, encryption))] #[cfg_attr( docsrs, doc(cfg(all( any( feature = "lz4", feature = "snappy", feature = "zstd", feature = "brotli" ), any(feature = "aes-gcm", feature = "chacha20-poly1305") ))) )] pub use compression::{encode_reliable_unit_with_encryption, take_reliable_unit_with_encryption}; pub use convert::{ AddrLengthMismatchInfo, ConvertError, id_from_bytes, id_to_bytes, socket_addr_from_bytes, socket_addr_to_bytes, }; pub use label::{ LABEL_OVERHEAD, LABELED_TAG, LabelError, LabelVerdict, MAX_LABEL_LEN, classify_header, effective_label, encode_label_prefix, validate_label, }; // `data::DecodeError` is reached via `crate::data::DecodeError`; the crate-root // `DecodeError` name is already taken by `event::DecodeError`. pub use data::{ Data, DataRef, DuplicateFieldInfo, EncodeError, InsufficientBufferCapacity, MissingFieldInfo, UnknownTagInfo, UnknownWireTypeInfo, }; #[cfg(encryption)] #[cfg_attr( docsrs, doc(cfg(any(feature = "aes-gcm", feature = "chacha20-poly1305"))) )] pub use encryption::{ ENCRYPTED_TAG, ENCRYPTED_WRAPPER_OVERHEAD, EncryptAlgorithm, EncryptionError, EncryptionOptions, Keyring, KeyringError, OversizeCiphertext, SecretKey, decode_encrypted_frame, decrypt, encode_encrypted_frame, encrypt, }; pub use framing::{ AnyMessage, COMPOUND_MAX_COUNT_PREFIX_LEN, COMPOUND_MAX_PART_PREFIX_LEN, COMPOUND_TAG_LEN, FrameError, IncompleteFrame, MessageTag, decode_compound, decode_message, decode_plain_frame, encode_compound, encode_message, encode_plain_frame, unwrap_transforms, }; // `unwrap_transforms_with_encryption` strips the outer `Encrypted` wrapper via // the configured keyring, so it exists only when an encryption backend is built // in (the base `unwrap_transforms` is always present above). #[cfg(encryption)] #[cfg_attr( docsrs, doc(cfg(any(feature = "aes-gcm", feature = "chacha20-poly1305"))) )] pub use framing::unwrap_transforms_with_encryption; pub use id::Id; pub use node::Node; /// `FxHashMap`/`FxHashSet` backed by hashbrown (no_std-capable) with rustc-hash's /// Fx hasher — rustc-hash's own `Fx*` map aliases are std-only. pub(crate) type FxHashMap = hashbrown::HashMap; pub(crate) type FxHashSet = hashbrown::HashSet;