Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace From<&str> for GUID with TryFrom<&str> #3193

Merged
merged 4 commits into from
Aug 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 57 additions & 51 deletions crates/libs/core/src/guid.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
#![allow(clippy::many_single_char_names)]

use super::*;

/// A globally unique identifier ([GUID](https://docs.microsoft.com/en-us/windows/win32/api/guiddef/ns-guiddef-guid))
Expand Down Expand Up @@ -120,37 +118,30 @@ impl core::fmt::Debug for GUID {
}
}

impl From<&str> for GUID {
fn from(value: &str) -> Self {
assert!(value.len() == 36, "Invalid GUID string");
let mut bytes = value.bytes();

let a = ((bytes.next_u32() * 16 + bytes.next_u32()) << 24)
+ ((bytes.next_u32() * 16 + bytes.next_u32()) << 16)
+ ((bytes.next_u32() * 16 + bytes.next_u32()) << 8)
+ bytes.next_u32() * 16
+ bytes.next_u32();
assert!(bytes.next().unwrap() == b'-', "Invalid GUID string");
let b = ((bytes.next_u16() * 16 + (bytes.next_u16())) << 8)
+ bytes.next_u16() * 16
+ bytes.next_u16();
assert!(bytes.next().unwrap() == b'-', "Invalid GUID string");
let c = ((bytes.next_u16() * 16 + bytes.next_u16()) << 8)
+ bytes.next_u16() * 16
+ bytes.next_u16();
assert!(bytes.next().unwrap() == b'-', "Invalid GUID string");
let d = bytes.next_u8() * 16 + bytes.next_u8();
let e = bytes.next_u8() * 16 + bytes.next_u8();
assert!(bytes.next().unwrap() == b'-', "Invalid GUID string");

let f = bytes.next_u8() * 16 + bytes.next_u8();
let g = bytes.next_u8() * 16 + bytes.next_u8();
let h = bytes.next_u8() * 16 + bytes.next_u8();
let i = bytes.next_u8() * 16 + bytes.next_u8();
let j = bytes.next_u8() * 16 + bytes.next_u8();
let k = bytes.next_u8() * 16 + bytes.next_u8();

Self::from_values(a, b, c, [d, e, f, g, h, i, j, k])
impl TryFrom<&str> for GUID {
type Error = Error;

fn try_from(from: &str) -> Result<Self> {
if from.len() != 36 {
return Err(invalid_guid());
}

let bytes = &mut from.bytes();
let mut guid = Self::zeroed();

guid.data1 = try_u32(bytes, true)?;
guid.data2 = try_u16(bytes, true)?;
guid.data3 = try_u16(bytes, true)?;
guid.data4[0] = try_u8(bytes, false)?;
guid.data4[1] = try_u8(bytes, true)?;
guid.data4[2] = try_u8(bytes, false)?;
guid.data4[3] = try_u8(bytes, false)?;
guid.data4[4] = try_u8(bytes, false)?;
guid.data4[5] = try_u8(bytes, false)?;
guid.data4[6] = try_u8(bytes, false)?;
guid.data4[7] = try_u8(bytes, false)?;

Ok(guid)
}
}

Expand All @@ -166,28 +157,43 @@ impl From<GUID> for u128 {
}
}

trait HexReader {
fn next_u8(&mut self) -> u8;
fn next_u16(&mut self) -> u16;
fn next_u32(&mut self) -> u32;
fn invalid_guid() -> Error {
Error::from_hresult(imp::E_INVALIDARG)
}

impl HexReader for core::str::Bytes<'_> {
fn next_u8(&mut self) -> u8 {
let value = self.next().unwrap();
match value {
b'0'..=b'9' => value - b'0',
b'A'..=b'F' => 10 + value - b'A',
b'a'..=b'f' => 10 + value - b'a',
_ => panic!(),
}
}
fn try_u32(bytes: &mut core::str::Bytes<'_>, delimiter: bool) -> Result<u32> {
next(bytes, 8, delimiter).ok_or_else(invalid_guid)
}

fn next_u16(&mut self) -> u16 {
self.next_u8().into()
fn try_u16(bytes: &mut core::str::Bytes<'_>, delimiter: bool) -> Result<u16> {
next(bytes, 4, delimiter)
.map(|value| value as u16)
.ok_or_else(invalid_guid)
}

fn try_u8(bytes: &mut core::str::Bytes<'_>, delimiter: bool) -> Result<u8> {
next(bytes, 2, delimiter)
.map(|value| value as u8)
.ok_or_else(invalid_guid)
}

fn next(bytes: &mut core::str::Bytes<'_>, len: usize, delimiter: bool) -> Option<u32> {
let mut value: u32 = 0;

for _ in 0..len {
let digit = bytes.next()?;

match digit {
b'0'..=b'9' => value = (value << 4) + (digit - b'0') as u32,
b'A'..=b'F' => value = (value << 4) + (digit - b'A' + 10) as u32,
b'a'..=b'f' => value = (value << 4) + (digit - b'a' + 10) as u32,
_ => return None,
}
}

fn next_u32(&mut self) -> u32 {
self.next_u8().into()
if delimiter && bytes.next() != Some(b'-') {
None
} else {
Some(value)
}
}
1 change: 1 addition & 0 deletions crates/libs/core/src/imp/com_bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ impl core::fmt::Debug for AgileReferenceOptions {
}
pub const CO_E_NOTINITIALIZED: windows_core::HRESULT = windows_core::HRESULT(0x800401F0_u32 as _);
pub const E_BOUNDS: windows_core::HRESULT = windows_core::HRESULT(0x8000000B_u32 as _);
pub const E_INVALIDARG: windows_core::HRESULT = windows_core::HRESULT(0x80070057_u32 as _);
pub const E_NOINTERFACE: windows_core::HRESULT = windows_core::HRESULT(0x80004002_u32 as _);
pub const E_OUTOFMEMORY: windows_core::HRESULT = windows_core::HRESULT(0x8007000E_u32 as _);
pub const E_POINTER: windows_core::HRESULT = windows_core::HRESULT(0x80004003_u32 as _);
Expand Down
2 changes: 0 additions & 2 deletions crates/libs/core/src/imp/sha1.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
#![allow(clippy::many_single_char_names)]

pub const fn sha1(data: &ConstBuffer) -> Digest {
let state: [u32; 5] = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0];
let len: u64 = 0;
Expand Down
50 changes: 47 additions & 3 deletions crates/tests/core/tests/guid.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use windows::core::GUID;
use windows::{core::*, Win32::Foundation::E_INVALIDARG};

#[test]
fn test_new() {
Expand All @@ -9,7 +9,7 @@ fn test_new() {

#[test]
fn from_u128() {
let a: GUID = "1FD63FEF-C0D2-42FE-823A-53A4052B8C8F".into();
let a: GUID = "1FD63FEF-C0D2-42FE-823A-53A4052B8C8F".try_into().unwrap();
let b = GUID::from_values(
0x1fd63fef,
0xc0d2,
Expand All @@ -25,7 +25,51 @@ fn from_u128() {
#[test]
fn to_u128() {
let num: u128 = 0x1fd63fef_c0d2_42fe_823a_53a4052b8c8f;
let guid: GUID = "1FD63FEF-C0D2-42FE-823A-53A4052B8C8F".into();
let guid: GUID = "1FD63FEF-C0D2-42FE-823A-53A4052B8C8F".try_into().unwrap();

assert_eq!(u128::from(guid), num); // From<GUID>
}

#[test]
fn parsing() {
assert_eq!(
GUID::zeroed(),
"00000000-0000-0000-0000-000000000000".try_into().unwrap()
);

// Validate invalid length and expected error information.
let e = GUID::try_from("wrong length").unwrap_err();
assert_eq!(e.code(), E_INVALIDARG);
assert!(e.as_ptr().is_null());

// Validate delimiter
GUID::try_from("00000000?0000-0000-0000-000000000000").unwrap_err();
GUID::try_from("00000000-0000?0000-0000-000000000000").unwrap_err();
GUID::try_from("00000000-0000-0000?0000-000000000000").unwrap_err();
GUID::try_from("00000000-0000-0000-0000?000000000000").unwrap_err();

// Validate invalid digits
GUID::try_from("z0000000-0000-0000-0000-000000000000").unwrap_err();
GUID::try_from("00000000-z000-0000-0000-000000000000").unwrap_err();
GUID::try_from("00000000-0000-z000-0000-000000000000").unwrap_err();
GUID::try_from("00000000-0000-0000-z000-000000000000").unwrap_err();
GUID::try_from("00000000-0000-0000-0000-z00000000000").unwrap_err();

// Validate case insensitivity
let value = GUID::from_u128(0x1fd63fef_c0d2_42fe_823a_53a4052b8c8f);
assert_eq!(
value,
"1FD63FEF-C0D2-42FE-823A-53A4052B8C8F".try_into().unwrap()
);
assert_eq!(
value,
"1fd63fef-c0d2-42fe-823a-53a4052b8c8f".try_into().unwrap()
);
}

#[test]
fn debug() {
let value = GUID::from_u128(0x1fd63fef_c0d2_42fe_823a_53a4052b8c8f);

assert_eq!(format!("{value:?}"), "1FD63FEF-C0D2-42FE-823A-53A4052B8C8F");
}
6 changes: 3 additions & 3 deletions crates/tests/interface/tests/com.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ struct PersistState {

impl ICustomPersist_Impl for Persist_Impl {
unsafe fn GetClassID(&self, clsid: *mut GUID) -> HRESULT {
*clsid = "117fb826-2155-483a-b50d-bc99a2c7cca3".into();
*clsid = "117fb826-2155-483a-b50d-bc99a2c7cca3".try_into().unwrap();
S_OK
}
}
Expand Down Expand Up @@ -136,7 +136,7 @@ fn test_custom_interface() -> windows::core::Result<()> {
let p: IPersistMemory = p.cast()?;
assert_eq!(
p.GetClassID()?,
"117fb826-2155-483a-b50d-bc99a2c7cca3".into()
"117fb826-2155-483a-b50d-bc99a2c7cca3".try_into()?,
);
assert_eq!(p.GetSizeMax()?, 10);
assert_eq!(p.IsDirty(), S_FALSE);
Expand Down Expand Up @@ -165,7 +165,7 @@ fn test_custom_interface() -> windows::core::Result<()> {
let p: ICustomPersist = p.cast()?;
let mut b = GUID::default();
p.GetClassID(&mut b).ok()?;
assert_eq!(b, "117fb826-2155-483a-b50d-bc99a2c7cca3".into());
assert_eq!(b, "117fb826-2155-483a-b50d-bc99a2c7cca3".try_into()?);

Ok(())
}
Expand Down
4 changes: 2 additions & 2 deletions crates/tests/interface/tests/com_from_existing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ struct Test;

impl IPersist_Impl for Test_Impl {
fn GetClassID(&self) -> Result<GUID> {
Ok("CEE1D356-0860-4262-90D4-C77423F0E352".into())
"CEE1D356-0860-4262-90D4-C77423F0E352".try_into()
}
}

Expand All @@ -30,7 +30,7 @@ fn test() -> Result<()> {
let p: IPersist = Test.into();
assert_eq!(
p.GetClassID()?,
"CEE1D356-0860-4262-90D4-C77423F0E352".into()
"CEE1D356-0860-4262-90D4-C77423F0E352".try_into()?
);

let m: ITestPersistMemory = p.cast()?;
Expand Down
4 changes: 2 additions & 2 deletions crates/tests/interface/tests/no_use.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ struct Test;

impl windows::Win32::System::Com::IPersist_Impl for Test_Impl {
fn GetClassID(&self) -> windows::core::Result<windows::core::GUID> {
Ok("CEE1D356-0860-4262-90D4-C77423F0E352".into())
"CEE1D356-0860-4262-90D4-C77423F0E352".try_into()
}
}

Expand All @@ -28,7 +28,7 @@ fn test() -> windows::core::Result<()> {
let p: windows::Win32::System::Com::IPersist = Test.into();
assert_eq!(
p.GetClassID()?,
"CEE1D356-0860-4262-90D4-C77423F0E352".into()
"CEE1D356-0860-4262-90D4-C77423F0E352".try_into()?
);

let m: ITestPersistMemory = windows_core::Interface::cast(&p)?;
Expand Down
5 changes: 4 additions & 1 deletion crates/tests/structs/tests/propertykey.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ use windows::Win32::Devices::Properties::DEVPKEY_Device_BiosDeviceName;

#[test]
fn test_debug_impl() {
assert!(DEVPKEY_Device_BiosDeviceName.fmtid == "540B947E-8B40-45BC-A8A2-6A0B894CBDA2".into());
assert!(
DEVPKEY_Device_BiosDeviceName.fmtid
== "540B947E-8B40-45BC-A8A2-6A0B894CBDA2".try_into().unwrap()
);
assert!(DEVPKEY_Device_BiosDeviceName.pid == 10);
}
4 changes: 2 additions & 2 deletions crates/tests/win32/tests/win32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ fn constant() {
assert!(WM_KEYUP == 257u32);
assert!(D3D12_DEFAULT_BLEND_FACTOR_ALPHA == 1f32);
assert!(UIA_ScrollPatternNoScroll == -1f64);
assert!(CLSID_D2D1Shadow == GUID::from("C67EA361-1863-4e69-89DB-695D3E9A5B6B"));
assert!(CLSID_D2D1Shadow == GUID::try_from("C67EA361-1863-4e69-89DB-695D3E9A5B6B").unwrap());

let b: PCSTR = D3DCOMPILER_DLL_A;
let c: PCWSTR = D3DCOMPILER_DLL_W;
Expand Down Expand Up @@ -264,5 +264,5 @@ fn empty_struct() {
assert!(ldap.0 == 123);
assert!(core::mem::size_of::<PLDAPSearch>() == core::mem::size_of::<usize>());

assert!(UIAnimationManager == GUID::from("4C1FC63A-695C-47E8-A339-1A194BE3D0B8"));
assert!(UIAnimationManager == GUID::try_from("4C1FC63A-695C-47E8-A339-1A194BE3D0B8").unwrap());
}
4 changes: 2 additions & 2 deletions crates/tests/winrt/tests/delegates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ fn non_generic() -> windows::core::Result<()> {

assert_eq!(
Handler::IID,
windows::core::GUID::from("A4ED5C81-76C9-40BD-8BE6-B1D90FB20AE7")
windows::core::GUID::try_from("A4ED5C81-76C9-40BD-8BE6-B1D90FB20AE7")?
);

let (tx, rx) = std::sync::mpsc::channel();
Expand All @@ -37,7 +37,7 @@ fn generic() -> windows::core::Result<()> {

assert_eq!(
Handler::IID,
windows::core::GUID::from("DAE18EA9-FCF3-5ACF-BCDD-8C354CBA6D23")
windows::core::GUID::try_from("DAE18EA9-FCF3-5ACF-BCDD-8C354CBA6D23")?
);

let uri = Uri::CreateUri(&windows::core::HSTRING::from("http://kennykerr.ca"))?;
Expand Down
Loading