1use derivative::Derivative;
11use semver::Version;
12use std::borrow::Borrow;
13use std::collections::{BTreeMap, BTreeSet, HashMap};
14use std::io::{Read, Write};
15
16#[derive(Clone, Derivative, Debug)]
45#[derivative(Default(bound = ""))]
46pub struct VersionMap<T> {
47 versions: BTreeMap<WrappedVersion, T>,
49 alternates: HashMap<Version, BTreeSet<WrappedVersion>>,
51}
52
53impl<T> VersionMap<T> {
54 pub fn new() -> Self {
56 Self {
57 versions: BTreeMap::new(),
58 alternates: HashMap::new(),
59 }
60 }
61
62 fn from_versions(versions: BTreeMap<WrappedVersion, T>) -> Self {
63 let mut alternates: HashMap<Version, BTreeSet<WrappedVersion>> = HashMap::new();
64
65 for (version, _) in &versions {
66 if let Some(alternate) = version_alternate(&version.inner) {
67 alternates
68 .entry(alternate)
69 .or_default()
70 .insert(version.clone());
71 }
72 }
73
74 Self {
75 versions,
76 alternates,
77 }
78 }
79
80 pub fn try_insert(&mut self, version: Version, value: T) -> Result<(), (Version, T)> {
82 let version: WrappedVersion = version.into();
83
84 if self.versions.contains_key(&version) {
85 return Err((version.into(), value));
86 }
87
88 if let Some(alternate) = version_alternate(&version.inner) {
89 self.alternates
90 .entry(alternate)
91 .or_default()
92 .insert(version.clone());
93 }
94
95 self.versions.insert(version, value);
96
97 Ok(())
98 }
99
100 pub fn insert(&mut self, version: Version, value: T) -> Option<T> {
104 let version: WrappedVersion = version.into();
105
106 if let Some(alternate) = version_alternate(&version.inner) {
107 self.alternates
108 .entry(alternate)
109 .or_default()
110 .insert(version.clone());
111 }
112
113 self.versions.insert(version, value)
114 }
115
116 pub fn get(&self, version: &Version) -> Option<&T> {
137 if version.build.is_empty() {
138 let maybe_value = version_alternate(version)
139 .as_ref()
140 .and_then(|alternate| self.alternates.get(alternate))
141 .and_then(|version_set| version_set.last())
142 .and_then(|version| self.versions.get(version));
143
144 if maybe_value.is_some() {
145 return maybe_value;
146 }
147 }
148
149 self.versions.get(version)
150 }
151
152 pub fn get_version(&self, version: &Version) -> Option<(&Version, &T)> {
174 if version.build.is_empty() {
175 let maybe_key_value = version_alternate(version)
176 .as_ref()
177 .and_then(|alternate| self.alternates.get(alternate))
178 .and_then(|version_set| version_set.last())
179 .and_then(|version| self.versions.get_key_value(version));
180
181 if maybe_key_value.is_some() {
182 return maybe_key_value.map(|(k, v)| (k.borrow(), v));
183 }
184 }
185
186 self.versions
187 .get_key_value(version)
188 .map(|(k, v)| (k.borrow(), v))
189 }
190
191 pub fn get_or_latest(&self, version: Option<&Version>) -> Option<&T> {
220 match version {
221 Some(v) => self.get(v),
222 None => self.get_latest().map(|(_, value)| value),
223 }
224 }
225
226 pub fn get_or_latest_version(&self, version: Option<&Version>) -> Option<(&Version, &T)> {
256 match version {
257 Some(v) => self.get_version(v),
258 None => self.get_latest(),
259 }
260 }
261
262 pub fn get_latest(&self) -> Option<(&Version, &T)> {
264 self.versions.last_key_value().map(|(k, v)| (k.borrow(), v))
265 }
266
267 pub fn get_exact(&self, version: &Version) -> Option<&T> {
269 self.versions.get(version)
270 }
271
272 pub fn remove(&mut self, version: &Version) -> Option<T> {
273 if let Some(alternate) = version_alternate(version) {
274 if let Some(set) = self.alternates.get_mut(&alternate) {
275 set.remove(version);
276 if set.is_empty() {
277 self.alternates.remove(&alternate);
278 }
279 }
280 }
281
282 self.versions.remove(version)
283 }
284}
285
286#[cfg(feature = "borsh")]
287impl<T: borsh::BorshSerialize> borsh::BorshSerialize for VersionMap<T> {
288 fn serialize<W: Write>(&self, writer: &mut W) -> std::io::Result<()> {
289 self.versions.serialize(writer)
290 }
291}
292
293#[cfg(feature = "borsh")]
294impl<T: borsh::BorshDeserialize> borsh::BorshDeserialize for VersionMap<T> {
295 fn deserialize_reader<R: Read>(reader: &mut R) -> std::io::Result<Self> {
296 let versions: BTreeMap<WrappedVersion, T> =
297 borsh::BorshDeserialize::deserialize_reader(reader)?;
298 Ok(Self::from_versions(versions))
299 }
300}
301
302#[cfg(feature = "serde")]
303impl<T: serde::Serialize> serde::Serialize for VersionMap<T> {
304 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
305 where
306 S: serde::Serializer,
307 {
308 self.versions.serialize(serializer)
309 }
310}
311
312#[cfg(feature = "serde")]
313impl<'de, T: serde::Deserialize<'de>> serde::Deserialize<'de> for VersionMap<T> {
314 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
315 where
316 D: serde::Deserializer<'de>,
317 {
318 let versions: BTreeMap<WrappedVersion, T> = serde::Deserialize::deserialize(deserializer)?;
319 Ok(Self::from_versions(versions))
320 }
321}
322
323fn version_alternate(version: &Version) -> Option<Version> {
331 if !version.pre.is_empty() {
333 None
334 } else if version.major > 0 {
335 Some(Version::new(version.major, 0, 0))
336 } else if version.minor > 0 {
337 Some(Version::new(0, version.minor, 0))
338 } else {
339 Some(Version::new(0, 0, version.patch))
340 }
341}
342
343#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
344#[repr(transparent)]
345struct WrappedVersion {
346 inner: Version,
347}
348
349impl Borrow<Version> for WrappedVersion {
350 fn borrow(&self) -> &Version {
351 &self.inner
352 }
353}
354
355impl From<Version> for WrappedVersion {
356 fn from(version: Version) -> Self {
357 Self { inner: version }
358 }
359}
360
361impl From<WrappedVersion> for Version {
362 fn from(wrapped: WrappedVersion) -> Self {
363 wrapped.inner
364 }
365}
366
367#[cfg(feature = "borsh")]
368impl borsh::BorshSerialize for WrappedVersion {
369 fn serialize<W: Write>(&self, writer: &mut W) -> std::io::Result<()> {
370 let s = self.inner.to_string();
371 borsh::BorshSerialize::serialize(&s, writer)
372 }
373}
374
375#[cfg(feature = "borsh")]
376impl borsh::BorshDeserialize for WrappedVersion {
377 fn deserialize_reader<R: Read>(reader: &mut R) -> std::io::Result<Self> {
378 let s: String = borsh::BorshDeserialize::deserialize_reader(reader)?;
379
380 let version = Version::parse(&s).map_err(|_| {
381 std::io::Error::new(
382 std::io::ErrorKind::InvalidData,
383 "Failed to parse version from string",
384 )
385 })?;
386
387 Ok(Self { inner: version })
388 }
389}
390
391#[cfg(feature = "serde")]
392impl serde::Serialize for WrappedVersion {
393 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
394 where
395 S: serde::Serializer,
396 {
397 self.inner.serialize(serializer)
398 }
399}
400
401#[cfg(feature = "serde")]
402impl<'de> serde::Deserialize<'de> for WrappedVersion {
403 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
404 where
405 D: serde::Deserializer<'de>,
406 {
407 Ok(Self {
408 inner: serde::Deserialize::deserialize(deserializer)?,
409 })
410 }
411}
412
413#[cfg(test)]
414mod tests {
415 use super::*;
416 use semver::Version;
417
418 #[test]
419 fn test_version_map_basic_operations() {
420 let mut map = VersionMap::new();
421
422 let version0 = Version::new(0, 4, 2);
423 let version1 = Version::new(1, 0, 0);
424 let version2 = Version::new(1, 0, 1);
425 let version3 = Version::new(2, 0, 0);
426
427 assert!(map.try_insert(version0.clone(), "value0").is_ok());
429 assert!(map.try_insert(version1.clone(), "value1").is_ok());
430 assert!(map.try_insert(version2.clone(), "value2").is_ok());
431 assert!(map.try_insert(version3.clone(), "value3").is_ok());
432
433 assert!(map.try_insert(version1.clone(), "duplicate").is_err());
435 }
436
437 #[test]
438 fn test_version_map_alternate_zero() {
439 let mut map = VersionMap::new();
440
441 let version0 = Version::new(0, 0, 3);
442 let version1 = Version::new(0, 3, 3);
443
444 map.try_insert(version0.clone(), "value0").unwrap();
445 map.try_insert(version1.clone(), "value1").unwrap();
446
447 assert_eq!(map.get_version(&Version::new(0, 0, 1)), None);
448
449 assert_eq!(
450 map.get_version(&Version::new(0, 0, 3)),
451 Some((&version0, &"value0"))
452 );
453
454 assert_eq!(
455 map.get_version(&Version::new(0, 3, 0)),
456 Some((&version1, &"value1"))
457 );
458 }
459
460 #[test]
461 fn test_version_map_alternate_lookups() {
462 let mut map = VersionMap::new();
463
464 let version0 = Version::new(0, 4, 2);
465 let version1 = Version::new(1, 0, 0);
466 let version2 = Version::new(1, 0, 1);
467 let version3 = Version::new(2, 0, 0);
468
469 map.try_insert(version0.clone(), "value0").unwrap();
470 map.try_insert(version1.clone(), "value1").unwrap();
471 map.try_insert(version2.clone(), "value2").unwrap();
472 map.try_insert(version3.clone(), "value3").unwrap();
473
474 assert_eq!(map.get(&version0), Some(&"value0"));
476 assert_eq!(map.get(&version2), Some(&"value2"));
477 assert_eq!(map.get(&version3), Some(&"value3"));
478
479 assert_eq!(map.get(&version1), Some(&"value2")); assert_eq!(map.get(&Version::new(0, 4, 1)), Some(&"value0")); assert_eq!(map.get(&Version::new(1, 1, 0)), Some(&"value2")); assert_eq!(map.get(&Version::new(2, 0, 4)), Some(&"value3")); assert_eq!(map.get_version(&version1), Some((&version2, &"value2"))); assert_eq!(
488 map.get_version(&Version::new(0, 4, 1)),
489 Some((&version0, &"value0"))
490 ); assert_eq!(
492 map.get_version(&Version::new(1, 1, 0)),
493 Some((&version2, &"value2"))
494 ); assert_eq!(
496 map.get_version(&Version::new(2, 0, 4)),
497 Some((&version3, &"value3"))
498 ); assert_eq!(map.get(&Version::new(0, 1, 0)), None);
502 assert_eq!(map.get(&Version::new(3, 0, 0)), None);
503
504 assert_eq!(map.get_exact(&version1), Some(&"value1"));
506 assert_eq!(map.get_exact(&Version::new(1, 1, 0)), None); }
508
509 #[test]
510 fn test_version_map_latest_operations() {
511 let mut map = VersionMap::new();
512
513 assert_eq!(map.get_latest(), None);
514 assert_eq!(map.get_or_latest(None), None);
515
516 map.insert(Version::new(1, 0, 0), "v1.0.0");
517 map.insert(Version::new(2, 0, 0), "v2.0.0");
518 map.insert(Version::new(0, 1, 0), "v0.1.0");
519
520 assert_eq!(map.get_latest(), Some((&Version::new(2, 0, 0), &"v2.0.0")));
521 assert_eq!(map.get_or_latest(None), Some(&"v2.0.0"));
522 assert_eq!(
523 map.get_or_latest(Some(&Version::new(1, 0, 0))),
524 Some(&"v1.0.0")
525 );
526 }
527
528 #[test]
529 fn test_version_map_insert_and_removal() {
530 let mut map = VersionMap::new();
531
532 let v1 = Version::new(1, 0, 0);
533 let v2 = Version::new(1, 0, 1);
534
535 map.insert(v1.clone(), "v1");
536 map.insert(v2.clone(), "v2");
537
538 assert_eq!(map.remove(&v1), Some("v1"));
539 assert_eq!(map.remove(&v1), None); }
541
542 #[test]
543 fn test_version_alternate_function() {
544 let pre = Version::parse("1.0.0-alpha").unwrap();
546 assert_eq!(version_alternate(&pre), None);
547
548 assert_eq!(
550 version_alternate(&Version::new(1, 2, 3)),
551 Some(Version::new(1, 0, 0))
552 );
553 assert_eq!(
554 version_alternate(&Version::new(2, 5, 1)),
555 Some(Version::new(2, 0, 0))
556 );
557
558 assert_eq!(
560 version_alternate(&Version::new(0, 1, 5)),
561 Some(Version::new(0, 1, 0))
562 );
563 assert_eq!(
564 version_alternate(&Version::new(0, 3, 2)),
565 Some(Version::new(0, 3, 0))
566 );
567
568 assert_eq!(
570 version_alternate(&Version::new(0, 0, 1)),
571 Some(Version::new(0, 0, 1))
572 );
573 assert_eq!(
574 version_alternate(&Version::new(0, 0, 5)),
575 Some(Version::new(0, 0, 5))
576 );
577 }
578
579 #[test]
580 #[cfg(feature = "borsh")]
581 fn test_borsh_serialize_deserialize() {
582 use borsh::{BorshDeserialize, BorshSerialize};
583
584 let mut map = VersionMap::new();
585 map.insert(Version::new(1, 0, 0), "v1.0.0");
586 map.insert(Version::new(2, 0, 0), "v2.0.0");
587
588 let mut buffer = Vec::new();
590 map.serialize(&mut buffer).unwrap();
591
592 let deserialized_map: VersionMap<String> =
594 BorshDeserialize::deserialize_reader(&mut &buffer[..]).unwrap();
595
596 assert_eq!(
597 deserialized_map.get(&Version::new(1, 0, 0)),
598 Some(&"v1.0.0".to_string())
599 );
600
601 assert_eq!(
602 deserialized_map.get(&Version::new(2, 0, 0)),
603 Some(&"v2.0.0".to_string())
604 );
605 }
606
607 #[test]
608 #[cfg(feature = "serde")]
609 fn test_serde_serialize_deserialize() {
610 let mut map = VersionMap::new();
611 map.insert(Version::new(1, 0, 0), "v1.0.0");
612 map.insert(Version::new(2, 0, 0), "v2.0.0");
613
614 let serialized = serde_json::to_string(&map).unwrap();
616
617 let deserialized_map: VersionMap<String> = serde_json::from_str(&serialized).unwrap();
619
620 assert_eq!(
621 deserialized_map.get(&Version::new(1, 0, 0)),
622 Some(&"v1.0.0".to_string())
623 );
624
625 assert_eq!(
626 deserialized_map.get(&Version::new(2, 0, 0)),
627 Some(&"v2.0.0".to_string())
628 );
629 }
630}