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 }