summaryrefslogtreecommitdiffstats
path: root/netwerk/base/http-sfv
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /netwerk/base/http-sfv
parentInitial commit. (diff)
downloadfirefox-upstream/124.0.1.tar.xz
firefox-upstream/124.0.1.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--netwerk/base/http-sfv/Cargo.toml15
-rw-r--r--netwerk/base/http-sfv/SFVService.cpp39
-rw-r--r--netwerk/base/http-sfv/SFVService.h14
-rw-r--r--netwerk/base/http-sfv/moz.build17
-rw-r--r--netwerk/base/http-sfv/nsIStructuredFieldValues.idl290
-rw-r--r--netwerk/base/http-sfv/src/lib.rs873
6 files changed, 1248 insertions, 0 deletions
diff --git a/netwerk/base/http-sfv/Cargo.toml b/netwerk/base/http-sfv/Cargo.toml
new file mode 100644
index 0000000000..4625cdf974
--- /dev/null
+++ b/netwerk/base/http-sfv/Cargo.toml
@@ -0,0 +1,15 @@
+[package]
+name = "http_sfv"
+version = "0.1.0"
+authors = ["barabass <yalyna.ts@gmail.com>"]
+edition = "2018"
+license = "MPL-2.0"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+nserror = { path = "../../../xpcom/rust/nserror" }
+nsstring = { path = "../../../xpcom/rust/nsstring" }
+sfv = "0.9.1"
+xpcom = { path = "../../../xpcom/rust/xpcom" }
+thin-vec = { version = "0.2.1", features = ["gecko-ffi"] }
diff --git a/netwerk/base/http-sfv/SFVService.cpp b/netwerk/base/http-sfv/SFVService.cpp
new file mode 100644
index 0000000000..9759993e7f
--- /dev/null
+++ b/netwerk/base/http-sfv/SFVService.cpp
@@ -0,0 +1,39 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/ClearOnShutdown.h"
+#include "mozilla/StaticPtr.h"
+#include "nsCOMPtr.h"
+#include "SFVService.h"
+
+// This anonymous namespace prevents outside C++ code from improperly accessing
+// these implementation details.
+namespace {
+extern "C" {
+// Implemented in Rust.
+void new_sfv_service(nsISFVService** result);
+}
+
+static mozilla::StaticRefPtr<nsISFVService> sService;
+} // namespace
+
+namespace mozilla::net {
+
+already_AddRefed<nsISFVService> GetSFVService() {
+ nsCOMPtr<nsISFVService> service;
+
+ if (sService) {
+ service = sService;
+ } else {
+ new_sfv_service(getter_AddRefs(service));
+ sService = service;
+ mozilla::ClearOnShutdown(&sService);
+ }
+
+ return service.forget();
+}
+
+} // namespace mozilla::net
diff --git a/netwerk/base/http-sfv/SFVService.h b/netwerk/base/http-sfv/SFVService.h
new file mode 100644
index 0000000000..4016951609
--- /dev/null
+++ b/netwerk/base/http-sfv/SFVService.h
@@ -0,0 +1,14 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 http://mozilla.org/MPL/2.0/. */
+
+#include "nsIStructuredFieldValues.h"
+namespace mozilla {
+namespace net {
+
+already_AddRefed<nsISFVService> GetSFVService();
+
+} // namespace net
+} // namespace mozilla
diff --git a/netwerk/base/http-sfv/moz.build b/netwerk/base/http-sfv/moz.build
new file mode 100644
index 0000000000..ed857c91a8
--- /dev/null
+++ b/netwerk/base/http-sfv/moz.build
@@ -0,0 +1,17 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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 http://mozilla.org/MPL/2.0/.
+
+XPIDL_SOURCES += [
+ "nsIStructuredFieldValues.idl",
+]
+
+XPIDL_MODULE = "http-sfv"
+
+EXPORTS.mozilla.net += ["SFVService.h"]
+
+SOURCES += ["SFVService.cpp"]
+
+FINAL_LIBRARY = "xul"
diff --git a/netwerk/base/http-sfv/nsIStructuredFieldValues.idl b/netwerk/base/http-sfv/nsIStructuredFieldValues.idl
new file mode 100644
index 0000000000..3f02b33953
--- /dev/null
+++ b/netwerk/base/http-sfv/nsIStructuredFieldValues.idl
@@ -0,0 +1,290 @@
+/* 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 http://mozilla.org/MPL/2.0/. */
+
+#include "nsISupports.idl"
+
+/**
+ * Conceptually, there are three types of structured field (header) values:
+ *
+ * Item - can be an Integer, Decimal, String, Token, Byte Sequence, or Boolean.
+ * It can have associated Parameters.
+ * List - array of zero or more members, each of which can be an Item or an InnerList,
+ * both of which can be Parameterized.
+ * Dictionary - ordered map of name-value pairs, where the names are short textual strings
+ * and the values are Items or arrays of Items (represented with InnerList),
+ * both of which can be Parameterized. There can be zero or more members,
+ * and their names are unique in the scope of the Dictionary they occur within.
+ *
+ *
+ * There's also a few primitive types used to construct structured field values:
+ * - BareItem used as Item's value or as a parameter value in Parameters.
+ * - Parameters are an ordered map of key-value pairs that are associated with an Item or InnerList.
+ * The keys are unique within the scope the Parameters they occur within, and the values are BareItem.
+ * - InnerList is an array of zero or more Items. Can have Parameters.
+ * - ListEntry represents either Item or InnerList as a member of List or as member-value in Dictionary.
+ */
+
+
+
+/**
+ * nsISFVBareItem is a building block for Item header value (nsISFVItem) and Parameters (nsISFVParams).
+ * It can be of type BOOL, STRING, DECIMAL, INTEGER, TOKEN, BYTE_SEQUENCE.
+ * Each type is represented by its own interface which is used to create
+ * a bare item of that type.
+ */
+[scriptable, builtinclass, uuid(7072853f-215b-4a8a-92e5-9732bccc377b)]
+interface nsISFVBareItem : nsISupports {
+ const long BOOL = 1;
+ const long STRING = 2;
+ const long DECIMAL = 3;
+ const long INTEGER = 4;
+ const long TOKEN = 5;
+ const long BYTE_SEQUENCE = 6;
+
+ /**
+ * Returns value associated with type of bare item.
+ * Used to identify type of bare item without querying for interface
+ * (like nsISFVString, etc).
+ */
+ readonly attribute long type;
+};
+
+[scriptable, builtinclass, uuid(843eea44-990a-422c-bbf2-2aa4ba9ee4d2)]
+interface nsISFVInteger : nsISFVBareItem {
+ attribute long long value;
+};
+
+[scriptable, builtinclass, uuid(df6a0787-7caa-4fef-b145-08c1104c2fde)]
+interface nsISFVString : nsISFVBareItem {
+ attribute ACString value;
+};
+
+[scriptable, builtinclass, uuid(d263c6d7-4123-4c39-a121-ccf874a19012)]
+interface nsISFVBool : nsISFVBareItem {
+ attribute boolean value;
+};
+
+[scriptable, builtinclass, uuid(1098da8b-b4df-4526-b985-53dbd4160ad2)]
+interface nsISFVDecimal : nsISFVBareItem {
+ attribute double value;
+};
+
+[scriptable, builtinclass, uuid(8ad33d52-b9b2-4a17-8aa8-991250fc1214)]
+interface nsISFVToken : nsISFVBareItem {
+ attribute ACString value;
+};
+
+[scriptable, builtinclass, uuid(887eaef0-19fe-42bc-9a42-9ff773aa8fea)]
+interface nsISFVByteSeq : nsISFVBareItem {
+ attribute ACString value;
+};
+
+
+/**
+ * nsISFVParams represents parameters, key-value pairs of ACString and nsISFVBareItem,
+ * which parametrize Item type header or InnerList type withing List type header.
+ */
+[scriptable, builtinclass, uuid(b1a397d7-3333-43e7-993a-fbe8ab90ee96)]
+interface nsISFVParams : nsISupports {
+ /**
+ * Return value (nsISFVBareItem) stored for key, if it is present
+ *
+ * @throws NS_ERROR_UNEXPECTED if the key does not exist in parameters.
+ */
+ nsISFVBareItem get(in ACString key);
+
+ /**
+ * Insert a new key-value pair.
+ * If an equivalent key already exists: the key remains and retains in its place in the order,
+ * its corresponding value is updated with the new value.
+ *
+ * @throws NS_ERROR_UNEXPECTED if supplied item does not implement nsISFVBareItem interface.
+ */
+ void set(in ACString key, in nsISFVBareItem item);
+
+ /**
+ * Remove the key-value pair equivalent to key.
+ *
+ * @throws NS_ERROR_UNEXPECTED upon attempt to delete key that does not exist in parameters.
+ */
+ void delete(in ACString key);
+
+ /**
+ * Returns array of keys.
+ */
+ Array<ACString> keys();
+};
+
+/**
+ * nsISFVParametrizable is implemented for types that
+ * can be parametrized with nsISFVParams
+ */
+[scriptable, builtinclass, uuid(6c0399f8-01de-4b25-b339-68e35e8d2e49)]
+interface nsISFVParametrizable : nsISupports {
+ readonly attribute nsISFVParams params;
+};
+
+/**
+ * nsISFVItemOrInnerList represents member in nsISFVList
+ * or member-value in nsISFVDictionary.
+ * nsISFVItemOrInnerList is implemented for
+ * nsISFVItem or nsISFVInnerList, both of which are used
+ * to create nsISFVList and nsISFVDictionary.
+ */
+[scriptable, builtinclass, uuid(99ac1b56-b5b3-44e7-ad96-db7444aae4b2)]
+interface nsISFVItemOrInnerList : nsISFVParametrizable {
+};
+
+/**
+ * nsISFVSerialize indicates that object can be serialized into ACString.
+ */
+[scriptable, builtinclass, uuid(28b9215d-c131-413c-9482-0004a371a5ec)]
+interface nsISFVSerialize : nsISupports {
+ ACString serialize();
+};
+
+/**
+ * nsISFVItem represents Item structured header value.
+ */
+[scriptable, builtinclass, uuid(abe8826b-6af7-4e54-bd2c-46ab231700ce)]
+interface nsISFVItem : nsISFVItemOrInnerList {
+ readonly attribute nsISFVBareItem value;
+ ACString serialize();
+};
+
+/**
+ * nsISFVInnerList can be used as a member of nsISFVList
+ * or a member-value of nsISFVDictionary.
+ */
+[scriptable, builtinclass, uuid(b2e52be2-8488-41b2-9ee2-3c48d92d095c)]
+interface nsISFVInnerList : nsISFVItemOrInnerList {
+ attribute Array<nsISFVItem> items;
+};
+
+/**
+ * nsISFVList represents List structured header value.
+ */
+[scriptable, builtinclass, uuid(02bb92a6-d1de-449c-b54f-d137f30c613d)]
+interface nsISFVList : nsISFVSerialize {
+ /**
+ * Returns array of members.
+ * QueryInterface can be used on a member to get more specific type.
+ */
+ attribute Array<nsISFVItemOrInnerList> members;
+
+ /**
+ * In case when header value is split across lines, it's possible
+ * this method parses supplied line and merges it with members of existing object.
+ */
+ void parseMore(in ACString header);
+};
+
+/**
+ * nsISFVDictionary represents nsISFVDictionary structured header value.
+ */
+[scriptable, builtinclass, uuid(6642a7fe-7026-4eba-b730-05e230ee3437)]
+interface nsISFVDictionary : nsISFVSerialize {
+
+ /**
+ * Return value (nsISFVItemOrInnerList) stored for key, if it is present.
+ * QueryInterface can be used on a value to get more specific type.
+ *
+ * @throws NS_ERROR_UNEXPECTED if the key does not exist in parameters.
+ */
+ nsISFVItemOrInnerList get(in ACString key);
+
+ /**
+ * Insert a new key-value pair.
+ * If an equivalent key already exists: the key remains and retains in its place in the order,
+ * its corresponding value is updated with the new value.
+ *
+ * @throws NS_ERROR_UNEXPECTED if supplied item does not implement nsISFVItemOrInnerList interface.
+ */
+ void set(in ACString key, in nsISFVItemOrInnerList member_value);
+
+ /**
+ * Remove the key-value pair equivalent to key.
+ *
+ * @throws NS_ERROR_UNEXPECTED upon attempt to delete key that does not exist in parameters.
+ */
+ void delete(in ACString key);
+
+ /**
+ * Returns array of keys.
+ */
+ Array<ACString> keys();
+
+ /**
+ * In case when header value is split across lines, it's possible
+ * this method parses supplied line and merges it with members of existing object.
+ */
+ void parseMore(in ACString header);
+};
+
+
+/**
+ * nsISFVService provides a set of functions for working with HTTP header value as an object.
+ * It exposes functions for creating object from string containing header value,
+ * as well as individual components for manual structured header object creation.
+ */
+[scriptable, builtinclass, uuid(049f4be1-2f22-4438-a8da-518552ed390c)]
+interface nsISFVService: nsISupports
+{
+ /**
+ * Parses provided string into Dictionary header value (nsISFVDictionary).
+ *
+ * @throws NS_ERROR_FAILURE if parsing fails.
+ */
+ nsISFVDictionary parseDictionary(in ACString header);
+
+ /**
+ * Parses provided string into List header value (nsISFVList).
+ *
+ * @throws NS_ERROR_FAILURE if parsing fails.
+ */
+ nsISFVList parseList(in ACString header);
+
+ /**
+ * Parses provided string into Item header value (nsISFVItem).
+ *
+ * @throws NS_ERROR_FAILURE if parsing fails.
+ */
+ nsISFVItem parseItem(in ACString header);
+
+ /**
+ * The following functions create bare item of specific type.
+ */
+ nsISFVInteger newInteger(in long long value);
+ nsISFVBool newBool(in bool value);
+ nsISFVDecimal newDecimal(in double value);
+ nsISFVString newString(in ACString value);
+ nsISFVByteSeq newByteSequence(in ACString value);
+ nsISFVToken newToken(in ACString value);
+
+ /**
+ * Creates nsISFVParams with no parameters. In other words, it's an empty map byt default.
+ */
+ nsISFVParams newParameters();
+
+ /**
+ * Creates nsISFVInnerList from nsISFVItem array and nsISFVParams.
+ */
+ nsISFVInnerList newInnerList(in Array<nsISFVItem> items, in nsISFVParams params);
+
+ /**
+ * Creates nsISFVItem, which represents Item header value, from nsISFVBareItem and associated nsISFVParams.
+ */
+ nsISFVItem newItem(in nsISFVBareItem value, in nsISFVParams params);
+
+ /**
+ * Creates nsISFVList, which represents List header value, from array of nsISFVItemOrInnerList.
+ * nsISFVItemOrInnerList represens either Item (nsISFVItem) or Inner List (nsISFVInnerList).
+ */
+ nsISFVList newList(in Array<nsISFVItemOrInnerList> members);
+
+ /**
+ * Creates nsISFVDictionary representing Dictionary header value. It is empty by default.
+ */
+ nsISFVDictionary newDictionary();
+};
diff --git a/netwerk/base/http-sfv/src/lib.rs b/netwerk/base/http-sfv/src/lib.rs
new file mode 100644
index 0000000000..fe669f5f3f
--- /dev/null
+++ b/netwerk/base/http-sfv/src/lib.rs
@@ -0,0 +1,873 @@
+/* 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 http://mozilla.org/MPL/2.0/. */
+
+use nserror::{nsresult, NS_ERROR_FAILURE, NS_ERROR_NULL_POINTER, NS_ERROR_UNEXPECTED, NS_OK};
+use nsstring::{nsACString, nsCString};
+use sfv::Parser;
+use sfv::SerializeValue;
+use sfv::{
+ BareItem, Decimal, Dictionary, FromPrimitive, InnerList, Item, List, ListEntry, Parameters,
+ ParseMore,
+};
+use std::cell::RefCell;
+use std::ops::Deref;
+use thin_vec::ThinVec;
+use xpcom::interfaces::{
+ nsISFVBareItem, nsISFVBool, nsISFVByteSeq, nsISFVDecimal, nsISFVDictionary, nsISFVInnerList,
+ nsISFVInteger, nsISFVItem, nsISFVItemOrInnerList, nsISFVList, nsISFVParams, nsISFVService,
+ nsISFVString, nsISFVToken,
+};
+use xpcom::{xpcom, xpcom_method, RefPtr, XpCom};
+
+#[no_mangle]
+pub unsafe extern "C" fn new_sfv_service(result: *mut *const nsISFVService) {
+ let service: RefPtr<SFVService> = SFVService::new();
+ RefPtr::new(service.coerce::<nsISFVService>()).forget(&mut *result);
+}
+
+#[xpcom(implement(nsISFVService), atomic)]
+struct SFVService {}
+
+impl SFVService {
+ fn new() -> RefPtr<SFVService> {
+ SFVService::allocate(InitSFVService {})
+ }
+
+ xpcom_method!(parse_dictionary => ParseDictionary(header: *const nsACString) -> *const nsISFVDictionary);
+ fn parse_dictionary(&self, header: &nsACString) -> Result<RefPtr<nsISFVDictionary>, nsresult> {
+ let parsed_dict = Parser::parse_dictionary(&header).map_err(|_| NS_ERROR_FAILURE)?;
+ let sfv_dict = SFVDictionary::new();
+ sfv_dict.value.replace(parsed_dict);
+ Ok(RefPtr::new(sfv_dict.coerce::<nsISFVDictionary>()))
+ }
+
+ xpcom_method!(parse_list => ParseList(field_value: *const nsACString) -> *const nsISFVList);
+ fn parse_list(&self, header: &nsACString) -> Result<RefPtr<nsISFVList>, nsresult> {
+ let parsed_list = Parser::parse_list(&header).map_err(|_| NS_ERROR_FAILURE)?;
+
+ let mut nsi_members = Vec::new();
+ for item_or_inner_list in parsed_list.iter() {
+ nsi_members.push(interface_from_list_entry(item_or_inner_list)?)
+ }
+ let sfv_list = SFVList::allocate(InitSFVList {
+ members: RefCell::new(nsi_members),
+ });
+ Ok(RefPtr::new(sfv_list.coerce::<nsISFVList>()))
+ }
+
+ xpcom_method!(parse_item => ParseItem(header: *const nsACString) -> *const nsISFVItem);
+ fn parse_item(&self, header: &nsACString) -> Result<RefPtr<nsISFVItem>, nsresult> {
+ let parsed_item = Parser::parse_item(&header).map_err(|_| NS_ERROR_FAILURE)?;
+ interface_from_item(&parsed_item)
+ }
+
+ xpcom_method!(new_integer => NewInteger(value: i64) -> *const nsISFVInteger);
+ fn new_integer(&self, value: i64) -> Result<RefPtr<nsISFVInteger>, nsresult> {
+ Ok(RefPtr::new(
+ SFVInteger::new(value).coerce::<nsISFVInteger>(),
+ ))
+ }
+
+ xpcom_method!(new_decimal => NewDecimal(value: f64) -> *const nsISFVDecimal);
+ fn new_decimal(&self, value: f64) -> Result<RefPtr<nsISFVDecimal>, nsresult> {
+ Ok(RefPtr::new(
+ SFVDecimal::new(value).coerce::<nsISFVDecimal>(),
+ ))
+ }
+
+ xpcom_method!(new_bool => NewBool(value: bool) -> *const nsISFVBool);
+ fn new_bool(&self, value: bool) -> Result<RefPtr<nsISFVBool>, nsresult> {
+ Ok(RefPtr::new(SFVBool::new(value).coerce::<nsISFVBool>()))
+ }
+
+ xpcom_method!(new_string => NewString(value: *const nsACString) -> *const nsISFVString);
+ fn new_string(&self, value: &nsACString) -> Result<RefPtr<nsISFVString>, nsresult> {
+ Ok(RefPtr::new(SFVString::new(value).coerce::<nsISFVString>()))
+ }
+
+ xpcom_method!(new_token => NewToken(value: *const nsACString) -> *const nsISFVToken);
+ fn new_token(&self, value: &nsACString) -> Result<RefPtr<nsISFVToken>, nsresult> {
+ Ok(RefPtr::new(SFVToken::new(value).coerce::<nsISFVToken>()))
+ }
+
+ xpcom_method!(new_byte_sequence => NewByteSequence(value: *const nsACString) -> *const nsISFVByteSeq);
+ fn new_byte_sequence(&self, value: &nsACString) -> Result<RefPtr<nsISFVByteSeq>, nsresult> {
+ Ok(RefPtr::new(
+ SFVByteSeq::new(value).coerce::<nsISFVByteSeq>(),
+ ))
+ }
+
+ xpcom_method!(new_parameters => NewParameters() -> *const nsISFVParams);
+ fn new_parameters(&self) -> Result<RefPtr<nsISFVParams>, nsresult> {
+ Ok(RefPtr::new(SFVParams::new().coerce::<nsISFVParams>()))
+ }
+
+ xpcom_method!(new_item => NewItem(value: *const nsISFVBareItem, params: *const nsISFVParams) -> *const nsISFVItem);
+ fn new_item(
+ &self,
+ value: &nsISFVBareItem,
+ params: &nsISFVParams,
+ ) -> Result<RefPtr<nsISFVItem>, nsresult> {
+ Ok(RefPtr::new(
+ SFVItem::new(value, params).coerce::<nsISFVItem>(),
+ ))
+ }
+
+ xpcom_method!(new_inner_list => NewInnerList(items: *const thin_vec::ThinVec<Option<RefPtr<nsISFVItem>>>, params: *const nsISFVParams) -> *const nsISFVInnerList);
+ fn new_inner_list(
+ &self,
+ items: &thin_vec::ThinVec<Option<RefPtr<nsISFVItem>>>,
+ params: &nsISFVParams,
+ ) -> Result<RefPtr<nsISFVInnerList>, nsresult> {
+ let items = items
+ .iter()
+ .cloned()
+ .map(|item| item.ok_or(NS_ERROR_NULL_POINTER))
+ .collect::<Result<Vec<_>, nsresult>>()?;
+ Ok(RefPtr::new(
+ SFVInnerList::new(items, params).coerce::<nsISFVInnerList>(),
+ ))
+ }
+
+ xpcom_method!(new_list => NewList(members: *const thin_vec::ThinVec<Option<RefPtr<nsISFVItemOrInnerList>>>) -> *const nsISFVList);
+ fn new_list(
+ &self,
+ members: &thin_vec::ThinVec<Option<RefPtr<nsISFVItemOrInnerList>>>,
+ ) -> Result<RefPtr<nsISFVList>, nsresult> {
+ let members = members
+ .iter()
+ .cloned()
+ .map(|item| item.ok_or(NS_ERROR_NULL_POINTER))
+ .collect::<Result<Vec<_>, nsresult>>()?;
+ Ok(RefPtr::new(SFVList::new(members).coerce::<nsISFVList>()))
+ }
+
+ xpcom_method!(new_dictionary => NewDictionary() -> *const nsISFVDictionary);
+ fn new_dictionary(&self) -> Result<RefPtr<nsISFVDictionary>, nsresult> {
+ Ok(RefPtr::new(
+ SFVDictionary::new().coerce::<nsISFVDictionary>(),
+ ))
+ }
+}
+
+#[xpcom(implement(nsISFVInteger, nsISFVBareItem), nonatomic)]
+struct SFVInteger {
+ value: RefCell<i64>,
+}
+
+impl SFVInteger {
+ fn new(value: i64) -> RefPtr<SFVInteger> {
+ SFVInteger::allocate(InitSFVInteger {
+ value: RefCell::new(value),
+ })
+ }
+
+ xpcom_method!(get_value => GetValue() -> i64);
+ fn get_value(&self) -> Result<i64, nsresult> {
+ Ok(*self.value.borrow())
+ }
+
+ xpcom_method!(set_value => SetValue(value: i64));
+ fn set_value(&self, value: i64) -> Result<(), nsresult> {
+ self.value.replace(value);
+ Ok(())
+ }
+
+ xpcom_method!(get_type => GetType() -> i32);
+ fn get_type(&self) -> Result<i32, nsresult> {
+ Ok(nsISFVBareItem::INTEGER)
+ }
+
+ fn from_bare_item_interface(obj: &nsISFVBareItem) -> &Self {
+ unsafe { ::std::mem::transmute(obj) }
+ }
+}
+
+#[xpcom(implement(nsISFVBool, nsISFVBareItem), nonatomic)]
+struct SFVBool {
+ value: RefCell<bool>,
+}
+
+impl SFVBool {
+ fn new(value: bool) -> RefPtr<SFVBool> {
+ SFVBool::allocate(InitSFVBool {
+ value: RefCell::new(value),
+ })
+ }
+
+ xpcom_method!(get_value => GetValue() -> bool);
+ fn get_value(&self) -> Result<bool, nsresult> {
+ Ok(*self.value.borrow())
+ }
+
+ xpcom_method!(set_value => SetValue(value: bool));
+ fn set_value(&self, value: bool) -> Result<(), nsresult> {
+ self.value.replace(value);
+ Ok(())
+ }
+
+ xpcom_method!(get_type => GetType() -> i32);
+ fn get_type(&self) -> Result<i32, nsresult> {
+ Ok(nsISFVBareItem::BOOL)
+ }
+
+ fn from_bare_item_interface(obj: &nsISFVBareItem) -> &Self {
+ unsafe { ::std::mem::transmute(obj) }
+ }
+}
+
+#[xpcom(implement(nsISFVString, nsISFVBareItem), nonatomic)]
+struct SFVString {
+ value: RefCell<nsCString>,
+}
+
+impl SFVString {
+ fn new(value: &nsACString) -> RefPtr<SFVString> {
+ SFVString::allocate(InitSFVString {
+ value: RefCell::new(nsCString::from(value)),
+ })
+ }
+
+ xpcom_method!(
+ get_value => GetValue(
+ ) -> nsACString
+ );
+
+ fn get_value(&self) -> Result<nsCString, nsresult> {
+ Ok(self.value.borrow().clone())
+ }
+
+ xpcom_method!(
+ set_value => SetValue(value: *const nsACString)
+ );
+
+ fn set_value(&self, value: &nsACString) -> Result<(), nsresult> {
+ self.value.borrow_mut().assign(value);
+ Ok(())
+ }
+
+ xpcom_method!(get_type => GetType() -> i32);
+ fn get_type(&self) -> Result<i32, nsresult> {
+ Ok(nsISFVBareItem::STRING)
+ }
+
+ fn from_bare_item_interface(obj: &nsISFVBareItem) -> &Self {
+ unsafe { ::std::mem::transmute(obj) }
+ }
+}
+
+#[xpcom(implement(nsISFVToken, nsISFVBareItem), nonatomic)]
+struct SFVToken {
+ value: RefCell<nsCString>,
+}
+
+impl SFVToken {
+ fn new(value: &nsACString) -> RefPtr<SFVToken> {
+ SFVToken::allocate(InitSFVToken {
+ value: RefCell::new(nsCString::from(value)),
+ })
+ }
+
+ xpcom_method!(
+ get_value => GetValue(
+ ) -> nsACString
+ );
+
+ fn get_value(&self) -> Result<nsCString, nsresult> {
+ Ok(self.value.borrow().clone())
+ }
+
+ xpcom_method!(
+ set_value => SetValue(value: *const nsACString)
+ );
+
+ fn set_value(&self, value: &nsACString) -> Result<(), nsresult> {
+ self.value.borrow_mut().assign(value);
+ Ok(())
+ }
+
+ xpcom_method!(get_type => GetType() -> i32);
+ fn get_type(&self) -> Result<i32, nsresult> {
+ Ok(nsISFVBareItem::TOKEN)
+ }
+
+ fn from_bare_item_interface(obj: &nsISFVBareItem) -> &Self {
+ unsafe { ::std::mem::transmute(obj) }
+ }
+}
+
+#[xpcom(implement(nsISFVByteSeq, nsISFVBareItem), nonatomic)]
+struct SFVByteSeq {
+ value: RefCell<nsCString>,
+}
+
+impl SFVByteSeq {
+ fn new(value: &nsACString) -> RefPtr<SFVByteSeq> {
+ SFVByteSeq::allocate(InitSFVByteSeq {
+ value: RefCell::new(nsCString::from(value)),
+ })
+ }
+
+ xpcom_method!(
+ get_value => GetValue(
+ ) -> nsACString
+ );
+
+ fn get_value(&self) -> Result<nsCString, nsresult> {
+ Ok(self.value.borrow().clone())
+ }
+
+ xpcom_method!(
+ set_value => SetValue(value: *const nsACString)
+ );
+
+ fn set_value(&self, value: &nsACString) -> Result<(), nsresult> {
+ self.value.borrow_mut().assign(value);
+ Ok(())
+ }
+
+ xpcom_method!(get_type => GetType() -> i32);
+ fn get_type(&self) -> Result<i32, nsresult> {
+ Ok(nsISFVBareItem::BYTE_SEQUENCE)
+ }
+
+ fn from_bare_item_interface(obj: &nsISFVBareItem) -> &Self {
+ unsafe { ::std::mem::transmute(obj) }
+ }
+}
+
+#[xpcom(implement(nsISFVDecimal, nsISFVBareItem), nonatomic)]
+struct SFVDecimal {
+ value: RefCell<f64>,
+}
+
+impl SFVDecimal {
+ fn new(value: f64) -> RefPtr<SFVDecimal> {
+ SFVDecimal::allocate(InitSFVDecimal {
+ value: RefCell::new(value),
+ })
+ }
+
+ xpcom_method!(
+ get_value => GetValue(
+ ) -> f64
+ );
+
+ fn get_value(&self) -> Result<f64, nsresult> {
+ Ok(*self.value.borrow())
+ }
+
+ xpcom_method!(
+ set_value => SetValue(value: f64)
+ );
+
+ fn set_value(&self, value: f64) -> Result<(), nsresult> {
+ self.value.replace(value);
+ Ok(())
+ }
+
+ xpcom_method!(get_type => GetType() -> i32);
+ fn get_type(&self) -> Result<i32, nsresult> {
+ Ok(nsISFVBareItem::DECIMAL)
+ }
+
+ fn from_bare_item_interface(obj: &nsISFVBareItem) -> &Self {
+ unsafe { ::std::mem::transmute(obj) }
+ }
+}
+
+#[xpcom(implement(nsISFVParams), nonatomic)]
+struct SFVParams {
+ params: RefCell<Parameters>,
+}
+
+impl SFVParams {
+ fn new() -> RefPtr<SFVParams> {
+ SFVParams::allocate(InitSFVParams {
+ params: RefCell::new(Parameters::new()),
+ })
+ }
+
+ xpcom_method!(
+ get => Get(key: *const nsACString) -> *const nsISFVBareItem
+ );
+
+ fn get(&self, key: &nsACString) -> Result<RefPtr<nsISFVBareItem>, nsresult> {
+ let key = key.to_utf8();
+ let params = self.params.borrow();
+ let param_val = params.get(key.as_ref());
+
+ match param_val {
+ Some(val) => interface_from_bare_item(val),
+ None => return Err(NS_ERROR_UNEXPECTED),
+ }
+ }
+
+ xpcom_method!(
+ set => Set(key: *const nsACString, item: *const nsISFVBareItem)
+ );
+
+ fn set(&self, key: &nsACString, item: &nsISFVBareItem) -> Result<(), nsresult> {
+ let key = key.to_utf8().into_owned();
+ let bare_item = bare_item_from_interface(item)?;
+ self.params.borrow_mut().insert(key, bare_item);
+ Ok(())
+ }
+
+ xpcom_method!(
+ delete => Delete(key: *const nsACString)
+ );
+ fn delete(&self, key: &nsACString) -> Result<(), nsresult> {
+ let key = key.to_utf8();
+ let mut params = self.params.borrow_mut();
+
+ if !params.contains_key(key.as_ref()) {
+ return Err(NS_ERROR_UNEXPECTED);
+ }
+
+ // Keeps only entries that don't match key
+ params.retain(|k, _| k != key.as_ref());
+ Ok(())
+ }
+
+ xpcom_method!(
+ keys => Keys() -> thin_vec::ThinVec<nsCString>
+ );
+ fn keys(&self) -> Result<thin_vec::ThinVec<nsCString>, nsresult> {
+ let keys = self.params.borrow();
+ let keys = keys
+ .keys()
+ .map(nsCString::from)
+ .collect::<ThinVec<nsCString>>();
+ Ok(keys)
+ }
+
+ fn from_interface(obj: &nsISFVParams) -> &Self {
+ unsafe { ::std::mem::transmute(obj) }
+ }
+}
+
+#[xpcom(implement(nsISFVItem, nsISFVItemOrInnerList), nonatomic)]
+struct SFVItem {
+ value: RefPtr<nsISFVBareItem>,
+ params: RefPtr<nsISFVParams>,
+}
+
+impl SFVItem {
+ fn new(value: &nsISFVBareItem, params: &nsISFVParams) -> RefPtr<SFVItem> {
+ SFVItem::allocate(InitSFVItem {
+ value: RefPtr::new(value),
+ params: RefPtr::new(params),
+ })
+ }
+
+ xpcom_method!(
+ get_value => GetValue(
+ ) -> *const nsISFVBareItem
+ );
+
+ fn get_value(&self) -> Result<RefPtr<nsISFVBareItem>, nsresult> {
+ Ok(self.value.clone())
+ }
+
+ xpcom_method!(
+ get_params => GetParams(
+ ) -> *const nsISFVParams
+ );
+ fn get_params(&self) -> Result<RefPtr<nsISFVParams>, nsresult> {
+ Ok(self.params.clone())
+ }
+
+ xpcom_method!(
+ serialize => Serialize() -> nsACString
+ );
+ fn serialize(&self) -> Result<nsCString, nsresult> {
+ let bare_item = bare_item_from_interface(self.value.deref())?;
+ let params = params_from_interface(self.params.deref())?;
+ let serialized = Item::with_params(bare_item, params)
+ .serialize_value()
+ .map_err(|_| NS_ERROR_FAILURE)?;
+ Ok(nsCString::from(serialized))
+ }
+
+ fn from_interface(obj: &nsISFVItem) -> &Self {
+ unsafe { ::std::mem::transmute(obj) }
+ }
+}
+
+#[xpcom(implement(nsISFVInnerList, nsISFVItemOrInnerList), nonatomic)]
+struct SFVInnerList {
+ items: RefCell<Vec<RefPtr<nsISFVItem>>>,
+ params: RefPtr<nsISFVParams>,
+}
+
+impl SFVInnerList {
+ fn new(items: Vec<RefPtr<nsISFVItem>>, params: &nsISFVParams) -> RefPtr<SFVInnerList> {
+ SFVInnerList::allocate(InitSFVInnerList {
+ items: RefCell::new(items),
+ params: RefPtr::new(params),
+ })
+ }
+
+ xpcom_method!(
+ get_items => GetItems() -> thin_vec::ThinVec<Option<RefPtr<nsISFVItem>>>
+ );
+
+ fn get_items(&self) -> Result<thin_vec::ThinVec<Option<RefPtr<nsISFVItem>>>, nsresult> {
+ let items = self.items.borrow().iter().cloned().map(Some).collect();
+ Ok(items)
+ }
+
+ #[allow(non_snake_case)]
+ unsafe fn SetItems(
+ &self,
+ value: *const thin_vec::ThinVec<Option<RefPtr<nsISFVItem>>>,
+ ) -> nsresult {
+ if value.is_null() {
+ return NS_ERROR_NULL_POINTER;
+ }
+ match (*value)
+ .iter()
+ .map(|v| v.clone().ok_or(NS_ERROR_NULL_POINTER))
+ .collect::<Result<Vec<_>, nsresult>>()
+ {
+ Ok(value) => *self.items.borrow_mut() = value,
+ Err(rv) => return rv,
+ }
+ NS_OK
+ }
+
+ xpcom_method!(
+ get_params => GetParams(
+ ) -> *const nsISFVParams
+ );
+ fn get_params(&self) -> Result<RefPtr<nsISFVParams>, nsresult> {
+ Ok(self.params.clone())
+ }
+
+ fn from_interface(obj: &nsISFVInnerList) -> &Self {
+ unsafe { ::std::mem::transmute(obj) }
+ }
+}
+
+#[xpcom(implement(nsISFVList, nsISFVSerialize), nonatomic)]
+struct SFVList {
+ members: RefCell<Vec<RefPtr<nsISFVItemOrInnerList>>>,
+}
+
+impl SFVList {
+ fn new(members: Vec<RefPtr<nsISFVItemOrInnerList>>) -> RefPtr<SFVList> {
+ SFVList::allocate(InitSFVList {
+ members: RefCell::new(members),
+ })
+ }
+
+ xpcom_method!(
+ get_members => GetMembers() -> thin_vec::ThinVec<Option<RefPtr<nsISFVItemOrInnerList>>>
+ );
+
+ fn get_members(
+ &self,
+ ) -> Result<thin_vec::ThinVec<Option<RefPtr<nsISFVItemOrInnerList>>>, nsresult> {
+ Ok(self.members.borrow().iter().cloned().map(Some).collect())
+ }
+
+ #[allow(non_snake_case)]
+ unsafe fn SetMembers(
+ &self,
+ value: *const thin_vec::ThinVec<Option<RefPtr<nsISFVItemOrInnerList>>>,
+ ) -> nsresult {
+ if value.is_null() {
+ return NS_ERROR_NULL_POINTER;
+ }
+ match (*value)
+ .iter()
+ .map(|v| v.clone().ok_or(NS_ERROR_NULL_POINTER))
+ .collect::<Result<Vec<_>, nsresult>>()
+ {
+ Ok(value) => *self.members.borrow_mut() = value,
+ Err(rv) => return rv,
+ }
+ NS_OK
+ }
+
+ xpcom_method!(
+ parse_more => ParseMore(header: *const nsACString)
+ );
+ fn parse_more(&self, header: &nsACString) -> Result<(), nsresult> {
+ // create List from SFVList to call parse_more on it
+ let mut list = List::new();
+ let members = self.members.borrow().clone();
+ for interface_entry in members.iter() {
+ let item_or_inner_list = list_entry_from_interface(interface_entry)?;
+ list.push(item_or_inner_list);
+ }
+
+ let _ = list.parse_more(&header).map_err(|_| NS_ERROR_FAILURE)?;
+
+ // replace SFVList's members with new_members
+ let mut new_members = Vec::new();
+ for item_or_inner_list in list.iter() {
+ new_members.push(interface_from_list_entry(item_or_inner_list)?)
+ }
+ self.members.replace(new_members);
+ Ok(())
+ }
+
+ xpcom_method!(
+ serialize => Serialize() -> nsACString
+ );
+ fn serialize(&self) -> Result<nsCString, nsresult> {
+ let mut list = List::new();
+ let members = self.members.borrow().clone();
+ for interface_entry in members.iter() {
+ let item_or_inner_list = list_entry_from_interface(interface_entry)?;
+ list.push(item_or_inner_list);
+ }
+
+ let serialized = list.serialize_value().map_err(|_| NS_ERROR_FAILURE)?;
+ Ok(nsCString::from(serialized))
+ }
+}
+
+#[xpcom(implement(nsISFVDictionary, nsISFVSerialize), nonatomic)]
+struct SFVDictionary {
+ value: RefCell<Dictionary>,
+}
+
+impl SFVDictionary {
+ fn new() -> RefPtr<SFVDictionary> {
+ SFVDictionary::allocate(InitSFVDictionary {
+ value: RefCell::new(Dictionary::new()),
+ })
+ }
+
+ xpcom_method!(
+ get => Get(key: *const nsACString) -> *const nsISFVItemOrInnerList
+ );
+
+ fn get(&self, key: &nsACString) -> Result<RefPtr<nsISFVItemOrInnerList>, nsresult> {
+ let key = key.to_utf8();
+ let value = self.value.borrow();
+ let member_value = value.get(key.as_ref());
+
+ match member_value {
+ Some(member) => interface_from_list_entry(member),
+ None => return Err(NS_ERROR_UNEXPECTED),
+ }
+ }
+
+ xpcom_method!(
+ set => Set(key: *const nsACString, item: *const nsISFVItemOrInnerList)
+ );
+
+ fn set(&self, key: &nsACString, member_value: &nsISFVItemOrInnerList) -> Result<(), nsresult> {
+ let key = key.to_utf8().into_owned();
+ let value = list_entry_from_interface(member_value)?;
+ self.value.borrow_mut().insert(key, value);
+ Ok(())
+ }
+
+ xpcom_method!(
+ delete => Delete(key: *const nsACString)
+ );
+
+ fn delete(&self, key: &nsACString) -> Result<(), nsresult> {
+ let key = key.to_utf8();
+ let mut params = self.value.borrow_mut();
+
+ if !params.contains_key(key.as_ref()) {
+ return Err(NS_ERROR_UNEXPECTED);
+ }
+
+ // Keeps only entries that don't match key
+ params.retain(|k, _| k != key.as_ref());
+ Ok(())
+ }
+
+ xpcom_method!(
+ keys => Keys() -> thin_vec::ThinVec<nsCString>
+ );
+ fn keys(&self) -> Result<thin_vec::ThinVec<nsCString>, nsresult> {
+ let members = self.value.borrow();
+ let keys = members
+ .keys()
+ .map(nsCString::from)
+ .collect::<ThinVec<nsCString>>();
+ Ok(keys)
+ }
+
+ xpcom_method!(
+ parse_more => ParseMore(header: *const nsACString)
+ );
+ fn parse_more(&self, header: &nsACString) -> Result<(), nsresult> {
+ let _ = self
+ .value
+ .borrow_mut()
+ .parse_more(&header)
+ .map_err(|_| NS_ERROR_FAILURE)?;
+ Ok(())
+ }
+
+ xpcom_method!(
+ serialize => Serialize() -> nsACString
+ );
+ fn serialize(&self) -> Result<nsCString, nsresult> {
+ let serialized = self
+ .value
+ .borrow()
+ .serialize_value()
+ .map_err(|_| NS_ERROR_FAILURE)?;
+ Ok(nsCString::from(serialized))
+ }
+}
+
+fn bare_item_from_interface(obj: &nsISFVBareItem) -> Result<BareItem, nsresult> {
+ let obj = obj
+ .query_interface::<nsISFVBareItem>()
+ .ok_or(NS_ERROR_UNEXPECTED)?;
+ let mut obj_type: i32 = -1;
+ unsafe {
+ obj.deref().GetType(&mut obj_type);
+ }
+
+ match obj_type {
+ nsISFVBareItem::BOOL => {
+ let item_value = SFVBool::from_bare_item_interface(obj.deref()).get_value()?;
+ Ok(BareItem::Boolean(item_value))
+ }
+ nsISFVBareItem::STRING => {
+ let string_itm = SFVString::from_bare_item_interface(obj.deref()).get_value()?;
+ let item_value = (*string_itm.to_utf8()).to_string();
+ Ok(BareItem::String(item_value))
+ }
+ nsISFVBareItem::TOKEN => {
+ let token_itm = SFVToken::from_bare_item_interface(obj.deref()).get_value()?;
+ let item_value = (*token_itm.to_utf8()).to_string();
+ Ok(BareItem::Token(item_value))
+ }
+ nsISFVBareItem::INTEGER => {
+ let item_value = SFVInteger::from_bare_item_interface(obj.deref()).get_value()?;
+ Ok(BareItem::Integer(item_value))
+ }
+ nsISFVBareItem::DECIMAL => {
+ let item_value = SFVDecimal::from_bare_item_interface(obj.deref()).get_value()?;
+ let decimal: Decimal = Decimal::from_f64(item_value).ok_or(NS_ERROR_UNEXPECTED)?;
+ Ok(BareItem::Decimal(decimal))
+ }
+ nsISFVBareItem::BYTE_SEQUENCE => {
+ let token_itm = SFVByteSeq::from_bare_item_interface(obj.deref()).get_value()?;
+ let item_value: String = (*token_itm.to_utf8()).to_string();
+ Ok(BareItem::ByteSeq(item_value.into_bytes()))
+ }
+ _ => return Err(NS_ERROR_UNEXPECTED),
+ }
+}
+
+fn params_from_interface(obj: &nsISFVParams) -> Result<Parameters, nsresult> {
+ let params = SFVParams::from_interface(obj).params.borrow();
+ Ok(params.clone())
+}
+
+fn item_from_interface(obj: &nsISFVItem) -> Result<Item, nsresult> {
+ let sfv_item = SFVItem::from_interface(obj);
+ let bare_item = bare_item_from_interface(sfv_item.value.deref())?;
+ let parameters = params_from_interface(sfv_item.params.deref())?;
+ Ok(Item::with_params(bare_item, parameters))
+}
+
+fn inner_list_from_interface(obj: &nsISFVInnerList) -> Result<InnerList, nsresult> {
+ let sfv_inner_list = SFVInnerList::from_interface(obj);
+
+ let mut inner_list_items: Vec<Item> = vec![];
+ for item in sfv_inner_list.items.borrow().iter() {
+ let item = item_from_interface(item)?;
+ inner_list_items.push(item);
+ }
+ let inner_list_params = params_from_interface(sfv_inner_list.params.deref())?;
+ Ok(InnerList::with_params(inner_list_items, inner_list_params))
+}
+
+fn list_entry_from_interface(obj: &nsISFVItemOrInnerList) -> Result<ListEntry, nsresult> {
+ if let Some(nsi_item) = obj.query_interface::<nsISFVItem>() {
+ let item = item_from_interface(nsi_item.deref())?;
+ Ok(ListEntry::Item(item))
+ } else if let Some(nsi_inner_list) = obj.query_interface::<nsISFVInnerList>() {
+ let inner_list = inner_list_from_interface(nsi_inner_list.deref())?;
+ Ok(ListEntry::InnerList(inner_list))
+ } else {
+ return Err(NS_ERROR_UNEXPECTED);
+ }
+}
+
+fn interface_from_bare_item(bare_item: &BareItem) -> Result<RefPtr<nsISFVBareItem>, nsresult> {
+ let bare_item = match bare_item {
+ BareItem::Boolean(val) => RefPtr::new(SFVBool::new(*val).coerce::<nsISFVBareItem>()),
+ BareItem::String(val) => {
+ RefPtr::new(SFVString::new(&nsCString::from(val)).coerce::<nsISFVBareItem>())
+ }
+ BareItem::Token(val) => {
+ RefPtr::new(SFVToken::new(&nsCString::from(val)).coerce::<nsISFVBareItem>())
+ }
+ BareItem::ByteSeq(val) => RefPtr::new(
+ SFVByteSeq::new(&nsCString::from(String::from_utf8(val.to_vec()).unwrap()))
+ .coerce::<nsISFVBareItem>(),
+ ),
+ BareItem::Decimal(val) => {
+ let val = val
+ .to_string()
+ .parse::<f64>()
+ .map_err(|_| NS_ERROR_UNEXPECTED)?;
+ RefPtr::new(SFVDecimal::new(val).coerce::<nsISFVBareItem>())
+ }
+ BareItem::Integer(val) => RefPtr::new(SFVInteger::new(*val).coerce::<nsISFVBareItem>()),
+ };
+
+ Ok(bare_item)
+}
+
+fn interface_from_item(item: &Item) -> Result<RefPtr<nsISFVItem>, nsresult> {
+ let nsi_bare_item = interface_from_bare_item(&item.bare_item)?;
+ let nsi_params = interface_from_params(&item.params)?;
+ Ok(RefPtr::new(
+ SFVItem::new(&nsi_bare_item, &nsi_params).coerce::<nsISFVItem>(),
+ ))
+}
+
+fn interface_from_params(params: &Parameters) -> Result<RefPtr<nsISFVParams>, nsresult> {
+ let sfv_params = SFVParams::new();
+ for (key, value) in params.iter() {
+ sfv_params
+ .params
+ .borrow_mut()
+ .insert(key.clone(), value.clone());
+ }
+ Ok(RefPtr::new(sfv_params.coerce::<nsISFVParams>()))
+}
+
+fn interface_from_list_entry(
+ member: &ListEntry,
+) -> Result<RefPtr<nsISFVItemOrInnerList>, nsresult> {
+ match member {
+ ListEntry::Item(item) => {
+ let nsi_bare_item = interface_from_bare_item(&item.bare_item)?;
+ let nsi_params = interface_from_params(&item.params)?;
+ Ok(RefPtr::new(
+ SFVItem::new(&nsi_bare_item, &nsi_params).coerce::<nsISFVItemOrInnerList>(),
+ ))
+ }
+ ListEntry::InnerList(inner_list) => {
+ let mut nsi_inner_list = Vec::new();
+ for item in inner_list.items.iter() {
+ let nsi_item = interface_from_item(item)?;
+ nsi_inner_list.push(nsi_item);
+ }
+
+ let nsi_params = interface_from_params(&inner_list.params)?;
+ Ok(RefPtr::new(
+ SFVInnerList::new(nsi_inner_list, &nsi_params).coerce::<nsISFVItemOrInnerList>(),
+ ))
+ }
+ }
+}