diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:22:09 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:22:09 +0000 |
commit | 43a97878ce14b72f0981164f87f2e35e14151312 (patch) | |
tree | 620249daf56c0258faa40cbdcf9cfba06de2a846 /third_party/rust/guid_win/src/lib.rs | |
parent | Initial commit. (diff) | |
download | firefox-upstream.tar.xz firefox-upstream.zip |
Adding upstream version 110.0.1.upstream/110.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/guid_win/src/lib.rs')
-rw-r--r-- | third_party/rust/guid_win/src/lib.rs | 189 |
1 files changed, 189 insertions, 0 deletions
diff --git a/third_party/rust/guid_win/src/lib.rs b/third_party/rust/guid_win/src/lib.rs new file mode 100644 index 0000000000..157df8e57a --- /dev/null +++ b/third_party/rust/guid_win/src/lib.rs @@ -0,0 +1,189 @@ +// Licensed under the Apache License, Version 2.0 +// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. + +//! Windows GUID/CLSID/IID string and binary serialization +//! +//! [`Guid`](struct.Guid.html) transparently wraps +//! [`GUID`](https://msdn.microsoft.com/en-us/library/windows/desktop/aa373931(v=vs.85).aspx). +//! +//! Implements `Display` and `FromStr` string conversion, also `Hash` and `Eq`. +//! +//! Curly braces (`{}`) are optional for `FromStr`. +//! +//! # serde # +//! +//! Use the `guid_serde` feature to derive `Serialize` and `Deserialize`, you can then +//! derive them for structs containing `GUID` like so: +//! +//! ``` +//! # fn main() {} +//! # +//! # #[cfg(feature = "guid_serde")] +//! # extern crate serde_derive; +//! # extern crate winapi; +//! # +//! # #[cfg(feature = "guid_serde")] +//! # mod test { +//! use guid_win::GUIDSerde; +//! use serde_derive::{Deserialize, Serialize}; +//! use winapi::shared::guiddef::GUID; +//! +//! #[derive(Serialize, Deserialize)] +//! struct SerdeTest { +//! #[serde(with = "GUIDSerde")] +//! guid: GUID, +//! } +//! # } +//! ``` + +extern crate comedy; +#[cfg(feature = "guid_serde")] +extern crate serde; +#[cfg(feature = "guid_serde")] +extern crate serde_derive; +extern crate winapi; + +use std::ffi::{OsStr, OsString}; +use std::fmt::{Debug, Display, Error, Formatter, Result}; +use std::hash::{Hash, Hasher}; +use std::mem; +use std::os::windows::ffi::{OsStrExt, OsStringExt}; +use std::result; +use std::str::FromStr; + +use comedy::check_succeeded; + +use winapi::ctypes; +use winapi::shared::guiddef::GUID; +use winapi::um::combaseapi::{CLSIDFromString, StringFromGUID2}; + +#[cfg(feature = "guid_serde")] +use serde_derive::{Deserialize, Serialize}; + +const GUID_STRING_CHARACTERS: usize = 38; + +#[cfg(feature = "guid_serde")] +#[allow(non_snake_case)] +#[derive(Serialize, Deserialize)] +#[serde(remote = "GUID")] +pub struct GUIDSerde { + Data1: ctypes::c_ulong, + Data2: ctypes::c_ushort, + Data3: ctypes::c_ushort, + Data4: [ctypes::c_uchar; 8], +} + +/// Wraps `GUID` +#[derive(Clone)] +#[cfg_attr(feature = "guid_serde", derive(Serialize, Deserialize))] +#[repr(transparent)] +pub struct Guid(#[cfg_attr(feature = "guid_serde", serde(with = "GUIDSerde"))] pub GUID); + +impl PartialEq for Guid { + fn eq(&self, other: &Guid) -> bool { + self.0.Data1 == other.0.Data1 + && self.0.Data2 == other.0.Data2 + && self.0.Data3 == other.0.Data3 + && self.0.Data4 == other.0.Data4 + } +} + +impl Eq for Guid {} + +impl Hash for Guid { + fn hash<H: Hasher>(&self, state: &mut H) { + self.0.Data1.hash(state); + self.0.Data2.hash(state); + self.0.Data3.hash(state); + self.0.Data4.hash(state); + } +} + +impl Debug for Guid { + fn fmt(&self, f: &mut Formatter) -> Result { + write!(f, "{:?}", unsafe { + &mem::transmute::<Guid, [u8; mem::size_of::<Guid>()]>(self.clone()) + }) + } +} + +/// Output a string via `StringFromGUID2()` +impl Display for Guid { + fn fmt(&self, f: &mut Formatter) -> Result { + let mut s: [u16; GUID_STRING_CHARACTERS + 1] = unsafe { mem::uninitialized() }; + + let len = unsafe { + StringFromGUID2( + &(*self).0 as *const _ as *mut _, + s.as_mut_ptr(), + s.len() as ctypes::c_int, + ) + }; + + if len <= 0 { + return Err(Error); + } + // len is number of characters, including the null terminator + + let s = &s[..len as usize - 1]; + // TODO: no reason to expect this to fail, maybe just unwrap() + if let Ok(s) = OsString::from_wide(&s).into_string() { + f.write_str(&s) + } else { + Err(Error) + } + } +} + +/// Read from a string via `CLSIDFromString()` +/// +/// Braces (`{}`) are added if missing. +impl FromStr for Guid { + type Err = comedy::error::HResult; + + fn from_str(s: &str) -> result::Result<Self, Self::Err> { + let mut guid = unsafe { mem::uninitialized() }; + + let braced; + let s = if s.starts_with('{') { + s + } else { + braced = format!("{{{}}}", s); + braced.as_str() + }; + let s: Vec<_> = OsStr::new(s).encode_wide().chain(Some(0)).collect(); + + unsafe { check_succeeded!(CLSIDFromString(s.as_ptr(), &mut guid)) }?; + + Ok(Guid(guid)) + } +} + +#[cfg(test)] +mod test { + use super::Guid; + use std::str::FromStr; + + #[test] + fn without_braces() { + let uuid = "F1BD1079-9F01-4BDC-8036-F09B70095066"; + let guid = Guid::from_str(uuid).unwrap(); + assert_eq!(format!("{}", guid), format!("{{{}}}", uuid)); + } + + #[test] + fn with_braces() { + let uuid = "{F1BD1079-9F01-4BDC-8036-F09B70095066}"; + let guid = Guid::from_str(uuid).unwrap(); + assert_eq!(format!("{}", guid), uuid); + } + + #[test] + fn format_error() { + let uuid = "foo"; + Guid::from_str(uuid).unwrap_err(); + } +} |