jetro-core 0.5.10

jetro-core: parser, compiler, and VM for the Jetro JSON query language
Documentation
use std::fs::File;
use std::io;
use std::path::Path;

#[cfg(unix)]
use std::os::fd::AsRawFd;
#[cfg(unix)]
use std::os::raw::{c_int, c_void};
#[cfg(unix)]
use std::ptr::NonNull;

pub(super) struct MappedBytes {
    inner: MappedBytesInner,
}

enum MappedBytesInner {
    #[cfg(unix)]
    Mmap(UnixMmap),
    Owned(Vec<u8>),
}

impl MappedBytes {
    pub(super) fn open(path: &Path) -> io::Result<Self> {
        let file = File::open(path)?;
        let len = file.metadata()?.len() as usize;
        if len == 0 {
            return Ok(Self {
                inner: MappedBytesInner::Owned(Vec::new()),
            });
        }

        #[cfg(unix)]
        {
            if let Ok(map) = UnixMmap::map(&file, len) {
                return Ok(Self {
                    inner: MappedBytesInner::Mmap(map),
                });
            }
        }

        let bytes = std::fs::read(path)?;
        Ok(Self {
            inner: MappedBytesInner::Owned(bytes),
        })
    }

    pub(super) fn as_slice(&self) -> &[u8] {
        match &self.inner {
            #[cfg(unix)]
            MappedBytesInner::Mmap(map) => map.as_slice(),
            MappedBytesInner::Owned(bytes) => bytes,
        }
    }
}

#[cfg(unix)]
struct UnixMmap {
    ptr: NonNull<u8>,
    len: usize,
}

#[cfg(unix)]
unsafe impl Send for UnixMmap {}
#[cfg(unix)]
unsafe impl Sync for UnixMmap {}

#[cfg(unix)]
impl UnixMmap {
    fn map(file: &File, len: usize) -> io::Result<Self> {
        const PROT_READ: c_int = 0x1;
        const MAP_PRIVATE: c_int = 0x02;

        extern "C" {
            fn mmap(
                addr: *mut c_void,
                len: usize,
                prot: c_int,
                flags: c_int,
                fd: c_int,
                offset: isize,
            ) -> *mut c_void;
        }

        let ptr = unsafe {
            mmap(
                std::ptr::null_mut(),
                len,
                PROT_READ,
                MAP_PRIVATE,
                file.as_raw_fd(),
                0,
            )
        };
        if ptr as isize == -1 {
            return Err(io::Error::last_os_error());
        }
        let ptr = NonNull::new(ptr.cast::<u8>())
            .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "mmap returned null"))?;
        Ok(Self { ptr, len })
    }

    fn as_slice(&self) -> &[u8] {
        unsafe { std::slice::from_raw_parts(self.ptr.as_ptr(), self.len) }
    }
}

#[cfg(unix)]
impl Drop for UnixMmap {
    fn drop(&mut self) {
        extern "C" {
            fn munmap(addr: *mut c_void, len: usize) -> c_int;
        }
        let _ = unsafe { munmap(self.ptr.as_ptr().cast::<c_void>(), self.len) };
    }
}