Skip to content

Instantly share code, notes, and snippets.

@matthewdowney
Created March 20, 2025 18:58
Show Gist options
  • Select an option

  • Save matthewdowney/1114c0ae679a14e4f6b98911606953bf to your computer and use it in GitHub Desktop.

Select an option

Save matthewdowney/1114c0ae679a14e4f6b98911606953bf to your computer and use it in GitHub Desktop.

Revisions

  1. matthewdowney created this gist Mar 20, 2025.
    120 changes: 120 additions & 0 deletions mmap_stdin.rs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,120 @@
    // Conditional extern definitions for Linux/Android
    #[cfg(any(target_os = "linux", target_os = "android"))]
    #[link(name = "c")]
    unsafe extern "C" {
    fn mmap(addr: *mut u8, len: usize, prot: i32, flags: i32, fd: i32, offset: i64) -> *mut u8;
    fn __errno_location() -> *const i32;
    fn lseek(fd: i32, offset: i64, whence: i32) -> i64;
    fn open(path: *const u8, oflag: i32) -> i32;
    }

    // Conditional extern definitions for macOS/iOS
    #[cfg(any(target_os = "macos", target_os = "ios"))]
    #[link(name = "c")]
    unsafe extern "C" {
    fn mmap(addr: *mut u8, len: usize, prot: i32, flags: i32, fd: i32, offset: i64) -> *mut u8;
    // macOS uses __error instead of __errno_location
    fn __error() -> *mut i32;
    fn lseek(fd: i32, offset: i64, whence: i32) -> i64;
    fn open(path: *const u8, oflag: i32) -> i32;
    }

    /// Helper function to get errno in a platform-independent way.
    #[inline]
    unsafe fn get_errno() -> i32 {
    #[cfg(any(target_os = "linux", target_os = "android"))]
    {
    unsafe { *__errno_location() }
    }
    #[cfg(any(target_os = "macos", target_os = "ios"))]
    {
    unsafe { *__error() }
    }
    }

    /// Define MAP_POPULATE conditionally:
    #[cfg(any(target_os = "linux", target_os = "android"))]
    const MAP_POPULATE: i32 = 0x08000;
    #[cfg(any(target_os = "macos", target_os = "ios"))]
    const MAP_POPULATE: i32 = 0; // MAP_POPULATE not supported on macOS

    /// Map the file descriptor for standard input.
    #[allow(dead_code)]
    pub unsafe fn mmap_stdin<'a>() -> &'a [u8] {
    unsafe { mmap_fd(0) }
    }

    /// Map the file at the given path.
    #[allow(dead_code)]
    pub unsafe fn mmap_path<'a>(path: &str) -> &'a [u8] {
    let cpath = std::ffi::CString::new(path).expect("CString::new failed");
    unsafe {
    let fd = open(cpath.as_ptr() as *const u8, 0);
    if fd == -1 {
    panic!("open failed, errno {}", get_errno());
    }
    mmap_fd(fd)
    }
    }

    /// Helper function that performs the mmap operation on a given file descriptor.
    pub unsafe fn mmap_fd<'a>(fd: i32) -> &'a [u8] {
    // SEEK_END is usually defined as 2
    let seek_end = 2;
    unsafe {
    let size = lseek(fd, 0, seek_end);
    if size == -1 {
    panic!("lseek failed, errno {}", get_errno());
    }
    let prot_read = 0x01; // PROT_READ
    let map_private = 0x02; // MAP_PRIVATE
    let ptr = mmap(
    std::ptr::null_mut(),
    size as usize,
    prot_read,
    map_private | MAP_POPULATE,
    fd,
    0,
    );
    if ptr as isize == -1 {
    panic!("mmap failed, errno {}", get_errno());
    }
    std::slice::from_raw_parts(ptr, size as usize)
    }
    }

    #[cfg(test)]
    mod tests {
    use super::*;
    use std::io::Write;
    use tempfile::NamedTempFile;

    #[test]
    fn test_mmap_path_success() {
    // Create a temporary file with known content.
    let mut tmpfile = NamedTempFile::new().expect("Failed to create temp file");
    let content = b"Hello, mmap!";
    tmpfile
    .write_all(content)
    .expect("Failed to write to temp file");

    // Flush and get the file path.
    tmpfile.flush().expect("Failed to flush file");
    let path = tmpfile.path().to_str().expect("Path is not valid UTF-8");

    // Map the file using your function.
    let mapped = unsafe { mmap_path(path) };

    // Verify that the mapped content matches.
    assert_eq!(mapped, content);
    }

    #[test]
    #[should_panic(expected = "open failed")]
    fn test_mmap_path_nonexistent() {
    // Attempt to map a file that doesn't exist.
    unsafe {
    mmap_path("nonexistent_file.txt");
    }
    }
    }