rust: Add element_offset() and subslice_range() functions.
authorBen Pfaff <blp@cs.stanford.edu>
Fri, 18 Jul 2025 01:12:26 +0000 (18:12 -0700)
committerBen Pfaff <blp@cs.stanford.edu>
Fri, 18 Jul 2025 01:12:26 +0000 (18:12 -0700)
rust/pspp/src/lib.rs

index ee567c5d8101f4e2250b5a44e5b02d3b3e860ac3..9ae4bdfcd96b2f4320ed1e0b5a57d3451c3836bd 100644 (file)
@@ -14,6 +14,8 @@
 // You should have received a copy of the GNU General Public License along with
 // this program.  If not, see <http://www.gnu.org/licenses/>.
 
+use std::ops::Range;
+
 pub mod calendar;
 pub mod command;
 pub mod crypto;
@@ -33,3 +35,56 @@ pub mod output;
 pub mod prompt;
 pub mod settings;
 pub mod sys;
+
+/// This is [slice::element_offset] copied out from the standard library so that
+/// we can use it while it is still experimental.
+#[allow(dead_code)]
+pub(crate) fn element_offset<T>(slice: &[T], element: &T) -> Option<usize> {
+    if size_of::<T>() == 0 {
+        panic!("elements are zero-sized");
+    }
+
+    let slice_start = slice.as_ptr().addr();
+    let elem_start = std::ptr::from_ref(element).addr();
+
+    let byte_offset = elem_start.wrapping_sub(slice_start);
+
+    if byte_offset % size_of::<T>() != 0 {
+        return None;
+    }
+
+    let offset = byte_offset / size_of::<T>();
+
+    if offset < slice.len() {
+        Some(offset)
+    } else {
+        None
+    }
+}
+
+/// This is [slice::subslice_range] copied out from the standard library so that
+/// we can use it while it is still experimental.
+#[allow(dead_code)]
+pub(crate) fn subslice_range<T>(slice: &[T], subslice: &[T]) -> Option<Range<usize>> {
+    if size_of::<T>() == 0 {
+        panic!("elements are zero-sized");
+    }
+
+    let slice_start = slice.as_ptr().addr();
+    let subslice_start = subslice.as_ptr().addr();
+
+    let byte_start = subslice_start.wrapping_sub(slice_start);
+
+    if byte_start % size_of::<T>() != 0 {
+        return None;
+    }
+
+    let start = byte_start / size_of::<T>();
+    let end = start.wrapping_add(subslice.len());
+
+    if start <= slice.len() && end <= slice.len() {
+        Some(start..end)
+    } else {
+        None
+    }
+}