Skip to main content

resolvo/
id.rs

1//! Public ID types used by dependency providers, snapshots, and diagnostics.
2
3use std::num::{NonZero, NonZeroU32};
4
5use crate::solver_id::DenseId;
6
7/// A dense zero-based ID that can be transformed to and from a `usize` index.
8///
9/// This is primarily used by dense storage such as [`crate::Mapping`] and the
10/// default pool-backed IDs. Sparse provider IDs should implement
11/// [`crate::SolverId`] without implementing this trait.
12pub trait DenseIndex {
13    /// Constructs a new ID from a zero-based index.
14    fn from_index(x: usize) -> Self;
15
16    /// Returns the zero-based index of the ID.
17    fn to_index(self) -> usize;
18}
19
20/// The id associated to a package name.
21pub type NameId = DenseId<NameTag>;
22
23/// Domain tag for [`NameId`].
24pub enum NameTag {}
25
26/// The id associated with a generic string.
27#[repr(transparent)]
28#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Ord, PartialOrd)]
29#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
30#[cfg_attr(feature = "serde", serde(transparent))]
31pub struct StringId(pub u32);
32
33impl DenseIndex for StringId {
34    fn from_index(x: usize) -> Self {
35        Self(x as u32)
36    }
37
38    fn to_index(self) -> usize {
39        self.0 as usize
40    }
41}
42
43/// The id associated with a version set.
44#[repr(transparent)]
45#[derive(Clone, Default, Copy, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
46#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
47#[cfg_attr(feature = "serde", serde(transparent))]
48pub struct VersionSetId(pub u32);
49
50impl DenseIndex for VersionSetId {
51    fn from_index(x: usize) -> Self {
52        Self(x as u32)
53    }
54
55    fn to_index(self) -> usize {
56        self.0 as usize
57    }
58}
59
60/// The id associated with a condition.
61#[repr(transparent)]
62#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
63#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
64#[cfg_attr(feature = "serde", serde(transparent))]
65pub struct ConditionId(NonZero<u32>);
66
67impl ConditionId {
68    /// Creates a new [`ConditionId`] from a `u32`.
69    pub fn new(id: u32) -> Self {
70        Self::from_index(id as usize)
71    }
72
73    /// Returns the inner `u32` value of the [`ConditionId`].
74    pub fn as_u32(self) -> u32 {
75        self.0.get() - 1
76    }
77}
78
79impl DenseIndex for ConditionId {
80    fn from_index(x: usize) -> Self {
81        let id = (x + 1).try_into().expect("condition id too big");
82        Self(unsafe { NonZero::new_unchecked(id) })
83    }
84
85    fn to_index(self) -> usize {
86        (self.0.get() - 1) as usize
87    }
88}
89
90/// The id associated with a union (logical OR) of two or more version sets.
91#[repr(transparent)]
92#[derive(Clone, Default, Copy, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
93#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
94#[cfg_attr(feature = "serde", serde(transparent))]
95pub struct VersionSetUnionId(pub u32);
96
97impl DenseIndex for VersionSetUnionId {
98    fn from_index(x: usize) -> Self {
99        Self(x as u32)
100    }
101
102    fn to_index(self) -> usize {
103        self.0 as usize
104    }
105}
106
107/// The id associated to a solvable.
108pub type SolvableId = DenseId<SolvableTag>;
109
110/// Domain tag for [`SolvableId`].
111pub enum SolvableTag {}
112
113/// A unique identifier for a variable in the solver.
114///
115/// Uses a non-zero representation so that `Option<VariableId>` is the same
116/// size as `VariableId`.
117#[repr(transparent)]
118#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord)]
119pub struct VariableId(NonZeroU32);
120
121impl VariableId {
122    const ROOT_ID: u32 = 1;
123
124    /// Returns the variable id representing the root of the decision tree.
125    pub fn root() -> Self {
126        // SAFETY: 1 is non-zero.
127        Self(unsafe { NonZeroU32::new_unchecked(Self::ROOT_ID) })
128    }
129
130    /// Returns `true` if this variable represents the root.
131    pub fn is_root(self) -> bool {
132        self.0.get() == Self::ROOT_ID
133    }
134}
135
136impl DenseIndex for VariableId {
137    #[inline]
138    fn from_index(x: usize) -> Self {
139        let raw: u32 = (x + Self::ROOT_ID as usize)
140            .try_into()
141            .expect("variable id too big");
142        // SAFETY: `raw` is `x + 1`, hence at least 1, hence non-zero.
143        Self(unsafe { NonZeroU32::new_unchecked(raw) })
144    }
145
146    #[inline]
147    fn to_index(self) -> usize {
148        (self.0.get() - Self::ROOT_ID) as usize
149    }
150}