commit 4356a1bc85404610cdb00d9a80a7f354e0c962b8
parent 573bc19b17cc0482e9408a1bf7187b53a46ea8ec
Author: nick <nick.libraries@gmail.com>
Date: Tue, 18 Jun 2024 09:54:15 -0400
Add iterators over manifests and resources in unstable API (#482)
* Add `Reader::iter_manifests` + `ResourceSource::iter_resources` + pub `ResourceStore`
* Move iter_resources to Manifest
Diffstat:
5 files changed, 40 insertions(+), 3 deletions(-)
diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs
@@ -129,7 +129,7 @@ pub use manifest_store::ManifestStore;
pub use manifest_store_report::ManifestStoreReport;
#[cfg(feature = "unstable_api")]
pub use reader::Reader;
-pub use resource_store::ResourceRef;
+pub use resource_store::{ResourceRef, ResourceStore};
pub use signer::{AsyncSigner, RemoteSigner, Signer};
pub use signing_alg::SigningAlg;
pub use utils::mime::format_from_path;
diff --git a/sdk/src/manifest.rs b/sdk/src/manifest.rs
@@ -34,7 +34,7 @@ use crate::{
ingredient::Ingredient,
jumbf,
manifest_assertion::ManifestAssertion,
- resource_store::{skip_serializing_resources, ResourceRef, ResourceStore},
+ resource_store::{mime_from_uri, skip_serializing_resources, ResourceRef, ResourceStore},
salt::DefaultSalt,
store::Store,
AsyncSigner, ClaimGeneratorInfo, HashRange, ManifestAssertionKind, RemoteSigner, Signer,
@@ -451,6 +451,14 @@ impl Manifest {
self.signature_info.to_owned().and_then(|sig| sig.time)
}
+ /// Returns an iterator over [`ResourceRef`][ResourceRef]s.
+ pub fn iter_resources(&self) -> impl Iterator<Item = ResourceRef> + '_ {
+ self.resources
+ .resources()
+ .keys()
+ .map(|uri| ResourceRef::new(mime_from_uri(uri), uri.to_owned()))
+ }
+
/// Return an immutable reference to the manifest resources
pub fn resources(&self) -> &ResourceStore {
&self.resources
diff --git a/sdk/src/manifest2.rs b/sdk/src/manifest2.rs
@@ -0,0 +1 @@
+
diff --git a/sdk/src/reader.rs b/sdk/src/reader.rs
@@ -186,6 +186,11 @@ impl Reader {
self.manifest_store.active_label()
}
+ /// Returns an iterator over [`Manifest`][Manifest]s.
+ pub fn iter_manifests(&self) -> impl Iterator<Item = &Manifest> + '_ {
+ self.manifest_store.manifests().values()
+ }
+
/// Return a [`Manifest`] for a given label if it exists.
/// # Arguments
/// * `label` - The label of the requested [`Manifest`]
diff --git a/sdk/src/resource_store.rs b/sdk/src/resource_store.rs
@@ -28,7 +28,13 @@ use serde::{Deserialize, Serialize};
#[cfg(feature = "unstable_api")]
use crate::asset_io::CAIRead;
-use crate::{assertions::AssetType, claim::Claim, hashed_uri::HashedUri, Error, Result};
+use crate::{
+ assertions::{labels, AssetType},
+ claim::Claim,
+ hashed_uri::HashedUri,
+ jumbf::labels::assertion_label_from_uri,
+ Error, Result,
+};
/// Function that is used by serde to determine whether or not we should serialize
/// resources based on the `serialize_resources` flag.
@@ -93,6 +99,8 @@ impl From<HashedUri> for UriOrResource {
#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)]
#[cfg_attr(feature = "json_schema", derive(JsonSchema))]
/// A reference to a resource to be used in JSON serialization.
+///
+/// The underlying data can be read as a stream via [`Reader::resource_to_stream`][crate::Reader::resource_to_stream].
pub struct ResourceRef {
/// The mime type of the referenced resource.
pub format: String,
@@ -361,6 +369,7 @@ impl Default for ResourceStore {
#[cfg(feature = "unstable_api")]
pub trait ResourceResolver {
+ /// Read the data in a [`ResourceRef`][ResourceRef] via a stream.
fn open(&self, reference: &ResourceRef) -> Result<Box<dyn CAIRead>>;
}
@@ -373,6 +382,20 @@ impl ResourceResolver for ResourceStore {
}
}
+pub fn mime_from_uri(uri: &str) -> String {
+ if let Some(label) = assertion_label_from_uri(uri) {
+ if label.starts_with(labels::THUMBNAIL) {
+ // https://c2pa.org/specifications/specifications/1.0/specs/C2PA_Specification.html#_thumbnail
+ if let Some(ext) = label.rsplit('.').next() {
+ return format!("image/{ext}");
+ }
+ }
+ }
+
+ // Unknown binary data.
+ String::from("application/octet-stream")
+}
+
#[cfg(test)]
#[cfg(feature = "openssl_sign")]
mod tests {