rust-for-linux.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/1] rust: fs: Add FileOffset instead "pub type Offset = bindings::loff_t;" and FileOffset test
@ 2025-10-22 12:25 Junzecao
  2025-10-22 13:07 ` Miguel Ojeda
  2025-10-22 14:33 ` Danilo Krummrich
  0 siblings, 2 replies; 3+ messages in thread
From: Junzecao @ 2025-10-22 12:25 UTC (permalink / raw)
  To: Miguel Ojeda, Alex Gaynor
  Cc: Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin,
	Andreas Hindborg, Alice Ryhl, Trevor Gross, Danilo Krummrich,
	rust-for-linux, Junzecao

Reference issue(https://github.com/Rust-for-Linux/linux/issues/1198).
Only addition and subtraction operations on FileOffset are retained

Signed-off-by: Junzecao <caojunze424@openatom.club>
Suggested-by: Miguel Ojeda <ojeda@kernel.org>
Link: https://lore.kernel.org/r/20251020222722.240473-1-dakr@kernel.org
---
 rust/kernel/fs/file.rs | 121 ++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 120 insertions(+), 1 deletion(-)

diff --git a/rust/kernel/fs/file.rs b/rust/kernel/fs/file.rs
index cd6987850332..8c292f9115ba 100644
--- a/rust/kernel/fs/file.rs
+++ b/rust/kernel/fs/file.rs
@@ -15,7 +15,7 @@
     sync::aref::{ARef, AlwaysRefCounted},
     types::{NotThreadSafe, Opaque},
 };
-use core::ptr;
+use core::{ops::Add, ops::Sub, ptr};
 
 /// Flags associated with a [`File`].
 pub mod flags {
@@ -100,6 +100,59 @@ pub mod flags {
     pub const O_RDWR: u32 = bindings::O_RDWR;
 }
 
+/// A file offset position.
+///
+/// This newtype wraps [`bindings::loff_t`] to provide type safety for file operations.
+/// It prevents accidental misuse by restricting operations to those that make sense
+/// for file offsets (addition, subtraction, comparison) while preventing meaningless
+/// operations like multiplication or division.
+///
+/// # Examples
+///
+/// ```
+/// use kernel::fs::file::FileOffset;
+///
+/// let start = FileOffset::zero();
+/// let position = FileOffset::new(1024);
+/// let new_pos = start + 512;        // Valid: move forward
+/// assert!(new_pos < position);      // Valid: comparison
+/// let raw: i64 = position.into();   // Convert for C interop
+/// ```
+#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
+pub struct FileOffset(bindings::loff_t);
+
+impl FileOffset {
+    /// Creates a new file offset from an i64 value.
+    pub const fn new(value: i64) -> Self {
+        Self(value)
+    }
+
+    /// Creates an offset representing the start of a file (offset 0).
+    pub const fn zero() -> Self {
+        Self(0)
+    }
+}
+
+impl Add<i64> for FileOffset {
+    type Output = Self;
+    fn add(self, rhs: i64) -> Self {
+        Self(self.0 + rhs)
+    }
+}
+
+impl Sub<i64> for FileOffset {
+    type Output = Self;
+    fn sub(self, rhs: i64) -> Self {
+        Self(self.0 - rhs)
+    }
+}
+
+impl From<FileOffset> for i64 {
+    fn from(offset: FileOffset) -> i64 {
+        offset.0
+    }
+}
+
 /// Wraps the kernel's `struct file`. Thread safe.
 ///
 /// This represents an open file rather than a file on a filesystem. Processes generally reference
@@ -466,3 +519,69 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.pad("EBADF")
     }
 }
+
+#[macros::kunit_tests(rust_file_offset_test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_file_offset_creation() {
+        let offset = FileOffset::new(1024);
+        let raw: i64 = offset.into();
+        assert_eq!(raw, 1024);
+    }
+
+    #[test]
+    fn test_file_offset_zero() {
+        let zero = FileOffset::zero();
+        let raw: i64 = zero.into();
+        assert_eq!(raw, 0);
+    }
+
+    #[test]
+    fn test_file_offset_addition() {
+        let start = FileOffset::new(100);
+        let result = start + 50;
+        let raw: i64 = result.into();
+        assert_eq!(raw, 150);
+    }
+
+    #[test]
+    fn test_file_offset_subtraction() {
+        let start = FileOffset::new(100);
+        let result = start - 30;
+        let raw: i64 = result.into();
+        assert_eq!(raw, 70);
+    }
+
+    #[test]
+    fn test_file_offset_comparison() {
+        let offset1 = FileOffset::new(100);
+        let offset2 = FileOffset::new(200);
+        let offset3 = FileOffset::new(100);
+
+        assert!(offset1 < offset2);
+        assert!(offset2 > offset1);
+        assert_eq!(offset1, offset3);
+        assert!(offset1 <= offset2);
+        assert!(offset2 >= offset1);
+    }
+
+    #[test]
+    fn test_file_offset_negative() {
+        let negative = FileOffset::new(-50);
+        let raw: i64 = negative.into();
+        assert_eq!(raw, -50);
+    }
+
+    #[test]
+    fn test_file_offset_large_values() {
+        let large = FileOffset::new(i64::MAX);
+        let raw: i64 = large.into();
+        assert_eq!(raw, i64::MAX);
+
+        let min = FileOffset::new(i64::MIN);
+        let raw_min: i64 = min.into();
+        assert_eq!(raw_min, i64::MIN);
+    }
+}
-- 
2.34.1

^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2025-10-22 14:33 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-10-22 12:25 [PATCH 1/1] rust: fs: Add FileOffset instead "pub type Offset = bindings::loff_t;" and FileOffset test Junzecao
2025-10-22 13:07 ` Miguel Ojeda
2025-10-22 14:33 ` Danilo Krummrich

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).