use crate::args::InputArg;
use eyre::Result;
use std::{
fs,
io::{self, Read},
os,
};
const MAX_EAGER_LEN: u64 = 1 << 20;
pub(super) enum JsonSource<S> {
File(fs::File),
Stdin(io::Stdin),
Inline(S),
}
pub(super) enum JsonSourceRead<'a> {
File(&'a mut fs::File),
Stdin(&'a mut io::Stdin),
}
pub(super) enum ResolvedInputKind {
Mmap,
Owned,
Buffered,
}
impl<S> JsonSource<S> {
#[cfg(unix)]
pub(crate) fn try_as_raw_desc(&self) -> Option<os::fd::RawFd> {
use std::os::fd::AsRawFd as _;
match self {
Self::File(f) => Some(f.as_raw_fd()),
Self::Stdin(s) => Some(s.as_raw_fd()),
Self::Inline(_) => None,
}
}
#[cfg(windows)]
pub(crate) fn try_as_raw_desc(&self) -> Option<os::windows::io::RawHandle> {
use os::windows::io::AsRawHandle;
match self {
Self::File(f) => Some(f.as_raw_handle()),
Self::Stdin(s) => Some(s.as_raw_handle()),
Self::Inline(_) => None,
}
}
pub(crate) fn try_as_read(&mut self) -> Option<JsonSourceRead<'_>> {
match self {
Self::File(f) => Some(JsonSourceRead::File(f)),
Self::Stdin(s) => Some(JsonSourceRead::Stdin(s)),
Self::Inline(_) => None,
}
}
}
impl Read for JsonSourceRead<'_> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
match self {
Self::File(f) => f.read(buf),
Self::Stdin(s) => s.read(buf),
}
}
}
pub(super) fn decide_input_strategy<S>(
source: &JsonSource<S>,
force_input: Option<&InputArg>,
) -> Result<(ResolvedInputKind, Option<ResolvedInputKind>)> {
if let Some(force) = force_input {
let forced = match force {
InputArg::Mmap => ResolvedInputKind::Mmap,
InputArg::Eager => ResolvedInputKind::Owned,
InputArg::Buffered => ResolvedInputKind::Buffered,
};
Ok((forced, None))
} else {
match source {
JsonSource::File(file) => match file.metadata() {
Ok(meta) if meta.len() <= MAX_EAGER_LEN => Ok((ResolvedInputKind::Owned, None)),
_ if is_mmap_available() => Ok((ResolvedInputKind::Mmap, Some(ResolvedInputKind::Buffered))),
_ => Ok((ResolvedInputKind::Buffered, None)),
},
JsonSource::Inline(_) => Ok((ResolvedInputKind::Owned, None)),
JsonSource::Stdin(_) => Ok((ResolvedInputKind::Buffered, None)),
}
}
}
fn is_mmap_available() -> bool {
cfg!(unix) || cfg!(windows)
}