1+ //! A specialized map for semantic versions with alternate version lookup support.
2+ //!
3+ //! This module provides `VersionMap<T>`, which stores values indexed by semantic versions
4+ //! and supports fallback lookups through version alternates (e.g., 1.2.3 can be found
5+ //! via 1.0.0 if it's the latest patch for major version 1).
6+
17use derivative:: Derivative ;
28use semver:: Version ;
39use std:: collections:: { BTreeMap , BTreeSet , HashMap } ;
410
11+ /// A map that stores values indexed by semantic versions with support for alternate lookups.
12+ ///
13+ /// The `VersionMap` maintains a primary mapping from versions to values, and a secondary
14+ /// mapping that groups versions by their "alternate" keys for fallback lookups.
15+ ///
16+ /// # Alternate Lookup Logic
17+ ///
18+ /// - For major versions > 0: alternate is `major.0.0`
19+ /// - For minor versions > 0 (when major is 0): alternate is `0.minor.0`
20+ /// - Otherwise: alternate is `0.0.patch`
21+ /// - Pre-release versions have no alternates
22+ ///
23+ /// # Example
24+ ///
25+ /// ```rust
26+ /// use semver::Version;
27+ /// # use wac_trampoline::semver::VersionMap;
28+ ///
29+ /// let mut map = VersionMap::new();
30+ /// map.insert(Version::new(1, 0, 1), "v1.0.1");
31+ /// map.insert(Version::new(1, 2, 0), "v1.2.0");
32+ ///
33+ /// // Exact lookups
34+ /// assert_eq!(map.get_exact(&Version::new(1, 0, 1)), Some(&"v1.0.1"));
35+ ///
36+ /// // Alternate lookups (finds latest patch for major version 1)
37+ /// assert_eq!(map.get(&Version::new(1, 0, 0)), Some(&"v1.2.0"));
38+ /// ```
539#[ derive( Clone , Derivative , Debug ) ]
640#[ derivative( Default ( bound = "" ) ) ]
741pub struct VersionMap < T > {
42+ /// Primary storage mapping versions to values
843 versions : BTreeMap < Version , T > ,
44+ /// Secondary mapping for alternate version lookups
945 alternates : HashMap < Version , BTreeSet < Version > > ,
1046}
1147
1248impl < T > VersionMap < T > {
49+ /// Creates a new empty `VersionMap`.
1350 pub fn new ( ) -> Self {
1451 Self {
1552 versions : BTreeMap :: new ( ) ,
1653 alternates : HashMap :: new ( ) ,
1754 }
1855 }
1956
57+ /// Attempts to insert a version-value pair, returning an error if the version already exists.
2058 pub fn try_insert ( & mut self , version : Version , value : T ) -> Result < ( ) , ( Version , T ) > {
2159 if self . versions . contains_key ( & version) {
2260 return Err ( ( version, value) ) ;
@@ -34,6 +72,7 @@ impl<T> VersionMap<T> {
3472 Ok ( ( ) )
3573 }
3674
75+ /// Insert a version-value pair, returning the old value if it exists.
3776 pub fn insert ( & mut self , version : Version , value : T ) -> Option < T > {
3877 if let Some ( alternate) = version_alternate ( & version) {
3978 self . alternates
@@ -45,6 +84,11 @@ impl<T> VersionMap<T> {
4584 self . versions . insert ( version, value)
4685 }
4786
87+ /// Gets a value by version, using alternate lookup if exact match is not found.
88+ ///
89+ /// This method first tries to find an exact match. If that fails and the version
90+ /// has no build metadata, it attempts to find an alternate version and returns
91+ /// the latest version within that alternate group.
4892 pub fn get ( & self , version : & Version ) -> Option < & T > {
4993 if version. build . is_empty ( ) {
5094 let maybe_value = version_alternate ( version)
@@ -61,18 +105,20 @@ impl<T> VersionMap<T> {
61105 self . get_exact ( version)
62106 }
63107
108+ /// Gets a value by version or returns the latest version if no specific version is provided.
64109 pub fn get_or_latest ( & self , version : Option < & Version > ) -> Option < & T > {
65- if let Some ( version) = version {
66- self . get ( version)
67- } else {
68- self . get_latest ( ) . map ( |( _, value) | value)
110+ match version {
111+ Some ( v) => self . get ( v) ,
112+ None => self . get_latest ( ) . map ( |( _, value) | value) ,
69113 }
70114 }
71115
116+ /// Returns the latest version and its associated value.
72117 pub fn get_latest ( & self ) -> Option < ( & Version , & T ) > {
73118 self . versions . last_key_value ( )
74119 }
75120
121+ /// Gets a value by exact version match only, without alternate lookup.
76122 pub fn get_exact ( & self , version : & Version ) -> Option < & T > {
77123 self . versions . get ( version)
78124 }
@@ -91,7 +137,15 @@ impl<T> VersionMap<T> {
91137 }
92138}
93139
140+ /// Computes the alternate version key for fallback lookups.
141+ ///
142+ /// This function implements the alternate lookup logic:
143+ /// - Pre-release versions return `None` (no alternates)
144+ /// - Major versions > 0: return `major.0.0`
145+ /// - Minor versions > 0 (when major is 0): return `0.minor.0`
146+ /// - Otherwise: return `0.0.patch`
94147fn version_alternate ( version : & Version ) -> Option < Version > {
148+ // Pre-release versions don't have alternates
95149 if !version. pre . is_empty ( ) {
96150 None
97151 } else if version. major > 0 {
0 commit comments