Move common indexeddb methods out of dom implementations (#38101)

A lot of shared functions were scattered around the dom files; I moved
them into `indexed_db.rs` for clarity.

Fixes: Nothing to my knowledge, just a cleanup

Signed-off-by: Ashwin Naren <arihant2math@gmail.com>
This commit is contained in:
Ashwin Naren 2025-07-16 21:19:03 -07:00 committed by GitHub
parent e10466b4c4
commit f70a4eb4ff
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 314 additions and 299 deletions

View file

@ -5,16 +5,16 @@
use std::default::Default;
use std::iter;
use webrender_api::units::DeviceIntRect;
use ipc_channel::ipc;
use dom_struct::dom_struct;
use embedder_traits::{EmbedderMsg, FormControl as EmbedderFormControl};
use embedder_traits::{SelectElementOption, SelectElementOptionOrOptgroup};
use euclid::{Point2D, Rect, Size2D};
use html5ever::{LocalName, Prefix, local_name};
use ipc_channel::ipc;
use js::rust::HandleObject;
use style::attr::AttrValue;
use stylo_dom::ElementState;
use embedder_traits::{SelectElementOptionOrOptgroup, SelectElementOption};
use euclid::{Size2D, Point2D, Rect};
use embedder_traits::{FormControl as EmbedderFormControl, EmbedderMsg};
use webrender_api::units::DeviceIntRect;
use crate::dom::bindings::refcounted::Trusted;
use crate::dom::event::{EventBubbles, EventCancelable, EventComposed};

View file

@ -30,6 +30,7 @@ use crate::dom::globalscope::GlobalScope;
use crate::dom::idbobjectstore::IDBObjectStore;
use crate::dom::idbtransaction::IDBTransaction;
use crate::dom::idbversionchangeevent::IDBVersionChangeEvent;
use crate::indexed_db::is_valid_key_path;
use crate::script_runtime::CanGc;
#[dom_struct]
@ -201,7 +202,7 @@ impl IDBDatabaseMethods<crate::DomTypeHolder> for IDBDatabase {
// Step 5
if let Some(path) = key_path {
if !IDBObjectStore::is_valid_key_path(path) {
if !is_valid_key_path(path) {
return Err(Error::Syntax);
}
}

View file

@ -2,24 +2,14 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use std::ptr;
use dom_struct::dom_struct;
use js::jsapi::{
ESClass, GetBuiltinClass, IsArrayBufferObject, JS_DeleteUCProperty,
JS_GetOwnUCPropertyDescriptor, JS_GetStringLength, JS_IsArrayBufferViewObject, JSObject,
ObjectOpResult, ObjectOpResult_SpecialCodes, PropertyDescriptor,
};
use js::jsval::UndefinedValue;
use js::rust::{HandleValue, MutableHandleValue};
use log::error;
use js::rust::HandleValue;
use net_traits::IpcSend;
use net_traits::indexeddb_thread::{
AsyncOperation, AsyncReadOnlyOperation, AsyncReadWriteOperation, IndexedDBKeyType,
IndexedDBThreadMsg, SyncOperation,
};
use profile_traits::ipc;
use script_bindings::conversions::SafeToJSValConvertible;
use crate::dom::bindings::cell::DomRefCell;
use crate::dom::bindings::codegen::Bindings::IDBDatabaseBinding::IDBObjectStoreParameters;
@ -27,7 +17,6 @@ use crate::dom::bindings::codegen::Bindings::IDBObjectStoreBinding::IDBObjectSto
use crate::dom::bindings::codegen::Bindings::IDBTransactionBinding::IDBTransactionMode;
// We need to alias this name, otherwise test-tidy complains at &String reference.
use crate::dom::bindings::codegen::UnionTypes::StringOrStringSequence as StrOrStringSequence;
use crate::dom::bindings::conversions::jsstring_to_str;
use crate::dom::bindings::error::{Error, Fallible};
use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object};
use crate::dom::bindings::root::{DomRoot, MutNullableDom};
@ -37,6 +26,7 @@ use crate::dom::domstringlist::DOMStringList;
use crate::dom::globalscope::GlobalScope;
use crate::dom::idbrequest::IDBRequest;
use crate::dom::idbtransaction::IDBTransaction;
use crate::indexed_db::{convert_value_to_key, extract_key};
use crate::script_runtime::{CanGc, JSContext as SafeJSContext};
#[derive(JSTraceable, MallocSizeOf)]
@ -119,229 +109,6 @@ impl IDBObjectStore {
self.transaction.get()
}
// https://www.w3.org/TR/IndexedDB-2/#valid-key-path
pub fn is_valid_key_path(key_path: &StrOrStringSequence) -> bool {
fn is_identifier(_s: &str) -> bool {
// FIXME: (arihant2math)
true
}
let is_valid = |path: &DOMString| {
path.is_empty() || is_identifier(path) || path.split(".").all(is_identifier)
};
match key_path {
StrOrStringSequence::StringSequence(paths) => {
if paths.is_empty() {
return false;
}
paths.iter().all(is_valid)
},
StrOrStringSequence::String(path) => is_valid(path),
}
}
#[allow(unsafe_code)]
// https://www.w3.org/TR/IndexedDB-2/#convert-value-to-key
fn convert_value_to_key(
cx: SafeJSContext,
input: HandleValue,
seen: Option<Vec<HandleValue>>,
) -> Result<IndexedDBKeyType, Error> {
// Step 1: If seen was not given, then let seen be a new empty set.
let _seen = seen.unwrap_or_default();
// Step 2: If seen contains input, then return invalid.
// FIXME:(arihant2math) implement this
// Check if we have seen this key
// Does not currently work with HandleValue,
// as it does not implement PartialEq
// Step 3
// FIXME:(arihant2math) Accept buffer, array and date as well
if input.is_number() {
// FIXME:(arihant2math) check for NaN
return Ok(IndexedDBKeyType::Number(input.to_number()));
}
if input.is_string() {
let string_ptr = std::ptr::NonNull::new(input.to_string()).unwrap();
let key = unsafe { jsstring_to_str(*cx, string_ptr).str().to_string() };
return Ok(IndexedDBKeyType::String(key));
}
if input.is_object() {
rooted!(in(*cx) let object = input.to_object());
unsafe {
let mut built_in_class = ESClass::Other;
if !GetBuiltinClass(*cx, object.handle().into(), &mut built_in_class) {
return Err(Error::Data);
}
if let ESClass::Date = built_in_class {
// FIXME:(arihant2math) implement it the correct way
let key =
structuredclone::write(cx, input, None).expect("Could not serialize key");
return Ok(IndexedDBKeyType::Date(key.serialized.clone()));
}
if IsArrayBufferObject(*object) || JS_IsArrayBufferViewObject(*object) {
// FIXME:(arihant2math)
error!("Array buffers as keys is currently unsupported");
return Err(Error::NotSupported);
}
if let ESClass::Array = built_in_class {
// FIXME:(arihant2math)
unimplemented!("Arrays as keys is currently unsupported");
}
}
}
Err(Error::Data)
}
// https://www.w3.org/TR/IndexedDB-2/#evaluate-a-key-path-on-a-value
#[allow(unsafe_code)]
fn evaluate_key_path_on_value(
cx: SafeJSContext,
value: HandleValue,
mut return_val: MutableHandleValue,
key_path: &KeyPath,
) {
// The implementation is translated from gecko:
// https://github.com/mozilla/gecko-dev/blob/master/dom/indexedDB/KeyPath.cpp
return_val.set(*value);
rooted!(in(*cx) let mut target_object = ptr::null_mut::<JSObject>());
rooted!(in(*cx) let mut current_val = *value);
rooted!(in(*cx) let mut object = ptr::null_mut::<JSObject>());
let mut target_object_prop_name: Option<String> = None;
match key_path {
KeyPath::String(path) => {
// Step 3
let path_as_string = path.to_string();
let mut tokenizer = path_as_string.split('.').peekable();
while let Some(token) = tokenizer.next() {
if target_object.get().is_null() {
if token == "length" &&
tokenizer.peek().is_none() &&
current_val.is_string()
{
rooted!(in(*cx) let input_val = current_val.to_string());
unsafe {
let string_len = JS_GetStringLength(*input_val) as u64;
string_len.safe_to_jsval(cx, return_val);
}
break;
}
if !current_val.is_object() {
// FIXME:(rasviitanen) Return a proper error
return;
}
object.handle_mut().set(current_val.to_object());
rooted!(in(*cx) let mut desc = PropertyDescriptor::default());
rooted!(in(*cx) let mut intermediate = UndefinedValue());
// So rust says that this value is never read, but it is.
#[allow(unused)]
let mut has_prop = false;
unsafe {
let prop_name_as_utf16: Vec<u16> = token.encode_utf16().collect();
let mut is_descriptor_none: bool = false;
let ok = JS_GetOwnUCPropertyDescriptor(
*cx,
object.handle().into(),
prop_name_as_utf16.as_ptr(),
prop_name_as_utf16.len(),
desc.handle_mut().into(),
&mut is_descriptor_none,
);
if !ok {
// FIXME:(arihant2math) Handle this
return;
}
if desc.hasWritable_() || desc.hasValue_() {
intermediate.handle_mut().set(desc.handle().value_);
has_prop = true;
} else {
// If we get here it means the object doesn't have the property or the
// property is available throuch a getter. We don't want to call any
// getters to avoid potential re-entrancy.
// The blob object is special since its properties are available
// only through getters but we still want to support them for key
// extraction. So they need to be handled manually.
unimplemented!("Blob tokens are not yet supported");
}
}
if has_prop {
// Treat undefined as an error
if intermediate.is_undefined() {
// FIXME:(rasviitanen) Throw/return error
return;
}
if tokenizer.peek().is_some() {
// ...and walk to it if there are more steps...
current_val.handle_mut().set(*intermediate);
} else {
// ...otherwise use it as key
return_val.set(*intermediate);
}
} else {
target_object.handle_mut().set(*object);
target_object_prop_name = Some(token.to_string());
}
}
if !target_object.get().is_null() {
// We have started inserting new objects or are about to just insert
// the first one.
// FIXME:(rasviitanen) Implement this piece
unimplemented!("keyPath tokens that requires insertion are not supported.");
}
} // All tokens processed
if !target_object.get().is_null() {
// If this fails, we lose, and the web page sees a magical property
// appear on the object :-(
unsafe {
let prop_name_as_utf16: Vec<u16> =
target_object_prop_name.unwrap().encode_utf16().collect();
#[allow(clippy::cast_enum_truncation)]
let mut succeeded = ObjectOpResult {
code_: ObjectOpResult_SpecialCodes::Uninitialized as usize,
};
if !JS_DeleteUCProperty(
*cx,
target_object.handle().into(),
prop_name_as_utf16.as_ptr(),
prop_name_as_utf16.len(),
&mut succeeded,
) {
// FIXME:(rasviitanen) Throw/return error
// return;
}
}
}
},
KeyPath::StringSequence(_) => {
unimplemented!("String sequence keyPath is currently unsupported");
},
}
}
fn has_key_generator(&self) -> bool {
let (sender, receiver) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
@ -361,26 +128,6 @@ impl IDBObjectStore {
receiver.recv().unwrap()
}
// https://www.w3.org/TR/IndexedDB-2/#extract-a-key-from-a-value-using-a-key-path
fn extract_key(
cx: SafeJSContext,
input: HandleValue,
key_path: &KeyPath,
multi_entry: Option<bool>,
) -> Result<IndexedDBKeyType, Error> {
// Step 1: Evaluate key path
// FIXME:(rasviitanen) Do this propertly
rooted!(in(*cx) let mut r = UndefinedValue());
IDBObjectStore::evaluate_key_path_on_value(cx, input, r.handle_mut(), key_path);
if let Some(_multi_entry) = multi_entry {
// FIXME:(rasviitanen) handle multi_entry cases
unimplemented!("multiEntry keys are not yet supported");
} else {
IDBObjectStore::convert_value_to_key(cx, r.handle(), None)
}
}
// https://www.w3.org/TR/IndexedDB-2/#object-store-in-line-keys
fn uses_inline_keys(&self) -> bool {
self.key_path.is_some()
@ -450,10 +197,10 @@ impl IDBObjectStore {
let serialized_key: IndexedDBKeyType;
if !key.is_undefined() {
serialized_key = IDBObjectStore::convert_value_to_key(cx, key, None)?;
serialized_key = convert_value_to_key(cx, key, None)?;
} else {
// Step 11: We should use in-line keys instead
if let Ok(kpk) = IDBObjectStore::extract_key(
if let Ok(kpk) = extract_key(
cx,
value,
self.key_path.as_ref().expect("No key path"),
@ -514,7 +261,7 @@ impl IDBObjectStoreMethods<crate::DomTypeHolder> for IDBObjectStore {
self.check_readwrite_transaction_active()?;
// Step 6
// TODO: Convert to key range instead
let serialized_query = IDBObjectStore::convert_value_to_key(cx, query, None);
let serialized_query = convert_value_to_key(cx, query, None);
// Step 7
serialized_query.and_then(|q| {
IDBRequest::execute_async(
@ -550,7 +297,7 @@ impl IDBObjectStoreMethods<crate::DomTypeHolder> for IDBObjectStore {
self.check_transaction_active()?;
// Step 5
// TODO: Convert to key range instead
let serialized_query = IDBObjectStore::convert_value_to_key(cx, query, None);
let serialized_query = convert_value_to_key(cx, query, None);
// Step 6
serialized_query.and_then(|q| {
IDBRequest::execute_async(
@ -604,7 +351,7 @@ impl IDBObjectStoreMethods<crate::DomTypeHolder> for IDBObjectStore {
self.check_transaction_active()?;
// Step 5
let serialized_query = IDBObjectStore::convert_value_to_key(cx, query, None);
let serialized_query = convert_value_to_key(cx, query, None);
// Step 6
serialized_query.and_then(|q| {

View file

@ -3,21 +3,18 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use std::cell::Cell;
use std::iter::repeat;
use constellation_traits::StructuredSerializedData;
use dom_struct::dom_struct;
use ipc_channel::router::ROUTER;
use js::gc::MutableHandle;
use js::jsapi::Heap;
use js::jsval::{DoubleValue, JSVal, UndefinedValue};
use js::rust::{HandleValue, MutableHandleValue};
use js::jsval::{JSVal, UndefinedValue};
use js::rust::HandleValue;
use net_traits::IpcSend;
use net_traits::indexeddb_thread::{
AsyncOperation, IdbResult, IndexedDBKeyType, IndexedDBThreadMsg, IndexedDBTxnMode,
AsyncOperation, IdbResult, IndexedDBThreadMsg, IndexedDBTxnMode,
};
use profile_traits::ipc;
use script_bindings::conversions::SafeToJSValConvertible;
use stylo_atoms::Atom;
use crate::dom::bindings::codegen::Bindings::IDBRequestBinding::{
@ -36,6 +33,7 @@ use crate::dom::eventtarget::EventTarget;
use crate::dom::globalscope::GlobalScope;
use crate::dom::idbobjectstore::IDBObjectStore;
use crate::dom::idbtransaction::IDBTransaction;
use crate::indexed_db::key_type_to_jsval;
use crate::realms::enter_realm;
use crate::script_runtime::{CanGc, JSContext as SafeJSContext};
@ -44,30 +42,6 @@ struct RequestListener {
request: Trusted<IDBRequest>,
}
#[allow(unsafe_code)]
fn key_type_to_jsval(cx: SafeJSContext, key: &IndexedDBKeyType, mut result: MutableHandleValue) {
match key {
IndexedDBKeyType::Number(n) => result.set(DoubleValue(*n)),
IndexedDBKeyType::String(s) => s.safe_to_jsval(cx, result),
IndexedDBKeyType::Binary(b) => b.safe_to_jsval(cx, result),
IndexedDBKeyType::Date(_d) => {
// TODO: implement this when Date's representation is finalized.
result.set(UndefinedValue());
},
IndexedDBKeyType::Array(a) => {
rooted_vec!(let mut values <- repeat(UndefinedValue()).take(a.len()));
for (key, value) in a.iter().zip(unsafe {
values
.iter_mut()
.map(|v| MutableHandle::from_marked_location(v))
}) {
key_type_to_jsval(cx, key, value);
}
values.safe_to_jsval(cx, result);
},
}
}
impl RequestListener {
fn handle_async_request_finished(&self, result: Result<Option<IdbResult>, ()>) {
let request = self.request.root();

View file

@ -12,7 +12,6 @@ use base::id::{MessagePortId, MessagePortIndex};
use constellation_traits::MessagePortImpl;
use dom_struct::dom_struct;
use ipc_channel::ipc::IpcSharedMemory;
use script_bindings::conversions::SafeToJSValConvertible;
use js::jsapi::{Heap, JSObject};
use js::jsval::{JSVal, ObjectValue, UndefinedValue};
use js::rust::{
@ -20,6 +19,7 @@ use js::rust::{
MutableHandleValue as SafeMutableHandleValue,
};
use js::typedarray::ArrayBufferViewU8;
use script_bindings::conversions::SafeToJSValConvertible;
use crate::dom::bindings::codegen::Bindings::QueuingStrategyBinding::QueuingStrategy;
use crate::dom::bindings::codegen::Bindings::ReadableStreamBinding::{

View file

@ -19,9 +19,9 @@ use js::typedarray::Float32Array;
use profile_traits::ipc;
use stylo_atoms::Atom;
use webxr_api::{
self, util, ApiSpace, ContextId as WebXRContextId, Display, EntityTypes, EnvironmentBlendMode,
self, ApiSpace, ContextId as WebXRContextId, Display, EntityTypes, EnvironmentBlendMode,
Event as XREvent, Frame, FrameUpdateEvent, HitTestId, HitTestSource, InputFrame, InputId, Ray,
SelectEvent, SelectKind, Session, SessionId, View, Viewer, Visibility,
SelectEvent, SelectKind, Session, SessionId, View, Viewer, Visibility, util,
};
use crate::conversions::Convert;

View file

@ -0,0 +1,292 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use std::iter::repeat;
use std::ptr;
use js::gc::MutableHandle;
use js::jsapi::{
ESClass, GetBuiltinClass, IsArrayBufferObject, JS_DeleteUCProperty,
JS_GetOwnUCPropertyDescriptor, JS_GetStringLength, JS_IsArrayBufferViewObject, JSObject,
ObjectOpResult, ObjectOpResult_SpecialCodes, PropertyDescriptor,
};
use js::jsval::{DoubleValue, UndefinedValue};
use js::rust::{HandleValue, MutableHandleValue};
use net_traits::indexeddb_thread::IndexedDBKeyType;
use script_bindings::conversions::SafeToJSValConvertible;
use script_bindings::str::DOMString;
use crate::dom::bindings::codegen::UnionTypes::StringOrStringSequence as StrOrStringSequence;
use crate::dom::bindings::conversions::jsstring_to_str;
use crate::dom::bindings::error::Error;
use crate::dom::bindings::import::module::SafeJSContext;
use crate::dom::bindings::structuredclone;
use crate::dom::idbobjectstore::KeyPath;
#[allow(unsafe_code)]
pub fn key_type_to_jsval(
cx: SafeJSContext,
key: &IndexedDBKeyType,
mut result: MutableHandleValue,
) {
match key {
IndexedDBKeyType::Number(n) => result.set(DoubleValue(*n)),
IndexedDBKeyType::String(s) => s.safe_to_jsval(cx, result),
IndexedDBKeyType::Binary(b) => b.safe_to_jsval(cx, result),
IndexedDBKeyType::Date(_d) => {
// TODO: implement this when Date's representation is finalized.
result.set(UndefinedValue());
},
IndexedDBKeyType::Array(a) => {
rooted_vec!(let mut values <- repeat(UndefinedValue()).take(a.len()));
for (key, value) in a.iter().zip(unsafe {
values
.iter_mut()
.map(|v| MutableHandle::from_marked_location(v))
}) {
key_type_to_jsval(cx, key, value);
}
values.safe_to_jsval(cx, result);
},
}
}
// https://www.w3.org/TR/IndexedDB-2/#valid-key-path
pub fn is_valid_key_path(key_path: &StrOrStringSequence) -> bool {
fn is_identifier(_s: &str) -> bool {
// FIXME: (arihant2math)
true
}
let is_valid = |path: &DOMString| {
path.is_empty() || is_identifier(path) || path.split(".").all(is_identifier)
};
match key_path {
StrOrStringSequence::StringSequence(paths) => {
if paths.is_empty() {
return false;
}
paths.iter().all(is_valid)
},
StrOrStringSequence::String(path) => is_valid(path),
}
}
#[allow(unsafe_code)]
// https://www.w3.org/TR/IndexedDB-2/#convert-value-to-key
pub fn convert_value_to_key(
cx: SafeJSContext,
input: HandleValue,
seen: Option<Vec<HandleValue>>,
) -> Result<IndexedDBKeyType, Error> {
// Step 1: If seen was not given, then let seen be a new empty set.
let _seen = seen.unwrap_or_default();
// Step 2: If seen contains input, then return invalid.
// FIXME:(arihant2math) implement this
// Check if we have seen this key
// Does not currently work with HandleValue,
// as it does not implement PartialEq
// Step 3
// FIXME:(arihant2math) Accept buffer, array and date as well
if input.is_number() {
// FIXME:(arihant2math) check for NaN
return Ok(IndexedDBKeyType::Number(input.to_number()));
}
if input.is_string() {
let string_ptr = std::ptr::NonNull::new(input.to_string()).unwrap();
let key = unsafe { jsstring_to_str(*cx, string_ptr).str().to_string() };
return Ok(IndexedDBKeyType::String(key));
}
if input.is_object() {
rooted!(in(*cx) let object = input.to_object());
unsafe {
let mut built_in_class = ESClass::Other;
if !GetBuiltinClass(*cx, object.handle().into(), &mut built_in_class) {
return Err(Error::Data);
}
if let ESClass::Date = built_in_class {
// FIXME:(arihant2math) implement it the correct way
let key = structuredclone::write(cx, input, None).expect("Could not serialize key");
return Ok(IndexedDBKeyType::Date(key.serialized.clone()));
}
if IsArrayBufferObject(*object) || JS_IsArrayBufferViewObject(*object) {
// FIXME:(arihant2math)
error!("Array buffers as keys is currently unsupported");
return Err(Error::NotSupported);
}
if let ESClass::Array = built_in_class {
// FIXME:(arihant2math)
unimplemented!("Arrays as keys is currently unsupported");
}
}
}
Err(Error::Data)
}
// https://www.w3.org/TR/IndexedDB-2/#evaluate-a-key-path-on-a-value
#[allow(unsafe_code)]
pub fn evaluate_key_path_on_value(
cx: SafeJSContext,
value: HandleValue,
mut return_val: MutableHandleValue,
key_path: &KeyPath,
) {
// The implementation is translated from gecko:
// https://github.com/mozilla/gecko-dev/blob/master/dom/indexedDB/KeyPath.cpp
return_val.set(*value);
rooted!(in(*cx) let mut target_object = ptr::null_mut::<JSObject>());
rooted!(in(*cx) let mut current_val = *value);
rooted!(in(*cx) let mut object = ptr::null_mut::<JSObject>());
let mut target_object_prop_name: Option<String> = None;
match key_path {
KeyPath::String(path) => {
// Step 3
let path_as_string = path.to_string();
let mut tokenizer = path_as_string.split('.').peekable();
while let Some(token) = tokenizer.next() {
if target_object.get().is_null() {
if token == "length" && tokenizer.peek().is_none() && current_val.is_string() {
rooted!(in(*cx) let input_val = current_val.to_string());
unsafe {
let string_len = JS_GetStringLength(*input_val) as u64;
string_len.safe_to_jsval(cx, return_val);
}
break;
}
if !current_val.is_object() {
// FIXME:(rasviitanen) Return a proper error
return;
}
object.handle_mut().set(current_val.to_object());
rooted!(in(*cx) let mut desc = PropertyDescriptor::default());
rooted!(in(*cx) let mut intermediate = UndefinedValue());
// So rust says that this value is never read, but it is.
#[allow(unused)]
let mut has_prop = false;
unsafe {
let prop_name_as_utf16: Vec<u16> = token.encode_utf16().collect();
let mut is_descriptor_none: bool = false;
let ok = JS_GetOwnUCPropertyDescriptor(
*cx,
object.handle().into(),
prop_name_as_utf16.as_ptr(),
prop_name_as_utf16.len(),
desc.handle_mut().into(),
&mut is_descriptor_none,
);
if !ok {
// FIXME:(arihant2math) Handle this
return;
}
if desc.hasWritable_() || desc.hasValue_() {
intermediate.handle_mut().set(desc.handle().value_);
has_prop = true;
} else {
// If we get here it means the object doesn't have the property or the
// property is available throuch a getter. We don't want to call any
// getters to avoid potential re-entrancy.
// The blob object is special since its properties are available
// only through getters but we still want to support them for key
// extraction. So they need to be handled manually.
unimplemented!("Blob tokens are not yet supported");
}
}
if has_prop {
// Treat undefined as an error
if intermediate.is_undefined() {
// FIXME:(rasviitanen) Throw/return error
return;
}
if tokenizer.peek().is_some() {
// ...and walk to it if there are more steps...
current_val.handle_mut().set(*intermediate);
} else {
// ...otherwise use it as key
return_val.set(*intermediate);
}
} else {
target_object.handle_mut().set(*object);
target_object_prop_name = Some(token.to_string());
}
}
if !target_object.get().is_null() {
// We have started inserting new objects or are about to just insert
// the first one.
// FIXME:(rasviitanen) Implement this piece
unimplemented!("keyPath tokens that requires insertion are not supported.");
}
} // All tokens processed
if !target_object.get().is_null() {
// If this fails, we lose, and the web page sees a magical property
// appear on the object :-(
unsafe {
let prop_name_as_utf16: Vec<u16> =
target_object_prop_name.unwrap().encode_utf16().collect();
#[allow(clippy::cast_enum_truncation)]
let mut succeeded = ObjectOpResult {
code_: ObjectOpResult_SpecialCodes::Uninitialized as usize,
};
if !JS_DeleteUCProperty(
*cx,
target_object.handle().into(),
prop_name_as_utf16.as_ptr(),
prop_name_as_utf16.len(),
&mut succeeded,
) {
// FIXME:(rasviitanen) Throw/return error
// return;
}
}
}
},
KeyPath::StringSequence(_) => {
unimplemented!("String sequence keyPath is currently unsupported");
},
}
}
// https://www.w3.org/TR/IndexedDB-2/#extract-a-key-from-a-value-using-a-key-path
pub fn extract_key(
cx: SafeJSContext,
input: HandleValue,
key_path: &KeyPath,
multi_entry: Option<bool>,
) -> Result<IndexedDBKeyType, Error> {
// Step 1: Evaluate key path
// FIXME:(rasviitanen) Do this propertly
rooted!(in(*cx) let mut r = UndefinedValue());
evaluate_key_path_on_value(cx, input, r.handle_mut(), key_path);
if let Some(_multi_entry) = multi_entry {
// FIXME:(rasviitanen) handle multi_entry cases
unimplemented!("multiEntry keys are not yet supported");
} else {
convert_value_to_key(cx, r.handle(), None)
}
}

View file

@ -34,6 +34,7 @@ mod dom;
mod canvas_context;
mod canvas_state;
pub(crate) mod fetch;
pub(crate) mod indexed_db;
mod init;
mod layout_image;