Skip to main content

worker/
images.rs

1use crate::send::SendFuture;
2use crate::{env::EnvBinding, Error, Result};
3use serde::de::DeserializeOwned;
4use serde::Serialize;
5use wasm_bindgen::{JsCast, JsValue};
6use wasm_bindgen_futures::JsFuture;
7use worker_sys::{
8    ImageTransformationResult as ImageTransformationResultSys, ImageTransformer as ImageTransformerSys,
9    ImagesBinding as ImagesBindingSys,
10};
11
12#[derive(Debug, Clone)]
13pub struct ImagesBinding(ImagesBindingSys);
14
15#[derive(Debug, Clone)]
16pub struct ImageTransformer(ImageTransformerSys);
17
18#[derive(Debug, Clone)]
19pub struct ImageTransformationResult(ImageTransformationResultSys);
20
21unsafe impl Send for ImagesBinding {}
22unsafe impl Sync for ImagesBinding {}
23unsafe impl Send for ImageTransformer {}
24unsafe impl Sync for ImageTransformer {}
25unsafe impl Send for ImageTransformationResult {}
26unsafe impl Sync for ImageTransformationResult {}
27
28impl ImagesBinding {
29    pub async fn transform(&self, input: JsValue) -> Result<JsValue> {
30        let promise = self.0.transform(input)?;
31        let output = SendFuture::new(JsFuture::from(promise)).await;
32        output.map_err(Error::from)
33    }
34
35    pub async fn transform_json<T: Serialize, U: DeserializeOwned>(&self, input: T) -> Result<U> {
36        let value = self.transform(serde_wasm_bindgen::to_value(&input)?).await?;
37        Ok(serde_wasm_bindgen::from_value(value)?)
38    }
39
40    pub async fn info(&self, input: JsValue, options: Option<JsValue>) -> Result<JsValue> {
41        let promise = self
42            .0
43            .info(input, options.unwrap_or(JsValue::UNDEFINED))?;
44        let output = SendFuture::new(JsFuture::from(promise)).await;
45        output.map_err(Error::from)
46    }
47
48    pub async fn info_json<T: Serialize, U: DeserializeOwned>(
49        &self,
50        input: T,
51        options: Option<serde_json::Value>,
52    ) -> Result<U> {
53        let input = serde_wasm_bindgen::to_value(&input)?;
54        let options = options
55            .map(|opt| serde_wasm_bindgen::to_value(&opt))
56            .transpose()?;
57        let value = self.info(input, options).await?;
58        Ok(serde_wasm_bindgen::from_value(value)?)
59    }
60
61    pub fn input(&self, input: JsValue, options: Option<JsValue>) -> Result<ImageTransformer> {
62        let transformer = self
63            .0
64            .input(input, options.unwrap_or(JsValue::UNDEFINED))?;
65        Ok(ImageTransformer(transformer))
66    }
67
68    pub fn input_json<T: Serialize>(
69        &self,
70        input: T,
71        options: Option<serde_json::Value>,
72    ) -> Result<ImageTransformer> {
73        let input = serde_wasm_bindgen::to_value(&input)?;
74        let options = options
75            .map(|opt| serde_wasm_bindgen::to_value(&opt))
76            .transpose()?;
77        self.input(input, options)
78    }
79}
80
81impl ImageTransformer {
82    pub fn transform(self, options: JsValue) -> Result<Self> {
83        Ok(Self(self.0.transform_step(options)?))
84    }
85
86    pub fn transform_json(self, options: serde_json::Value) -> Result<Self> {
87        self.transform(serde_wasm_bindgen::to_value(&options)?)
88    }
89
90    pub fn draw(self, image: JsValue) -> Result<Self> {
91        Ok(Self(self.0.draw(image)?))
92    }
93
94    pub async fn output(self, options: Option<JsValue>) -> Result<ImageTransformationResult> {
95        let promise = self.0.output(options.unwrap_or(JsValue::UNDEFINED))?;
96        let output = SendFuture::new(JsFuture::from(promise)).await;
97        let value = output.map_err(Error::from)?;
98        Ok(ImageTransformationResult(value.unchecked_into()))
99    }
100
101    pub async fn output_json(self, options: Option<serde_json::Value>) -> Result<ImageTransformationResult> {
102        let options = options
103            .map(|opt| serde_wasm_bindgen::to_value(&opt))
104            .transpose()?;
105        self.output(options).await
106    }
107}
108
109impl ImageTransformationResult {
110    pub fn response_raw(&self) -> JsValue {
111        self.0.response()
112    }
113
114    pub fn content_type(&self) -> Option<String> {
115        self.0.content_type()
116    }
117
118    pub fn image_raw(&self) -> JsValue {
119        self.0.image()
120    }
121
122    pub fn image_json<U: DeserializeOwned>(&self) -> Result<U> {
123        Ok(serde_wasm_bindgen::from_value(self.0.image())?)
124    }
125}
126
127impl EnvBinding for ImagesBinding {
128    const TYPE_NAME: &'static str = "Object";
129
130    fn get(val: JsValue) -> Result<Self> {
131        if !val.is_object() {
132            return Err("Binding cannot be cast to ImagesBinding from non-object value".into());
133        }
134
135        let has_transform = js_sys::Reflect::has(&val, &JsValue::from("transform"))?;
136        if !has_transform {
137            return Err("Binding cannot be cast to ImagesBinding: missing `transform` method".into());
138        }
139
140        Ok(Self(val.unchecked_into()))
141    }
142}
143
144impl JsCast for ImagesBinding {
145    fn instanceof(val: &JsValue) -> bool {
146        val.is_object()
147    }
148
149    fn unchecked_from_js(val: JsValue) -> Self {
150        Self(val.unchecked_into())
151    }
152
153    fn unchecked_from_js_ref(val: &JsValue) -> &Self {
154        unsafe { &*(val as *const JsValue as *const Self) }
155    }
156}
157
158impl AsRef<JsValue> for ImagesBinding {
159    fn as_ref(&self) -> &JsValue {
160        &self.0
161    }
162}
163
164impl From<JsValue> for ImagesBinding {
165    fn from(val: JsValue) -> Self {
166        Self(val.unchecked_into())
167    }
168}
169
170impl From<ImagesBinding> for JsValue {
171    fn from(value: ImagesBinding) -> Self {
172        value.0.into()
173    }
174}