pub struct SupportedVersions { /* private fields */ }Expand description
A non-empty, sorted, duplicate-free set of protocol versions.
Construct it with new or from_slice;
both return Result because emptiness is the one thing a caller gets
wrong by accident and cannot fix afterwards.
§Examples
use protocol_droid::domain::{ProtocolVersion, SupportedVersions};
let ours = SupportedVersions::new([ProtocolVersion::V2024_11_05, ProtocolVersion::V2025_03_26])?;
assert_eq!(ours.latest(), ProtocolVersion::V2025_03_26);
assert!(ours.contains(&ProtocolVersion::V2024_11_05));
// Newest mutually supported wins, which is what the specification requires
// when both sides can speak more than one revision.
let theirs = [ProtocolVersion::V2025_06_18, ProtocolVersion::V2025_03_26];
assert_eq!(ours.best_match(&theirs), Some(ProtocolVersion::V2025_03_26));Implementations§
Source§impl SupportedVersions
impl SupportedVersions
Sourcepub fn all() -> Result<Self, SupportedVersionsError>
pub fn all() -> Result<Self, SupportedVersionsError>
Every revision this build has wire types for.
§Errors
Never. It exists so callers do not spell the list out, and the list is
known non-empty, so the Result is a formality rather than a branch.
Sourcepub fn as_slice(&self) -> &[ProtocolVersion]
pub fn as_slice(&self) -> &[ProtocolVersion]
The set of every revision this build knows, as a slice.
A convenience for the read-only cases; new and
from_slice are the ways to build one that can be
held.
Sourcepub fn new(
versions: impl IntoIterator<Item = ProtocolVersion>,
) -> Result<Self, SupportedVersionsError>
pub fn new( versions: impl IntoIterator<Item = ProtocolVersion>, ) -> Result<Self, SupportedVersionsError>
Sorts, deduplicates, and rejects an empty set.
§Errors
SupportedVersionsError::Empty when versions has no members.
§Examples
use protocol_droid::domain::{ProtocolVersion, SupportedVersions};
// Order and duplicates are the caller's problem, not the caller's job.
let set = SupportedVersions::new([
ProtocolVersion::V2025_03_26,
ProtocolVersion::V2024_11_05,
ProtocolVersion::V2025_03_26,
])?;
assert_eq!(set.as_slice(), &[ProtocolVersion::V2024_11_05, ProtocolVersion::V2025_03_26]);Sourcepub fn from_slice(
versions: &[ProtocolVersion],
) -> Result<Self, SupportedVersionsError>
pub fn from_slice( versions: &[ProtocolVersion], ) -> Result<Self, SupportedVersionsError>
new for a slice that is already borrowed.
§Errors
SupportedVersionsError::Empty when versions is empty.
Sourcepub fn len(&self) -> usize
pub fn len(&self) -> usize
How many revisions the peer supports.
At least one, always — that is the invariant.
Sourcepub fn latest(&self) -> ProtocolVersion
pub fn latest(&self) -> ProtocolVersion
The newest revision the peer supports.
Infallible rather than Option because the set is non-empty and
sorted: the last element is the answer, and there is no path to a set
where that element does not exist.
Sourcepub fn latest_handshake(&self) -> ProtocolVersion
pub fn latest_handshake(&self) -> ProtocolVersion
The newest revision here that still defines a handshake.
Not latest. SEP-2575 removed initialize from
2026-07-28, and that revision is currently the newest the crate
knows — so a ceiling taken from latest would be a revision no peer can
complete a handshake on, and a server gating its whole life on one can
never finish talking to anybody.
Infallible for the same reason latest is: the set is
non-empty and sorted, and the earliest-known revision still has a
handshake, so the scan has something to return.
Sourcepub fn earliest(&self) -> ProtocolVersion
pub fn earliest(&self) -> ProtocolVersion
The oldest revision the peer supports.
Sourcepub fn contains(&self, version: &ProtocolVersion) -> bool
pub fn contains(&self, version: &ProtocolVersion) -> bool
Whether the peer supports version.
Sourcepub fn best_match(&self, offered: &[ProtocolVersion]) -> Option<ProtocolVersion>
pub fn best_match(&self, offered: &[ProtocolVersion]) -> Option<ProtocolVersion>
The newest revision this set and offered have in common, or None.
Newest-common rather than first-offered: the specification tells a peer
to use the latest version it can support, and a client that advertised
["2024-11-05", "2025-06-18"] is not asking for 2024-11-05.
offered is taken as a slice and scanned rather than sorted into a set,
because it arrives from the wire, may contain duplicates, and is usually
a handful of entries. The cost is one linear pass, and ProtocolVersion
is Copy so the comparison is a field compare.
§Why Option when the task said -> ProtocolVersion
There is a real outcome where no revision is shared, and a peer’s offer
can be empty. Returning a ProtocolVersion there means returning a
value the peer did not offer, which is how a bridge ends up announcing a
version it cannot speak. T06 maps None onto JSON-RPC’s
UnsupportedProtocolVersion error, which is the answer the wire format
already has for exactly this case.
§Examples
use protocol_droid::domain::{ProtocolVersion, SupportedVersions};
let ours = SupportedVersions::new(ProtocolVersion::KNOWN)?;
assert_eq!(
ours.best_match(&[ProtocolVersion::V2025_06_18, ProtocolVersion::V2024_11_05]),
Some(ProtocolVersion::V2025_06_18)
);
assert_eq!(ours.best_match(&[ProtocolVersion::Unknown("2027-01-01".parse().unwrap())]), None);
assert_eq!(ours.best_match(&[]), None);Sourcepub fn not_offered_by<'a>(
&'a self,
offered: &'a [ProtocolVersion],
) -> impl Iterator<Item = ProtocolVersion> + 'a
pub fn not_offered_by<'a>( &'a self, offered: &'a [ProtocolVersion], ) -> impl Iterator<Item = ProtocolVersion> + 'a
The revisions in this set that offered does not contain.
The negotiation log wants both directions, and a codec wants to know what it must translate away from, so this is a first-class operation rather than something each caller reassembles.