#[cfg(feature = "d1")]
use crate::d1::D1Database;
use crate::error::Error;
#[cfg(feature = "queue")]
use crate::Queue;
use crate::{durable::ObjectNamespace, Bucket, DynamicDispatcher, Fetcher, Result};
use js_sys::Object;
use wasm_bindgen::{prelude::*, JsCast, JsValue};
use worker_kv::KvStore;
#[wasm_bindgen]
extern "C" {
#[derive(Clone)]
pub type Env;
}
unsafe impl Send for Env {}
unsafe impl Sync for Env {}
impl Env {
pub fn get_binding<T: EnvBinding>(&self, name: &str) -> Result<T> {
let binding = js_sys::Reflect::get(self, &JsValue::from(name))
.map_err(|_| Error::JsError(format!("Env does not contain binding `{name}`")))?;
if binding.is_undefined() {
Err(format!("Binding `{name}` is undefined.").into())
} else {
T::get(binding)
}
}
pub fn secret(&self, binding: &str) -> Result<Secret> {
self.get_binding::<Secret>(binding)
}
pub fn var(&self, binding: &str) -> Result<Var> {
self.get_binding::<Var>(binding)
}
pub fn kv(&self, binding: &str) -> Result<KvStore> {
KvStore::from_this(self, binding).map_err(From::from)
}
pub fn durable_object(&self, binding: &str) -> Result<ObjectNamespace> {
self.get_binding(binding)
}
pub fn dynamic_dispatcher(&self, binding: &str) -> Result<DynamicDispatcher> {
self.get_binding(binding)
}
pub fn service(&self, binding: &str) -> Result<Fetcher> {
self.get_binding(binding)
}
#[cfg(feature = "queue")]
pub fn queue(&self, binding: &str) -> Result<Queue> {
self.get_binding(binding)
}
pub fn bucket(&self, binding: &str) -> Result<Bucket> {
self.get_binding(binding)
}
#[cfg(feature = "d1")]
pub fn d1(&self, binding: &str) -> Result<D1Database> {
self.get_binding(binding)
}
}
pub trait EnvBinding: Sized + JsCast {
const TYPE_NAME: &'static str;
fn get(val: JsValue) -> Result<Self> {
let obj = Object::from(val);
if obj.constructor().name() == Self::TYPE_NAME {
Ok(obj.unchecked_into())
} else {
Err(format!(
"Binding cannot be cast to the type {} from {}",
Self::TYPE_NAME,
obj.constructor().name()
)
.into())
}
}
}
pub struct StringBinding(JsValue);
impl EnvBinding for StringBinding {
const TYPE_NAME: &'static str = "String";
}
impl JsCast for StringBinding {
fn instanceof(val: &JsValue) -> bool {
val.is_string()
}
fn unchecked_from_js(val: JsValue) -> Self {
StringBinding(val)
}
fn unchecked_from_js_ref(val: &JsValue) -> &Self {
unsafe { &*(val as *const JsValue as *const Self) }
}
}
impl AsRef<JsValue> for StringBinding {
fn as_ref(&self) -> &wasm_bindgen::JsValue {
unsafe { &*(&self.0 as *const JsValue) }
}
}
impl From<JsValue> for StringBinding {
fn from(val: JsValue) -> Self {
StringBinding(val)
}
}
impl From<StringBinding> for JsValue {
fn from(sec: StringBinding) -> Self {
sec.0
}
}
impl ToString for StringBinding {
fn to_string(&self) -> String {
self.0.as_string().unwrap_or_default()
}
}
#[doc(inline)]
pub use StringBinding as Secret;
pub type Var = StringBinding;