use std::borrow::Cow;
use deno_core::WebIDL;
use deno_core::cppgc::Ref;
use deno_core::v8;
use deno_core::webidl::ContextFn;
use deno_core::webidl::IntOptions;
use deno_core::webidl::WebIdlConverter;
use deno_core::webidl::WebIdlError;
use deno_core::webidl::WebIdlErrorKind;
use deno_error::JsErrorBox;
#[derive(WebIDL)]
#[webidl(dictionary)]
pub(crate) struct GPUExtent3DDict {
#[options(enforce_range = true)]
width: u32,
#[webidl(default = 1)]
#[options(enforce_range = true)]
height: u32,
#[webidl(default = 1)]
#[options(enforce_range = true)]
depth_or_array_layers: u32,
}
pub(crate) enum GPUExtent3D {
Dict(GPUExtent3DDict),
Sequence((u32, u32, u32)),
}
impl<'a> WebIdlConverter<'a> for GPUExtent3D {
type Options = ();
fn convert<'b>(
scope: &mut v8::PinScope<'a, '_>,
value: v8::Local<'a, v8::Value>,
prefix: Cow<'static, str>,
context: ContextFn<'b>,
options: &Self::Options,
) -> Result<Self, WebIdlError> {
if value.is_null_or_undefined() {
return Ok(GPUExtent3D::Dict(GPUExtent3DDict::convert(
scope,
value,
prefix,
context.borrowed(),
options,
)?));
}
if let Ok(obj) = value.try_cast::<v8::Object>() {
let iter = v8::Symbol::get_iterator(scope);
if let Some(iter) = obj.get(scope, iter.into())
&& !iter.is_undefined()
{
let conv = <Vec<u32>>::convert(
scope,
value,
prefix.clone(),
context.borrowed(),
&IntOptions {
clamp: false,
enforce_range: true,
},
)?;
if conv.is_empty() || conv.len() > 3 {
return Err(WebIdlError::other(
prefix,
context,
JsErrorBox::type_error(format!(
"A sequence of number used as a GPUExtent3D must have between 1 and 3 elements, received {} elements",
conv.len()
)),
));
}
let mut iter = conv.into_iter();
return Ok(GPUExtent3D::Sequence((
iter.next().unwrap(),
iter.next().unwrap_or(1),
iter.next().unwrap_or(1),
)));
}
return Ok(GPUExtent3D::Dict(GPUExtent3DDict::convert(
scope, value, prefix, context, options,
)?));
}
Err(WebIdlError::new(
prefix,
context,
WebIdlErrorKind::ConvertToConverterType(
"sequence<GPUIntegerCoordinate> or GPUExtent3DDict",
),
))
}
}
impl From<GPUExtent3D> for wgpu_types::Extent3d {
fn from(value: GPUExtent3D) -> Self {
match value {
GPUExtent3D::Dict(dict) => Self {
width: dict.width,
height: dict.height,
depth_or_array_layers: dict.depth_or_array_layers,
},
GPUExtent3D::Sequence((width, height, depth)) => Self {
width,
height,
depth_or_array_layers: depth,
},
}
}
}
#[derive(WebIDL)]
#[webidl(dictionary)]
pub(crate) struct GPUOrigin3DDict {
#[webidl(default = 0)]
#[options(enforce_range = true)]
x: u32,
#[webidl(default = 0)]
#[options(enforce_range = true)]
y: u32,
#[webidl(default = 0)]
#[options(enforce_range = true)]
z: u32,
}
pub(crate) enum GPUOrigin3D {
Dict(GPUOrigin3DDict),
Sequence((u32, u32, u32)),
}
impl Default for GPUOrigin3D {
fn default() -> Self {
GPUOrigin3D::Sequence((0, 0, 0))
}
}
impl<'a> WebIdlConverter<'a> for GPUOrigin3D {
type Options = ();
fn convert<'b>(
scope: &mut v8::PinScope<'a, '_>,
value: v8::Local<'a, v8::Value>,
prefix: Cow<'static, str>,
context: ContextFn<'b>,
options: &Self::Options,
) -> Result<Self, WebIdlError> {
if value.is_null_or_undefined() {
return Ok(GPUOrigin3D::Dict(GPUOrigin3DDict::convert(
scope,
value,
prefix,
context.borrowed(),
options,
)?));
}
if let Ok(obj) = value.try_cast::<v8::Object>() {
let iter = v8::Symbol::get_iterator(scope);
if let Some(iter) = obj.get(scope, iter.into())
&& !iter.is_undefined()
{
let conv = <Vec<u32>>::convert(
scope,
value,
prefix.clone(),
context.borrowed(),
&IntOptions {
clamp: false,
enforce_range: true,
},
)?;
if conv.len() > 3 {
return Err(WebIdlError::other(
prefix,
context,
JsErrorBox::type_error(format!(
"A sequence of number used as a GPUOrigin3D must have at most 3 elements, received {} elements",
conv.len()
)),
));
}
let mut iter = conv.into_iter();
return Ok(GPUOrigin3D::Sequence((
iter.next().unwrap_or(0),
iter.next().unwrap_or(0),
iter.next().unwrap_or(0),
)));
}
return Ok(GPUOrigin3D::Dict(GPUOrigin3DDict::convert(
scope, value, prefix, context, options,
)?));
}
Err(WebIdlError::new(
prefix,
context,
WebIdlErrorKind::ConvertToConverterType(
"sequence<GPUIntegerCoordinate> or GPUOrigin3DDict",
),
))
}
}
impl From<GPUOrigin3D> for wgpu_types::Origin3d {
fn from(value: GPUOrigin3D) -> Self {
match value {
GPUOrigin3D::Dict(dict) => Self {
x: dict.x,
y: dict.y,
z: dict.z,
},
GPUOrigin3D::Sequence((x, y, z)) => Self { x, y, z },
}
}
}
#[derive(WebIDL)]
#[webidl(dictionary)]
pub(crate) struct GPUColorDict {
r: f64,
g: f64,
b: f64,
a: f64,
}
pub(crate) enum GPUColor {
Dict(GPUColorDict),
Sequence((f64, f64, f64, f64)),
}
impl<'a> WebIdlConverter<'a> for GPUColor {
type Options = ();
fn convert<'b>(
scope: &mut v8::PinScope<'a, '_>,
value: v8::Local<'a, v8::Value>,
prefix: Cow<'static, str>,
context: ContextFn<'b>,
options: &Self::Options,
) -> Result<Self, WebIdlError> {
if value.is_null_or_undefined() {
return Ok(GPUColor::Dict(GPUColorDict::convert(
scope,
value,
prefix,
context.borrowed(),
options,
)?));
}
if let Ok(obj) = value.try_cast::<v8::Object>() {
let iter = v8::Symbol::get_iterator(scope);
if let Some(iter) = obj.get(scope, iter.into())
&& !iter.is_undefined()
{
let conv = <Vec<f64>>::convert(
scope,
value,
prefix.clone(),
context.borrowed(),
options,
)?;
if conv.len() != 4 {
return Err(WebIdlError::other(
prefix,
context,
JsErrorBox::type_error(format!(
"A sequence of number used as a GPUColor must have exactly 4 elements, received {} elements",
conv.len()
)),
));
}
let mut iter = conv.into_iter();
return Ok(GPUColor::Sequence((
iter.next().unwrap(),
iter.next().unwrap(),
iter.next().unwrap(),
iter.next().unwrap(),
)));
}
return Ok(GPUColor::Dict(GPUColorDict::convert(
scope, value, prefix, context, options,
)?));
}
Err(WebIdlError::new(
prefix,
context,
WebIdlErrorKind::ConvertToConverterType(
"sequence<GPUIntegerCoordinate> or GPUOrigin3DDict",
),
))
}
}
impl From<GPUColor> for wgpu_types::Color {
fn from(value: GPUColor) -> Self {
match value {
GPUColor::Dict(dict) => Self {
r: dict.r,
g: dict.g,
b: dict.b,
a: dict.a,
},
GPUColor::Sequence((r, g, b, a)) => Self { r, g, b, a },
}
}
}
#[derive(WebIDL)]
#[webidl(enum)]
pub(crate) enum GPUAutoLayoutMode {
Auto,
}
pub(crate) enum GPUPipelineLayoutOrGPUAutoLayoutMode {
PipelineLayout(Ref<crate::pipeline_layout::GPUPipelineLayout>),
AutoLayoutMode(GPUAutoLayoutMode),
}
impl From<GPUPipelineLayoutOrGPUAutoLayoutMode>
for Option<wgpu_core::id::PipelineLayoutId>
{
fn from(value: GPUPipelineLayoutOrGPUAutoLayoutMode) -> Self {
match value {
GPUPipelineLayoutOrGPUAutoLayoutMode::PipelineLayout(layout) => {
Some(layout.id)
}
GPUPipelineLayoutOrGPUAutoLayoutMode::AutoLayoutMode(
GPUAutoLayoutMode::Auto,
) => None,
}
}
}
impl<'a> WebIdlConverter<'a> for GPUPipelineLayoutOrGPUAutoLayoutMode {
type Options = ();
fn convert<'b>(
scope: &mut v8::PinScope<'a, '_>,
value: v8::Local<'a, v8::Value>,
prefix: Cow<'static, str>,
context: ContextFn<'b>,
options: &Self::Options,
) -> Result<Self, WebIdlError> {
if value.is_object() {
Ok(Self::PipelineLayout(WebIdlConverter::convert(
scope, value, prefix, context, options,
)?))
} else {
Ok(Self::AutoLayoutMode(WebIdlConverter::convert(
scope, value, prefix, context, options,
)?))
}
}
}
impl<'a> WebIdlConverter<'a> for GPUFeatureName {
type Options = ();
fn convert<'b>(
scope: &mut v8::PinScope<'a, '_>,
value: v8::Local<'a, v8::Value>,
prefix: Cow<'static, str>,
context: ContextFn<'b>,
_options: &Self::Options,
) -> Result<Self, WebIdlError> {
let s = value.to_rust_string_lossy(scope);
s.parse().map(Self).map_err(|()| {
WebIdlError::new(
prefix,
context,
WebIdlErrorKind::InvalidEnumVariant {
converter: "GPUFeatureName",
variant: s,
},
)
})
}
}
#[derive(Clone, Copy, Hash, Eq, PartialEq)]
pub struct GPUFeatureName(wgpu_types::Features);
impl From<GPUFeatureName> for wgpu_types::Features {
fn from(value: GPUFeatureName) -> wgpu_types::Features {
value.0
}
}
#[derive(Clone, Copy)]
pub struct GPUTextureUsageFlags(pub wgpu_types::TextureUsages);
impl<'a> WebIdlConverter<'a> for GPUTextureUsageFlags {
type Options = ();
fn convert<'b>(
scope: &mut v8::PinScope<'a, '_>,
value: v8::Local<'a, v8::Value>,
prefix: Cow<'static, str>,
context: ContextFn<'b>,
_options: &Self::Options,
) -> Result<Self, WebIdlError> {
let flags_value = u32::convert(
scope,
value,
prefix.clone(),
context.borrowed(),
&IntOptions {
clamp: false,
enforce_range: true,
},
)?;
let flags =
wgpu_types::TextureUsages::from_bits(flags_value).ok_or_else(|| {
WebIdlError::other(
prefix,
context,
JsErrorBox::type_error("usage is not valid"),
)
})?;
Ok(GPUTextureUsageFlags(flags))
}
}
impl From<GPUTextureUsageFlags> for wgpu_types::TextureUsages {
fn from(value: GPUTextureUsageFlags) -> Self {
value.0
}
}
impl GPUTextureUsageFlags {
pub fn bits(&self) -> u32 {
self.0.bits()
}
}
#[derive(Clone, Copy)]
pub(crate) struct GPUShaderStageFlags(pub(crate) wgpu_types::ShaderStages);
impl<'a> WebIdlConverter<'a> for GPUShaderStageFlags {
type Options = ();
fn convert<'b>(
scope: &mut v8::PinScope<'a, '_>,
value: v8::Local<'a, v8::Value>,
prefix: Cow<'static, str>,
context: ContextFn<'b>,
_options: &Self::Options,
) -> Result<Self, WebIdlError> {
let flags_value = u32::convert(
scope,
value,
prefix.clone(),
context.borrowed(),
&IntOptions {
clamp: false,
enforce_range: true,
},
)?;
let flags =
wgpu_types::ShaderStages::from_bits(flags_value).ok_or_else(|| {
WebIdlError::other(
prefix,
context,
JsErrorBox::type_error("shader stage is not valid"),
)
})?;
Ok(GPUShaderStageFlags(flags))
}
}
impl From<GPUShaderStageFlags> for wgpu_types::ShaderStages {
fn from(value: GPUShaderStageFlags) -> Self {
value.0
}
}
#[derive(Clone, Copy)]
pub(crate) struct GPUColorWriteFlags(pub(crate) wgpu_types::ColorWrites);
impl<'a> WebIdlConverter<'a> for GPUColorWriteFlags {
type Options = ();
fn convert<'b>(
scope: &mut v8::PinScope<'a, '_>,
value: v8::Local<'a, v8::Value>,
prefix: Cow<'static, str>,
context: ContextFn<'b>,
_options: &Self::Options,
) -> Result<Self, WebIdlError> {
let flags_value = u32::convert(
scope,
value,
prefix.clone(),
context.borrowed(),
&IntOptions {
clamp: false,
enforce_range: true,
},
)?;
Ok(GPUColorWriteFlags(
wgpu_types::ColorWrites::from_bits_retain(flags_value),
))
}
}
impl From<GPUColorWriteFlags> for wgpu_types::ColorWrites {
fn from(value: GPUColorWriteFlags) -> Self {
value.0
}
}