author | Sylvestre Ledru <sledru@mozilla.com> |
Tue, 25 Feb 2020 16:17:12 +0000 | |
changeset 515475 | 902bbf296882ca7ab614eb34a9dcf49ee58712b8 |
parent 515474 | bb4ff187fbece788fb3bfec7e8ab79e9e264c960 |
child 515476 | c1bc7695e720abdc45a092218f1cf6916ae04205 |
push id | 37158 |
push user | opoprus@mozilla.com |
push date | Wed, 26 Feb 2020 09:27:57 +0000 |
treeherder | mozilla-central@7f41334e1044 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | froydnj |
bugs | 1617369 |
milestone | 75.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/tools/lint/rustfmt.yml +++ b/tools/lint/rustfmt.yml @@ -10,16 +10,17 @@ rust: - servo/components/to_shmem_derive/ - testing/mozbase/rust/mozprofile/ - testing/mozbase/rust/mozversion/ - testing/ - toolkit/components/telemetry/fog/ - toolkit/crashreporter/ - toolkit/library/ - tools/fuzzing/rust/ + - xpcom/ exclude: - dom/media/gtest/ - dom/webauthn/libudev-sys/ - gfx/wr/direct-composition/ - gfx/wr/peek-poke/ - gfx/wr/webrender_build/ - gfx/wr/wr_malloc_size_of/ - js/src/ @@ -32,17 +33,15 @@ rust: - servo/components/derive_common/ - servo/components/selectors/ - servo/components/servo_arc/ - servo/components/style/ - servo/components/style_derive/ - servo/components/style_traits/ - servo/components/to_shmem/ - servo/tests/unit/style/ - - xpcom/rust/gtest/bench-collections/ - - xpcom/rust/xpcom/xpcom_macros/ extensions: - rs support-files: - 'tools/lint/rust/**' type: external payload: rust:lint code_review_warnings: true
--- a/xpcom/rust/gtest/bench-collections/bench.rs +++ b/xpcom/rust/gtest/bench-collections/bench.rs @@ -11,80 +11,91 @@ use fnv::FnvHashSet; use fxhash::FxHashSet; use std::collections::HashSet; use std::os::raw::{c_char, c_void}; use std::slice; /// Keep this in sync with Params in Bench.cpp. #[derive(Debug)] #[repr(C)] -pub struct Params -{ - config_name: *const c_char, - num_inserts: usize, - num_successful_lookups: usize, - num_failing_lookups: usize, - num_iterations: usize, - remove_inserts: bool, +pub struct Params { + config_name: *const c_char, + num_inserts: usize, + num_successful_lookups: usize, + num_failing_lookups: usize, + num_iterations: usize, + remove_inserts: bool, } #[no_mangle] -pub extern "C" fn Bench_Rust_HashSet(params: *const Params, vals: *const *const c_void, - len: usize) { +pub extern "C" fn Bench_Rust_HashSet( + params: *const Params, + vals: *const *const c_void, + len: usize, +) { let hs: HashSet<_> = std::collections::HashSet::default(); Bench_Rust(hs, params, vals, len); } #[no_mangle] -pub extern "C" fn Bench_Rust_FnvHashSet(params: *const Params, vals: *const *const c_void, - len: usize) { +pub extern "C" fn Bench_Rust_FnvHashSet( + params: *const Params, + vals: *const *const c_void, + len: usize, +) { let hs = FnvHashSet::default(); Bench_Rust(hs, params, vals, len); } #[no_mangle] -pub extern "C" fn Bench_Rust_FxHashSet(params: *const Params, vals: *const *const c_void, - len: usize) { +pub extern "C" fn Bench_Rust_FxHashSet( + params: *const Params, + vals: *const *const c_void, + len: usize, +) { let hs = FxHashSet::default(); Bench_Rust(hs, params, vals, len); } // Keep this in sync with all the other Bench_*() functions. -fn Bench_Rust<H: std::hash::BuildHasher>(mut hs: HashSet<*const c_void, H>, params: *const Params, - vals: *const *const c_void, len: usize) { +fn Bench_Rust<H: std::hash::BuildHasher>( + mut hs: HashSet<*const c_void, H>, + params: *const Params, + vals: *const *const c_void, + len: usize, +) { let params = unsafe { &*params }; let vals = unsafe { slice::from_raw_parts(vals, len) }; for j in 0..params.num_inserts { hs.insert(vals[j]); } for _i in 0..params.num_successful_lookups { for j in 0..params.num_inserts { assert!(hs.contains(&vals[j])); } } for _i in 0..params.num_failing_lookups { - for j in params.num_inserts..params.num_inserts*2 { + for j in params.num_inserts..params.num_inserts * 2 { assert!(!hs.contains(&vals[j])); } } for _i in 0..params.num_iterations { - let mut n = 0; - for _ in hs.iter() { - n += 1; - } - assert!(params.num_inserts == n); - assert!(hs.len() == n); + let mut n = 0; + for _ in hs.iter() { + n += 1; + } + assert!(params.num_inserts == n); + assert!(hs.len() == n); } if params.remove_inserts { for j in 0..params.num_inserts { assert!(hs.remove(&vals[j])); } assert!(hs.len() == 0); } else { assert!(hs.len() == params.num_inserts); } } -
--- a/xpcom/rust/gtest/nsstring/test.rs +++ b/xpcom/rust/gtest/nsstring/test.rs @@ -1,74 +1,81 @@ #![allow(non_snake_case)] extern crate nsstring; -use std::fmt::Write; +use nsstring::*; use std::ffi::CString; +use std::fmt::Write; use std::os::raw::c_char; -use nsstring::*; fn nonfatal_fail(msg: String) { extern "C" { fn GTest_ExpectFailure(message: *const c_char); } unsafe { GTest_ExpectFailure(CString::new(msg).unwrap().as_ptr()); } } /// This macro checks if the two arguments are equal, and causes a non-fatal /// GTest test failure if they are not. macro_rules! expect_eq { ($x:expr, $y:expr) => { match (&$x, &$y) { - (x, y) => if *x != *y { - nonfatal_fail(format!("check failed: (`{:?}` == `{:?}`) at {}:{}", - x, y, file!(), line!())) + (x, y) => { + if *x != *y { + nonfatal_fail(format!( + "check failed: (`{:?}` == `{:?}`) at {}:{}", + x, + y, + file!(), + line!() + )) + } } } - } + }; } #[no_mangle] -pub extern fn Rust_StringFromCpp(cs: *const nsACString, s: *const nsAString) { +pub extern "C" fn Rust_StringFromCpp(cs: *const nsACString, s: *const nsAString) { unsafe { expect_eq!(&*cs, "Hello, World!"); expect_eq!(&*s, "Hello, World!"); } } #[no_mangle] -pub extern fn Rust_AssignFromRust(cs: *mut nsACString, s: *mut nsAString) { +pub extern "C" fn Rust_AssignFromRust(cs: *mut nsACString, s: *mut nsAString) { unsafe { (*cs).assign(&nsCString::from("Hello, World!")); expect_eq!(&*cs, "Hello, World!"); (*s).assign(&nsString::from("Hello, World!")); expect_eq!(&*s, "Hello, World!"); } } extern "C" { fn Cpp_AssignFromCpp(cs: *mut nsACString, s: *mut nsAString); } #[no_mangle] -pub extern fn Rust_AssignFromCpp() { +pub extern "C" fn Rust_AssignFromCpp() { let mut cs = nsCString::new(); let mut s = nsString::new(); unsafe { Cpp_AssignFromCpp(&mut *cs, &mut *s); } expect_eq!(cs, "Hello, World!"); expect_eq!(s, "Hello, World!"); } #[no_mangle] -pub extern fn Rust_StringWrite() { +pub extern "C" fn Rust_StringWrite() { let mut cs = nsCString::new(); let mut s = nsString::new(); write!(s, "a").unwrap(); write!(cs, "a").unwrap(); expect_eq!(s, "a"); expect_eq!(cs, "a"); write!(s, "bc").unwrap(); @@ -77,24 +84,29 @@ pub extern fn Rust_StringWrite() { expect_eq!(cs, "abc"); write!(s, "{}", 123).unwrap(); write!(cs, "{}", 123).unwrap(); expect_eq!(s, "abc123"); expect_eq!(cs, "abc123"); } #[no_mangle] -pub extern fn Rust_FromEmptyRustString() { +pub extern "C" fn Rust_FromEmptyRustString() { let mut test = nsString::from("Blah"); test.assign_utf8(&nsCString::from(String::new())); assert!(test.is_empty()); } #[no_mangle] -pub extern fn Rust_WriteToBufferFromRust(cs: *mut nsACString, s: *mut nsAString, fallible_cs: *mut nsACString, fallible_s: *mut nsAString) { +pub extern "C" fn Rust_WriteToBufferFromRust( + cs: *mut nsACString, + s: *mut nsAString, + fallible_cs: *mut nsACString, + fallible_s: *mut nsAString, +) { unsafe { let cs_buf = (*cs).to_mut(); let s_buf = (*s).to_mut(); let fallible_cs_buf = (*fallible_cs).fallible_to_mut().unwrap(); let fallible_s_buf = (*fallible_s).fallible_to_mut().unwrap(); cs_buf[0] = b'A'; cs_buf[1] = b'B';
--- a/xpcom/rust/gtest/xpcom/test.rs +++ b/xpcom/rust/gtest/xpcom/test.rs @@ -4,69 +4,79 @@ #![allow(non_snake_case)] #[macro_use] extern crate xpcom; extern crate nserror; +use nserror::{nsresult, NS_OK}; +use std::ffi::{CStr, CString}; use std::os::raw::c_char; use std::ptr; -use std::ffi::{CStr, CString}; use xpcom::interfaces; -use nserror::{nsresult, NS_OK}; #[no_mangle] -pub unsafe extern fn Rust_ObserveFromRust() -> *const interfaces::nsIObserverService { +pub unsafe extern "C" fn Rust_ObserveFromRust() -> *const interfaces::nsIObserverService { let obssvc = xpcom::services::get_ObserverService().unwrap(); // Define an observer #[derive(xpcom)] #[xpimplements(nsIObserver)] #[refcnt = "nonatomic"] struct InitObserver { - run: *mut bool + run: *mut bool, } impl Observer { unsafe fn Observe( &self, _subject: *const interfaces::nsISupports, topic: *const c_char, - _data: *const i16 + _data: *const i16, ) -> nsresult { *self.run = true; assert!(CStr::from_ptr(topic).to_str() == Ok("test-rust-observe")); NS_OK } } let topic = CString::new("test-rust-observe").unwrap(); let mut run = false; - let observer = Observer::allocate(InitObserver{ run: &mut run }); - let rv = obssvc.AddObserver(observer.coerce::<interfaces::nsIObserver>(), topic.as_ptr(), false); + let observer = Observer::allocate(InitObserver { run: &mut run }); + let rv = obssvc.AddObserver( + observer.coerce::<interfaces::nsIObserver>(), + topic.as_ptr(), + false, + ); assert!(rv.succeeded()); let rv = obssvc.NotifyObservers(ptr::null(), topic.as_ptr(), ptr::null()); assert!(rv.succeeded()); assert!(run, "The observer should have been run!"); let rv = obssvc.RemoveObserver(observer.coerce::<interfaces::nsIObserver>(), topic.as_ptr()); assert!(rv.succeeded()); - assert!(observer.coerce::<interfaces::nsISupports>() as *const _== - &*observer.query_interface::<interfaces::nsISupports>().unwrap() as *const _); + assert!( + observer.coerce::<interfaces::nsISupports>() as *const _ + == &*observer + .query_interface::<interfaces::nsISupports>() + .unwrap() as *const _ + ); &*obssvc } #[no_mangle] -pub unsafe extern fn Rust_ImplementRunnableInRust(it_worked: *mut bool, - runnable: *mut *const interfaces::nsIRunnable) { +pub unsafe extern "C" fn Rust_ImplementRunnableInRust( + it_worked: *mut bool, + runnable: *mut *const interfaces::nsIRunnable, +) { // Define a type which implements nsIRunnable in rust. #[derive(xpcom)] #[xpimplements(nsIRunnable)] #[refcnt = "atomic"] struct InitMyRunnable { it_worked: *mut bool, } @@ -74,12 +84,15 @@ pub unsafe extern fn Rust_ImplementRunna unsafe fn Run(&self) -> nsresult { *self.it_worked = true; NS_OK } } // Create my runnable type, and forget it into the outparameter! let my_runnable = MyRunnable::allocate(InitMyRunnable { - it_worked: it_worked + it_worked: it_worked, }); - my_runnable.query_interface::<interfaces::nsIRunnable>().unwrap().forget(&mut *runnable); + my_runnable + .query_interface::<interfaces::nsIRunnable>() + .unwrap() + .forget(&mut *runnable); }
--- a/xpcom/rust/moz_task/src/lib.rs +++ b/xpcom/rust/moz_task/src/lib.rs @@ -10,20 +10,20 @@ extern crate libc; extern crate nserror; extern crate nsstring; extern crate xpcom; use nserror::{nsresult, NS_OK}; use nsstring::{nsACString, nsCString}; use std::{ + ffi::CStr, marker::PhantomData, mem, ptr, sync::atomic::{AtomicBool, Ordering}, - ffi::CStr, }; use xpcom::{ getter_addrefs, interfaces::{nsIEventTarget, nsIRunnable, nsISupports, nsIThread}, xpcom, xpcom_method, AtomicRefcnt, RefCounted, RefPtr, XpCom, }; extern "C" {
--- a/xpcom/rust/nsstring/src/conversions.rs +++ b/xpcom/rust/nsstring/src/conversions.rs @@ -299,17 +299,18 @@ impl nsAString { self.fallible_append_latin1_impl(other, len, false) .expect("Out of memory"); } /// Convert a Latin1 (i.e. byte value equals scalar value; not windows-1252!) /// into UTF-16 and fallibly append the conversion result to this string. pub fn fallible_append_latin1(&mut self, other: &[u8]) -> Result<(), ()> { let len = self.len(); - self.fallible_append_latin1_impl(other, len, false).map(|_| ()) + self.fallible_append_latin1_impl(other, len, false) + .map(|_| ()) } } impl nsACString { // UTF-16 to UTF-8 fn fallible_append_utf16_to_utf8_impl( &mut self, @@ -325,45 +326,45 @@ impl nsACString { if worst_case <= inline_capacity { Some(worst_case) } else { None } } else { None }; - let (filled, read, mut handle) = if worst_case_needed.is_none() && - long_string_stars_with_basic_latin(other) { - let new_len_with_ascii = old_len.checked_add(other.len()).ok_or(())?; - let mut handle = unsafe { self.bulk_write(new_len_with_ascii, old_len, false)? }; - let (read, written) = convert_utf16_to_utf8_partial(other, &mut handle.as_mut_slice()[old_len..]); - let left = other.len() - read; - if left == 0 { - return Ok(handle.finish(old_len + written, true)); - } - let filled = old_len + written; - let needed = times_three(left).ok_or(())?; - let new_len = filled.checked_add(needed).ok_or(())?; - unsafe { - handle.restart_bulk_write(new_len, filled, false)?; - } - (filled, read, handle) - } else { - // Started with non-ASCII. Compute worst case - let needed = if let Some(n) = worst_case_needed { - n + let (filled, read, mut handle) = + if worst_case_needed.is_none() && long_string_stars_with_basic_latin(other) { + let new_len_with_ascii = old_len.checked_add(other.len()).ok_or(())?; + let mut handle = unsafe { self.bulk_write(new_len_with_ascii, old_len, false)? }; + let (read, written) = + convert_utf16_to_utf8_partial(other, &mut handle.as_mut_slice()[old_len..]); + let left = other.len() - read; + if left == 0 { + return Ok(handle.finish(old_len + written, true)); + } + let filled = old_len + written; + let needed = times_three(left).ok_or(())?; + let new_len = filled.checked_add(needed).ok_or(())?; + unsafe { + handle.restart_bulk_write(new_len, filled, false)?; + } + (filled, read, handle) } else { - times_three(other.len()).ok_or(())? + // Started with non-ASCII. Compute worst case + let needed = if let Some(n) = worst_case_needed { + n + } else { + times_three(other.len()).ok_or(())? + }; + let new_len = old_len.checked_add(needed).ok_or(())?; + let handle = unsafe { self.bulk_write(new_len, old_len, false)? }; + (old_len, 0, handle) }; - let new_len = old_len.checked_add(needed).ok_or(())?; - let handle = unsafe { self.bulk_write(new_len, old_len, false)? }; - (old_len, 0, handle) - }; - let written = - convert_utf16_to_utf8(&other[read..], &mut handle.as_mut_slice()[filled..]); + let written = convert_utf16_to_utf8(&other[read..], &mut handle.as_mut_slice()[filled..]); Ok(handle.finish(filled + written, true)) } /// Convert a potentially-invalid UTF-16 string into valid UTF-8 /// (replacing invalid sequences with the REPLACEMENT CHARACTER) and /// replace the content of this string with the conversion result. pub fn assign_utf16_to_utf8(&mut self, other: &[u16]) { self.fallible_append_utf16_to_utf8_impl(other, 0) @@ -600,17 +601,18 @@ impl nsACString { None }; if worst_case_needed.is_none() && long_string_starts_with_ascii(other) { // Wrapper didn't check for ASCII, so let's see if `other` starts with ASCII // `other` starts with ASCII, so let's first size the buffer // with optimism that it's ASCII-only. let new_len_with_ascii = old_len.checked_add(other.len()).ok_or(())?; let mut handle = unsafe { self.bulk_write(new_len_with_ascii, old_len, false)? }; - let (read, written) = convert_latin1_to_utf8_partial(other, &mut handle.as_mut_slice()[old_len..]); + let (read, written) = + convert_latin1_to_utf8_partial(other, &mut handle.as_mut_slice()[old_len..]); let left = other.len() - read; let filled = old_len + written; if left == 0 { // `other` fit in the initial allocation return Ok(handle.finish(filled, true)); } let needed = left.checked_mul(2).ok_or(())?; let new_len = filled.checked_add(needed).ok_or(())?; @@ -625,18 +627,17 @@ impl nsACString { } else { other.len().checked_mul(2).ok_or(())? }; let new_len = old_len.checked_add(needed).ok_or(())?; let handle = unsafe { self.bulk_write(new_len, old_len, false)? }; (old_len, 0, handle) } }; - let written = - convert_latin1_to_utf8(&other[read..], &mut handle.as_mut_slice()[filled..]); + let written = convert_latin1_to_utf8(&other[read..], &mut handle.as_mut_slice()[filled..]); Ok(handle.finish(filled + written, true)) } /// Convert a Latin1 (i.e. byte value equals scalar value; not windows-1252!) /// into UTF-8 and replace the content of this string with the conversion result. pub fn assign_latin1_to_utf8<T: Latin1StringLike + ?Sized>(&mut self, other: &T) { self.fallible_append_latin1_to_utf8_check(other, 0) .expect("Out of memory");
--- a/xpcom/rust/nsstring/src/lib.rs +++ b/xpcom/rust/nsstring/src/lib.rs @@ -1329,136 +1329,186 @@ pub mod test_helpers { use std::mem; /// Generates an #[no_mangle] extern "C" function which returns the size and /// alignment of the given type with the given name. macro_rules! size_align_check { ($T:ty, $fname:ident) => { #[no_mangle] #[allow(non_snake_case)] - pub extern fn $fname(size: *mut usize, align: *mut usize) { + pub extern "C" fn $fname(size: *mut usize, align: *mut usize) { unsafe { *size = mem::size_of::<$T>(); *align = mem::align_of::<$T>(); } } }; ($T:ty, $U:ty, $V:ty, $fname:ident) => { #[no_mangle] #[allow(non_snake_case)] - pub extern fn $fname(size: *mut usize, align: *mut usize) { + pub extern "C" fn $fname(size: *mut usize, align: *mut usize) { unsafe { *size = mem::size_of::<$T>(); *align = mem::align_of::<$T>(); assert_eq!(*size, mem::size_of::<$U>()); assert_eq!(*align, mem::align_of::<$U>()); assert_eq!(*size, mem::size_of::<$V>()); assert_eq!(*align, mem::align_of::<$V>()); } } - } + }; } - size_align_check!(nsStringRepr, nsString, nsStr<'static>, - Rust_Test_ReprSizeAlign_nsString); - size_align_check!(nsCStringRepr, nsCString, nsCStr<'static>, - Rust_Test_ReprSizeAlign_nsCString); + size_align_check!( + nsStringRepr, + nsString, + nsStr<'static>, + Rust_Test_ReprSizeAlign_nsString + ); + size_align_check!( + nsCStringRepr, + nsCString, + nsCStr<'static>, + Rust_Test_ReprSizeAlign_nsCString + ); /// Generates a $[no_mangle] extern "C" function which returns the size, /// alignment and offset in the parent struct of a given member, with the /// given name. /// /// This method can trigger Undefined Behavior if the accessing the member /// $member on a given type would use that type's `Deref` implementation. macro_rules! member_check { ($T:ty, $U:ty, $V:ty, $member:ident, $method:ident) => { #[no_mangle] #[allow(non_snake_case)] - pub extern fn $method(size: *mut usize, - align: *mut usize, - offset: *mut usize) { + pub extern "C" fn $method(size: *mut usize, align: *mut usize, offset: *mut usize) { unsafe { // Create a temporary value of type T to get offsets, sizes // and alignments from. let tmp: mem::MaybeUninit<$T> = mem::MaybeUninit::uninit(); // FIXME: This should use &raw references when available, // this is technically UB as it creates a reference to // uninitialized memory, but there's no better way to do // this right now. let tmp = &*tmp.as_ptr(); *size = mem::size_of_val(&tmp.$member); *align = mem::align_of_val(&tmp.$member); - *offset = - (&tmp.$member as *const _ as usize) - - (tmp as *const $T as usize); + *offset = (&tmp.$member as *const _ as usize) - (tmp as *const $T as usize); let tmp: mem::MaybeUninit<$U> = mem::MaybeUninit::uninit(); let tmp = &*tmp.as_ptr(); assert_eq!(*size, mem::size_of_val(&tmp.hdr.$member)); assert_eq!(*align, mem::align_of_val(&tmp.hdr.$member)); - assert_eq!(*offset, - (&tmp.hdr.$member as *const _ as usize) - - (tmp as *const $U as usize)); + assert_eq!( + *offset, + (&tmp.hdr.$member as *const _ as usize) - (tmp as *const $U as usize) + ); let tmp: mem::MaybeUninit<$V> = mem::MaybeUninit::uninit(); let tmp = &*tmp.as_ptr(); assert_eq!(*size, mem::size_of_val(&tmp.hdr.$member)); assert_eq!(*align, mem::align_of_val(&tmp.hdr.$member)); - assert_eq!(*offset, - (&tmp.hdr.$member as *const _ as usize) - - (tmp as *const $V as usize)); + assert_eq!( + *offset, + (&tmp.hdr.$member as *const _ as usize) - (tmp as *const $V as usize) + ); } } - } + }; } - member_check!(nsStringRepr, nsString, nsStr<'static>, - data, Rust_Test_Member_nsString_mData); - member_check!(nsStringRepr, nsString, nsStr<'static>, - length, Rust_Test_Member_nsString_mLength); - member_check!(nsStringRepr, nsString, nsStr<'static>, - dataflags, Rust_Test_Member_nsString_mDataFlags); - member_check!(nsStringRepr, nsString, nsStr<'static>, - classflags, Rust_Test_Member_nsString_mClassFlags); - member_check!(nsCStringRepr, nsCString, nsCStr<'static>, - data, Rust_Test_Member_nsCString_mData); - member_check!(nsCStringRepr, nsCString, nsCStr<'static>, - length, Rust_Test_Member_nsCString_mLength); - member_check!(nsCStringRepr, nsCString, nsCStr<'static>, - dataflags, Rust_Test_Member_nsCString_mDataFlags); - member_check!(nsCStringRepr, nsCString, nsCStr<'static>, - classflags, Rust_Test_Member_nsCString_mClassFlags); + member_check!( + nsStringRepr, + nsString, + nsStr<'static>, + data, + Rust_Test_Member_nsString_mData + ); + member_check!( + nsStringRepr, + nsString, + nsStr<'static>, + length, + Rust_Test_Member_nsString_mLength + ); + member_check!( + nsStringRepr, + nsString, + nsStr<'static>, + dataflags, + Rust_Test_Member_nsString_mDataFlags + ); + member_check!( + nsStringRepr, + nsString, + nsStr<'static>, + classflags, + Rust_Test_Member_nsString_mClassFlags + ); + member_check!( + nsCStringRepr, + nsCString, + nsCStr<'static>, + data, + Rust_Test_Member_nsCString_mData + ); + member_check!( + nsCStringRepr, + nsCString, + nsCStr<'static>, + length, + Rust_Test_Member_nsCString_mLength + ); + member_check!( + nsCStringRepr, + nsCString, + nsCStr<'static>, + dataflags, + Rust_Test_Member_nsCString_mDataFlags + ); + member_check!( + nsCStringRepr, + nsCString, + nsCStr<'static>, + classflags, + Rust_Test_Member_nsCString_mClassFlags + ); #[no_mangle] #[allow(non_snake_case)] - pub extern fn Rust_Test_NsStringFlags(f_terminated: *mut u16, - f_voided: *mut u16, - f_refcounted: *mut u16, - f_owned: *mut u16, - f_inline: *mut u16, - f_literal: *mut u16, - f_class_inline: *mut u16, - f_class_null_terminated: *mut u16) { + pub extern "C" fn Rust_Test_NsStringFlags( + f_terminated: *mut u16, + f_voided: *mut u16, + f_refcounted: *mut u16, + f_owned: *mut u16, + f_inline: *mut u16, + f_literal: *mut u16, + f_class_inline: *mut u16, + f_class_null_terminated: *mut u16, + ) { unsafe { *f_terminated = DataFlags::TERMINATED.bits(); *f_voided = DataFlags::VOIDED.bits(); *f_refcounted = DataFlags::REFCOUNTED.bits(); *f_owned = DataFlags::OWNED.bits(); *f_inline = DataFlags::INLINE.bits(); *f_literal = DataFlags::LITERAL.bits(); *f_class_inline = ClassFlags::INLINE.bits(); *f_class_null_terminated = ClassFlags::NULL_TERMINATED.bits(); } } #[no_mangle] #[allow(non_snake_case)] - pub extern fn Rust_InlineCapacityFromRust(cstring: *const nsACString, - string: *const nsAString, - cstring_capacity: *mut usize, - string_capacity: *mut usize) { + pub extern "C" fn Rust_InlineCapacityFromRust( + cstring: *const nsACString, + string: *const nsAString, + cstring_capacity: *mut usize, + string_capacity: *mut usize, + ) { unsafe { *cstring_capacity = (*cstring).inline_capacity().unwrap(); *string_capacity = (*string).inline_capacity().unwrap(); } } }
--- a/xpcom/rust/xpcom/src/base.rs +++ b/xpcom/rust/xpcom/src/base.rs @@ -1,18 +1,14 @@ /* 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 { - RefCounted, - RefPtr, - GetterAddrefs -}; use interfaces::{nsIInterfaceRequestor, nsISupports}; +use {GetterAddrefs, RefCounted, RefPtr}; #[repr(C)] #[derive(Copy, Clone, Eq, PartialEq)] /// A "unique identifier". This is modeled after OSF DCE UUIDs. pub struct nsID(pub u32, pub u16, pub u16, pub [u8; 8]); /// Interface IDs pub type nsIID = nsID; @@ -20,29 +16,29 @@ pub type nsIID = nsID; pub type nsCID = nsID; /// A type which implements XpCom must follow the following rules: /// /// * It must be a legal XPCOM interface. /// * The result of a QueryInterface or similar call, passing IID, must return a /// valid reference to an object of the given type. /// * It must be valid to cast a &self reference to a &nsISupports reference. -pub unsafe trait XpCom : RefCounted { +pub unsafe trait XpCom: RefCounted { const IID: nsIID; /// Perform a QueryInterface call on this object, attempting to dynamically /// cast it to the requested interface type. Returns Some(RefPtr<T>) if the /// cast succeeded, and None otherwise. fn query_interface<T: XpCom>(&self) -> Option<RefPtr<T>> { let mut ga = GetterAddrefs::<T>::new(); unsafe { - if (*(self as *const Self as *const nsISupports)).QueryInterface( - &T::IID, - ga.void_ptr(), - ).succeeded() { + if (*(self as *const Self as *const nsISupports)) + .QueryInterface(&T::IID, ga.void_ptr()) + .succeeded() + { ga.refptr() } else { None } } } /// Perform a `GetInterface` call on this object, returning `None` if the
--- a/xpcom/rust/xpcom/src/interfaces/idl.rs +++ b/xpcom/rust/xpcom/src/interfaces/idl.rs @@ -1,12 +1,12 @@ /* 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/. */ #![allow(bad_style)] +use interfaces::*; use *; -use interfaces::*; // NOTE: This file contains a series of `include!()` invocations, defining all // idl interfaces directly within this module. include!(concat!(env!("MOZ_TOPOBJDIR"), "/dist/xpcrs/rt/all.rs"));
--- a/xpcom/rust/xpcom/src/interfaces/nonidl.rs +++ b/xpcom/rust/xpcom/src/interfaces/nonidl.rs @@ -36,75 +36,145 @@ macro_rules! nonidl { self.Release(); } } impl ::std::ops::Deref for $name { type Target = $crate::interfaces::nsISupports; #[inline] fn deref(&self) -> &$crate::interfaces::nsISupports { - unsafe { - ::std::mem::transmute(self) - } + unsafe { ::std::mem::transmute(self) } } } - } + }; } // Must be kept in sync with Document.h -nonidl!(Document, - nsID(0xce1f7627, 0x7109, 0x4977, - [0xba, 0x77, 0x49, 0x0f, 0xfd, 0xe0, 0x7a, 0xaa])); +nonidl!( + Document, + nsID( + 0xce1f7627, + 0x7109, + 0x4977, + [0xba, 0x77, 0x49, 0x0f, 0xfd, 0xe0, 0x7a, 0xaa] + ) +); // Must be kept in sync with nsINode.h -nonidl!(nsINode, - nsID(0x70ba4547, 0x7699, 0x44fc, - [0xb3, 0x20, 0x52, 0xdb, 0xe3, 0xd1, 0xf9, 0x0a])); +nonidl!( + nsINode, + nsID( + 0x70ba4547, + 0x7699, + 0x44fc, + [0xb3, 0x20, 0x52, 0xdb, 0xe3, 0xd1, 0xf9, 0x0a] + ) +); // Must be kept in sync with nsIContent.h -nonidl!(nsIContent, - nsID(0x8e1bab9d, 0x8815, 0x4d2c, - [0xa2, 0x4d, 0x7a, 0xba, 0x52, 0x39, 0xdc, 0x22])); +nonidl!( + nsIContent, + nsID( + 0x8e1bab9d, + 0x8815, + 0x4d2c, + [0xa2, 0x4d, 0x7a, 0xba, 0x52, 0x39, 0xdc, 0x22] + ) +); // Must be kept in sync with nsIConsoleReportCollector.h -nonidl!(nsIConsoleReportCollector, - nsID(0xdd98a481, 0xd2c4, 0x4203, - [0x8d, 0xfa, 0x85, 0xbf, 0xd7, 0xdc, 0xd7, 0x05])); +nonidl!( + nsIConsoleReportCollector, + nsID( + 0xdd98a481, + 0xd2c4, + 0x4203, + [0x8d, 0xfa, 0x85, 0xbf, 0xd7, 0xdc, 0xd7, 0x05] + ) +); // Must be kept in sync with nsIGlobalObject.h -nonidl!(nsIGlobalObject, - nsID(0x11afa8be, 0xd997, 0x4e07, - [0xa6, 0xa3, 0x6f, 0x87, 0x2e, 0xc3, 0xee, 0x7f])); +nonidl!( + nsIGlobalObject, + nsID( + 0x11afa8be, + 0xd997, + 0x4e07, + [0xa6, 0xa3, 0x6f, 0x87, 0x2e, 0xc3, 0xee, 0x7f] + ) +); // Must be kept in sync with nsIScriptElement.h -nonidl!(nsIScriptElement, - nsID(0xe60fca9b, 0x1b96, 0x4e4e, - [0xa9, 0xb4, 0xdc, 0x98, 0x4f, 0x88, 0x3f, 0x9c])); +nonidl!( + nsIScriptElement, + nsID( + 0xe60fca9b, + 0x1b96, + 0x4e4e, + [0xa9, 0xb4, 0xdc, 0x98, 0x4f, 0x88, 0x3f, 0x9c] + ) +); // Must be kept in sync with nsPIDOMWindow.h -nonidl!(nsPIDOMWindowOuter, - nsID(0x769693d4, 0xb009, 0x4fe2, - [0xaf, 0x18, 0x7d, 0xc8, 0xdf, 0x74, 0x96, 0xdf])); +nonidl!( + nsPIDOMWindowOuter, + nsID( + 0x769693d4, + 0xb009, + 0x4fe2, + [0xaf, 0x18, 0x7d, 0xc8, 0xdf, 0x74, 0x96, 0xdf] + ) +); // Must be kept in sync with nsPIDOMWindow.h -nonidl!(nsPIDOMWindowInner, - nsID(0x775dabc9, 0x8f43, 0x4277, - [0x9a, 0xdb, 0xf1, 0x99, 0x0d, 0x77, 0xcf, 0xfb])); +nonidl!( + nsPIDOMWindowInner, + nsID( + 0x775dabc9, + 0x8f43, + 0x4277, + [0x9a, 0xdb, 0xf1, 0x99, 0x0d, 0x77, 0xcf, 0xfb] + ) +); // Must be kept in sync with nsIScriptContext.h -nonidl!(nsIScriptContext, - nsID(0x54cbe9cf, 0x7282, 0x421a, - [0x91, 0x6f, 0xd0, 0x70, 0x73, 0xde, 0xb8, 0xc0])); +nonidl!( + nsIScriptContext, + nsID( + 0x54cbe9cf, + 0x7282, + 0x421a, + [0x91, 0x6f, 0xd0, 0x70, 0x73, 0xde, 0xb8, 0xc0] + ) +); // Must be kept in sync with nsIScriptGlobalObject.h -nonidl!(nsIScriptGlobalObject, - nsID(0x876f83bd, 0x6314, 0x460a, - [0xa0, 0x45, 0x1c, 0x8f, 0x46, 0x2f, 0xb8, 0xe1])); +nonidl!( + nsIScriptGlobalObject, + nsID( + 0x876f83bd, + 0x6314, + 0x460a, + [0xa0, 0x45, 0x1c, 0x8f, 0x46, 0x2f, 0xb8, 0xe1] + ) +); // Must be kept in sync with nsIScrollObserver.h -nonidl!(nsIScrollObserver, - nsID(0xaa5026eb, 0x2f88, 0x4026, - [0xa4, 0x6b, 0xf4, 0x59, 0x6b, 0x4e, 0xdf, 0x00])); +nonidl!( + nsIScrollObserver, + nsID( + 0xaa5026eb, + 0x2f88, + 0x4026, + [0xa4, 0x6b, 0xf4, 0x59, 0x6b, 0x4e, 0xdf, 0x00] + ) +); // Must be kept in sync with nsIWidget.h -nonidl!(nsIWidget, - nsID(0x06396bf6, 0x2dd8, 0x45e5, - [0xac, 0x45, 0x75, 0x26, 0x53, 0xb1, 0xc9, 0x80])); +nonidl!( + nsIWidget, + nsID( + 0x06396bf6, + 0x2dd8, + 0x45e5, + [0xac, 0x45, 0x75, 0x26, 0x53, 0xb1, 0xc9, 0x80] + ) +);
--- a/xpcom/rust/xpcom/src/lib.rs +++ b/xpcom/rust/xpcom/src/lib.rs @@ -7,20 +7,20 @@ //! //! For documentation on how to implement XPCOM methods, see the documentation //! for the [`xpcom_macros`](../xpcom_macros/index.html) crate. #![allow(non_snake_case)] #![allow(non_camel_case_types)] extern crate libc; +extern crate nserror; extern crate nsstring; -extern crate nserror; +extern crate thin_vec; extern crate threadbound; -extern crate thin_vec; // re-export the xpcom_macros macro #[macro_use] #[allow(unused_imports)] extern crate xpcom_macros; #[doc(hidden)] pub use xpcom_macros::*;
--- a/xpcom/rust/xpcom/src/method.rs +++ b/xpcom/rust/xpcom/src/method.rs @@ -229,21 +229,17 @@ impl<'a, T: 'a> Ensure<*const T> for Res } else { Ok(&*ptr) } } } impl<'a, T: 'a> Ensure<*const T> for Result<Option<&'a T>, nsresult> { unsafe fn ensure(ptr: *const T) -> Result<Option<&'a T>, nsresult> { - Ok(if ptr.is_null() { - None - } else { - Some(&*ptr) - }) + Ok(if ptr.is_null() { None } else { Some(&*ptr) }) } } impl<T: Copy> Ensure<T> for Result<T, nsresult> { unsafe fn ensure(copyable: T) -> Result<T, nsresult> { Ok(copyable) } }
--- a/xpcom/rust/xpcom/src/reexports.rs +++ b/xpcom/rust/xpcom/src/reexports.rs @@ -2,17 +2,16 @@ * 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/. */ /// The automatically generated code from `xpcom_macros` depends on some types /// which are defined in other libraries which `xpcom` depends on, but which may /// not be `extern crate`-ed into the crate the macros are expanded into. This /// module re-exports those types from `xpcom` so that they can be used from the /// macro. - // re-export libc so it can be used by the procedural macro. pub extern crate libc; pub use nsstring::{nsACString, nsAString, nsCString, nsString}; pub use nserror::{nsresult, NS_ERROR_NO_INTERFACE, NS_OK}; pub use std::ops::Deref;
--- a/xpcom/rust/xpcom/src/refptr.rs +++ b/xpcom/rust/xpcom/src/refptr.rs @@ -1,18 +1,18 @@ /* 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 std::mem; -use std::ptr; -use std::ops::Deref; +use std::cell::Cell; use std::fmt; use std::marker::PhantomData; -use std::cell::Cell; +use std::mem; +use std::ops::Deref; +use std::ptr; use std::sync::atomic::{self, AtomicUsize, Ordering}; use nserror::{nsresult, NS_OK}; use libc; use interfaces::nsrefcnt; @@ -38,17 +38,17 @@ pub struct RefPtr<T: RefCounted + 'stati // I believe that this is "safe enough", as this module is private and // no other module can read this reference. _ptr: &'static T, // As we aren't using Shared<T>, we need to add this phantomdata to // prevent unsoundness in dropck _marker: PhantomData<T>, } -impl <T: RefCounted + 'static> RefPtr<T> { +impl<T: RefCounted + 'static> RefPtr<T> { /// Construct a new RefPtr from a reference to the refcounted object. #[inline] pub fn new(p: &T) -> RefPtr<T> { unsafe { p.addref(); RefPtr { _ptr: mem::transmute(p), _marker: PhantomData, @@ -84,41 +84,41 @@ impl <T: RefCounted + 'static> RefPtr<T> /// Write this RefPtr's value into an outparameter. #[inline] pub fn forget(self, into: &mut *const T) { *into = &*self; mem::forget(self); } } -impl <T: RefCounted + 'static> Deref for RefPtr<T> { +impl<T: RefCounted + 'static> Deref for RefPtr<T> { type Target = T; #[inline] fn deref(&self) -> &T { self._ptr } } -impl <T: RefCounted + 'static> Drop for RefPtr<T> { +impl<T: RefCounted + 'static> Drop for RefPtr<T> { #[inline] fn drop(&mut self) { unsafe { self._ptr.release(); } } } -impl <T: RefCounted + 'static> Clone for RefPtr<T> { +impl<T: RefCounted + 'static> Clone for RefPtr<T> { #[inline] fn clone(&self) -> RefPtr<T> { RefPtr::new(self) } } -impl <T: RefCounted + 'static + fmt::Debug> fmt::Debug for RefPtr<T> { +impl<T: RefCounted + 'static + fmt::Debug> fmt::Debug for RefPtr<T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "RefPtr<{:?}>", self.deref()) } } /// A wrapper that binds a RefCounted value to its original thread, /// preventing retrieval from other threads and panicking if the value /// is dropped on a different thread. @@ -153,17 +153,17 @@ impl<T: RefCounted + 'static> Drop for T /// destructed, and can be easily transformed into an `Option<RefPtr<T>>`. /// /// It many cases it may be easier to use the `getter_addrefs` method. pub struct GetterAddrefs<T: RefCounted + 'static> { _ptr: *const T, _marker: PhantomData<T>, } -impl <T: RefCounted + 'static> GetterAddrefs<T> { +impl<T: RefCounted + 'static> GetterAddrefs<T> { /// Create a `GetterAddrefs`, initializing it with the null pointer. #[inline] pub fn new() -> GetterAddrefs<T> { GetterAddrefs { _ptr: ptr::null(), _marker: PhantomData, } } @@ -187,23 +187,21 @@ impl <T: RefCounted + 'static> GetterAdd /// Transform this `GetterAddrefs` into an `Option<RefPtr<T>>`, without /// performing any addrefs or releases. #[inline] pub fn refptr(self) -> Option<RefPtr<T>> { let p = self._ptr; // Don't run the destructor because we don't want to release the stored // pointer. mem::forget(self); - unsafe { - RefPtr::from_raw_dont_addref(p) - } + unsafe { RefPtr::from_raw_dont_addref(p) } } } -impl <T: RefCounted + 'static> Drop for GetterAddrefs<T> { +impl<T: RefCounted + 'static> Drop for GetterAddrefs<T> { #[inline] fn drop(&mut self) { if !self._ptr.is_null() { unsafe { (*self._ptr).release(); } } } @@ -223,17 +221,18 @@ impl <T: RefCounted + 'static> Drop for /// # Usage /// /// ``` /// let x: Result<RefPtr<T>, nsresult> = /// getter_addrefs(|p| iosvc.NewURI(uri, ptr::null(), ptr::null(), p)); /// ``` #[inline] pub fn getter_addrefs<T: RefCounted, F>(f: F) -> Result<RefPtr<T>, nsresult> - where F: FnOnce(*mut *const T) -> nsresult +where + F: FnOnce(*mut *const T) -> nsresult, { let mut ga = GetterAddrefs::<T>::new(); let rv = f(unsafe { ga.ptr() }); if rv.failed() { return Err(rv); } ga.refptr().ok_or(NS_OK) }
--- a/xpcom/rust/xpcom/src/statics.rs +++ b/xpcom/rust/xpcom/src/statics.rs @@ -1,99 +1,82 @@ /* 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 std::ffi::CStr; use std::ptr; -use { - RefPtr, - GetterAddrefs, - XpCom, -}; +use {GetterAddrefs, RefPtr, XpCom}; -use interfaces::{ - nsIComponentManager, - nsIServiceManager, - nsIComponentRegistrar, -}; +use interfaces::{nsIComponentManager, nsIComponentRegistrar, nsIServiceManager}; macro_rules! try_opt { ($e: expr) => { match $e { Some(x) => x, None => return None, } - } + }; } /// Get a reference to the global `nsIComponentManager`. /// /// Can return `None` during shutdown. #[inline] pub fn component_manager() -> Option<RefPtr<nsIComponentManager>> { - unsafe { - RefPtr::from_raw(Gecko_GetComponentManager()) - } + unsafe { RefPtr::from_raw(Gecko_GetComponentManager()) } } /// Get a reference to the global `nsIServiceManager`. /// /// Can return `None` during shutdown. #[inline] pub fn service_manager() -> Option<RefPtr<nsIServiceManager>> { - unsafe { - RefPtr::from_raw(Gecko_GetServiceManager()) - } + unsafe { RefPtr::from_raw(Gecko_GetServiceManager()) } } /// Get a reference to the global `nsIComponentRegistrar` /// /// Can return `None` during shutdown. #[inline] pub fn component_registrar() -> Option<RefPtr<nsIComponentRegistrar>> { - unsafe { - RefPtr::from_raw(Gecko_GetComponentRegistrar()) - } + unsafe { RefPtr::from_raw(Gecko_GetComponentRegistrar()) } } /// Helper for calling `nsIComponentManager::CreateInstanceByContractID` on the /// global `nsIComponentRegistrar`. /// /// This method is similar to `do_CreateInstance` in C++. #[inline] pub fn create_instance<T: XpCom>(id: &CStr) -> Option<RefPtr<T>> { unsafe { let mut ga = GetterAddrefs::<T>::new(); - if try_opt!(component_manager()).CreateInstanceByContractID( - id.as_ptr(), - ptr::null(), - &T::IID, - ga.void_ptr(), - ).succeeded() { + if try_opt!(component_manager()) + .CreateInstanceByContractID(id.as_ptr(), ptr::null(), &T::IID, ga.void_ptr()) + .succeeded() + { ga.refptr() } else { None } } } /// Helper for calling `nsIServiceManager::GetServiceByContractID` on the global /// `nsIServiceManager`. /// /// This method is similar to `do_GetService` in C++. #[inline] pub fn get_service<T: XpCom>(id: &CStr) -> Option<RefPtr<T>> { unsafe { let mut ga = GetterAddrefs::<T>::new(); - if try_opt!(service_manager()).GetServiceByContractID( - id.as_ptr(), - &T::IID, - ga.void_ptr() - ).succeeded() { + if try_opt!(service_manager()) + .GetServiceByContractID(id.as_ptr(), &T::IID, ga.void_ptr()) + .succeeded() + { ga.refptr() } else { None } } } extern "C" {
--- a/xpcom/rust/xpcom/xpcom_macros/src/lib.rs +++ b/xpcom/rust/xpcom/xpcom_macros/src/lib.rs @@ -137,35 +137,38 @@ //! //! [`xpcom`]: ../xpcom/index.html //! [`nsIRunnable`]: ../xpcom/struct.nsIRunnable.html //! [`RefCounted`]: ../xpcom/struct.RefCounted.html //! [`RefPtr`]: ../xpcom/struct.RefPtr.html // NOTE: We use some really big quote! invocations, so we need a high recursion // limit. -#![recursion_limit="256"] +#![recursion_limit = "256"] #[macro_use] extern crate quote; extern crate syn; extern crate proc_macro; extern crate proc_macro2; #[macro_use] extern crate lazy_static; use proc_macro::TokenStream; +use proc_macro2::{Span, TokenStream as TokenStream2}; use quote::ToTokens; -use proc_macro2::{Span, TokenStream as TokenStream2}; -use syn::{parse, parse_quote, Attribute, Data, DataStruct, DeriveInput, Field, Fields, Ident, Lit, Meta, NestedMeta, Token, Type}; +use syn::{ + parse, parse_quote, Attribute, Data, DataStruct, DeriveInput, Field, Fields, Ident, Lit, Meta, + NestedMeta, Token, Type, +}; use syn::punctuated::Punctuated; use std::collections::{HashMap, HashSet}; use std::error::Error; /* These are the structs generated by the rust_macros.py script */ @@ -191,19 +194,21 @@ struct Interface { name: &'static str, base: Option<&'static str>, methods: Result<&'static [Method], &'static str>, } impl Interface { fn base(&self) -> Result<Option<&'static Interface>, Box<dyn Error>> { Ok(if let Some(base) = self.base { - Some(*IFACES.get(base).ok_or_else( - || format!("Base interface {} does not exist", base) - )?) + Some( + *IFACES + .get(base) + .ok_or_else(|| format!("Base interface {} does not exist", base))?, + ) } else { None }) } } lazy_static! { /// This item contains the information generated by the procedural macro in @@ -237,17 +242,20 @@ impl ToTokens for RefcntKind { RefcntKind::Atomic => quote!(xpcom::AtomicRefcnt).to_tokens(tokens), } } } /// Scans through the attributes on a struct, and extracts the type of the refcount to use. fn get_refcnt_kind(attrs: &[Attribute]) -> Result<RefcntKind, Box<dyn Error>> { for attr in attrs { - if let Meta::NameValue(syn::MetaNameValue{ref path, ref lit, .. }) = attr.parse_meta()? { + if let Meta::NameValue(syn::MetaNameValue { + ref path, ref lit, .. + }) = attr.parse_meta()? + { if !path.is_ident("refcnt") { continue; } let value = if let Lit::Str(ref s) = lit { s.value() } else { Err("Unexpected non-string value in #[refcnt]")? @@ -268,167 +276,192 @@ fn get_refcnt_kind(attrs: &[Attribute]) } /// Scan the attributes looking for an #[xpimplements] attribute. The identifier /// arguments passed to this attribute are the interfaces which the type wants to /// directly implement. fn get_bases(attrs: &[Attribute]) -> Result<Vec<&'static Interface>, Box<dyn Error>> { let mut inherits = Vec::new(); for attr in attrs { - if let Meta::List(syn::MetaList{ ref path, ref nested, .. }) = attr.parse_meta()? { + if let Meta::List(syn::MetaList { + ref path, + ref nested, + .. + }) = attr.parse_meta()? + { if !path.is_ident("xpimplements") { continue; } for item in nested.iter() { let iface = match *item { NestedMeta::Meta(syn::Meta::Path(ref iface)) => iface, _ => Err("Unexpected non-identifier in #[xpimplements(..)]")?, }; let ident = match iface.get_ident() { Some(ref iface) => iface.to_string(), _ => Err("Too many components in xpimplements path")?, }; if let Some(&iface) = IFACES.get(ident.as_str()) { inherits.push(iface); } else { - Err(format!("Unexpected invalid base interface `{}` in \ - #[xpimplements(..)]", ident))? + Err(format!( + "Unexpected invalid base interface `{}` in \ + #[xpimplements(..)]", + ident + ))? } } } } Ok(inherits) } /// Extract the fields list from the input struct. fn get_fields(di: &DeriveInput) -> Result<&Punctuated<Field, Token![,]>, Box<dyn Error>> { match di.data { Data::Struct(DataStruct { - fields: Fields::Named(ref named), .. + fields: Fields::Named(ref named), + .. }) => Ok(&named.named), _ => Err("The initializer struct must be a standard \ - named value struct definition".into()) + named value struct definition" + .into()), } } /// Takes the `Init*` struct in, and generates a `DeriveInput` for the "real" struct. -fn gen_real_struct(init: &DeriveInput, bases: &[&Interface], refcnt_ty: RefcntKind) -> Result<DeriveInput, Box<dyn Error>> { +fn gen_real_struct( + init: &DeriveInput, + bases: &[&Interface], + refcnt_ty: RefcntKind, +) -> Result<DeriveInput, Box<dyn Error>> { // Determine the name for the real struct based on the name of the // initializer struct's name. if !init.ident.to_string().starts_with("Init") { Err("The target struct's name must begin with Init")? } let name: Ident = Ident::new(&init.ident.to_string()[4..], Span::call_site()); let vis = &init.vis; let bases = bases.iter().map(|base| { let ident = Ident::new(&format!("__base_{}", base.name), Span::call_site()); let vtable = Ident::new(&format!("{}VTable", base.name), Span::call_site()); quote!(#ident : *const xpcom::interfaces::#vtable) - }); + }); let fields = get_fields(init)?; Ok(parse_quote! { - #[repr(C)] - #vis struct #name { - #(#bases,)* - __refcnt: #refcnt_ty, - #fields - } - }) + #[repr(C)] + #vis struct #name { + #(#bases,)* + __refcnt: #refcnt_ty, + #fields + } + }) } /// Generates the `extern "system"` methods which are actually included in the /// VTable for the given interface. /// /// These methods attempt to invoke the `recover_self` method to translate from /// the passed-in raw pointer to the actual `&self` value, and it is expected to /// be in scope. fn gen_vtable_methods(iface: &Interface) -> Result<TokenStream2, Box<dyn Error>> { let base_ty = Ident::new(iface.name, Span::call_site()); let base_methods = if let Some(base) = iface.base()? { gen_vtable_methods(base)? } else { - quote!{} + quote! {} }; - let methods = iface.methods - .map_err(|reason| format!("Interface {} cannot be implemented in rust \ - because {} is not supported yet", iface.name, reason))?; + let methods = iface.methods.map_err(|reason| { + format!( + "Interface {} cannot be implemented in rust \ + because {} is not supported yet", + iface.name, reason + ) + })?; let mut method_defs = Vec::new(); for method in methods { let name = Ident::new(method.name, Span::call_site()); let ret = syn::parse_str::<Type>(method.ret)?; let mut params = Vec::new(); let mut args = Vec::new(); for param in method.params { let name = Ident::new(param.name, Span::call_site()); let ty = syn::parse_str::<Type>(param.ty)?; - params.push(quote!{#name : #ty,}); - args.push(quote!{#name,}); + params.push(quote! {#name : #ty,}); + args.push(quote! {#name,}); } - method_defs.push(quote!{ + method_defs.push(quote! { unsafe extern "system" fn #name (this: *const #base_ty, #(#params)*) -> #ret { let lt = (); recover_self(this, <).#name(#(#args)*) } }); } - Ok(quote!{ + Ok(quote! { #base_methods #(#method_defs)* }) } /// Generates the VTable for a given base interface. This assumes that the /// implementations of each of the `extern "system"` methods are in scope. fn gen_inner_vtable(iface: &Interface) -> Result<TokenStream2, Box<dyn Error>> { let vtable_ty = Ident::new(&format!("{}VTable", iface.name), Span::call_site()); - let methods = iface.methods - .map_err(|reason| format!("Interface {} cannot be implemented in rust \ - because {} is not supported yet", iface.name, reason))?; + let methods = iface.methods.map_err(|reason| { + format!( + "Interface {} cannot be implemented in rust \ + because {} is not supported yet", + iface.name, reason + ) + })?; // Generate the vtable for the base interface. let base_vtable = if let Some(base) = iface.base()? { let vt = gen_inner_vtable(base)?; - quote!{__base: #vt,} + quote! {__base: #vt,} } else { - quote!{} + quote! {} }; // Include each of the method definitions for this interface. - let vtable_init = methods.into_iter().map(|method| { - let name = Ident::new(method.name, Span::call_site()); - quote!{ #name : #name , } - }).collect::<Vec<_>>(); + let vtable_init = methods + .into_iter() + .map(|method| { + let name = Ident::new(method.name, Span::call_site()); + quote! { #name : #name , } + }) + .collect::<Vec<_>>(); Ok(quote!(#vtable_ty { #base_vtable #(#vtable_init)* })) } fn gen_root_vtable(name: &Ident, base: &Interface) -> Result<TokenStream2, Box<dyn Error>> { let field = Ident::new(&format!("__base_{}", base.name), Span::call_site()); let vtable_ty = Ident::new(&format!("{}VTable", base.name), Span::call_site()); let methods = gen_vtable_methods(base)?; let value = gen_inner_vtable(base)?; // Define the `recover_self` method. This performs an offset calculation to // recover a pointer to the original struct from a pointer to the given // VTable field. - Ok(quote!{#field: { + Ok(quote! {#field: { // NOTE: The &'a () dummy lifetime parameter is useful as it easily // allows the caller to limit the lifetime of the returned parameter // to a local lifetime, preventing the calling of methods with // receivers like `&'static self`. #[inline] unsafe fn recover_self<'a, T>(this: *const T, _: &'a ()) -> &'a #name { // Calculate the offset of the field in our struct. // XXX: Should we use the fact that our type is #[repr(C)] to avoid @@ -458,30 +491,24 @@ fn gen_root_vtable(name: &Ident, base: & fn gen_casts( seen: &mut HashSet<&'static str>, iface: &Interface, name: &Ident, coerce_name: &Ident, vtable_field: &Ident, ) -> Result<(TokenStream2, TokenStream2), Box<dyn Error>> { if !seen.insert(iface.name) { - return Ok((quote!{}, quote!{})); + return Ok((quote! {}, quote! {})); } // Generate the cast implementations for the base interfaces. let (base_qi, base_coerce) = if let Some(base) = iface.base()? { - gen_casts( - seen, - base, - name, - coerce_name, - vtable_field, - )? + gen_casts(seen, base, name, coerce_name, vtable_field)? } else { - (quote!{}, quote!{}) + (quote! {}, quote! {}) }; // Add the if statment to QueryInterface for the base class. let base_name = Ident::new(iface.name, Span::call_site()); let qi = quote! { #base_qi if *uuid == #base_name::IID { @@ -518,25 +545,27 @@ fn gen_casts( /// The root xpcom procedural macro definition. fn xpcom(init: DeriveInput) -> Result<TokenStream2, Box<dyn Error>> { if !init.generics.params.is_empty() || !init.generics.where_clause.is_none() { return Err("Cannot #[derive(xpcom)] on a generic type, due to \ rust limitations. It is not possible to instantiate \ a static with a generic type parameter, meaning that \ generic types cannot have their VTables instantiated \ - correctly.".into()); + correctly." + .into()); } let bases = get_bases(&init.attrs)?; if bases.is_empty() { return Err("Types with #[derive(xpcom)] must implement at least one \ interface. Interfaces can be implemented by adding the \ #[xpimplements(nsIFoo, nsIBar)] attribute to the struct \ - declaration.".into()); + declaration." + .into()); } // Determine what reference count type to use, and generate the real struct. let refcnt_ty = get_refcnt_kind(&init.attrs)?; let real = gen_real_struct(&init, &bases, refcnt_ty)?; let name_init = &init.ident; let name = &real.ident; @@ -547,17 +576,17 @@ fn xpcom(init: DeriveInput) -> Result<To for base in &bases { vtables.push(gen_root_vtable(name, base)?); } // Generate the field initializers for the final struct, moving each field // out of the original __init struct. let inits = get_fields(&init)?.iter().map(|field| { let id = &field.ident; - quote!{ #id : __init.#id, } + quote! { #id : __init.#id, } }); let vis = &real.vis; // Generate the implementation for QueryInterface and Coerce. let mut seen = HashSet::new(); let mut qi_impl = Vec::new(); let mut coerce_impl = Vec::new(); @@ -682,10 +711,11 @@ fn xpcom(init: DeriveInput) -> Result<To } } }) } #[proc_macro_derive(xpcom, attributes(xpimplements, refcnt))] pub fn xpcom_internal(input: TokenStream) -> TokenStream { xpcom(parse(input).expect("Invalid derive input")) - .expect("#[derive(xpcom)] failed").into() + .expect("#[derive(xpcom)] failed") + .into() }