use dom_struct::dom_struct;
use indexmap::IndexSet;
use js::context::JSContext;
use js::rust::HandleObject;
use script_bindings::cell::DomRefCell;
use script_bindings::like::Setlike;
use script_bindings::reflector::{Reflector, reflect_dom_object_with_proto_and_cx};
use wgpu_types::Features;
use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{
GPUFeatureName, GPUSupportedFeaturesMethods,
};
use crate::dom::bindings::error::Fallible;
use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::str::DOMString;
use crate::dom::globalscope::GlobalScope;
#[dom_struct]
pub(crate) struct GPUSupportedFeatures {
reflector: Reflector,
#[custom_trace]
internal: DomRefCell<IndexSet<GPUFeatureName>>,
#[ignore_malloc_size_of = "defined in wgpu-types"]
#[no_trace]
features: Features,
}
impl GPUSupportedFeatures {
fn new(
cx: &mut JSContext,
global: &GlobalScope,
proto: Option<HandleObject>,
features: Features,
) -> DomRoot<GPUSupportedFeatures> {
let mut set = IndexSet::new();
set.insert(GPUFeatureName::Core_features_and_limits);
if features.contains(Features::DEPTH_CLIP_CONTROL) {
set.insert(GPUFeatureName::Depth_clip_control);
}
if features.contains(Features::DEPTH32FLOAT_STENCIL8) {
set.insert(GPUFeatureName::Depth32float_stencil8);
}
if features.contains(Features::TEXTURE_COMPRESSION_BC) {
set.insert(GPUFeatureName::Texture_compression_bc);
}
if features.contains(Features::TEXTURE_COMPRESSION_ETC2) {
set.insert(GPUFeatureName::Texture_compression_etc2);
}
if features.contains(Features::TEXTURE_COMPRESSION_ASTC) {
set.insert(GPUFeatureName::Texture_compression_astc);
}
if features.contains(Features::TIMESTAMP_QUERY) {
set.insert(GPUFeatureName::Timestamp_query);
}
if features.contains(Features::INDIRECT_FIRST_INSTANCE) {
set.insert(GPUFeatureName::Indirect_first_instance);
}
if features.contains(Features::RG11B10UFLOAT_RENDERABLE) {
set.insert(GPUFeatureName::Rg11b10ufloat_renderable);
}
if features.contains(Features::BGRA8UNORM_STORAGE) {
set.insert(GPUFeatureName::Bgra8unorm_storage);
}
if features.contains(Features::FLOAT32_FILTERABLE) {
set.insert(GPUFeatureName::Float32_filterable);
}
if features.contains(Features::DUAL_SOURCE_BLENDING) {
set.insert(GPUFeatureName::Dual_source_blending);
}
reflect_dom_object_with_proto_and_cx(
Box::new(GPUSupportedFeatures {
reflector: Reflector::new(),
internal: DomRefCell::new(set),
features,
}),
global,
proto,
cx,
)
}
#[expect(non_snake_case)]
pub(crate) fn Constructor(
cx: &mut JSContext,
global: &GlobalScope,
proto: Option<HandleObject>,
features: Features,
) -> Fallible<DomRoot<GPUSupportedFeatures>> {
Ok(GPUSupportedFeatures::new(cx, global, proto, features))
}
}
impl GPUSupportedFeatures {
pub(crate) fn wgpu_features(&self) -> &Features {
&self.features
}
}
impl GPUSupportedFeaturesMethods<crate::DomTypeHolder> for GPUSupportedFeatures {
fn Size(&self) -> u32 {
self.internal.size()
}
}
pub(crate) fn gpu_to_wgt_feature(feature: GPUFeatureName) -> Option<Features> {
match feature {
GPUFeatureName::Core_features_and_limits => Some(Features::empty()),
GPUFeatureName::Depth_clip_control => Some(Features::DEPTH_CLIP_CONTROL),
GPUFeatureName::Depth32float_stencil8 => Some(Features::DEPTH32FLOAT_STENCIL8),
GPUFeatureName::Texture_compression_bc => Some(Features::TEXTURE_COMPRESSION_BC),
GPUFeatureName::Texture_compression_etc2 => Some(Features::TEXTURE_COMPRESSION_ETC2),
GPUFeatureName::Texture_compression_astc => Some(Features::TEXTURE_COMPRESSION_ASTC),
GPUFeatureName::Timestamp_query => Some(Features::TIMESTAMP_QUERY),
GPUFeatureName::Indirect_first_instance => Some(Features::INDIRECT_FIRST_INSTANCE),
GPUFeatureName::Shader_f16 => None,
GPUFeatureName::Rg11b10ufloat_renderable => Some(Features::RG11B10UFLOAT_RENDERABLE),
GPUFeatureName::Bgra8unorm_storage => Some(Features::BGRA8UNORM_STORAGE),
GPUFeatureName::Float32_filterable => Some(Features::FLOAT32_FILTERABLE),
GPUFeatureName::Dual_source_blending => Some(Features::DUAL_SOURCE_BLENDING),
GPUFeatureName::Texture_compression_bc_sliced_3d => None,
GPUFeatureName::Clip_distances => None,
GPUFeatureName::Subgroups => None,
}
}
impl Setlike for GPUSupportedFeatures {
type Key = DOMString;
#[inline(always)]
fn get_index(&self, index: u32) -> Option<Self::Key> {
self.internal
.get_index(index)
.map(|key| key.as_str().into())
}
#[inline(always)]
fn size(&self) -> u32 {
self.internal.size()
}
#[inline(always)]
fn add(&self, _key: Self::Key) {
unreachable!("readonly");
}
#[inline(always)]
fn has(&self, key: Self::Key) -> bool {
if let Ok(key) = key.parse() {
self.internal.has(key)
} else {
false
}
}
#[inline(always)]
fn clear(&self) {
unreachable!("readonly");
}
#[inline(always)]
fn delete(&self, _key: Self::Key) -> bool {
unreachable!("readonly");
}
}