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