tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

lib.rs (28593B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #![expect(
      6    clippy::unnecessary_wraps,
      7    clippy::unused_self,
      8    reason = "These are needed here."
      9 )]
     10 
     11 use nserror::{nsresult, NS_ERROR_FAILURE, NS_ERROR_NULL_POINTER, NS_ERROR_UNEXPECTED, NS_OK};
     12 use nsstring::{nsACString, nsCString};
     13 use sfv::{
     14    BareItem, Decimal, Dictionary, InnerList, Integer, Item, List, ListEntry, Parameters, Token,
     15 };
     16 use sfv::{FieldType as _, Key, Parser};
     17 use std::cell::RefCell;
     18 use std::ops::Deref as _;
     19 use thin_vec::ThinVec;
     20 use xpcom::interfaces::{
     21    nsISFVBareItem, nsISFVBool, nsISFVByteSeq, nsISFVDecimal, nsISFVDictionary, nsISFVInnerList,
     22    nsISFVInteger, nsISFVItem, nsISFVItemOrInnerList, nsISFVList, nsISFVParams, nsISFVService,
     23    nsISFVString, nsISFVToken,
     24 };
     25 use xpcom::{xpcom, xpcom_method, RefPtr, XpCom as _};
     26 
     27 #[no_mangle]
     28 #[expect(clippy::missing_safety_doc, reason = "Inherently unsafe.")]
     29 pub unsafe extern "C" fn new_sfv_service(result: *mut *const nsISFVService) {
     30    let service: RefPtr<SFVService> = SFVService::new();
     31    RefPtr::new(service.coerce::<nsISFVService>()).forget(&mut *result);
     32 }
     33 
     34 #[xpcom(implement(nsISFVService), atomic)]
     35 struct SFVService {}
     36 
     37 impl SFVService {
     38    fn new() -> RefPtr<Self> {
     39        Self::allocate(InitSFVService {})
     40    }
     41 
     42    xpcom_method!(parse_dictionary => ParseDictionary(header: *const nsACString) -> *const nsISFVDictionary);
     43    fn parse_dictionary(&self, header: &nsACString) -> Result<RefPtr<nsISFVDictionary>, nsresult> {
     44        let parsed_dict: Dictionary = Parser::new(&header).parse().map_err(|_| NS_ERROR_FAILURE)?;
     45        let sfv_dict = SFVDictionary::new();
     46        sfv_dict.value.replace(parsed_dict);
     47        Ok(RefPtr::new(sfv_dict.coerce::<nsISFVDictionary>()))
     48    }
     49 
     50    xpcom_method!(parse_list => ParseList(field_value: *const nsACString) -> *const nsISFVList);
     51    fn parse_list(&self, header: &nsACString) -> Result<RefPtr<nsISFVList>, nsresult> {
     52        let parsed_list: List = Parser::new(&header).parse().map_err(|_| NS_ERROR_FAILURE)?;
     53 
     54        let mut nsi_members = Vec::new();
     55        for item_or_inner_list in &parsed_list {
     56            nsi_members.push(interface_from_list_entry(item_or_inner_list)?);
     57        }
     58        let sfv_list = SFVList::allocate(InitSFVList {
     59            members: RefCell::new(nsi_members),
     60        });
     61        Ok(RefPtr::new(sfv_list.coerce::<nsISFVList>()))
     62    }
     63 
     64    xpcom_method!(parse_item => ParseItem(header: *const nsACString) -> *const nsISFVItem);
     65    fn parse_item(&self, header: &nsACString) -> Result<RefPtr<nsISFVItem>, nsresult> {
     66        let parsed_item: Item = Parser::new(&header).parse().map_err(|_| NS_ERROR_FAILURE)?;
     67        interface_from_item(&parsed_item)
     68    }
     69 
     70    xpcom_method!(new_integer => NewInteger(value: i64) -> *const nsISFVInteger);
     71    fn new_integer(&self, value: i64) -> Result<RefPtr<nsISFVInteger>, nsresult> {
     72        Ok(RefPtr::new(
     73            SFVInteger::new(value).coerce::<nsISFVInteger>(),
     74        ))
     75    }
     76 
     77    xpcom_method!(new_decimal => NewDecimal(value: f64) -> *const nsISFVDecimal);
     78    fn new_decimal(&self, value: f64) -> Result<RefPtr<nsISFVDecimal>, nsresult> {
     79        Ok(RefPtr::new(
     80            SFVDecimal::new(value).coerce::<nsISFVDecimal>(),
     81        ))
     82    }
     83 
     84    xpcom_method!(new_bool => NewBool(value: bool) -> *const nsISFVBool);
     85    fn new_bool(&self, value: bool) -> Result<RefPtr<nsISFVBool>, nsresult> {
     86        Ok(RefPtr::new(SFVBool::new(value).coerce::<nsISFVBool>()))
     87    }
     88 
     89    xpcom_method!(new_string => NewString(value: *const nsACString) -> *const nsISFVString);
     90    fn new_string(&self, value: &nsACString) -> Result<RefPtr<nsISFVString>, nsresult> {
     91        Ok(RefPtr::new(SFVString::new(value).coerce::<nsISFVString>()))
     92    }
     93 
     94    xpcom_method!(new_token => NewToken(value: *const nsACString) -> *const nsISFVToken);
     95    fn new_token(&self, value: &nsACString) -> Result<RefPtr<nsISFVToken>, nsresult> {
     96        Ok(RefPtr::new(SFVToken::new(value).coerce::<nsISFVToken>()))
     97    }
     98 
     99    xpcom_method!(new_byte_sequence => NewByteSequence(value: *const nsACString) -> *const nsISFVByteSeq);
    100    fn new_byte_sequence(&self, value: &nsACString) -> Result<RefPtr<nsISFVByteSeq>, nsresult> {
    101        Ok(RefPtr::new(
    102            SFVByteSeq::new(value).coerce::<nsISFVByteSeq>(),
    103        ))
    104    }
    105 
    106    xpcom_method!(new_parameters => NewParameters() -> *const nsISFVParams);
    107    fn new_parameters(&self) -> Result<RefPtr<nsISFVParams>, nsresult> {
    108        Ok(RefPtr::new(SFVParams::new().coerce::<nsISFVParams>()))
    109    }
    110 
    111    xpcom_method!(new_item => NewItem(value: *const nsISFVBareItem, params:  *const nsISFVParams) -> *const nsISFVItem);
    112    fn new_item(
    113        &self,
    114        value: &nsISFVBareItem,
    115        params: &nsISFVParams,
    116    ) -> Result<RefPtr<nsISFVItem>, nsresult> {
    117        Ok(RefPtr::new(
    118            SFVItem::new(value, params).coerce::<nsISFVItem>(),
    119        ))
    120    }
    121 
    122    xpcom_method!(new_inner_list => NewInnerList(items: *const ThinVec<Option<RefPtr<nsISFVItem>>>, params:  *const nsISFVParams) -> *const nsISFVInnerList);
    123    fn new_inner_list(
    124        &self,
    125        items: &ThinVec<Option<RefPtr<nsISFVItem>>>,
    126        params: &nsISFVParams,
    127    ) -> Result<RefPtr<nsISFVInnerList>, nsresult> {
    128        let items = items
    129            .iter()
    130            .cloned()
    131            .map(|item| item.ok_or(NS_ERROR_NULL_POINTER))
    132            .collect::<Result<Vec<_>, nsresult>>()?;
    133        Ok(RefPtr::new(
    134            SFVInnerList::new(items, params).coerce::<nsISFVInnerList>(),
    135        ))
    136    }
    137 
    138    xpcom_method!(new_list => NewList(members: *const ThinVec<Option<RefPtr<nsISFVItemOrInnerList>>>) -> *const nsISFVList);
    139    fn new_list(
    140        &self,
    141        members: &ThinVec<Option<RefPtr<nsISFVItemOrInnerList>>>,
    142    ) -> Result<RefPtr<nsISFVList>, nsresult> {
    143        let members = members
    144            .iter()
    145            .cloned()
    146            .map(|item| item.ok_or(NS_ERROR_NULL_POINTER))
    147            .collect::<Result<Vec<_>, nsresult>>()?;
    148        Ok(RefPtr::new(SFVList::new(members).coerce::<nsISFVList>()))
    149    }
    150 
    151    xpcom_method!(new_dictionary => NewDictionary() -> *const nsISFVDictionary);
    152    fn new_dictionary(&self) -> Result<RefPtr<nsISFVDictionary>, nsresult> {
    153        Ok(RefPtr::new(
    154            SFVDictionary::new().coerce::<nsISFVDictionary>(),
    155        ))
    156    }
    157 }
    158 
    159 #[xpcom(implement(nsISFVInteger, nsISFVBareItem), nonatomic)]
    160 struct SFVInteger {
    161    value: RefCell<i64>,
    162 }
    163 
    164 impl SFVInteger {
    165    fn new(value: i64) -> RefPtr<Self> {
    166        Self::allocate(InitSFVInteger {
    167            value: RefCell::new(value),
    168        })
    169    }
    170 
    171    xpcom_method!(get_value => GetValue() -> i64);
    172    fn get_value(&self) -> Result<i64, nsresult> {
    173        Ok(*self.value.borrow())
    174    }
    175 
    176    xpcom_method!(set_value => SetValue(value: i64));
    177    fn set_value(&self, value: i64) -> Result<(), nsresult> {
    178        self.value.replace(value);
    179        Ok(())
    180    }
    181 
    182    xpcom_method!(get_type => GetType() -> i32);
    183    const fn get_type(&self) -> Result<i32, nsresult> {
    184        Ok(nsISFVBareItem::INTEGER)
    185    }
    186 
    187    const fn from_bare_item_interface(obj: &nsISFVBareItem) -> &Self {
    188        unsafe { &*std::ptr::from_ref::<nsISFVBareItem>(obj).cast::<Self>() }
    189    }
    190 }
    191 
    192 #[xpcom(implement(nsISFVBool, nsISFVBareItem), nonatomic)]
    193 struct SFVBool {
    194    value: RefCell<bool>,
    195 }
    196 
    197 impl SFVBool {
    198    fn new(value: bool) -> RefPtr<Self> {
    199        Self::allocate(InitSFVBool {
    200            value: RefCell::new(value),
    201        })
    202    }
    203 
    204    xpcom_method!(get_value => GetValue() -> bool);
    205    fn get_value(&self) -> Result<bool, nsresult> {
    206        Ok(*self.value.borrow())
    207    }
    208 
    209    xpcom_method!(set_value => SetValue(value: bool));
    210    fn set_value(&self, value: bool) -> Result<(), nsresult> {
    211        self.value.replace(value);
    212        Ok(())
    213    }
    214 
    215    xpcom_method!(get_type => GetType() -> i32);
    216    const fn get_type(&self) -> Result<i32, nsresult> {
    217        Ok(nsISFVBareItem::BOOL)
    218    }
    219 
    220    const fn from_bare_item_interface(obj: &nsISFVBareItem) -> &Self {
    221        unsafe { &*std::ptr::from_ref::<nsISFVBareItem>(obj).cast::<Self>() }
    222    }
    223 }
    224 
    225 #[xpcom(implement(nsISFVString, nsISFVBareItem), nonatomic)]
    226 struct SFVString {
    227    value: RefCell<nsCString>,
    228 }
    229 
    230 impl SFVString {
    231    fn new(value: &nsACString) -> RefPtr<Self> {
    232        Self::allocate(InitSFVString {
    233            value: RefCell::new(nsCString::from(value)),
    234        })
    235    }
    236 
    237    xpcom_method!(
    238        get_value => GetValue(
    239        ) -> nsACString
    240    );
    241 
    242    fn get_value(&self) -> Result<nsCString, nsresult> {
    243        Ok(self.value.borrow().clone())
    244    }
    245 
    246    xpcom_method!(
    247        set_value => SetValue(value: *const nsACString)
    248    );
    249 
    250    fn set_value(&self, value: &nsACString) -> Result<(), nsresult> {
    251        self.value.borrow_mut().assign(value);
    252        Ok(())
    253    }
    254 
    255    xpcom_method!(get_type => GetType() -> i32);
    256    const fn get_type(&self) -> Result<i32, nsresult> {
    257        Ok(nsISFVBareItem::STRING)
    258    }
    259 
    260    const fn from_bare_item_interface(obj: &nsISFVBareItem) -> &Self {
    261        unsafe { &*std::ptr::from_ref::<nsISFVBareItem>(obj).cast::<Self>() }
    262    }
    263 }
    264 
    265 #[xpcom(implement(nsISFVToken, nsISFVBareItem), nonatomic)]
    266 struct SFVToken {
    267    value: RefCell<nsCString>,
    268 }
    269 
    270 impl SFVToken {
    271    fn new(value: &nsACString) -> RefPtr<Self> {
    272        Self::allocate(InitSFVToken {
    273            value: RefCell::new(nsCString::from(value)),
    274        })
    275    }
    276 
    277    xpcom_method!(
    278        get_value => GetValue(
    279        ) -> nsACString
    280    );
    281 
    282    fn get_value(&self) -> Result<nsCString, nsresult> {
    283        Ok(self.value.borrow().clone())
    284    }
    285 
    286    xpcom_method!(
    287        set_value => SetValue(value: *const nsACString)
    288    );
    289 
    290    fn set_value(&self, value: &nsACString) -> Result<(), nsresult> {
    291        self.value.borrow_mut().assign(value);
    292        Ok(())
    293    }
    294 
    295    xpcom_method!(get_type => GetType() -> i32);
    296    const fn get_type(&self) -> Result<i32, nsresult> {
    297        Ok(nsISFVBareItem::TOKEN)
    298    }
    299 
    300    const fn from_bare_item_interface(obj: &nsISFVBareItem) -> &Self {
    301        unsafe { &*std::ptr::from_ref::<nsISFVBareItem>(obj).cast::<Self>() }
    302    }
    303 }
    304 
    305 #[xpcom(implement(nsISFVByteSeq, nsISFVBareItem), nonatomic)]
    306 struct SFVByteSeq {
    307    value: RefCell<nsCString>,
    308 }
    309 
    310 impl SFVByteSeq {
    311    fn new(value: &nsACString) -> RefPtr<Self> {
    312        Self::allocate(InitSFVByteSeq {
    313            value: RefCell::new(nsCString::from(value)),
    314        })
    315    }
    316 
    317    xpcom_method!(
    318        get_value => GetValue(
    319        ) -> nsACString
    320    );
    321 
    322    fn get_value(&self) -> Result<nsCString, nsresult> {
    323        Ok(self.value.borrow().clone())
    324    }
    325 
    326    xpcom_method!(
    327        set_value => SetValue(value: *const nsACString)
    328    );
    329 
    330    fn set_value(&self, value: &nsACString) -> Result<(), nsresult> {
    331        self.value.borrow_mut().assign(value);
    332        Ok(())
    333    }
    334 
    335    xpcom_method!(get_type => GetType() -> i32);
    336    const fn get_type(&self) -> Result<i32, nsresult> {
    337        Ok(nsISFVBareItem::BYTE_SEQUENCE)
    338    }
    339 
    340    const fn from_bare_item_interface(obj: &nsISFVBareItem) -> &Self {
    341        unsafe { &*std::ptr::from_ref::<nsISFVBareItem>(obj).cast::<Self>() }
    342    }
    343 }
    344 
    345 #[xpcom(implement(nsISFVDecimal, nsISFVBareItem), nonatomic)]
    346 struct SFVDecimal {
    347    value: RefCell<f64>,
    348 }
    349 
    350 impl SFVDecimal {
    351    fn new(value: f64) -> RefPtr<Self> {
    352        Self::allocate(InitSFVDecimal {
    353            value: RefCell::new(value),
    354        })
    355    }
    356 
    357    xpcom_method!(
    358        get_value => GetValue(
    359        ) -> f64
    360    );
    361 
    362    fn get_value(&self) -> Result<f64, nsresult> {
    363        Ok(*self.value.borrow())
    364    }
    365 
    366    xpcom_method!(
    367        set_value => SetValue(value: f64)
    368    );
    369 
    370    fn set_value(&self, value: f64) -> Result<(), nsresult> {
    371        self.value.replace(value);
    372        Ok(())
    373    }
    374 
    375    xpcom_method!(get_type => GetType() -> i32);
    376    const fn get_type(&self) -> Result<i32, nsresult> {
    377        Ok(nsISFVBareItem::DECIMAL)
    378    }
    379 
    380    const fn from_bare_item_interface(obj: &nsISFVBareItem) -> &Self {
    381        unsafe { &*std::ptr::from_ref::<nsISFVBareItem>(obj).cast::<Self>() }
    382    }
    383 }
    384 
    385 #[xpcom(implement(nsISFVParams), nonatomic)]
    386 struct SFVParams {
    387    params: RefCell<Parameters>,
    388 }
    389 
    390 impl SFVParams {
    391    fn new() -> RefPtr<Self> {
    392        Self::allocate(InitSFVParams {
    393            params: RefCell::new(Parameters::new()),
    394        })
    395    }
    396 
    397    xpcom_method!(
    398        get => Get(key: *const nsACString) -> *const nsISFVBareItem
    399    );
    400 
    401    fn get(&self, key: &nsACString) -> Result<RefPtr<nsISFVBareItem>, nsresult> {
    402        let key = key.to_utf8();
    403        let params = self.params.borrow();
    404        let param_val = params.get(key.as_ref());
    405 
    406        param_val.map_or_else(|| Err(NS_ERROR_UNEXPECTED), interface_from_bare_item)
    407    }
    408 
    409    xpcom_method!(
    410        set => Set(key: *const nsACString, item: *const nsISFVBareItem)
    411    );
    412 
    413    fn set(&self, key: &nsACString, item: &nsISFVBareItem) -> Result<(), nsresult> {
    414        let Ok(key) = Key::from_string(key.to_utf8().into_owned()) else {
    415            return Err(NS_ERROR_UNEXPECTED);
    416        };
    417        let bare_item = bare_item_from_interface(item)?;
    418        self.params.borrow_mut().insert(key, bare_item);
    419        Ok(())
    420    }
    421 
    422    xpcom_method!(
    423        delete => Delete(key: *const nsACString)
    424    );
    425    fn delete(&self, key: &nsACString) -> Result<(), nsresult> {
    426        let key = key.to_utf8();
    427        let mut params = self.params.borrow_mut();
    428 
    429        if !params.contains_key(key.as_ref()) {
    430            return Err(NS_ERROR_UNEXPECTED);
    431        }
    432 
    433        // Keeps only entries that don't match key
    434        params.retain(|k, _| k.as_str() != key.as_ref());
    435        Ok(())
    436    }
    437 
    438    xpcom_method!(
    439        keys => Keys() -> ThinVec<nsCString>
    440    );
    441    fn keys(&self) -> Result<ThinVec<nsCString>, nsresult> {
    442        let keys = self.params.borrow();
    443        let keys = keys
    444            .keys()
    445            .map(|key| nsCString::from(key.as_str()))
    446            .collect::<ThinVec<nsCString>>();
    447        Ok(keys)
    448    }
    449 
    450    const fn from_interface(obj: &nsISFVParams) -> &Self {
    451        unsafe { &*std::ptr::from_ref::<nsISFVParams>(obj).cast::<Self>() }
    452    }
    453 }
    454 
    455 #[xpcom(implement(nsISFVItem, nsISFVItemOrInnerList), nonatomic)]
    456 struct SFVItem {
    457    value: RefPtr<nsISFVBareItem>,
    458    params: RefPtr<nsISFVParams>,
    459 }
    460 
    461 impl SFVItem {
    462    fn new(value: &nsISFVBareItem, params: &nsISFVParams) -> RefPtr<Self> {
    463        Self::allocate(InitSFVItem {
    464            value: RefPtr::new(value),
    465            params: RefPtr::new(params),
    466        })
    467    }
    468 
    469    xpcom_method!(
    470        get_value => GetValue(
    471        ) -> *const nsISFVBareItem
    472    );
    473 
    474    fn get_value(&self) -> Result<RefPtr<nsISFVBareItem>, nsresult> {
    475        Ok(self.value.clone())
    476    }
    477 
    478    xpcom_method!(
    479        get_params => GetParams(
    480        ) -> *const nsISFVParams
    481    );
    482    fn get_params(&self) -> Result<RefPtr<nsISFVParams>, nsresult> {
    483        Ok(self.params.clone())
    484    }
    485 
    486    xpcom_method!(
    487        serialize => Serialize() -> nsACString
    488    );
    489    fn serialize(&self) -> Result<nsCString, nsresult> {
    490        let bare_item = bare_item_from_interface(&self.value)?;
    491        let params = params_from_interface(&self.params)?;
    492        let serialized = Item::with_params(bare_item, params).serialize();
    493        Ok(nsCString::from(serialized))
    494    }
    495 
    496    const fn from_interface(obj: &nsISFVItem) -> &Self {
    497        unsafe { &*std::ptr::from_ref::<nsISFVItem>(obj).cast::<Self>() }
    498    }
    499 }
    500 
    501 #[xpcom(implement(nsISFVInnerList, nsISFVItemOrInnerList), nonatomic)]
    502 struct SFVInnerList {
    503    items: RefCell<Vec<RefPtr<nsISFVItem>>>,
    504    params: RefPtr<nsISFVParams>,
    505 }
    506 
    507 impl SFVInnerList {
    508    fn new(items: Vec<RefPtr<nsISFVItem>>, params: &nsISFVParams) -> RefPtr<Self> {
    509        Self::allocate(InitSFVInnerList {
    510            items: RefCell::new(items),
    511            params: RefPtr::new(params),
    512        })
    513    }
    514 
    515    xpcom_method!(
    516        get_items => GetItems() -> ThinVec<Option<RefPtr<nsISFVItem>>>
    517    );
    518 
    519    fn get_items(&self) -> Result<ThinVec<Option<RefPtr<nsISFVItem>>>, nsresult> {
    520        let items = self.items.borrow().iter().cloned().map(Some).collect();
    521        Ok(items)
    522    }
    523 
    524    #[expect(non_snake_case, reason = "XPCom method naming convention.")]
    525    unsafe fn SetItems(&self, value: *const ThinVec<Option<RefPtr<nsISFVItem>>>) -> nsresult {
    526        if value.is_null() {
    527            return NS_ERROR_NULL_POINTER;
    528        }
    529        match (*value)
    530            .iter()
    531            .map(|v| v.clone().ok_or(NS_ERROR_NULL_POINTER))
    532            .collect::<Result<Vec<_>, nsresult>>()
    533        {
    534            Ok(value) => *self.items.borrow_mut() = value,
    535            Err(rv) => return rv,
    536        }
    537        NS_OK
    538    }
    539 
    540    xpcom_method!(
    541        get_params => GetParams(
    542        ) -> *const nsISFVParams
    543    );
    544    fn get_params(&self) -> Result<RefPtr<nsISFVParams>, nsresult> {
    545        Ok(self.params.clone())
    546    }
    547 
    548    const fn from_interface(obj: &nsISFVInnerList) -> &Self {
    549        unsafe { &*std::ptr::from_ref::<nsISFVInnerList>(obj).cast::<Self>() }
    550    }
    551 }
    552 
    553 #[xpcom(implement(nsISFVList, nsISFVSerialize), nonatomic)]
    554 struct SFVList {
    555    members: RefCell<Vec<RefPtr<nsISFVItemOrInnerList>>>,
    556 }
    557 
    558 impl SFVList {
    559    fn new(members: Vec<RefPtr<nsISFVItemOrInnerList>>) -> RefPtr<Self> {
    560        Self::allocate(InitSFVList {
    561            members: RefCell::new(members),
    562        })
    563    }
    564 
    565    xpcom_method!(
    566        get_members => GetMembers() -> ThinVec<Option<RefPtr<nsISFVItemOrInnerList>>>
    567    );
    568 
    569    fn get_members(&self) -> Result<ThinVec<Option<RefPtr<nsISFVItemOrInnerList>>>, nsresult> {
    570        Ok(self.members.borrow().iter().cloned().map(Some).collect())
    571    }
    572 
    573    #[expect(non_snake_case, reason = "XPCom method naming convention.")]
    574    unsafe fn SetMembers(
    575        &self,
    576        value: *const ThinVec<Option<RefPtr<nsISFVItemOrInnerList>>>,
    577    ) -> nsresult {
    578        if value.is_null() {
    579            return NS_ERROR_NULL_POINTER;
    580        }
    581        match (*value)
    582            .iter()
    583            .map(|v| v.clone().ok_or(NS_ERROR_NULL_POINTER))
    584            .collect::<Result<Vec<_>, nsresult>>()
    585        {
    586            Ok(value) => *self.members.borrow_mut() = value,
    587            Err(rv) => return rv,
    588        }
    589        NS_OK
    590    }
    591 
    592    xpcom_method!(
    593        parse_more => ParseMore(header: *const nsACString)
    594    );
    595    fn parse_more(&self, header: &nsACString) -> Result<(), nsresult> {
    596        // create List from SFVList
    597        let mut list = List::new();
    598        let members = self.members.borrow().clone();
    599        for interface_entry in &members {
    600            let item_or_inner_list = list_entry_from_interface(interface_entry)?;
    601            list.push(item_or_inner_list);
    602        }
    603 
    604        Parser::new(&header)
    605            .parse_list_with_visitor(&mut list)
    606            .map_err(|_| NS_ERROR_FAILURE)?;
    607 
    608        // replace SFVList's members with new_members
    609        let mut new_members = Vec::new();
    610        for item_or_inner_list in &list {
    611            new_members.push(interface_from_list_entry(item_or_inner_list)?);
    612        }
    613        self.members.replace(new_members);
    614        Ok(())
    615    }
    616 
    617    xpcom_method!(
    618        serialize => Serialize() -> nsACString
    619    );
    620    fn serialize(&self) -> Result<nsCString, nsresult> {
    621        let mut list = List::new();
    622        let members = self.members.borrow().clone();
    623        for interface_entry in &members {
    624            let item_or_inner_list = list_entry_from_interface(interface_entry)?;
    625            list.push(item_or_inner_list);
    626        }
    627 
    628        let Some(serialized) = list.serialize() else {
    629            return Err(NS_ERROR_FAILURE);
    630        };
    631        Ok(nsCString::from(serialized))
    632    }
    633 }
    634 
    635 #[xpcom(implement(nsISFVDictionary, nsISFVSerialize), nonatomic)]
    636 struct SFVDictionary {
    637    value: RefCell<Dictionary>,
    638 }
    639 
    640 impl SFVDictionary {
    641    fn new() -> RefPtr<Self> {
    642        Self::allocate(InitSFVDictionary {
    643            value: RefCell::new(Dictionary::new()),
    644        })
    645    }
    646 
    647    xpcom_method!(
    648        get => Get(key: *const nsACString) -> *const nsISFVItemOrInnerList
    649    );
    650 
    651    fn get(&self, key: &nsACString) -> Result<RefPtr<nsISFVItemOrInnerList>, nsresult> {
    652        let key = key.to_utf8();
    653        let value = self.value.borrow();
    654        let member_value = value.get(key.as_ref());
    655 
    656        member_value.map_or_else(|| Err(NS_ERROR_UNEXPECTED), interface_from_list_entry)
    657    }
    658 
    659    xpcom_method!(
    660        set => Set(key: *const nsACString, item: *const nsISFVItemOrInnerList)
    661    );
    662 
    663    fn set(&self, key: &nsACString, member_value: &nsISFVItemOrInnerList) -> Result<(), nsresult> {
    664        let Ok(key) = Key::from_string(key.to_utf8().into_owned()) else {
    665            return Err(NS_ERROR_UNEXPECTED);
    666        };
    667        let value = list_entry_from_interface(member_value)?;
    668        self.value.borrow_mut().insert(key, value);
    669        Ok(())
    670    }
    671 
    672    xpcom_method!(
    673        delete => Delete(key: *const nsACString)
    674    );
    675 
    676    fn delete(&self, key: &nsACString) -> Result<(), nsresult> {
    677        let key = key.to_utf8();
    678        let mut params = self.value.borrow_mut();
    679 
    680        if !params.contains_key(key.as_ref()) {
    681            return Err(NS_ERROR_UNEXPECTED);
    682        }
    683 
    684        // Keeps only entries that don't match key
    685        params.retain(|k, _| k.as_str() != key.as_ref());
    686        Ok(())
    687    }
    688 
    689    xpcom_method!(
    690        keys => Keys() -> ThinVec<nsCString>
    691    );
    692    fn keys(&self) -> Result<ThinVec<nsCString>, nsresult> {
    693        let members = self.value.borrow();
    694        let keys = members
    695            .keys()
    696            .map(|key| nsCString::from(key.as_str()))
    697            .collect::<ThinVec<nsCString>>();
    698        Ok(keys)
    699    }
    700 
    701    xpcom_method!(
    702        parse_more => ParseMore(header: *const nsACString)
    703    );
    704    fn parse_more(&self, header: &nsACString) -> Result<(), nsresult> {
    705        Parser::new(&header)
    706            .parse_dictionary_with_visitor(&mut *self.value.borrow_mut())
    707            .map_err(|_| NS_ERROR_FAILURE)?;
    708        Ok(())
    709    }
    710 
    711    xpcom_method!(
    712        serialize => Serialize() -> nsACString
    713    );
    714    fn serialize(&self) -> Result<nsCString, nsresult> {
    715        let Some(serialized) = self.value.borrow().serialize() else {
    716            return Err(NS_ERROR_FAILURE);
    717        };
    718        Ok(nsCString::from(serialized))
    719    }
    720 }
    721 
    722 fn bare_item_from_interface(obj: &nsISFVBareItem) -> Result<BareItem, nsresult> {
    723    let obj = obj
    724        .query_interface::<nsISFVBareItem>()
    725        .ok_or(NS_ERROR_UNEXPECTED)?;
    726    let mut obj_type: i32 = -1;
    727    unsafe {
    728        obj.deref().GetType(&mut obj_type);
    729    }
    730 
    731    match obj_type {
    732        nsISFVBareItem::BOOL => {
    733            let item_value = SFVBool::from_bare_item_interface(&obj).get_value()?;
    734            Ok(BareItem::Boolean(item_value))
    735        }
    736        nsISFVBareItem::STRING => {
    737            let string_itm = SFVString::from_bare_item_interface(&obj).get_value()?;
    738            let item_value = sfv::String::from_string((*string_itm.to_utf8()).to_string())
    739                .map_err(|_| NS_ERROR_UNEXPECTED)?;
    740            Ok(BareItem::String(item_value))
    741        }
    742        nsISFVBareItem::TOKEN => {
    743            let token_itm = SFVToken::from_bare_item_interface(&obj).get_value()?;
    744            let item_value = Token::from_string((*token_itm.to_utf8()).to_string())
    745                .map_err(|_| NS_ERROR_UNEXPECTED)?;
    746            Ok(BareItem::Token(item_value))
    747        }
    748        nsISFVBareItem::INTEGER => {
    749            let item_value =
    750                Integer::constant(SFVInteger::from_bare_item_interface(&obj).get_value()?);
    751            Ok(BareItem::Integer(item_value))
    752        }
    753        nsISFVBareItem::DECIMAL => {
    754            let item_value = SFVDecimal::from_bare_item_interface(&obj).get_value()?;
    755            let decimal: Decimal =
    756                Decimal::try_from(item_value).map_err(|_| NS_ERROR_UNEXPECTED)?;
    757            Ok(BareItem::Decimal(decimal))
    758        }
    759        nsISFVBareItem::BYTE_SEQUENCE => {
    760            let token_itm = SFVByteSeq::from_bare_item_interface(&obj).get_value()?;
    761            let item_value: String = (*token_itm.to_utf8()).to_string();
    762            Ok(BareItem::ByteSequence(item_value.into_bytes()))
    763        }
    764        _ => Err(NS_ERROR_UNEXPECTED),
    765    }
    766 }
    767 
    768 fn params_from_interface(obj: &nsISFVParams) -> Result<Parameters, nsresult> {
    769    let params = SFVParams::from_interface(obj).params.borrow();
    770    Ok(params.clone())
    771 }
    772 
    773 fn item_from_interface(obj: &nsISFVItem) -> Result<Item, nsresult> {
    774    let sfv_item = SFVItem::from_interface(obj);
    775    let bare_item = bare_item_from_interface(&sfv_item.value)?;
    776    let parameters = params_from_interface(&sfv_item.params)?;
    777    Ok(Item::with_params(bare_item, parameters))
    778 }
    779 
    780 fn inner_list_from_interface(obj: &nsISFVInnerList) -> Result<InnerList, nsresult> {
    781    let sfv_inner_list = SFVInnerList::from_interface(obj);
    782 
    783    let mut inner_list_items: Vec<Item> = vec![];
    784    for item in sfv_inner_list.items.borrow().iter() {
    785        let item = item_from_interface(item)?;
    786        inner_list_items.push(item);
    787    }
    788    let inner_list_params = params_from_interface(&sfv_inner_list.params)?;
    789    Ok(InnerList::with_params(inner_list_items, inner_list_params))
    790 }
    791 
    792 fn list_entry_from_interface(obj: &nsISFVItemOrInnerList) -> Result<ListEntry, nsresult> {
    793    if let Some(nsi_item) = obj.query_interface::<nsISFVItem>() {
    794        let item = item_from_interface(&nsi_item)?;
    795        Ok(ListEntry::Item(item))
    796    } else if let Some(nsi_inner_list) = obj.query_interface::<nsISFVInnerList>() {
    797        let inner_list = inner_list_from_interface(&nsi_inner_list)?;
    798        Ok(ListEntry::InnerList(inner_list))
    799    } else {
    800        Err(NS_ERROR_UNEXPECTED)
    801    }
    802 }
    803 
    804 fn interface_from_bare_item(bare_item: &BareItem) -> Result<RefPtr<nsISFVBareItem>, nsresult> {
    805    let bare_item = match bare_item {
    806        BareItem::Boolean(val) => RefPtr::new(SFVBool::new(*val).coerce::<nsISFVBareItem>()),
    807        BareItem::String(val) => {
    808            RefPtr::new(SFVString::new(&nsCString::from(val.as_str())).coerce::<nsISFVBareItem>())
    809        }
    810        BareItem::Token(val) => {
    811            RefPtr::new(SFVToken::new(&nsCString::from(val.as_str())).coerce::<nsISFVBareItem>())
    812        }
    813        BareItem::ByteSequence(val) => RefPtr::new(
    814            SFVByteSeq::new(&nsCString::from(
    815                String::from_utf8(val.clone()).map_err(|_| NS_ERROR_UNEXPECTED)?,
    816            ))
    817            .coerce::<nsISFVBareItem>(),
    818        ),
    819        BareItem::Decimal(val) => {
    820            let val = val
    821                .to_string()
    822                .parse::<f64>()
    823                .map_err(|_| NS_ERROR_UNEXPECTED)?;
    824            RefPtr::new(SFVDecimal::new(val).coerce::<nsISFVBareItem>())
    825        }
    826        BareItem::Integer(val) => {
    827            RefPtr::new(SFVInteger::new((*val).into()).coerce::<nsISFVBareItem>())
    828        }
    829        _ => return Err(NS_ERROR_UNEXPECTED), // TODO: Handle other BareItem types.
    830    };
    831 
    832    Ok(bare_item)
    833 }
    834 
    835 fn interface_from_item(item: &Item) -> Result<RefPtr<nsISFVItem>, nsresult> {
    836    let nsi_bare_item = interface_from_bare_item(&item.bare_item)?;
    837    let nsi_params = interface_from_params(&item.params)?;
    838    Ok(RefPtr::new(
    839        SFVItem::new(&nsi_bare_item, &nsi_params).coerce::<nsISFVItem>(),
    840    ))
    841 }
    842 
    843 fn interface_from_params(params: &Parameters) -> Result<RefPtr<nsISFVParams>, nsresult> {
    844    let sfv_params = SFVParams::new();
    845    for (key, value) in params {
    846        sfv_params
    847            .params
    848            .borrow_mut()
    849            .insert(key.clone(), value.clone());
    850    }
    851    Ok(RefPtr::new(sfv_params.coerce::<nsISFVParams>()))
    852 }
    853 
    854 fn interface_from_list_entry(
    855    member: &ListEntry,
    856 ) -> Result<RefPtr<nsISFVItemOrInnerList>, nsresult> {
    857    match member {
    858        ListEntry::Item(item) => {
    859            let nsi_bare_item = interface_from_bare_item(&item.bare_item)?;
    860            let nsi_params = interface_from_params(&item.params)?;
    861            Ok(RefPtr::new(
    862                SFVItem::new(&nsi_bare_item, &nsi_params).coerce::<nsISFVItemOrInnerList>(),
    863            ))
    864        }
    865        ListEntry::InnerList(inner_list) => {
    866            let mut nsi_inner_list = Vec::new();
    867            for item in &inner_list.items {
    868                let nsi_item = interface_from_item(item)?;
    869                nsi_inner_list.push(nsi_item);
    870            }
    871 
    872            let nsi_params = interface_from_params(&inner_list.params)?;
    873            Ok(RefPtr::new(
    874                SFVInnerList::new(nsi_inner_list, &nsi_params).coerce::<nsISFVItemOrInnerList>(),
    875            ))
    876        }
    877    }
    878 }