Initial library commit.
This commit is contained in:
commit
ca780e71ef
17
.gitignore
vendored
Normal file
17
.gitignore
vendored
Normal 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
13
Cargo.toml
Normal 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
5
README.md
Normal 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
110
src/c_enum.rs
Normal 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
232
src/c_flags.rs
Normal 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
61
src/c_string.rs
Normal 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
20
src/lib.rs
Normal 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
45
src/raw.rs
Normal 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;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user