Treat SQLite result codes as error kinds

This commit is contained in:
Ivan Ukhov 2015-06-08 18:05:17 -04:00
parent bde720bddc
commit 985cde931f
3 changed files with 88 additions and 103 deletions

View File

@ -1,33 +1,78 @@
use libc::c_int;
use raw;
use std::convert::{From, Into};
use std::fmt::{self, Display, Formatter};
use ResultCode;
/// An error.
#[derive(Debug)]
pub struct Error {
pub code: ResultCode,
pub kind: ErrorKind,
pub message: Option<String>,
}
macro_rules! declare(
($($left:ident => $right:ident,)*) => (
/// An error kind.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ErrorKind {
$($left = raw::$right as isize,)*
Unknown,
}
pub fn kind_from_code(code: c_int) -> ErrorKind {
match code {
$(raw::$right => ErrorKind::$left,)*
_ => ErrorKind::Unknown,
}
}
);
);
declare!(
Abort => SQLITE_ABORT,
Authorization => SQLITE_AUTH,
Busy => SQLITE_BUSY,
CantOpen => SQLITE_CANTOPEN,
Constraint => SQLITE_CONSTRAINT,
Corruption => SQLITE_CORRUPT,
Done => SQLITE_DONE,
Empty => SQLITE_EMPTY,
Error => SQLITE_ERROR,
Format => SQLITE_FORMAT,
Full => SQLITE_FULL,
Internal => SQLITE_INTERNAL,
Interruption => SQLITE_INTERRUPT,
IOError => SQLITE_IOERR,
Locked => SQLITE_LOCKED,
Mismatch => SQLITE_MISMATCH,
Misuse => SQLITE_MISUSE,
NoLargeFileSupport => SQLITE_NOLFS,
NoMemory => SQLITE_NOMEM,
NotDatabase => SQLITE_NOTADB,
NotFound => SQLITE_NOTFOUND,
Notice => SQLITE_NOTICE,
OK => SQLITE_OK,
Permission => SQLITE_PERM,
Protocol => SQLITE_PROTOCOL,
Range => SQLITE_RANGE,
ReadOnly => SQLITE_READONLY,
Row => SQLITE_ROW,
Schema => SQLITE_SCHEMA,
TooBig => SQLITE_TOOBIG,
Warning => SQLITE_WARNING,
);
impl<T> From<T> for Error where T: Into<String> {
#[inline]
fn from(message: T) -> Error {
Error {
code: ResultCode::Error,
message: Some(message.into()),
}
Error { kind: ErrorKind::Error, message: Some(message.into()) }
}
}
impl From<ResultCode> for Error {
impl From<ErrorKind> for Error {
#[inline]
fn from(code: ResultCode) -> Error {
Error {
code: code,
message: None,
}
fn from(kind: ErrorKind) -> Error {
Error { kind: kind, message: None }
}
}
@ -35,7 +80,16 @@ impl Display for Error {
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
match self.message {
Some(ref message) => Display::fmt(message, formatter),
None => Display::fmt(&self.code, formatter),
None => Display::fmt(&self.kind, formatter),
}
}
}
impl Display for ErrorKind {
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
match *self {
ErrorKind::Unknown => write!(formatter, "an unknown SQLite result code"),
_ => write!(formatter, "SQLite result code {}", *self as isize),
}
}
}
@ -51,8 +105,21 @@ pub fn last(raw: *mut raw::sqlite3) -> Option<Error> {
return None;
}
Some(Error {
code: ::result::code_from_raw(code),
kind: kind_from_code(code),
message: Some(c_str_to_string!(message)),
})
}
}
#[cfg(test)]
mod tests {
use super::{ErrorKind, kind_from_code};
#[test]
fn fmt() {
assert_eq!(format!("{}", ErrorKind::OK),
String::from("SQLite result code 0"));
assert_eq!(format!("{}", kind_from_code(777)),
String::from("an unknown SQLite result code"));
}
}

View File

@ -14,7 +14,7 @@ macro_rules! failure(
($database:expr, $code:expr) => (
match ::error::last($database) {
Some(error) => return Err(error),
None => return Err(::Error::from(::result::code_from_raw($code))),
None => return Err(::Error::from(::error::kind_from_code($code))),
}
);
);
@ -29,7 +29,7 @@ macro_rules! success(
($result:expr) => (
match $result {
::raw::SQLITE_OK => {},
code => return Err(::Error::from(::result::code_from_raw(code))),
code => return Err(::Error::from(::error::kind_from_code(code))),
}
);
);
@ -64,14 +64,15 @@ macro_rules! c_str_to_string(
mod database;
mod error;
mod result;
mod statement;
pub use error::Error;
pub use database::Database;
pub use result::{Result, ResultCode};
pub use error::{Error, ErrorKind};
pub use statement::{Statement, Binding, Value, State};
/// A result.
pub type Result<T> = ::std::result::Result<T, Error>;
/// Open a database.
#[inline]
pub fn open<'l>(path: &std::path::Path) -> Result<Database<'l>> {

View File

@ -1,83 +0,0 @@
use libc::c_int;
use std::fmt::{self, Display, Formatter};
use raw;
use Error;
/// A result.
pub type Result<T> = ::std::result::Result<T, Error>;
macro_rules! declare(
($($left:ident => $right:ident,)*) => (
/// A result code.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ResultCode {
$($left = raw::$right as isize,)*
Unknown,
}
pub fn code_from_raw(code: c_int) -> ResultCode {
match code {
$(raw::$right => ResultCode::$left,)*
_ => ResultCode::Unknown,
}
}
);
);
declare!(
Abort => SQLITE_ABORT,
Authorization => SQLITE_AUTH,
Busy => SQLITE_BUSY,
CantOpen => SQLITE_CANTOPEN,
Constraint => SQLITE_CONSTRAINT,
Corruption => SQLITE_CORRUPT,
Done => SQLITE_DONE,
Empty => SQLITE_EMPTY,
Error => SQLITE_ERROR,
Format => SQLITE_FORMAT,
Full => SQLITE_FULL,
Internal => SQLITE_INTERNAL,
Interruption => SQLITE_INTERRUPT,
IOError => SQLITE_IOERR,
Locked => SQLITE_LOCKED,
Mismatch => SQLITE_MISMATCH,
Misuse => SQLITE_MISUSE,
NoLargeFileSupport => SQLITE_NOLFS,
NoMemory => SQLITE_NOMEM,
NotDatabase => SQLITE_NOTADB,
NotFound => SQLITE_NOTFOUND,
Notice => SQLITE_NOTICE,
OK => SQLITE_OK,
Permission => SQLITE_PERM,
Protocol => SQLITE_PROTOCOL,
Range => SQLITE_RANGE,
ReadOnly => SQLITE_READONLY,
Row => SQLITE_ROW,
Schema => SQLITE_SCHEMA,
TooBig => SQLITE_TOOBIG,
Warning => SQLITE_WARNING,
);
impl Display for ResultCode {
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
match *self {
ResultCode::Unknown => write!(formatter, "an unknown SQLite result code"),
_ => write!(formatter, "SQLite result code {}", *self as isize),
}
}
}
#[cfg(test)]
mod tests {
use ResultCode;
use super::code_from_raw;
#[test]
fn fmt() {
assert_eq!(format!("{}", ResultCode::OK),
String::from("SQLite result code 0"));
assert_eq!(format!("{}", code_from_raw(777)),
String::from("an unknown SQLite result code"));
}
}