Repository: typst/typst
File: crates/typst-kit/src/package.rs (Rust)

Code before:
            Err(err) => {
                return Err(PackageError::NetworkFailed(Some(eco_format!("{err}"))))
            }
        };

        let decompressed = flate2::read::GzDecoder::new(data.as_slice());
        tar::Archive::new(decompressed).unpack(package_dir).map_err(|err| {
            fs::remove_dir_all(package_dir).ok();
            PackageError::MalformedArchive(Some(eco_format!("{err}")))
        })
    }
}

/// An iterator that deserializes its items lazily.
struct LazyDeser<T, I> {
    inner: I,
    _phantom: PhantomData<T>,
}

trait LazyDeserExt: Sized {
    /// Creates an iterator that returns deserialized items from the current
    /// iterator.
    fn lazy_deser<T>(self) -> LazyDeser<T, Self>;
}

impl<'a, I> LazyDeserExt for I
where
    I: Iterator<Item = &'a serde_json::Value>,
{
    fn lazy_deser<T>(self) -> LazyDeser<T, Self> {
        LazyDeser { inner: self, _phantom: PhantomData }
    }
}

impl<'a, T, I> Iterator for LazyDeser<T, I>
where
    T: DeserializeOwned,
    I: Iterator<Item = &'a serde_json::Value>,
{
    type Item = Result<T, serde_json::Error>;

    fn next(&mut self) -> Option<Self::Item> {
        let inner = self.inner.next()?;
        Some(serde_json::from_value(inner.clone()))
    }
}

#[cfg(test)]
mod tests {
    use super::*;


Review comment (refactor):
This test should normally never download anything, but maybe we want to have a stronger guarantee that it can't (unless it's fine to make network calls in tests) by introducing an abstraction over `Downloader`?

Code after:
        let decompressed = flate2::read::GzDecoder::new(data.as_slice());
        tar::Archive::new(decompressed).unpack(package_dir).map_err(|err| {
            fs::remove_dir_all(package_dir).ok();
            PackageError::MalformedArchive(Some(eco_format!("{err}")))
        })
    }
}

/// Minimal information required about a package to determine its latest
/// version.
#[derive(Deserialize)]
struct MinimalPackageInfo {
    name: String,
    version: PackageVersion,
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn lazy_deser_index() {
        let storage = PackageStorage::with_index(
            None,
            None,
            Downloader::new("typst/test"),
            OnceCell::with_value(vec![
                serde_json::json!({
                    "name": "charged-ieee",
                    "version": "0.1.0",
                    "entrypoint": "lib.typ",
                }),
                serde_json::json!({
                    "name": "unequivocal-ams",
                    // This version number is currently not valid, so this package
                    // can't be parsed.
                    "version": "0.2.0-dev",
                    "entrypoint": "lib.typ",
                }),
            ]),
        );

        let ieee_version = storage.determine_latest_version(&VersionlessPackageSpec {
            namespace: "preview".into(),
            name: "charged-ieee".into(),
        });
        assert_eq!(ieee_version, Ok(PackageVersion { major: 0, minor: 1, patch: 0 }));

        let ams_version = storage.determine_latest_version(&VersionlessPackageSpec {
            namespace: "preview".into(),
            name: "unequivocal-ams".into(),