use std::fmt::Debug;
#[derive(Debug, Clone)]
pub enum UnstructuredBinary<MT: AllowedMimeTypes> {
Url(String),
Inline { data: Vec<u8>, mime_type: MT },
}
impl<T: AllowedMimeTypes> UnstructuredBinary<T> {
pub fn from_inline(data: Vec<u8>, mime_type: T) -> UnstructuredBinary<T> {
UnstructuredBinary::Inline { data, mime_type }
}
pub fn from_url(url: impl Into<String>) -> UnstructuredBinary<T> {
UnstructuredBinary::Url(url.into())
}
#[cfg(any(feature = "host", feature = "guest"))]
pub fn from_wit_value(wit_value: crate::WitValue) -> Result<Self, String> {
let value = crate::Value::from(wit_value);
let (case_idx, case_value) = match value {
crate::Value::Variant {
case_idx,
case_value,
} => (case_idx, case_value),
_ => return Err("Expected Variant for UnstructuredBinary".into()),
};
match case_idx {
0 => {
let boxed = case_value.ok_or("Expected value for Url variant")?;
match *boxed {
crate::Value::String(url) => Ok(UnstructuredBinary::Url(url)),
_ => Err("Expected String for Url variant".into()),
}
}
1 => {
let boxed = case_value.ok_or("Expected value for Inline variant")?;
let fields = match *boxed {
crate::Value::Record(fields) => fields,
_ => return Err("Expected Record for Inline variant".into()),
};
if fields.len() < 2 {
return Err("Expected at least two fields in Inline variant".into());
}
let data_str = match &fields[0] {
crate::Value::String(s) => s,
_ => return Err("Expected String for data field".into()),
};
let data_bytes = data_str.as_bytes().to_vec();
let mime_type_val = match &fields[1] {
crate::Value::Option(Some(inner)) => inner.as_ref(),
crate::Value::Option(None) => {
return Err("Mime type restriction is required for inline binary".into());
}
_ => return Err("Expected Option for mime type restriction".into()),
};
let mime_type_record = match mime_type_val {
crate::Value::Record(fields) => fields,
_ => return Err("Expected Record for mime type restriction".into()),
};
if mime_type_record.is_empty() {
return Err("Expected at least one field in mime type restriction".into());
}
let mime_code = match &mime_type_record[0] {
crate::Value::String(code) => code,
_ => return Err("Expected String for mime type".into()),
};
let mime_type = T::from_string(mime_code)
.ok_or_else(|| format!("Failed to convert mime type '{}'", mime_code))?;
Ok(UnstructuredBinary::Inline {
data: data_bytes,
mime_type,
})
}
_ => Err("Unknown variant index for UnstructuredBinary".into()),
}
}
}
pub trait AllowedMimeTypes: Debug + Clone {
fn all() -> &'static [&'static str];
fn from_string(mime_type: &str) -> Option<Self>
where
Self: Sized;
fn to_string(&self) -> String;
}
impl AllowedMimeTypes for String {
fn all() -> &'static [&'static str] {
&[]
}
fn from_string(mime_type: &str) -> Option<Self> {
Some(mime_type.to_string())
}
fn to_string(&self) -> String {
self.clone()
}
}