#![cfg(any(target_os = "android", target_os = "linux"))]
use std::ffi::FromBytesWithNulError;
use std::fs::File;
use std::io;
use remain::sorted;
use thiserror::Error as ThisError;
pub mod filesystem;
pub mod fuzzing;
pub mod mount;
mod server;
#[allow(dead_code)]
pub mod sys;
pub mod worker;
use filesystem::FileSystem;
pub use mount::mount;
pub use server::Mapper;
pub use server::Reader;
pub use server::Server;
pub use server::Writer;
#[sorted]
#[derive(ThisError, Debug)]
pub enum Error {
    #[error("failed to decode fuse message: {0}")]
    DecodeMessage(io::Error),
    #[error("failed to encode fuse message: {0}")]
    EncodeMessage(io::Error),
    #[error("failed to set up FUSE endpoint to talk with: {0}")]
    EndpointSetup(io::Error),
    #[error("failed to flush fuse message: {0}")]
    FlushMessage(io::Error),
    #[error("a c string parameter is invalid: {0}")]
    InvalidCString(FromBytesWithNulError),
    #[error("the `len` field of the header is too small")]
    InvalidHeaderLength,
    #[error(
        "The `size` field of the `SetxattrIn` message does not match the\
             length of the decoded value: size = {0}, value.len() = {1}"
    )]
    InvalidXattrSize(u32, usize),
    #[error("one or more parameters are missing")]
    MissingParameter,
    #[error("Thread exited")]
    ThreadExited,
    #[error(
        "requested too many `iovec`s for an `ioctl` retry reply: requested\
            {0}, max: {1}"
    )]
    TooManyIovecs(usize, usize),
}
pub type Result<T> = ::std::result::Result<T, Error>;
#[derive(Default)]
pub struct FuseConfig {
    dev_fuse_file: Option<File>,
    max_write_bytes: Option<u32>,
    max_read_bytes: Option<u32>,
    num_of_threads: Option<usize>,
}
impl FuseConfig {
    pub fn new() -> Self {
        FuseConfig {
            ..Default::default()
        }
    }
    pub fn dev_fuse(&mut self, file: File) -> &mut Self {
        self.dev_fuse_file = Some(file);
        self
    }
    pub fn max_read(&mut self, bytes: u32) -> &mut Self {
        self.max_read_bytes = Some(bytes);
        self
    }
    pub fn max_write(&mut self, bytes: u32) -> &mut Self {
        self.max_write_bytes = Some(bytes);
        self
    }
    pub fn num_threads(&mut self, num: usize) -> &mut Self {
        self.num_of_threads = Some(num);
        self
    }
    pub fn enter_message_loop<F: FileSystem + Sync + Send>(self, fs: F) -> Result<()> {
        let FuseConfig {
            dev_fuse_file,
            max_write_bytes,
            max_read_bytes,
            num_of_threads,
        } = self;
        let num = num_of_threads.unwrap_or(1);
        if num == 1 {
            worker::start_message_loop(
                dev_fuse_file.ok_or(Error::MissingParameter)?,
                max_read_bytes.ok_or(Error::MissingParameter)?,
                max_write_bytes.ok_or(Error::MissingParameter)?,
                fs,
            )
        } else {
            worker::internal::start_message_loop_mt(
                dev_fuse_file.ok_or(Error::MissingParameter)?,
                max_read_bytes.ok_or(Error::MissingParameter)?,
                max_write_bytes.ok_or(Error::MissingParameter)?,
                num,
                fs,
            )
        }
    }
}