Initial library commit.

This commit is contained in:
Myrddin Dundragon 2017-01-06 19:10:10 -05:00
commit ca780e71ef
8 changed files with 503 additions and 0 deletions

17
.gitignore vendored Normal file
View File

@ -0,0 +1,17 @@
# Ignore swap files from text editors.
*.swp
# Ignore compiled files.
*.o
*.so
*.rlib
*.dll
*.exe
# Ignore files/directories generated by Cargo.
/target/
# Remove Cargo.lock from gitignore if creating an executable,
# leave it for libraries.
# More information here: http://doc.crates.io/guide.html#cargotoml-vs-cargolock
Cargo.lock

13
Cargo.toml Normal file
View File

@ -0,0 +1,13 @@
[package]
name = "binding"
version = "0.1.0"
authors = ["Jason Travis Smith <Myrddin@CyberMagesLLC.com>"]
description = "Defines macros and functions used when binding to C libraries."
license = ""
repository = "https://gitlab.com/CyberMages/binding.git"
documentation = ""
keywords = ["binding", "c types", "c enums", "c flags", "c strings"]
[dependencies.scribe]
git = "https://gitlab.com/CyberMages/scribe.git"

5
README.md Normal file
View File

@ -0,0 +1,5 @@
# Binding #
There are many common data types and functions used when interfacing
with C libraries. The Binding library attempts to define the more commonly
needed types and functions to help speed up the process of wrapping
these libraries.

110
src/c_enum.rs Normal file
View File

@ -0,0 +1,110 @@
/// Create a C exportable enum. These are useful for working with C FFIs.
///
/// As C has no idea about tuples or structs enums
/// using this macro must only contain Unit variants.
#[macro_export]
macro_rules! c_enum
{
{
$(#[$attribute: meta])* enum $name: ident : $fieldType: ty
{
$(
$(#[$variantAttribute: meta])*
variant $variant: ident = $value: expr
),*
}
} =>
{
$(#[$attribute])*
#[repr(C)]
pub enum $name
{
$($(#[$variantAttribute])* $variant = $value,)*
}
impl $name
{
/// Generate a variant of the enum from a given value.
///
/// This is not very performant. Becareful when using this
/// to not use this in a high performance loop.
pub fn from_value(val: $fieldType) -> Option<$name>
{
// This would be better as a match statement, but
// unfortunately, it needs to be a giant set of if
// statements since we only have the expression type
// to work with, not a pattern type.
/*
match val
{
$($value => {Some($name::$variant)})*
_ => {None}
}
*/
$(if val == $value {return Some($name::$variant);})*
// No variant was found.
None
}
/// 'true', if the given value matches a variant
/// of the enumeration; Otherwise, 'false'.
pub fn is_valid_value(val: $fieldType) -> bool
{
match $name::from_value(val)
{
Some(_) =>
{
true
}
None =>
{
false
}
}
}
/// Turn an enum variant into a value.
pub fn to_value(&self) -> $fieldType
{
match *self
{
$($name::$variant => {$value})*
}
}
/// Get a str representation of this variant.
pub fn to_str(&self) -> &'static str
{
match *self
{
$($name::$variant => {stringify!($variant)})*
}
}
/// Get a String representation of this variant.
pub fn to_string(&self) -> String
{
String::from(self.to_str())
}
}
impl ::std::fmt::Debug for $name
{
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result
{
write!(f, "{}", self.to_str())
}
}
impl ::std::fmt::Display for $name
{
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result
{
write!(f, "{}", self.to_str())
}
}
}
}

232
src/c_flags.rs Normal file
View File

@ -0,0 +1,232 @@
/// Creates a Flag type that is also very useful for working with C FFIs.
#[macro_export]
macro_rules! c_flags
{
{
$(#[$attribute: meta])* flags $name: ident : $fieldType: ty
{
$(
$(#[$flagAttribute: meta])*
const $flag: ident = $value: expr
),+
}
} =>
{
// Create the structure that will represent the bitflag.
// Derive the basic needed functionality and
// add any required extra attributes.
$(#[$attribute])*
#[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash)]
pub struct $name
{
bits: $fieldType
}
$($(#[$flagAttribute])* pub const $flag: $name = $name {bits: $value};)+
impl $name
{
/// Create a new default version of the
/// bitflag structure.
pub fn new() -> $name
{
$name::empty()
}
/// Create a new bitflag structure from
/// the given bits.
pub fn from_bits(bits: $fieldType) -> Option<$name>
{
if bits & !$name::all().get_bits() != 0
{
None
}
else
{
Some($name {bits: bits})
}
}
/// Returns an empty set of flags.
#[inline]
pub fn empty() -> $name
{
$name {bits: 0}
}
/// Returns the set containing all flags.
pub fn all() -> $name
{
$name {bits: $($flag.bits)|+}
}
/// Returns `true` if no flags are currently stored;
/// Otherwise, `false` is returned.
pub fn is_empty(&self) -> bool
{
*self == $name::empty()
}
/// Returns `true` if all the flags are currently set;
/// Otherwise, `false` is returned.
pub fn is_all(&self) -> bool
{
*self == $name::all()
}
/// Returns the raw value of the flags currently stored.
pub fn get_bits(&self) -> $fieldType
{
self.bits
}
/// Turn the flag into a String representation of its self.
#[warn(unused_assignments)]
pub fn to_string(&self) -> String
{
let mut first: bool;
let mut string: String;
// Push the left bracket onto the string.
string = String::new();
string.push_str("{");
// Handle checking each flag to see if it
// is part of this flag.
first = true;
$(
if self.intersects($flag) == true
{
// If this is not the first flag,
// then add an OR symbol.
if first == false
{
string.push_str(" | ");
}
// Push the flags name onto the string.
string.push_str(stringify!($flag));
first = false;
}
)+
// No flags were set.
if first == true
{
// Put a space in the string.
string.push_str(" ");
}
// Push the right bracket onto the string
// and return it.
string.push_str("}");
string
}
/// Returns `true` if there are flags common to
/// both `self` and `other`; Otherwise, `false` is returned.
pub fn intersects(&self, other: $name) -> bool
{
!(*self & other).is_empty()
}
/// Returns `true` all of the flags in `other` are
/// contained within `self`; Otherwise, `false` is returned.
pub fn contains(&self, other: $name) -> bool
{
(*self & other) == other
}
/// Inserts the specified flags in-place.
pub fn insert(&mut self, other: $name)
{
self.bits |= other.bits;
}
/// Removes the specified flags in-place.
pub fn remove(&mut self, other: $name)
{
self.bits &= !other.bits;
}
/// Toggles the specified flags in-place.
pub fn toggle(&mut self, other: $name)
{
self.bits ^= other.bits;
}
}
impl ::std::ops::BitOr for $name
{
type Output = $name;
/// Returns the union of the two sets of flags.
fn bitor(self, other: $name) -> $name
{
$name {bits: self.bits | other.bits}
}
}
impl ::std::ops::BitXor for $name
{
type Output = $name;
/// Returns the left flags, but with all the right flags toggled.
fn bitxor(self, other: $name) -> $name
{
$name {bits: self.bits ^ other.bits}
}
}
impl ::std::ops::BitAnd for $name
{
type Output = $name;
/// Returns the intersection between the two sets of flags.
fn bitand(self, other: $name) -> $name
{
$name {bits: self.bits & other.bits}
}
}
impl ::std::ops::Sub for $name
{
type Output = $name;
/// Returns the set difference of the two sets of flags.
fn sub(self, other: $name) -> $name
{
$name {bits: self.bits & !other.bits}
}
}
impl ::std::ops::Not for $name
{
type Output = $name;
/// Returns the complement of this set of flags.
fn not(self) -> $name
{
$name {bits: !self.bits} & $name::all()
}
}
impl ::std::fmt::Debug for $name
{
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result
{
write!(f, "{}", self.to_string())
}
}
impl ::std::fmt::Display for $name
{
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result
{
write!(f, "{}", self.to_string())
}
}
}
}

61
src/c_string.rs Normal file
View File

@ -0,0 +1,61 @@
use std::ffi::{CStr, CString};
use std::os::raw::c_char;
/// Defines an empty string.
pub const EMPTY_STRING: &'static str = "";
/// Creates a new String from the data in the pointer.
///
/// Any conversion errors will result in an Empty
/// String being returned. Option is not used here for
/// simplicities sake.
pub fn from_c_string(c_string: *const c_char) -> String
{
unsafe
{
CStr::from_ptr(c_string).to_string_lossy().into_owned()
}
}
/// Creates a CString from a given str.
///
/// This may be "" if there is an UTF8 conversion error.
/// If it can not create an empty CString, then it will panic.
pub fn to_c_string<P>(string: P) -> CString
where P: AsRef<str>
{
// Try to create a CString from the given str.
match CString::new(string.as_ref())
{
Ok(c_string) =>
{
// Return the new CString.
c_string
}
Err(error) =>
{
warn!("Unable to create a CString from the given str: {}", error);
// Try to atleast make an empty CString.
match CString::new(EMPTY_STRING)
{
Ok(c_string) =>
{
// Return the new CString.
c_string
}
Err(final_error) =>
{
// This is a show stopping error.
error!("Unable to create an empty CString: {}", final_error);
}
}
}
}
}

20
src/lib.rs Normal file
View File

@ -0,0 +1,20 @@
//! The Binding library is a place where common macros and functions
//! that are used when interfacing with C libraries can be stored
//! for use amoungst all of CyberMages LLC's projects.
#[macro_use]
extern crate scribe;
// Basic C type macro modules.
mod c_enum;
mod c_flags;
mod c_string;
// Raw platform data retrieval.
mod raw;
pub use self::c_string::{EMPTY_STRING, from_c_string, to_c_string};
pub use self::raw::{AsRaw, AsRawMut, AsRawPtr, AsRawMutPtr, FromRaw, IntoRaw};

45
src/raw.rs Normal file
View File

@ -0,0 +1,45 @@
/// Some times there are types that need to return a platform specific
/// data type that can be used by the platform specific functions. This
/// type creates a path to easily get that data.
pub trait AsRaw<T> where T: Sized
{
fn as_raw(&self) -> &T;
}
/// Some times there are types that need to return a platform specific
/// data type that can be used by the platform specific functions. This
/// type creates a path to easily get that data in a mutable manner.
pub trait AsRawMut<T> where T: Sized
{
fn as_raw_mut(&mut self) -> &mut T;
}
/// Some times there are types that need to return a platform specific
/// data type that can be used by the platform specific functions. This
/// type creates a path to easily get that data as a raw const pointer.
pub trait AsRawPtr<T> where T: Sized
{
fn as_raw_ptr(&self) -> *const T;
}
/// Some times there are types that need to return a platform specific
/// data type that can be used by the platform specific functions. This
/// type creates a path to easily get that data as a raw mutable pointer.
pub trait AsRawMutPtr<T> where T: Sized
{
fn as_raw_mut_ptr(&mut self) -> *mut T;
}
/// This makes it possible to create an object from a given piece of platform
/// specific data.
pub trait FromRaw<T>
{
fn from_raw(raw: T) -> Self;
}
/// This makes it possible to convert an object into platform
/// specific data.
pub trait IntoRaw<T>
{
fn into_raw(self) -> T;
}