The pictures that go with what Whiskers remembers. A picture's name is the same on every device
(made from the time and a counter), so the same name is the same picture and is never replaced.
Names arrive from outside, so a name that could touch a path or a key it should not is not
representable here: a [SafePictureId] can only be made by passing [PictureId::is_safe].
9use crate::error::StoreError;
A picture name that has been checked: a bare file name of the kind pictures are given, with no path, no odd characters and a picture extension.
16#[derive(Clone, Copy, Debug, PartialEq, Eq)] 17pub struct UnsafePictureId; 18 19impl SafePictureId { 20 pub fn new(id: PictureId) -> Result<Self, UnsafePictureId> { 21 if id.is_safe() { Ok(Self(id)) } else { Err(UnsafePictureId) } 22 } 23 24 pub fn parse(name: &str) -> Result<Self, UnsafePictureId> { 25 Self::new(PictureId(name.to_owned())) 26 } 27 28 pub fn as_str(&self) -> &str { 29 &self.0.0 30 } 31}
The shelf of pictures.
Contract, for every adapter:
- Never replaces.
putunder a name already kept changes nothing and says so. - Exactly what was put.
getreturns the bytesputstored, byte for byte. - Atomic. A
getnever sees half of aput; of twoputs of one name, one wins whole. - Durable once
putreturnsOk.
49#[expect(async_fn_in_trait, reason = "a Worker's futures hold JavaScript values and cannot be Send, so no Send bound may be required here")] 50pub trait PictureShelf { 51 async fn has(&self, id: &SafePictureId) -> Result<bool, StoreError>; 52 53 async fn put(&self, id: &SafePictureId, bytes: &[u8]) -> Result<Put, StoreError>; 54 55 async fn get(&self, id: &SafePictureId) -> Result<Option<Vec<u8>>, StoreError>; 56}
58#[cfg(test)] 59mod tests { 60 use super::*; 61 62 #[test] 63 fn a_name_that_could_reach_a_path_is_not_a_picture_id() { 64 assert!(SafePictureId::parse("0000000000000000-0000.jpg").is_ok()); 65 for bad in ["../x.jpg", "a/b.jpg", ".hidden.jpg", "a..b.jpg", "noextension", "x.exe", "", &"a".repeat(70)] { 66 assert!(SafePictureId::parse(bad).is_err(), "{bad:?}"); 67 } 68 } 69}