use std::error;
use std::fmt::{self, Formatter, Display, Debug};
use gl::types::*;
use gl;
pub struct Error{
gl_code: Option<GLenum>,
description: Option<String>,
cause: Option<Box<dyn error::Error + Send + Sync>>,
kind: ErrorKind,
}
#[derive(Copy,Clone,Debug)]
pub enum ErrorKind{
ContextCreationError,
OutOfMemory,
MapError,
OutOfBounds,
SizeGreaterThanMaxSize,
NoColorAttachments,
MaxColorAttachments,
FramebufferCreationError,
ProgramCreationError,
CompileError,
LinkError,
UniformNotFound,
ZeroWidth,
ZeroHeight,
ZeroDepth,
WidthTooBig,
HeightTooBig,
DepthTooBig,
CorruptedImage,
FormatSizeBiggerThanAllocated,
FormatSizeBiggerThanData,
FormatMandatoryOnCompressed,
FormatNotSupported,
NotSquareImage,
DifferentFormatsPerImage,
DifferentDimensionsPerImage,
VaoCreationError,
AttributeNotFound,
WaitFailed,
NotReady,
}
impl Debug for Error{
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result{
if let Some(gl_code) = self.gl_code{
fmt.write_str(&format!("{{ kind: {:?}, gl_code: {}, description: {:?}, cause: {:?} }}", self.kind, error_to_string(gl_code), self.description, self.cause))
}else{
fmt.write_str(&format!("{{ kind: {:?}, description: {:?}, cause: {:?} }}", self.kind, self.description, self.cause))
}
}
}
impl ErrorKind{
pub fn as_str(self) -> &'static str{
use ErrorKind::*;
match self{
FormatNotSupported => "Fromat not supported",
ContextCreationError => "Context creation error",
OutOfMemory => "Out of memory",
MapError => "Buffer mapping error",
OutOfBounds => "Out of bounds",
SizeGreaterThanMaxSize => "Size greater than maximum allowed size",
NoColorAttachments => "No color attachments",
MaxColorAttachments => "More than allowed maximum number of attachments",
FramebufferCreationError => "Framebuffer creation error",
ProgramCreationError => "Program creation error",
CompileError => "Compile error",
LinkError => "Link error",
UniformNotFound => "Uniform not found",
ZeroWidth => "Zero width",
ZeroHeight => "Zero height",
ZeroDepth => "Zero depth",
WidthTooBig => "Width greater than maximum allowed",
HeightTooBig => "Height greater than maximum allowed",
DepthTooBig => "Depth greater than maximum allowed",
CorruptedImage => "Corrupted image",
FormatSizeBiggerThanAllocated => "Format size is bigger than allocated",
FormatSizeBiggerThanData => "Format size is bigger than passed data",
FormatMandatoryOnCompressed => "Format has to be specified for compressed texture",
NotSquareImage => "Image needs to have same width and height",
DifferentFormatsPerImage => "All images need to have the same format",
DifferentDimensionsPerImage => "All images need to have the same dimension",
VaoCreationError => "Vao creation error",
AttributeNotFound => "Attribute not found",
WaitFailed => "Wait sync failed",
NotReady => "Wait sync not ready yet",
}
}
}
impl Error{
pub fn new<'a, S: Into<Option<&'a str>>>(kind: ErrorKind, desc: S) -> Error{
Error{
kind: kind,
description: desc.into().map(|d| d.to_owned()),
gl_code: None,
cause: None,
}
}
pub fn with_gl_code<'a, S: Into<Option<&'a str>>>(kind: ErrorKind, desc: S, gl_code: GLenum) -> Error{
Error{
kind: kind,
description: desc.into().map(|d| d.to_owned()),
gl_code: Some(gl_code),
cause: None,
}
}
pub fn with_cause<'a, E: error::Error + Send + Sync + 'static, S: Into<Option<&'a str>>>(kind: ErrorKind, desc: S, cause: E) -> Error{
Error{
kind: kind,
description: desc.into().map(|d| d.to_owned()),
gl_code: None,
cause: Some(Box::new(cause) as Box<dyn error::Error + Send + Sync>)
}
}
pub fn gl_code_description(&self) -> Option<&'static str>{
self.gl_code.map(error_to_string)
}
pub fn kind(&self) -> ErrorKind{
self.kind
}
}
impl error::Error for Error{
fn source(&self) -> Option<&(dyn error::Error + 'static)>{
self.cause.as_ref().map(|e| &**e as &dyn error::Error)
}
}
impl Display for Error{
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result{
let msg = self.description.as_ref()
.map(|d| d.as_ref())
.unwrap_or(self.kind.as_str());
fmt.write_str(msg)?;
if let Some(gl_code) = self.gl_code {
fmt.write_fmt(format_args!("\ngl_code: {}", gl_code))?;
}
if let Some(cause) = self.cause.as_ref(){
fmt.write_str("\ncause: ")?;
fmt.write_fmt(format_args!("{}", cause))?;
}
Ok(())
}
}
impl From<ErrorKind> for Error{
fn from(kind: ErrorKind) -> Error{
Error::new(kind, "")
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn error_to_string(err: GLenum) -> &'static str{
match err{
0 => "Ok",
gl::INVALID_ENUM => "GL_INVALID_ENUM",
gl::INVALID_VALUE => "GL_INVALID_VALUE",
gl::INVALID_OPERATION => "GL_INVALID_OPERATION",
gl::STACK_OVERFLOW => "GL_STACK_OVERFLOW",
gl::STACK_UNDERFLOW => "GL_STACK_UNDERFLOW",
gl::OUT_OF_MEMORY => "GL_OUT_OF_MEMORY",
gl::FRAMEBUFFER_UNDEFINED => "GL_FRAMEBUFFER_UNDEFINED",
gl::FRAMEBUFFER_INCOMPLETE_ATTACHMENT => "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT",
gl::FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT => "GL_FRAMEBUFFER_INCOMPLETE_MissingATTACHMENT",
gl::FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER => "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER",
gl::FRAMEBUFFER_INCOMPLETE_READ_BUFFER => "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER",
gl::FRAMEBUFFER_UNSUPPORTED => "GL_FRAMEBUFFER_UNSUPPORTED",
gl::FRAMEBUFFER_INCOMPLETE_MULTISAMPLE => "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE",
gl::FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS => "GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS",
_ => "Unknown error",
}
}
#[cfg(any(feature = "gles", feature="webgl"))]
pub fn error_to_string(err: GLenum) -> &'static str{
match err{
0 => "Ok",
gl::INVALID_ENUM => "GL_INVALID_ENUM",
gl::INVALID_VALUE => "GL_INVALID_VALUE",
gl::INVALID_OPERATION => "GL_INVALID_OPERATION",
gl::OUT_OF_MEMORY => "GL_OUT_OF_MEMORY",
gl::FRAMEBUFFER_INCOMPLETE_ATTACHMENT => "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT",
gl::FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT => "GL_FRAMEBUFFER_INCOMPLETE_MissingATTACHMENT",
gl::FRAMEBUFFER_UNSUPPORTED => "GL_FRAMEBUFFER_UNSUPPORTED",
_ => "Unknown error",
}
}