|  | 
|  | 1 | +use std::fmt::{self, Display}; | 
|  | 2 | +use std::iter::repeat_n; | 
|  | 3 | +use std::num::NonZeroU64; | 
|  | 4 | +use std::rc::Rc; | 
|  | 5 | + | 
|  | 6 | +use crate::experimental::{VersionIndex, VersionSet}; | 
|  | 7 | + | 
|  | 8 | +/// Package allowing more than 63 versions | 
|  | 9 | +#[derive(Debug, Clone, Eq, PartialEq, Hash)] | 
|  | 10 | +pub struct Pkg<P> { | 
|  | 11 | +    pkg: P, | 
|  | 12 | +    quotient: u64, | 
|  | 13 | +    count: u64, | 
|  | 14 | +} | 
|  | 15 | + | 
|  | 16 | +impl<P> Pkg<P> { | 
|  | 17 | +    pub fn pkg(&self) -> &P { | 
|  | 18 | +        &self.pkg | 
|  | 19 | +    } | 
|  | 20 | +} | 
|  | 21 | + | 
|  | 22 | +impl<P: Display> Display for Pkg<P> { | 
|  | 23 | +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 
|  | 24 | +        write!(f, "{} (q={})", self.pkg, self.quotient) | 
|  | 25 | +    } | 
|  | 26 | +} | 
|  | 27 | + | 
|  | 28 | +/// Virtual package ensuring package unicity | 
|  | 29 | +#[derive(Debug, Clone, Eq, PartialEq, Hash)] | 
|  | 30 | +pub struct VirtualPkg<P> { | 
|  | 31 | +    pkg: P, | 
|  | 32 | +    quotient: u64, | 
|  | 33 | +    count: u64, | 
|  | 34 | +} | 
|  | 35 | + | 
|  | 36 | +impl<P> VirtualPkg<P> { | 
|  | 37 | +    pub fn pkg(&self) -> &P { | 
|  | 38 | +        &self.pkg | 
|  | 39 | +    } | 
|  | 40 | +} | 
|  | 41 | + | 
|  | 42 | +impl<P: Display> Display for VirtualPkg<P> { | 
|  | 43 | +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 
|  | 44 | +        write!( | 
|  | 45 | +            f, | 
|  | 46 | +            "VirtualPkg({}, q={}, c={})", | 
|  | 47 | +            self.pkg, self.quotient, self.count | 
|  | 48 | +        ) | 
|  | 49 | +    } | 
|  | 50 | +} | 
|  | 51 | + | 
|  | 52 | +/// Virtual package dependency allowing more than 63 versions | 
|  | 53 | +#[derive(Debug, Clone, Eq, PartialEq, Hash)] | 
|  | 54 | +pub struct VirtualDep<P> { | 
|  | 55 | +    pkg: P, | 
|  | 56 | +    version_indices: Rc<[VersionSet]>, | 
|  | 57 | +    offset: u64, | 
|  | 58 | +    quotient: u64, | 
|  | 59 | +} | 
|  | 60 | + | 
|  | 61 | +impl<P> VirtualDep<P> { | 
|  | 62 | +    pub fn pkg(&self) -> &P { | 
|  | 63 | +        &self.pkg | 
|  | 64 | +    } | 
|  | 65 | +} | 
|  | 66 | + | 
|  | 67 | +impl<P: Display> Display for VirtualDep<P> { | 
|  | 68 | +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 
|  | 69 | +        let vc = self | 
|  | 70 | +            .version_indices | 
|  | 71 | +            .iter() | 
|  | 72 | +            .map(|vs| vs.count()) | 
|  | 73 | +            .sum::<usize>(); | 
|  | 74 | + | 
|  | 75 | +        write!( | 
|  | 76 | +            f, | 
|  | 77 | +            "VirtualDep({}, vc={vc}, o={}, q={})", | 
|  | 78 | +            self.pkg, self.offset, self.quotient | 
|  | 79 | +        ) | 
|  | 80 | +    } | 
|  | 81 | +} | 
|  | 82 | + | 
|  | 83 | +/// Package wrapper used to allow more than 63 versions per package. | 
|  | 84 | +#[derive(Debug, Clone, Eq, PartialEq, Hash)] | 
|  | 85 | +pub enum PackageVersionWrapper<P: Clone + Display> { | 
|  | 86 | +    /// Package allowing more than 63 versions | 
|  | 87 | +    Pkg(Pkg<P>), | 
|  | 88 | +    /// Virtual package ensuring package unicity | 
|  | 89 | +    VirtualPkg(VirtualPkg<P>), | 
|  | 90 | +    /// Virtual package dependency allowing more than 63 versions | 
|  | 91 | +    VirtualDep(VirtualDep<P>), | 
|  | 92 | +} | 
|  | 93 | + | 
|  | 94 | +impl<P: Clone + Display> Display for PackageVersionWrapper<P> { | 
|  | 95 | +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 
|  | 96 | +        match self { | 
|  | 97 | +            Self::Pkg(p) => p.fmt(f), | 
|  | 98 | +            Self::VirtualPkg(vp) => vp.fmt(f), | 
|  | 99 | +            Self::VirtualDep(vd) => vd.fmt(f), | 
|  | 100 | +        } | 
|  | 101 | +    } | 
|  | 102 | +} | 
|  | 103 | + | 
|  | 104 | +impl<P: Clone + Display> PackageVersionWrapper<P> { | 
|  | 105 | +    /// Create a new package. | 
|  | 106 | +    pub fn new_pkg( | 
|  | 107 | +        pkg: P, | 
|  | 108 | +        true_version_index: u64, | 
|  | 109 | +        version_count: NonZeroU64, | 
|  | 110 | +    ) -> (Self, VersionIndex) { | 
|  | 111 | +        ( | 
|  | 112 | +            Self::Pkg(Pkg { | 
|  | 113 | +                pkg, | 
|  | 114 | +                quotient: true_version_index / VersionIndex::MAX, | 
|  | 115 | +                count: (version_count.get() - 1) / VersionIndex::MAX, | 
|  | 116 | +            }), | 
|  | 117 | +            VersionIndex::new((true_version_index % VersionIndex::MAX) as u8).unwrap(), | 
|  | 118 | +        ) | 
|  | 119 | +    } | 
|  | 120 | + | 
|  | 121 | +    /// Create a new package dependency with no versions. | 
|  | 122 | +    pub fn new_empty_dep(pkg: P) -> (Self, VersionSet) { | 
|  | 123 | +        ( | 
|  | 124 | +            Self::Pkg(Pkg { | 
|  | 125 | +                pkg, | 
|  | 126 | +                quotient: 0, | 
|  | 127 | +                count: 0, | 
|  | 128 | +            }), | 
|  | 129 | +            VersionSet::empty(), | 
|  | 130 | +        ) | 
|  | 131 | +    } | 
|  | 132 | + | 
|  | 133 | +    /// Create a new package dependency at the specified version. | 
|  | 134 | +    pub fn new_singleton_dep( | 
|  | 135 | +        pkg: P, | 
|  | 136 | +        true_version_index: u64, | 
|  | 137 | +        version_count: u64, | 
|  | 138 | +    ) -> (Self, VersionSet) { | 
|  | 139 | +        match NonZeroU64::new(version_count) { | 
|  | 140 | +            Some(version_count) => { | 
|  | 141 | +                assert!(true_version_index < version_count.get()); | 
|  | 142 | +                let (this, v) = Self::new_pkg(pkg, true_version_index, version_count); | 
|  | 143 | +                (this, VersionSet::singleton(v)) | 
|  | 144 | +            } | 
|  | 145 | +            None => Self::new_empty_dep(pkg), | 
|  | 146 | +        } | 
|  | 147 | +    } | 
|  | 148 | + | 
|  | 149 | +    /// Create a new package dependency at the specified versions. | 
|  | 150 | +    pub fn new_dep( | 
|  | 151 | +        pkg: P, | 
|  | 152 | +        true_version_indices: impl IntoIterator<Item = u64>, | 
|  | 153 | +        version_count: u64, | 
|  | 154 | +    ) -> (Self, VersionSet) { | 
|  | 155 | +        let Some(nz_version_count) = NonZeroU64::new(version_count) else { | 
|  | 156 | +            return Self::new_empty_dep(pkg); | 
|  | 157 | +        }; | 
|  | 158 | +        if version_count <= VersionIndex::MAX { | 
|  | 159 | +            let mut set = VersionSet::empty(); | 
|  | 160 | +            for true_version_index in true_version_indices { | 
|  | 161 | +                assert!(true_version_index < version_count); | 
|  | 162 | +                let v = VersionIndex::new(true_version_index as u8).unwrap(); | 
|  | 163 | +                set = set.union(VersionSet::singleton(v)); | 
|  | 164 | +            } | 
|  | 165 | +            return ( | 
|  | 166 | +                Self::Pkg(Pkg { | 
|  | 167 | +                    pkg, | 
|  | 168 | +                    quotient: 0, | 
|  | 169 | +                    count: (version_count - 1) / VersionIndex::MAX, | 
|  | 170 | +                }), | 
|  | 171 | +                set, | 
|  | 172 | +            ); | 
|  | 173 | +        } | 
|  | 174 | + | 
|  | 175 | +        let mut true_version_indices = true_version_indices.into_iter(); | 
|  | 176 | + | 
|  | 177 | +        let Some(first) = true_version_indices.next() else { | 
|  | 178 | +            return Self::new_empty_dep(pkg); | 
|  | 179 | +        }; | 
|  | 180 | +        assert!(first < version_count); | 
|  | 181 | + | 
|  | 182 | +        let Some(second) = true_version_indices.next() else { | 
|  | 183 | +            let (d, vs) = Self::new_pkg(pkg, first, nz_version_count); | 
|  | 184 | +            return (d, VersionSet::singleton(vs)); | 
|  | 185 | +        }; | 
|  | 186 | +        assert!(second < version_count); | 
|  | 187 | + | 
|  | 188 | +        let mut version_indices = Rc::from_iter(repeat_n( | 
|  | 189 | +            VersionSet::empty(), | 
|  | 190 | +            (1 + (version_count - 1) / VersionIndex::MAX) as usize, | 
|  | 191 | +        )); | 
|  | 192 | +        let versions_slice = Rc::make_mut(&mut version_indices); | 
|  | 193 | + | 
|  | 194 | +        for true_version_index in [first, second].into_iter().chain(true_version_indices) { | 
|  | 195 | +            assert!(true_version_index < version_count); | 
|  | 196 | +            let index = (true_version_index / VersionIndex::MAX) as usize; | 
|  | 197 | +            let v = VersionIndex::new((true_version_index % VersionIndex::MAX) as u8).unwrap(); | 
|  | 198 | +            let set = versions_slice.get_mut(index).unwrap(); | 
|  | 199 | +            *set = set.union(VersionSet::singleton(v)); | 
|  | 200 | +        } | 
|  | 201 | + | 
|  | 202 | +        let offset = 0; | 
|  | 203 | +        let quotient = VersionIndex::MAX.pow(version_count.ilog(VersionIndex::MAX) - 1); | 
|  | 204 | +        let version_set = Self::dep_version_set(&version_indices, offset, quotient); | 
|  | 205 | + | 
|  | 206 | +        let this = Self::VirtualDep(VirtualDep { | 
|  | 207 | +            pkg, | 
|  | 208 | +            version_indices, | 
|  | 209 | +            offset, | 
|  | 210 | +            quotient, | 
|  | 211 | +        }); | 
|  | 212 | + | 
|  | 213 | +        (this, version_set) | 
|  | 214 | +    } | 
|  | 215 | + | 
|  | 216 | +    /// Clone and replace the package of this wrapper. | 
|  | 217 | +    pub fn replace_pkg<T: Clone + Display>(&self, new_pkg: T) -> PackageVersionWrapper<T> { | 
|  | 218 | +        match *self { | 
|  | 219 | +            Self::Pkg(Pkg { | 
|  | 220 | +                pkg: _, | 
|  | 221 | +                quotient, | 
|  | 222 | +                count, | 
|  | 223 | +            }) => PackageVersionWrapper::Pkg(Pkg { | 
|  | 224 | +                pkg: new_pkg, | 
|  | 225 | +                quotient, | 
|  | 226 | +                count, | 
|  | 227 | +            }), | 
|  | 228 | +            Self::VirtualPkg(VirtualPkg { | 
|  | 229 | +                pkg: _, | 
|  | 230 | +                quotient, | 
|  | 231 | +                count, | 
|  | 232 | +            }) => PackageVersionWrapper::VirtualPkg(VirtualPkg { | 
|  | 233 | +                pkg: new_pkg, | 
|  | 234 | +                quotient, | 
|  | 235 | +                count, | 
|  | 236 | +            }), | 
|  | 237 | +            Self::VirtualDep(VirtualDep { | 
|  | 238 | +                pkg: _, | 
|  | 239 | +                ref version_indices, | 
|  | 240 | +                offset, | 
|  | 241 | +                quotient, | 
|  | 242 | +            }) => PackageVersionWrapper::VirtualDep(VirtualDep { | 
|  | 243 | +                pkg: new_pkg, | 
|  | 244 | +                version_indices: version_indices.clone(), | 
|  | 245 | +                offset, | 
|  | 246 | +                quotient, | 
|  | 247 | +            }), | 
|  | 248 | +        } | 
|  | 249 | +    } | 
|  | 250 | + | 
|  | 251 | +    /// Get the inner package if existing. | 
|  | 252 | +    pub fn inner_pkg(&self) -> Option<&P> { | 
|  | 253 | +        match self { | 
|  | 254 | +            Self::Pkg(Pkg { pkg, .. }) => Some(pkg), | 
|  | 255 | +            _ => None, | 
|  | 256 | +        } | 
|  | 257 | +    } | 
|  | 258 | + | 
|  | 259 | +    /// Get the inner package if existing. | 
|  | 260 | +    pub fn inner(&self, version_index: VersionIndex) -> Option<(&P, u64)> { | 
|  | 261 | +        match self { | 
|  | 262 | +            Self::Pkg(Pkg { pkg, quotient, .. }) => Some(( | 
|  | 263 | +                pkg, | 
|  | 264 | +                quotient * VersionIndex::MAX + version_index.get() as u64, | 
|  | 265 | +            )), | 
|  | 266 | +            _ => None, | 
|  | 267 | +        } | 
|  | 268 | +    } | 
|  | 269 | + | 
|  | 270 | +    /// Get the inner package if existing. | 
|  | 271 | +    pub fn into_inner(self, version_index: VersionIndex) -> Option<(P, u64)> { | 
|  | 272 | +        match self { | 
|  | 273 | +            Self::Pkg(Pkg { pkg, quotient, .. }) => Some(( | 
|  | 274 | +                pkg, | 
|  | 275 | +                quotient * VersionIndex::MAX + version_index.get() as u64, | 
|  | 276 | +            )), | 
|  | 277 | +            _ => None, | 
|  | 278 | +        } | 
|  | 279 | +    } | 
|  | 280 | + | 
|  | 281 | +    /// Get the wrapper virtual dependency if existing. | 
|  | 282 | +    pub fn dependency(&self, version_index: VersionIndex) -> Option<(Self, VersionSet)> { | 
|  | 283 | +        match *self { | 
|  | 284 | +            Self::Pkg(Pkg { | 
|  | 285 | +                ref pkg, | 
|  | 286 | +                quotient, | 
|  | 287 | +                count, | 
|  | 288 | +            }) | 
|  | 289 | +            | Self::VirtualPkg(VirtualPkg { | 
|  | 290 | +                ref pkg, | 
|  | 291 | +                quotient, | 
|  | 292 | +                count, | 
|  | 293 | +            }) => { | 
|  | 294 | +                if count == 0 { | 
|  | 295 | +                    None | 
|  | 296 | +                } else { | 
|  | 297 | +                    Some(( | 
|  | 298 | +                        Self::VirtualPkg(VirtualPkg { | 
|  | 299 | +                            pkg: pkg.clone(), | 
|  | 300 | +                            quotient: quotient / VersionIndex::MAX, | 
|  | 301 | +                            count: count / VersionIndex::MAX, | 
|  | 302 | +                        }), | 
|  | 303 | +                        VersionSet::singleton( | 
|  | 304 | +                            VersionIndex::new((quotient % VersionIndex::MAX) as u8).unwrap(), | 
|  | 305 | +                        ), | 
|  | 306 | +                    )) | 
|  | 307 | +                } | 
|  | 308 | +            } | 
|  | 309 | +            Self::VirtualDep(VirtualDep { | 
|  | 310 | +                ref pkg, | 
|  | 311 | +                ref version_indices, | 
|  | 312 | +                offset, | 
|  | 313 | +                quotient, | 
|  | 314 | +            }) => { | 
|  | 315 | +                let offset = offset + version_index.get() as u64 * quotient; | 
|  | 316 | +                if quotient == 1 { | 
|  | 317 | +                    return Some(( | 
|  | 318 | +                        Self::Pkg(Pkg { | 
|  | 319 | +                            pkg: pkg.clone(), | 
|  | 320 | +                            quotient: offset, | 
|  | 321 | +                            count: (version_indices.len() - 1) as u64, | 
|  | 322 | +                        }), | 
|  | 323 | +                        version_indices[offset as usize], | 
|  | 324 | +                    )); | 
|  | 325 | +                } | 
|  | 326 | +                let quotient = quotient / VersionIndex::MAX; | 
|  | 327 | +                let version_set = Self::dep_version_set(version_indices, offset, quotient); | 
|  | 328 | + | 
|  | 329 | +                let this = Self::VirtualDep(VirtualDep { | 
|  | 330 | +                    pkg: pkg.clone(), | 
|  | 331 | +                    version_indices: version_indices.clone(), | 
|  | 332 | +                    offset, | 
|  | 333 | +                    quotient, | 
|  | 334 | +                }); | 
|  | 335 | + | 
|  | 336 | +                Some((this, version_set)) | 
|  | 337 | +            } | 
|  | 338 | +        } | 
|  | 339 | +    } | 
|  | 340 | + | 
|  | 341 | +    fn dep_version_set(sets: &[VersionSet], offset: u64, quotient: u64) -> VersionSet { | 
|  | 342 | +        sets[offset as usize..] | 
|  | 343 | +            .chunks(quotient as usize) | 
|  | 344 | +            .take(VersionIndex::MAX as usize) | 
|  | 345 | +            .enumerate() | 
|  | 346 | +            .filter(|&(_, sets)| sets.iter().any(|&vs| vs != VersionSet::empty())) | 
|  | 347 | +            .map(|(i, _)| VersionSet::singleton(VersionIndex::new(i as u8).unwrap())) | 
|  | 348 | +            .fold(VersionSet::empty(), |acc, vs| acc.union(vs)) | 
|  | 349 | +    } | 
|  | 350 | +} | 
0 commit comments