viceroy_lib/wiggle_abi/
dictionary_impl.rs

1//! fastly_dictionary` hostcall implementations.
2
3use {
4    crate::{
5        error::Error,
6        session::Session,
7        wiggle_abi::{
8            fastly_dictionary::FastlyDictionary,
9            types::{DictionaryHandle, FastlyStatus},
10        },
11    },
12    wiggle::{GuestMemory, GuestPtr},
13};
14
15#[derive(Debug, thiserror::Error)]
16pub enum DictionaryError {
17    /// A dictionary item with the given key was not found.
18    #[error("Unknown dictionary item: {0}")]
19    UnknownDictionaryItem(String),
20    /// A dictionary with the given name was not found.
21    #[error("Unknown dictionary: {0}")]
22    UnknownDictionary(String),
23}
24
25impl DictionaryError {
26    /// Convert to an error code representation suitable for passing across the ABI boundary.
27    pub fn to_fastly_status(&self) -> FastlyStatus {
28        use DictionaryError::*;
29        match self {
30            UnknownDictionaryItem(_) => FastlyStatus::None,
31            UnknownDictionary(_) => FastlyStatus::Badf,
32        }
33    }
34}
35
36impl FastlyDictionary for Session {
37    fn open(
38        &mut self,
39        memory: &mut GuestMemory<'_>,
40        name: GuestPtr<str>,
41    ) -> Result<DictionaryHandle, Error> {
42        self.dictionary_handle(memory.as_str(name)?.ok_or(Error::SharedMemory)?)
43    }
44
45    fn get(
46        &mut self,
47        memory: &mut GuestMemory<'_>,
48        dictionary: DictionaryHandle,
49        key: GuestPtr<str>,
50        buf: GuestPtr<u8>,
51        buf_len: u32,
52        nwritten_out: GuestPtr<u32>,
53    ) -> Result<(), Error> {
54        let dict = &self.dictionary(dictionary)?.contents;
55
56        let item_bytes = {
57            let key = memory.as_str(key)?.ok_or(Error::SharedMemory)?;
58            dict.get(key)
59                .ok_or_else(|| DictionaryError::UnknownDictionaryItem(key.to_owned()))?
60                .as_bytes()
61        };
62
63        if item_bytes.len() > usize::try_from(buf_len).expect("buf_len must fit in usize") {
64            // Write out the number of bytes necessary to fit this item, or zero on overflow to
65            // signal an error condition. This is probably unnecessary, as config store entries
66            // may be at most 8000 utf-8 characters large.
67            memory.write(nwritten_out, u32::try_from(item_bytes.len()).unwrap_or(0))?;
68            return Err(Error::BufferLengthError {
69                buf: "dictionary_item",
70                len: "dictionary_item_max_len",
71            });
72        }
73
74        // We know the conversion of item_bytes.len() to u32 will succeed, as it's <= buf_len.
75        let item_len = u32::try_from(item_bytes.len()).unwrap();
76
77        memory.write(nwritten_out, item_len)?;
78        memory.copy_from_slice(item_bytes, buf.as_array(item_len))?;
79
80        Ok(())
81    }
82}