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

Feature request: Bitfield setter and getter #1475

Closed
ANOLASC opened this issue Feb 23, 2023 · 4 comments
Closed

Feature request: Bitfield setter and getter #1475

ANOLASC opened this issue Feb 23, 2023 · 4 comments
Labels
enhancement New feature or request

Comments

@ANOLASC
Copy link

ANOLASC commented Feb 23, 2023

Motivation

Structs like MEM_EXTENDED_PARAMETER which have bitfield member is hard to be accessed and modified.

Original definition

typedef struct MEM_EXTENDED_PARAMETER {
  struct {
    DWORD64 Type : MEM_EXTENDED_PARAMETER_TYPE_BITS;
    DWORD64 Reserved : 64 - MEM_EXTENDED_PARAMETER_TYPE_BITS;
  } DUMMYSTRUCTNAME;
  union {
    DWORD64 ULong64;
    PVOID   Pointer;
    SIZE_T  Size;
    HANDLE  Handle;
    DWORD   ULong;
  } DUMMYUNIONNAME;
} MEM_EXTENDED_PARAMETER, *PMEM_EXTENDED_PARAMETER;

Rust definition

pub struct MEM_EXTENDED_PARAMETER {
    pub Anonymous1: MEM_EXTENDED_PARAMETER_0,
    pub Anonymous2: MEM_EXTENDED_PARAMETER_1,
}

pub struct MEM_EXTENDED_PARAMETER_0 {
    pub _bitfield: u64,
}

Currently Rust does not support bitfields. It is cumbersome, clumsy and error-prone that when I try to pass a struct like MEM_EXTENDED_PARAMETER to VirtualAlloc.
I think provide interfaces like

pub fn set_type();
pub fn get_type();
pub fn set_reserved();
pub fn get_reserved();

would be easier to use this struct

Drawbacks

No response

Rationale and alternatives

No response

Additional context

No response

@ANOLASC ANOLASC added the enhancement New feature or request label Feb 23, 2023
@ANOLASC
Copy link
Author

ANOLASC commented Feb 23, 2023

I try to use the way that bindgen use to process bitfield.

patch is below

@ANOLASC
Copy link
Author

ANOLASC commented Feb 23, 2023

From d41d1bfe5fd4b9d3f57501adcbaa75cef032853f Mon Sep 17 00:00:00 2001
From: ANOLASC
Date: Thu, 23 Feb 2023 18:15:58 +0800
Subject: [PATCH] add bitfield support

---
 .../src/Windows/Win32/System/Memory/mod.rs    | 95 +++++++++++++++++++
 1 file changed, 95 insertions(+)

diff --git a/crates/libs/windows/src/Windows/Win32/System/Memory/mod.rs b/crates/libs/windows/src/Windows/Win32/System/Memory/mod.rs
index 1fd1f3858..a9224a803 100644
--- a/crates/libs/windows/src/Windows/Win32/System/Memory/mod.rs
+++ b/crates/libs/windows/src/Windows/Win32/System/Memory/mod.rs
@@ -2022,12 +2022,107 @@ impl ::core::default::Default for MEM_EXTENDED_PARAMETER {
         unsafe { ::core::mem::zeroed() }
     }
 }
+
+#[repr(C)]
+#[derive(Copy, Clone, Debug, Default)]
+pub struct BitfieldUnit<Storage, Align> {
+    storage: Storage,
+    align: [Align; 0],
+}
+
+impl<Storage, Align> BitfieldUnit<Storage, Align> {
+    #[inline]
+    pub const fn new(storage: Storage) -> Self {
+        Self { storage, align: [] }
+    }
+}
+
+impl<Storage, Align> BitfieldUnit<Storage, Align>
+where
+    Storage: AsRef<[u8]> + AsMut<[u8]>,
+{
+    #[inline]
+    pub fn get_bit(&self, index: usize) -> bool {
+        debug_assert!(index / 8 < self.storage.as_ref().len());
+        let byte_index = index / 8;
+        let byte = self.storage.as_ref()[byte_index];
+        let bit_index = if cfg!(target_endian = "big") { 7 - (index % 8) } else { index % 8 };
+        let mask = 1 << bit_index;
+        byte & mask == mask
+    }
+
+    #[inline]
+    pub fn set_bit(&mut self, index: usize, val: bool) {
+        debug_assert!(index / 8 < self.storage.as_ref().len());
+        let byte_index = index / 8;
+        let byte = &mut self.storage.as_mut()[byte_index];
+        let bit_index = if cfg!(target_endian = "big") { 7 - (index % 8) } else { index % 8 };
+        let mask = 1 << bit_index;
+        if val {
+            *byte |= mask;
+        } else {
+            *byte &= !mask;
+        }
+    }
+
+    #[inline]
+    pub fn get(&self, bit_offset: usize, bit_width: u8) -> u64 {
+        debug_assert!(bit_width <= 64);
+        debug_assert!(bit_offset / 8 <= self.storage.as_ref().len());
+        debug_assert!((bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len());
+
+        let mut val = 0;
+        for i in 0..(bit_width as usize) {
+            if self.get_bit(i + bit_offset) {
+                let index = if cfg!(target_endian = "big") { bit_width as usize - 1 - i } else { i };
+                val |= 1 << index;
+            }
+        }
+        val
+    }
+
+    #[inline]
+    pub fn set(&mut self, bit_offset: usize, bit_width: u8, val: u64) {
+        debug_assert!(bit_width <= 64);
+        debug_assert!(bit_offset / 8 <= self.storage.as_ref().len());
+        debug_assert!((bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len());
+
+        for i in 0..(bit_width as usize) {
+            let mask = 1 << i;
+            let val_bit_is_set = val & mask == mask;
+            let index = if cfg!(target_endian = "big") { bit_width as usize - 1 - i } else { i };
+            self.set_bit(index + bit_offset, val_bit_is_set);
+        }
+    }
+}
+
 #[repr(C)]
 #[doc = "*Required features: `\"Win32_System_Memory\"`, `\"Win32_Foundation\"`*"]
 #[cfg(feature = "Win32_Foundation")]
 pub struct MEM_EXTENDED_PARAMETER_0 {
     pub _bitfield: u64,
+    pub _bitfield_1: BitfieldUnit<[u8; 8usize], u64>,
+}
+
+impl MEM_EXTENDED_PARAMETER_0 {
+    #[inline]
+    pub fn get_type(&self) -> u64 {
+        self._bitfield_1.get(0usize, 8u8)
+    }
+    #[inline]
+    pub fn set_type(&mut self, val: u64) {
+        self._bitfield_1.set(0usize, 8u8, val)
+    }
+    #[inline]
+    pub fn get_reserved(&self) -> u64 {
+        self._bitfield_1.get(8usize, 56u8)
+    }
+    #[inline]
+    pub fn set_reserved(&mut self, val: u64) {
+        self._bitfield_1.set(8usize, 56u8, val)
+    }
 }
+
 #[cfg(feature = "Win32_Foundation")]
 impl ::core::marker::Copy for MEM_EXTENDED_PARAMETER_0 {}
 #[cfg(feature = "Win32_Foundation")]
-- 
2.29.2.windows.3

@kennykerr
Copy link
Contributor

I don't think there's currently any metadata describing this. I'm not sure it's worth the complexity, but I'll pass it on for their consideration.

@kennykerr kennykerr transferred this issue from microsoft/windows-rs Feb 23, 2023
@mikebattista
Copy link
Contributor

I believe this is a duplicate of #1392.

@mikebattista mikebattista closed this as not planned Won't fix, can't repro, duplicate, stale Feb 23, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants