ic_asset_certification/
asset_map.rs

1use crate::{AssetEncoding, CertifiedAssetResponse, RequestKey};
2use ic_http_certification::HttpResponse;
3use std::collections::{hash_map::Iter, HashMap};
4
5/// A map of assets, indexed by path, encoding, and the starting range.
6pub trait AssetMap<'content> {
7    /// Get an asset by path, encoding, and starting range.
8    ///
9    /// For standard assets, the path refers to the asset's path, e.g. `/index.html`.
10    ///
11    /// For fallback assets, the path refers to the scope that the fallback is valid for, e.g. `/`.
12    /// See the [fallback_for](crate::AssetConfig::File::fallback_for) config option for more information
13    /// on fallback scopes.
14    ///
15    /// For all types of assets, the encoding refers to the encoding of the asset, see [AssetEncoding].
16    ///
17    /// Assets greater than 2mb are split into multiple ranges, the starting range allows retrieval of
18    /// individual chunks of these large assets. The first range is `Some(0)`, the second range is
19    /// `Some(ASSET_CHUNK_SIZE)`, the third range is `Some(ASSET_CHUNK_SIZE * 2)`, and so on. The entire asset can
20    /// also be retrieved by passing `None` as the starting range. See [ASSET_CHUNK_SIZE](crate::ASSET_CHUNK_SIZE) for the size of each chunk.
21    fn get(
22        &self,
23        path: impl Into<String>,
24        encoding: Option<AssetEncoding>,
25        starting_range: Option<usize>,
26    ) -> Option<&HttpResponse<'content>>;
27
28    /// Returns the number of assets in the map.
29    fn len(&self) -> usize;
30
31    /// Returns `true` if the map contains no assets.
32    fn is_empty(&self) -> bool {
33        self.len() == 0
34    }
35
36    /// Returns an iterator over the assets in the map.
37    fn iter(&'content self) -> AssetMapIterator<'content>;
38}
39
40impl<'content> AssetMap<'content> for HashMap<RequestKey, CertifiedAssetResponse<'content>> {
41    fn get(
42        &self,
43        path: impl Into<String>,
44        encoding: Option<AssetEncoding>,
45        range_begin: Option<usize>,
46    ) -> Option<&HttpResponse<'content>> {
47        let req_key = RequestKey::new(path, encoding.map(|e| e.to_string()), range_begin);
48
49        self.get(&req_key).map(|e| &e.response)
50    }
51
52    fn len(&self) -> usize {
53        self.len()
54    }
55
56    fn iter(&'content self) -> AssetMapIterator<'content> {
57        AssetMapIterator { inner: self.iter() }
58    }
59}
60
61/// An iterator over the assets in an asset map.
62#[derive(Debug)]
63pub struct AssetMapIterator<'content> {
64    inner: Iter<'content, RequestKey, CertifiedAssetResponse<'content>>,
65}
66
67impl<'content> Iterator for AssetMapIterator<'content> {
68    type Item = (
69        (&'content str, Option<&'content str>, Option<usize>),
70        &'content HttpResponse<'content>,
71    );
72
73    fn next(&mut self) -> Option<Self::Item> {
74        self.inner.next().map(|(key, asset)| {
75            (
76                (key.path.as_str(), key.encoding.as_deref(), key.range_begin),
77                &asset.response,
78            )
79        })
80    }
81}