use crate::rust::{fmt, vec::Vec, format, string::String};
use crate::io;
macro_rules! buffered_read {
	($buffer_size: expr, $length: expr, $reader: expr) => {
		{
			let mut vec_buf = Vec::new();
			let mut total_read = 0;
			let mut buf = [0u8; $buffer_size];
			while total_read < $length {
				let next_to_read = if $length - total_read > $buffer_size { $buffer_size } else { $length - total_read };
				$reader.read(&mut buf[0..next_to_read])?;
				vec_buf.extend_from_slice(&buf[0..next_to_read]);
				total_read += next_to_read;
			}
			vec_buf
		}
	}
}
mod primitives;
mod module;
mod section;
mod types;
mod import_entry;
mod export_entry;
mod global_entry;
mod ops;
mod func;
mod segment;
mod index_map;
mod name_section;
mod reloc_section;
pub use self::module::{Module, peek_size, ImportCountType};
pub use self::section::{
	Section, FunctionSection, CodeSection, MemorySection, DataSection,
	ImportSection, ExportSection, GlobalSection, TypeSection, ElementSection,
	TableSection, CustomSection,
};
pub use self::import_entry::{ImportEntry, ResizableLimits, MemoryType, TableType, GlobalType, External};
pub use self::export_entry::{ExportEntry, Internal};
pub use self::global_entry::GlobalEntry;
pub use self::primitives::{
	VarUint32, VarUint7, Uint8, VarUint1, VarInt7, Uint32, VarInt32, VarInt64,
	Uint64, VarUint64, CountedList, CountedWriter, CountedListWriter,
};
pub use self::types::{Type, ValueType, BlockType, FunctionType, TableElementType};
pub use self::ops::{Instruction, Instructions, InitExpr, opcodes, BrTableData};
#[cfg(feature="atomics")]
pub use self::ops::AtomicsInstruction;
#[cfg(feature="simd")]
pub use self::ops::SimdInstruction;
#[cfg(feature="sign_ext")]
pub use self::ops::SignExtInstruction;
#[cfg(feature="bulk")]
pub use self::ops::BulkInstruction;
#[cfg(any(feature="simd", feature="atomics"))]
pub use self::ops::MemArg;
pub use self::func::{Func, FuncBody, Local};
pub use self::segment::{ElementSegment, DataSegment};
pub use self::index_map::IndexMap;
pub use self::name_section::{
	NameMap, NameSection, ModuleNameSubsection, FunctionNameSubsection,
	LocalNameSubsection,
};
pub use self::reloc_section::{
	RelocSection, RelocationEntry,
};
pub trait Deserialize : Sized {
	
	type Error: From<io::Error>;
	
	fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error>;
}
pub trait Serialize {
	
	type Error: From<io::Error>;
	
	fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error>;
}
#[derive(Debug, Clone)]
pub enum Error {
	
	UnexpectedEof,
	
	InvalidMagic,
	
	UnsupportedVersion(u32),
	
	InconsistentLength {
		
		expected: usize,
		
		actual: usize
	},
	
	Other(&'static str),
	
	HeapOther(String),
	
	UnknownValueType(i8),
	
	UnknownTableElementType(i8),
	
	NonUtf8String,
	
	UnknownExternalKind(u8),
	
	UnknownInternalKind(u8),
	
	UnknownOpcode(u8),
	#[cfg(feature="simd")]
	
	UnknownSimdOpcode(u32),
	
	InvalidVarUint1(u8),
	
	InvalidVarInt32,
	
	InvalidVarInt64,
	
	InvalidVarUint32,
	
	InvalidVarUint64,
	
	InconsistentMetadata,
	
	InvalidSectionId(u8),
	
	SectionsOutOfOrder,
	
	DuplicatedSections(u8),
	
	InvalidMemoryReference(u8),
	
	InvalidTableReference(u8),
	
	InvalidLimitsFlags(u8),
	
	UnknownFunctionForm(u8),
	
	InvalidVarInt7(u8),
	
	InconsistentCode,
	
	InvalidSegmentFlags(u32),
	
	TooManyLocals,
	
	DuplicatedNameSubsections(u8),
	
	UnknownNameSubsectionType(u8),
}
impl fmt::Display for Error {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		match *self {
			Error::UnexpectedEof => write!(f, "Unexpected end of input"),
			Error::InvalidMagic => write!(f, "Invalid magic number at start of file"),
			Error::UnsupportedVersion(v) => write!(f, "Unsupported wasm version {}", v),
			Error::InconsistentLength { expected, actual } => {
				write!(f, "Expected length {}, found {}", expected, actual)
			}
			Error::Other(msg) => write!(f, "{}", msg),
			Error::HeapOther(ref msg) => write!(f, "{}", msg),
			Error::UnknownValueType(ty) => write!(f, "Invalid or unknown value type {}", ty),
			Error::UnknownTableElementType(ty) => write!(f, "Unknown table element type {}", ty),
			Error::NonUtf8String => write!(f, "Non-UTF-8 string"),
			Error::UnknownExternalKind(kind) => write!(f, "Unknown external kind {}", kind),
			Error::UnknownInternalKind(kind) => write!(f, "Unknown internal kind {}", kind),
			Error::UnknownOpcode(opcode) => write!(f, "Unknown opcode {}", opcode),
			#[cfg(feature="simd")]
			Error::UnknownSimdOpcode(opcode) => write!(f, "Unknown SIMD opcode {}", opcode),
			Error::InvalidVarUint1(val) => write!(f, "Not an unsigned 1-bit integer: {}", val),
			Error::InvalidVarInt7(val) => write!(f, "Not a signed 7-bit integer: {}", val),
			Error::InvalidVarInt32 => write!(f, "Not a signed 32-bit integer"),
			Error::InvalidVarUint32 => write!(f, "Not an unsigned 32-bit integer"),
			Error::InvalidVarInt64 => write!(f, "Not a signed 64-bit integer"),
			Error::InvalidVarUint64 => write!(f, "Not an unsigned 64-bit integer"),
			Error::InconsistentMetadata =>  write!(f, "Inconsistent metadata"),
			Error::InvalidSectionId(ref id) =>  write!(f, "Invalid section id: {}", id),
			Error::SectionsOutOfOrder =>  write!(f, "Sections out of order"),
			Error::DuplicatedSections(ref id) =>  write!(f, "Duplicated sections ({})", id),
			Error::InvalidMemoryReference(ref mem_ref) =>  write!(f, "Invalid memory reference ({})", mem_ref),
			Error::InvalidTableReference(ref table_ref) =>  write!(f, "Invalid table reference ({})", table_ref),
			Error::InvalidLimitsFlags(ref flags) =>  write!(f, "Invalid limits flags ({})", flags),
			Error::UnknownFunctionForm(ref form) =>  write!(f, "Unknown function form ({})", form),
			Error::InconsistentCode =>  write!(f, "Number of function body entries and signatures does not match"),
			Error::InvalidSegmentFlags(n) =>  write!(f, "Invalid segment flags: {}", n),
			Error::TooManyLocals => write!(f, "Too many locals"),
			Error::DuplicatedNameSubsections(n) =>  write!(f, "Duplicated name subsections: {}", n),
			Error::UnknownNameSubsectionType(n) => write!(f, "Unknown subsection type: {}", n),
		}
	}
}
#[cfg(feature = "std")]
impl ::std::error::Error for Error {
	fn description(&self) -> &str {
		match *self {
			Error::UnexpectedEof => "Unexpected end of input",
			Error::InvalidMagic => "Invalid magic number at start of file",
			Error::UnsupportedVersion(_) => "Unsupported wasm version",
			Error::InconsistentLength { .. } => "Inconsistent length",
			Error::Other(msg) => msg,
			Error::HeapOther(ref msg) => &msg[..],
			Error::UnknownValueType(_) => "Invalid or unknown value type",
			Error::UnknownTableElementType(_) => "Unknown table element type",
			Error::NonUtf8String => "Non-UTF-8 string",
			Error::UnknownExternalKind(_) => "Unknown external kind",
			Error::UnknownInternalKind(_) => "Unknown internal kind",
			Error::UnknownOpcode(_) => "Unknown opcode",
			#[cfg(feature="simd")]
			Error::UnknownSimdOpcode(_) => "Unknown SIMD opcode",
			Error::InvalidVarUint1(_) => "Not an unsigned 1-bit integer",
			Error::InvalidVarInt32 => "Not a signed 32-bit integer",
			Error::InvalidVarInt7(_) => "Not a signed 7-bit integer",
			Error::InvalidVarUint32 => "Not an unsigned 32-bit integer",
			Error::InvalidVarInt64 => "Not a signed 64-bit integer",
			Error::InvalidVarUint64 => "Not an unsigned 64-bit integer",
			Error::InconsistentMetadata => "Inconsistent metadata",
			Error::InvalidSectionId(_) =>  "Invalid section id",
			Error::SectionsOutOfOrder =>  "Sections out of order",
			Error::DuplicatedSections(_) =>  "Duplicated section",
			Error::InvalidMemoryReference(_) =>  "Invalid memory reference",
			Error::InvalidTableReference(_) =>  "Invalid table reference",
			Error::InvalidLimitsFlags(_) => "Invalid limits flags",
			Error::UnknownFunctionForm(_) =>  "Unknown function form",
			Error::InconsistentCode =>  "Number of function body entries and signatures does not match",
			Error::InvalidSegmentFlags(_) =>  "Invalid segment flags",
			Error::TooManyLocals => "Too many locals",
			Error::DuplicatedNameSubsections(_) =>  "Duplicated name subsections",
			Error::UnknownNameSubsectionType(_) => "Unknown name subsections type",
		}
	}
}
impl From<io::Error> for Error {
	fn from(err: io::Error) -> Self {
		Error::HeapOther(format!("I/O Error: {:?}", err))
	}
}
impl From<(Vec<(usize, Error)>, Module)> for Error {
	fn from(err: (Vec<(usize, Error)>, Module)) -> Self {
		let ret = err.0.iter()
			.fold(
				String::new(),
				|mut acc, item| { acc.push_str(&format!("In section {}: {}\n", item.0, item.1)); acc }
			);
		Error::HeapOther(ret)
	}
}
pub struct Unparsed(pub Vec<u8>);
impl Deserialize for Unparsed {
	type Error = Error;
	fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
		let len = VarUint32::deserialize(reader)?.into();
		let mut vec = vec![0u8; len];
		reader.read(&mut vec[..])?;
		Ok(Unparsed(vec))
	}
}
impl From<Unparsed> for Vec<u8> {
	fn from(u: Unparsed) -> Vec<u8> {
		u.0
	}
}
pub fn deserialize_buffer<T: Deserialize>(contents: &[u8]) -> Result<T, T::Error> {
	let mut reader = io::Cursor::new(contents);
	let result = T::deserialize(&mut reader)?;
	if reader.position() != contents.len() {
		
		
		return Err(io::Error::TrailingData.into())
	}
	Ok(result)
}
pub fn serialize<T: Serialize>(val: T) -> Result<Vec<u8>, T::Error> {
	let mut buf = Vec::new();
	val.serialize(&mut buf)?;
	Ok(buf)
}
#[cfg(feature = "std")]
pub fn deserialize_file<P: AsRef<::std::path::Path>>(p: P) -> Result<Module, Error> {
	let mut f = ::std::fs::File::open(p)
		.map_err(|e| Error::HeapOther(format!("Can't read from the file: {:?}", e)))?;
	Module::deserialize(&mut f)
}
#[cfg(feature = "std")]
pub fn serialize_to_file<P: AsRef<::std::path::Path>>(p: P, module: Module) -> Result<(), Error> {
	let mut io = ::std::fs::File::create(p)
		.map_err(|e|
			Error::HeapOther(format!("Can't create the file: {:?}", e))
		)?;
	module.serialize(&mut io)?;
	Ok(())
}