Bug 1530506 - Add a generic writable property bag wrapper for Rust code. r=nika

This commit adds a `storage_variant::HashPropertyBag` type that
exposes an idiomatic Rust interface for `nsIWritablePropertyBag`.

Differential Revision: https://phabricator.services.mozilla.com/D21062

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Lina Cambridge 2019-02-26 21:53:32 +00:00
Родитель 41138306e0
Коммит 8f82f61df9
3 изменённых файлов: 108 добавлений и 0 удалений

Просмотреть файл

@ -0,0 +1,94 @@
/* 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_OK};
use nsstring::nsString;
use xpcom::{getter_addrefs, interfaces::nsIWritablePropertyBag, RefPtr};
use crate::VariantType;
extern "C" {
fn NS_NewHashPropertyBag(bag: *mut *const nsIWritablePropertyBag) -> libc::c_void;
}
/// A hash property bag backed by storage variant values.
pub struct HashPropertyBag(RefPtr<nsIWritablePropertyBag>);
impl Default for HashPropertyBag {
fn default() -> HashPropertyBag {
// This is safe to unwrap because `NS_NewHashPropertyBag` is infallible.
let bag = getter_addrefs(|p| {
unsafe { NS_NewHashPropertyBag(p) };
NS_OK
}).unwrap();
HashPropertyBag(bag)
}
}
impl HashPropertyBag {
/// Creates an empty property bag.
#[inline]
pub fn new() -> HashPropertyBag {
HashPropertyBag::default()
}
/// Returns the value for a property name. Fails with `NS_ERROR_FAILURE`
/// if the property doesn't exist, or `NS_ERROR_CANNOT_CONVERT_DATA` if the
/// property exists, but is not of the value type `V`.
pub fn get<K, V>(&self, name: K) -> Result<V, nsresult>
where
K: AsRef<str>,
V: VariantType,
{
getter_addrefs(|p| unsafe { self.0.GetProperty(&*nsString::from(name.as_ref()), p) })
.and_then(|v| V::from_variant(v.coerce()))
}
/// Returns the value for a property name, or the default if not set or
/// not of the value type `V`.
#[inline]
pub fn get_or_default<K, V>(&self, name: K) -> V
where
K: AsRef<str>,
V: VariantType + Default,
{
self.get(name).unwrap_or_default()
}
/// Sets a property with the name to the value, overwriting any previous
/// value.
pub fn set<K, V>(&mut self, name: K, value: V)
where
K: AsRef<str>,
V: VariantType,
{
let v = value.into_variant();
unsafe {
// This is safe to unwrap because
// `nsHashPropertyBagBase::SetProperty` only returns an error if `v`
// is a null pointer.
self.0
.SetProperty(&*nsString::from(name.as_ref()), v.coerce())
.to_result()
.unwrap()
}
}
/// Deletes a property with the name. Returns `true` if the property
/// was previously in the bag, `false` if not.
pub fn delete(&mut self, name: impl AsRef<str>) -> bool {
unsafe {
self.0
.DeleteProperty(&*nsString::from(name.as_ref()))
.to_result()
.is_ok()
}
}
/// Returns a reference to the backing `nsIWritablePropertyBag`.
#[inline]
pub fn bag(&self) -> &nsIWritablePropertyBag {
&self.0
}
}

Просмотреть файл

@ -7,11 +7,15 @@ extern crate nserror;
extern crate nsstring;
extern crate xpcom;
mod bag;
use libc::{c_double, int64_t, uint16_t};
use nserror::{nsresult, NS_OK};
use nsstring::{nsACString, nsAString, nsCString, nsString};
use xpcom::{getter_addrefs, interfaces::nsIVariant, RefPtr};
pub use crate::bag::HashPropertyBag;
extern "C" {
fn NS_GetDataType(variant: *const nsIVariant) -> uint16_t;
fn NS_NewStorageNullVariant(result: *mut *const nsIVariant);

Просмотреть файл

@ -14,6 +14,16 @@
#include "mozilla/Attributes.h"
#include "mozilla/Move.h"
extern "C" {
// This function uses C linkage because it's exposed to Rust to support the
// `HashPropertyBag` wrapper in the `storage_variant` crate.
void NS_NewHashPropertyBag(nsIWritablePropertyBag** aBag) {
MakeRefPtr<nsHashPropertyBag>().forget(aBag);
}
} // extern "C"
/*
* nsHashPropertyBagBase implementation.
*/