use crate::protocol::prelude::*;
#[cfg(test)]
mod fuse_init_test;
#[derive(Debug)]
pub struct FuseInitRequest {
	protocol_version: crate::ProtocolVersion,
	max_readahead: u32,
	flags: FuseInitFlags,
}
impl FuseInitRequest {
	pub fn protocol_version(&self) -> crate::ProtocolVersion {
		self.protocol_version
	}
	pub fn max_readahead(&self) -> u32 {
		self.max_readahead
	}
	pub fn set_max_readahead(&mut self, max_readahead: u32) {
		self.max_readahead = max_readahead;
	}
	pub fn flags(&self) -> FuseInitFlags {
		self.flags
	}
	pub fn set_flags(&mut self, flags: FuseInitFlags) {
		self.flags = flags;
	}
}
#[repr(C)]
struct fuse_init_in_v7p1 {
	major: u32,
	minor: u32,
}
impl<'a> fuse_io::DecodeRequest<'a> for FuseInitRequest {
	fn decode_request(
		mut dec: fuse_io::RequestDecoder<'a>,
	) -> io::Result<Self> {
		debug_assert!(dec.header().opcode == fuse_kernel::FUSE_INIT);
		
		
		
		
		
		
		
		
		
		
		let raw_v7p1: &'a fuse_init_in_v7p1 = dec.peek_sized()?;
		if raw_v7p1.minor < 6
			|| raw_v7p1.major != fuse_kernel::FUSE_KERNEL_VERSION
		{
			return Ok(FuseInitRequest {
				protocol_version: crate::ProtocolVersion::new(
					raw_v7p1.major,
					raw_v7p1.minor,
				),
				max_readahead: 0,
				flags: FuseInitFlags { bits: 0 },
			});
		}
		let raw: &'a fuse_kernel::fuse_init_in = dec.next_sized()?;
		Ok(FuseInitRequest {
			protocol_version: crate::ProtocolVersion::new(raw.major, raw.minor),
			max_readahead: raw.max_readahead,
			flags: FuseInitFlags { bits: raw.flags },
		})
	}
}
pub struct FuseInitResponse {
	raw: fuse_kernel::fuse_init_out,
}
impl FuseInitResponse {
	pub fn new(version: crate::ProtocolVersion) -> Self {
		FuseInitResponse {
			raw: fuse_kernel::fuse_init_out {
				major: version.major(),
				minor: version.minor(),
				max_readahead: 0,
				flags: 0,
				max_background: 0,
				congestion_threshold: 0,
				max_write: 0,
				time_gran: 0,
				unused: [0; 9],
			},
		}
	}
	pub fn for_request(request: &FuseInitRequest) -> Self {
		let version = request.protocol_version();
		let v_minor;
		if version.major() == fuse_kernel::FUSE_KERNEL_VERSION {
			
			
			v_minor =
				min(version.minor(), fuse_kernel::FUSE_KERNEL_MINOR_VERSION);
		} else {
			
			
			
			v_minor = fuse_kernel::FUSE_KERNEL_MINOR_VERSION;
		}
		let v_major = fuse_kernel::FUSE_KERNEL_VERSION;
		let version = crate::ProtocolVersion::new(v_major, v_minor);
		let mut response = FuseInitResponse::new(version);
		response.set_max_readahead(request.max_readahead());
		
		response.set_flags(request.flags());
		response
	}
	pub fn protocol_version(&self) -> crate::ProtocolVersion {
		crate::ProtocolVersion::new(self.raw.major, self.raw.minor)
	}
	pub fn max_readahead(&self) -> u32 {
		self.raw.max_readahead
	}
	pub fn set_max_readahead(&mut self, max_readahead: u32) {
		self.raw.max_readahead = max_readahead;
	}
	pub fn flags(&self) -> FuseInitFlags {
		FuseInitFlags {
			bits: self.raw.flags,
		}
	}
	pub fn set_flags(&mut self, flags: FuseInitFlags) {
		self.raw.flags = flags.bits;
	}
	pub fn max_background(&self) -> u16 {
		self.raw.max_background
	}
	pub fn set_max_background(&mut self, max_background: u16) {
		self.raw.max_background = max_background;
	}
	pub fn congestion_threshold(&self) -> u16 {
		self.raw.congestion_threshold
	}
	pub fn set_congestion_threshold(&mut self, congestion_threshold: u16) {
		self.raw.congestion_threshold = congestion_threshold;
	}
	pub fn max_write(&self) -> u32 {
		self.raw.max_write
	}
	pub fn set_max_write(&mut self, max_write: u32) {
		self.raw.max_write = max_write;
	}
	pub fn time_gran(&self) -> u32 {
		self.raw.time_gran
	}
	pub fn set_time_gran(&mut self, time_gran: u32) {
		self.raw.time_gran = time_gran;
	}
}
impl fmt::Debug for FuseInitResponse {
	fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
		fmt.debug_struct("FuseInitResponse")
			.field("protocol_version", &self.protocol_version())
			.field("max_readahead", &self.max_readahead())
			.field("flags", &self.flags())
			.field("max_background", &self.max_background())
			.field("congestion_threshold", &self.congestion_threshold())
			.field("max_write", &self.max_write())
			.field("time_gran", &self.time_gran())
			.finish()
	}
}
#[repr(C)]
struct fuse_init_out_v7p1 {
	major: u32,
	minor: u32,
}
#[repr(C)]
struct fuse_init_out_v7p5 {
	major: u32,
	minor: u32,
	max_readahead: u32,        
	flags: u32,                
	max_background: u16,       
	congestion_threshold: u16, 
	max_write: u32,
}
impl fuse_io::EncodeResponse for FuseInitResponse {
	fn encode_response<'a, Chan: fuse_io::Channel>(
		&'a self,
		enc: fuse_io::ResponseEncoder<Chan>,
	) -> std::io::Result<()> {
		if self.raw.minor >= 23 {
			return enc.encode_sized(&self.raw);
		}
		if self.raw.minor >= 5 {
			let compat: &'a fuse_init_out_v7p5 =
				unsafe { std::mem::transmute(&self.raw) };
			return enc.encode_sized(compat);
		}
		let compat: &'a fuse_init_out_v7p1 =
			unsafe { std::mem::transmute(&self.raw) };
		enc.encode_sized(compat)
	}
}
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct FuseInitFlag {
	bits: u32,
}
impl FuseInitFlag {
	pub const ASYNC_READ: FuseInitFlag = FuseInitFlag {
		bits: fuse_kernel::FUSE_ASYNC_READ,
	};
	pub const POSIX_LOCKS: FuseInitFlag = FuseInitFlag {
		bits: fuse_kernel::FUSE_POSIX_LOCKS,
	};
	pub const ATOMIC_O_TRUNC: FuseInitFlag = FuseInitFlag {
		bits: fuse_kernel::FUSE_ATOMIC_O_TRUNC,
	};
	pub const BIG_WRITES: FuseInitFlag = FuseInitFlag {
		bits: fuse_kernel::FUSE_BIG_WRITES,
	};
	pub const EXPORT_SUPPORT: FuseInitFlag = FuseInitFlag {
		bits: fuse_kernel::FUSE_EXPORT_SUPPORT,
	};
	pub const DONT_MASK: FuseInitFlag = FuseInitFlag {
		bits: fuse_kernel::FUSE_DONT_MASK,
	};
	pub const SPLICE_WRITE: FuseInitFlag = FuseInitFlag {
		bits: fuse_kernel::FUSE_SPLICE_WRITE,
	};
	pub const SPLICE_MOVE: FuseInitFlag = FuseInitFlag {
		bits: fuse_kernel::FUSE_SPLICE_MOVE,
	};
	pub const SPLICE_READ: FuseInitFlag = FuseInitFlag {
		bits: fuse_kernel::FUSE_SPLICE_READ,
	};
	pub const FLOCK_LOCKS: FuseInitFlag = FuseInitFlag {
		bits: fuse_kernel::FUSE_FLOCK_LOCKS,
	};
	pub const IOCTL_DIR: FuseInitFlag = FuseInitFlag {
		bits: fuse_kernel::FUSE_HAS_IOCTL_DIR,
	};
	pub const AUTO_INVAL_DATA: FuseInitFlag = FuseInitFlag {
		bits: fuse_kernel::FUSE_AUTO_INVAL_DATA,
	};
	pub const READDIRPLUS: FuseInitFlag = FuseInitFlag {
		bits: fuse_kernel::FUSE_DO_READDIRPLUS,
	};
	pub const READDIRPLUS_AUTO: FuseInitFlag = FuseInitFlag {
		bits: fuse_kernel::FUSE_READDIRPLUS_AUTO,
	};
	pub const ASYNC_DIO: FuseInitFlag = FuseInitFlag {
		bits: fuse_kernel::FUSE_ASYNC_DIO,
	};
	pub const WRITEBACK_CACHE: FuseInitFlag = FuseInitFlag {
		bits: fuse_kernel::FUSE_WRITEBACK_CACHE,
	};
	pub const NO_OPEN_SUPPORT: FuseInitFlag = FuseInitFlag {
		bits: fuse_kernel::FUSE_NO_OPEN_SUPPORT,
	};
	pub const PARALLEL_DIROPS: FuseInitFlag = FuseInitFlag {
		bits: fuse_kernel::FUSE_PARALLEL_DIROPS,
	};
	pub const HANDLE_KILLPRIV: FuseInitFlag = FuseInitFlag {
		bits: fuse_kernel::FUSE_HANDLE_KILLPRIV,
	};
	pub const POSIX_ACL: FuseInitFlag = FuseInitFlag {
		bits: fuse_kernel::FUSE_POSIX_ACL,
	};
	pub const ABORT_ERROR: FuseInitFlag = FuseInitFlag {
		bits: fuse_kernel::FUSE_ABORT_ERROR,
	};
}
impl fmt::Binary for FuseInitFlag {
	fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
		self.bits.fmt(fmt)
	}
}
impl fmt::LowerHex for FuseInitFlag {
	fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
		self.bits.fmt(fmt)
	}
}
impl fmt::UpperHex for FuseInitFlag {
	fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
		self.bits.fmt(fmt)
	}
}
impl fmt::Debug for FuseInitFlag {
	fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
		fmt::Display::fmt(self, fmt)
	}
}
impl fmt::Display for FuseInitFlag {
	fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
		match *self {
			FuseInitFlag::ASYNC_READ => fmt.write_str("ASYNC_READ"),
			FuseInitFlag::POSIX_LOCKS => fmt.write_str("POSIX_LOCKS"),
			FuseInitFlag::ATOMIC_O_TRUNC => fmt.write_str("ATOMIC_O_TRUNC"),
			FuseInitFlag::BIG_WRITES => fmt.write_str("BIG_WRITES"),
			FuseInitFlag::EXPORT_SUPPORT => fmt.write_str("EXPORT_SUPPORT"),
			FuseInitFlag::DONT_MASK => fmt.write_str("DONT_MASK"),
			FuseInitFlag::SPLICE_WRITE => fmt.write_str("SPLICE_WRITE"),
			FuseInitFlag::SPLICE_MOVE => fmt.write_str("SPLICE_MOVE"),
			FuseInitFlag::SPLICE_READ => fmt.write_str("SPLICE_READ"),
			FuseInitFlag::FLOCK_LOCKS => fmt.write_str("FLOCK_LOCKS"),
			FuseInitFlag::IOCTL_DIR => fmt.write_str("IOCTL_DIR"),
			FuseInitFlag::AUTO_INVAL_DATA => fmt.write_str("AUTO_INVAL_DATA"),
			FuseInitFlag::READDIRPLUS => fmt.write_str("READDIRPLUS"),
			FuseInitFlag::READDIRPLUS_AUTO => fmt.write_str("READDIRPLUS_AUTO"),
			FuseInitFlag::ASYNC_DIO => fmt.write_str("ASYNC_DIO"),
			FuseInitFlag::WRITEBACK_CACHE => fmt.write_str("WRITEBACK_CACHE"),
			FuseInitFlag::NO_OPEN_SUPPORT => fmt.write_str("NO_OPEN_SUPPORT"),
			FuseInitFlag::PARALLEL_DIROPS => fmt.write_str("PARALLEL_DIROPS"),
			FuseInitFlag::HANDLE_KILLPRIV => fmt.write_str("HANDLE_KILLPRIV"),
			FuseInitFlag::POSIX_ACL => fmt.write_str("POSIX_ACL"),
			FuseInitFlag::ABORT_ERROR => fmt.write_str("ABORT_ERROR"),
			_ => write!(fmt, "{:#010X}", self.bits),
		}
	}
}
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct FuseInitFlags {
	bits: u32,
}
impl fmt::Binary for FuseInitFlags {
	fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
		self.bits.fmt(fmt)
	}
}
impl fmt::LowerHex for FuseInitFlags {
	fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
		self.bits.fmt(fmt)
	}
}
impl fmt::UpperHex for FuseInitFlags {
	fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
		self.bits.fmt(fmt)
	}
}
impl fmt::Debug for FuseInitFlags {
	fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
		fmt::Display::fmt(self, fmt)
	}
}
impl fmt::Display for FuseInitFlags {
	fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
		let mut chunks = [FuseInitFlag { bits: 0 }; 32];
		let mut ii = 0;
		for bit in 0..31 {
			let mask: u32 = 1 << bit;
			if (self.bits & mask) > 0 {
				chunks[ii].bits = mask;
				ii += 1;
			}
		}
		fmt.debug_list().entries(chunks[0..ii].iter()).finish()
	}
}
impl FuseInitFlags {
	pub fn new() -> FuseInitFlags {
		FuseInitFlags { bits: 0 }
	}
	pub fn get(&self, flag: FuseInitFlag) -> bool {
		(self.bits & flag.bits) > 0
	}
	pub fn set(&mut self, flag: FuseInitFlag, value: bool) {
		if value {
			self.bits |= flag.bits;
		} else {
			self.bits &= !(flag.bits);
		}
	}
}