Initial commit
This commit is contained in:
commit
87334384f9
15 changed files with 801 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
Cargo.lock
|
||||
target/
|
7
.vscode/settings.json
vendored
Normal file
7
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"workbench.colorCustomizations": {
|
||||
"activityBar.background": "#551A02",
|
||||
"titleBar.activeBackground": "#772503",
|
||||
"titleBar.activeForeground": "#FFF9F6"
|
||||
}
|
||||
}
|
17
Cargo.toml
Normal file
17
Cargo.toml
Normal file
|
@ -0,0 +1,17 @@
|
|||
[package]
|
||||
name = "utilities"
|
||||
version = "0.1.0"
|
||||
authors = ["hodasemi <michaelh.95@t-online.de>"]
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
cgmath = { version = "0.18.0", features = ["swizzle"] }
|
||||
rand = "0.8.5"
|
||||
backtrace = "0.3.67"
|
||||
assetpath = { git = "https://gavania.de/hodasemi/vulkan_lib.git" }
|
||||
anyhow = { version = "1.0.68", features = ["backtrace"] }
|
||||
|
||||
# networking
|
||||
serde = { version = "1.0.152", features = ["derive"] }
|
||||
|
||||
|
59
src/arc_unique_vec.rs
Normal file
59
src/arc_unique_vec.rs
Normal file
|
@ -0,0 +1,59 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
/// Wrapper around a `Vec` if `Rc`,
|
||||
/// that ensures pointer uniqueness of its elements
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct ArcUniqueVec<T> {
|
||||
data: Vec<Arc<T>>,
|
||||
}
|
||||
|
||||
impl<T> ArcUniqueVec<T> {
|
||||
/// Creates an empty `RcUniqueVec`
|
||||
pub fn new() -> ArcUniqueVec<T> {
|
||||
ArcUniqueVec { data: Vec::new() }
|
||||
}
|
||||
|
||||
/// Checks for pointer collision while inserting.
|
||||
/// Returns the index for the position of the inserted element.
|
||||
pub fn insert(&mut self, element: Arc<T>) -> usize {
|
||||
match self.data.iter().position(|t| Arc::ptr_eq(t, &element)) {
|
||||
Some(index) => index,
|
||||
None => {
|
||||
let index = self.data.len();
|
||||
self.data.push(element);
|
||||
index
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if the given element is in the vector, then returns true,
|
||||
/// otherwise false.
|
||||
pub fn remove(&mut self, element: &Arc<T>) -> bool {
|
||||
match self.data.iter().position(|t| Arc::ptr_eq(t, element)) {
|
||||
Some(index) => {
|
||||
self.data.remove(index);
|
||||
true
|
||||
}
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if that element is in this `RcUniqueVec`
|
||||
/// and returns its index if possible
|
||||
pub fn get_index(&self, element: &Arc<T>) -> Option<usize> {
|
||||
match self.data.iter().position(|t| Arc::ptr_eq(t, element)) {
|
||||
Some(index) => Some(index),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Clears all elements from this vector
|
||||
pub fn clear(&mut self) {
|
||||
self.data.clear();
|
||||
}
|
||||
|
||||
/// Returns the reference to the internal vector
|
||||
pub fn as_vec(&self) -> &Vec<Arc<T>> {
|
||||
&self.data
|
||||
}
|
||||
}
|
92
src/asyncthread.rs
Normal file
92
src/asyncthread.rs
Normal file
|
@ -0,0 +1,92 @@
|
|||
//! Asynchronous thread to check if result is returned (non-blocking)
|
||||
|
||||
use std::sync::{mpsc, RwLock};
|
||||
use std::thread;
|
||||
|
||||
/// Asynchronous thread handle
|
||||
pub struct AsyncThread<T: Send + Sync + 'static> {
|
||||
receiver: mpsc::Receiver<T>,
|
||||
result: RwLock<Option<T>>,
|
||||
}
|
||||
|
||||
impl<T: Send + Sync + 'static> AsyncThread<T> {
|
||||
/// Spawns a thread
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// `f` is a function to be executed in a separate thread
|
||||
pub fn spawn<F>(f: F) -> AsyncThread<T>
|
||||
where
|
||||
F: FnOnce() -> T,
|
||||
F: Send + 'static,
|
||||
{
|
||||
let (sender, receiver) = mpsc::channel();
|
||||
|
||||
thread::spawn(move || {
|
||||
if let Err(err) = sender.send((f)()) {
|
||||
panic!("sending failed! ({})", err);
|
||||
}
|
||||
});
|
||||
|
||||
AsyncThread {
|
||||
receiver,
|
||||
result: RwLock::new(None),
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if the thread is already returned
|
||||
/// Returns the Some(result) if the thread has finished its work,
|
||||
/// otherwise None
|
||||
pub fn check(&self) -> Result<bool, anyhow::Error> {
|
||||
let mut result = self
|
||||
.result
|
||||
.write()
|
||||
.map_err(|_err| anyhow::Error::msg("Asyncthread: Failed getting write lock"))?;
|
||||
|
||||
match result.as_ref() {
|
||||
Some(_) => Ok(true),
|
||||
None => match self.receiver.try_recv() {
|
||||
Ok(res) => {
|
||||
*result = Some(res);
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
Err(_) => Ok(false),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// consumes the result
|
||||
pub fn take(&self) -> Result<T, anyhow::Error> {
|
||||
let mut result = self
|
||||
.result
|
||||
.write()
|
||||
.map_err(|_err| anyhow::Error::msg("Asyncthread: Failed getting write lock"))?;
|
||||
|
||||
if result.is_some() {
|
||||
// actually safe to not panic, since we just checked
|
||||
let res = result.take().unwrap();
|
||||
|
||||
Ok(res)
|
||||
} else {
|
||||
Err(anyhow::Error::msg("Asyncthread: Result not present"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send + Sync + 'static> AsyncThread<T>
|
||||
where
|
||||
T: Clone,
|
||||
{
|
||||
pub fn get(&self) -> Result<T, anyhow::Error> {
|
||||
let result = self
|
||||
.result
|
||||
.read()
|
||||
.map_err(|_err| anyhow::Error::msg("Asyncthread: Failed getting write lock"))?;
|
||||
|
||||
match result.as_ref() {
|
||||
Some(res) => Ok(res.clone()),
|
||||
None => Err(anyhow::Error::msg("Asyncthread: Result not present")),
|
||||
}
|
||||
}
|
||||
}
|
83
src/closures.rs
Normal file
83
src/closures.rs
Normal file
|
@ -0,0 +1,83 @@
|
|||
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
// !!!!!!!!!!! very unstable, use at your own risk !!!!!!!!!!!!!!!!!
|
||||
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
use super::prelude::*;
|
||||
use std::ops::Fn;
|
||||
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const void: () = ();
|
||||
|
||||
pub struct Callback {
|
||||
function: FunctionType,
|
||||
}
|
||||
|
||||
impl Callback {
|
||||
pub fn new<F, Args>(function: F) -> Callback
|
||||
where
|
||||
F: Fn(Args) -> (),
|
||||
F: 'static,
|
||||
FunctionType: FunctionTypeCreator<F, Args>,
|
||||
{
|
||||
Callback {
|
||||
function: FunctionType::new(function),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn execute<Args>(&self, arguments: Args)
|
||||
where
|
||||
FunctionType: FunctionTypeExecutorOneArg<Args>,
|
||||
{
|
||||
display_error!(self.function.execute(arguments));
|
||||
}
|
||||
}
|
||||
|
||||
pub trait FunctionTypeCreator<F: Fn(Args) -> () + 'static, Args> {
|
||||
fn new(function: F) -> FunctionType;
|
||||
}
|
||||
|
||||
pub trait FunctionTypeExecutorOneArg<Args> {
|
||||
fn execute(&self, execute: Args) -> VerboseResult<()>;
|
||||
}
|
||||
|
||||
macro_rules! build_function_type {
|
||||
($struct_name: ident, $($ty: ty, $name: ident), *) => {
|
||||
pub enum $struct_name {
|
||||
$($name(Box<dyn Fn($ty)>)),*
|
||||
}
|
||||
|
||||
$(
|
||||
impl<F: Fn($ty) -> () + 'static> FunctionTypeCreator<F, $ty> for $struct_name {
|
||||
fn new(function: F) -> FunctionType {
|
||||
$struct_name::$name(Box::new(function))
|
||||
}
|
||||
}
|
||||
|
||||
impl FunctionTypeExecutorOneArg<$ty> for $struct_name {
|
||||
fn execute(&self, args: $ty) -> VerboseResult<()> {
|
||||
match self {
|
||||
FunctionType::$name(ref function) => {
|
||||
(function)(args);
|
||||
Ok(())
|
||||
}
|
||||
_ => {
|
||||
create_error!("wrong argument type for this callback");
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
) *
|
||||
}
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
build_function_type!(
|
||||
FunctionType,
|
||||
String, String,
|
||||
i32, I32,
|
||||
u32, U32,
|
||||
f32, F32,
|
||||
(), Void
|
||||
);
|
167
src/color.rs
Normal file
167
src/color.rs
Normal file
|
@ -0,0 +1,167 @@
|
|||
use std::fmt;
|
||||
use std::ops::MulAssign;
|
||||
use std::str::FromStr;
|
||||
use std::{convert::TryFrom, ops::Mul};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// `TextColor` describes the color of the text
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
|
||||
pub enum Color {
|
||||
White,
|
||||
Black,
|
||||
Red,
|
||||
Blue,
|
||||
Green,
|
||||
Orange,
|
||||
Yellow,
|
||||
Custom(u8, u8, u8),
|
||||
}
|
||||
|
||||
impl Into<[f32; 3]> for Color {
|
||||
fn into(self) -> [f32; 3] {
|
||||
match self {
|
||||
Color::White => [1.0, 1.0, 1.0],
|
||||
Color::Black => [0.0, 0.0, 0.0],
|
||||
Color::Red => [1.0, 0.0, 0.0],
|
||||
Color::Blue => [0.0, 0.0, 1.0],
|
||||
Color::Green => [0.0, 1.0, 0.0],
|
||||
Color::Orange => [1.0, 0.65, 0.0],
|
||||
Color::Yellow => [1.0, 1.0, 0.0],
|
||||
Color::Custom(r, g, b) => [r as f32 / 255.0, g as f32 / 255.0, b as f32 / 255.0],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<[u8; 3]> for Color {
|
||||
fn into(self) -> [u8; 3] {
|
||||
match self {
|
||||
Color::White => [255, 255, 255],
|
||||
Color::Black => [0, 0, 0],
|
||||
Color::Red => [255, 0, 0],
|
||||
Color::Blue => [0, 0, 255],
|
||||
Color::Green => [0, 255, 0],
|
||||
Color::Orange => [255, 166, 0],
|
||||
Color::Yellow => [255, 255, 0],
|
||||
Color::Custom(r, g, b) => [r, g, b],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<f32> for Color {
|
||||
type Output = Self;
|
||||
|
||||
fn mul(self, rhs: f32) -> Self::Output {
|
||||
let values: [f32; 3] = self.into();
|
||||
|
||||
let r = (values[0] * rhs).min(1.0);
|
||||
let g = (values[1] * rhs).min(1.0);
|
||||
let b = (values[2] * rhs).min(1.0);
|
||||
|
||||
Color::from([r, g, b])
|
||||
}
|
||||
}
|
||||
|
||||
impl MulAssign<f32> for Color {
|
||||
fn mul_assign(&mut self, rhs: f32) {
|
||||
*self = *self * rhs;
|
||||
}
|
||||
}
|
||||
|
||||
impl From<[u8; 3]> for Color {
|
||||
fn from(array: [u8; 3]) -> Self {
|
||||
Self::Custom(array[0], array[1], array[2])
|
||||
}
|
||||
}
|
||||
|
||||
impl From<[f32; 3]> for Color {
|
||||
fn from(array: [f32; 3]) -> Self {
|
||||
Self::Custom(
|
||||
(array[0] * 255.0).min(255.0) as u8,
|
||||
(array[1] * 255.0).min(255.0) as u8,
|
||||
(array[2] * 255.0).min(255.0) as u8,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&str> for Color {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn try_from(text: &str) -> Result<Color, Self::Error> {
|
||||
// check if color is a hex value
|
||||
if text.starts_with("#") {
|
||||
let without_prefix = text.trim_start_matches("#");
|
||||
|
||||
if without_prefix.len() != 6 {
|
||||
return Err(anyhow::Error::msg(format!(
|
||||
"Hex color format has wrong format: {}",
|
||||
without_prefix
|
||||
)));
|
||||
}
|
||||
|
||||
let r = u8::from_str_radix(&without_prefix[0..2], 16)?;
|
||||
let g = u8::from_str_radix(&without_prefix[2..4], 16)?;
|
||||
let b = u8::from_str_radix(&without_prefix[4..6], 16)?;
|
||||
|
||||
return Ok(Color::Custom(r, g, b));
|
||||
}
|
||||
|
||||
match text {
|
||||
"white" => Ok(Color::White),
|
||||
"black" => Ok(Color::Black),
|
||||
"red" => Ok(Color::Red),
|
||||
"blue" => Ok(Color::Blue),
|
||||
"green" => Ok(Color::Green),
|
||||
"orange" => Ok(Color::Orange),
|
||||
"yellow" => Ok(Color::Yellow),
|
||||
_ => Err(anyhow::Error::msg(format!("Unknown color: {}", text))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Color {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Color::White => write!(f, "white"),
|
||||
Color::Black => write!(f, "black"),
|
||||
Color::Red => write!(f, "red"),
|
||||
Color::Blue => write!(f, "blue"),
|
||||
Color::Green => write!(f, "green"),
|
||||
Color::Orange => write!(f, "orange"),
|
||||
Color::Yellow => write!(f, "yellow"),
|
||||
Color::Custom(r, g, b) => write!(f, "#{:X?}{:X?}{:X?}", r, g, b),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Color {
|
||||
type Err = anyhow::Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Self::try_from(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Color {
|
||||
fn default() -> Self {
|
||||
Self::Black
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn simple_color_conversion() {
|
||||
let color = Color::try_from("white").unwrap();
|
||||
|
||||
assert_eq!(color, Color::White);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hex_color_conversion() {
|
||||
let color = Color::try_from("#FFFFFF").unwrap();
|
||||
|
||||
assert_eq!(color, Color::Custom(255, 255, 255));
|
||||
|
||||
let string = format!("{}", color);
|
||||
|
||||
assert_eq!(string, "#FFFFFF");
|
||||
}
|
36
src/future.rs
Normal file
36
src/future.rs
Normal file
|
@ -0,0 +1,36 @@
|
|||
use std::cell::{Ref, RefCell};
|
||||
use std::thread::{spawn, JoinHandle};
|
||||
|
||||
pub struct Future<T: Send + 'static> {
|
||||
thread: RefCell<Option<JoinHandle<T>>>,
|
||||
data: RefCell<Option<T>>,
|
||||
}
|
||||
|
||||
impl<T: Send + 'static> Future<T> {
|
||||
pub fn new<F>(f: F) -> Future<T>
|
||||
where
|
||||
F: Fn() -> T,
|
||||
F: Send + 'static,
|
||||
{
|
||||
let thread = spawn(f);
|
||||
|
||||
Future {
|
||||
thread: RefCell::new(Some(thread)),
|
||||
data: RefCell::new(None),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn data(&self) -> Ref<'_, Option<T>> {
|
||||
let mut thread_opt = self.thread.borrow_mut();
|
||||
|
||||
if thread_opt.is_some() {
|
||||
let thread_tmp = thread_opt.take();
|
||||
let thread = thread_tmp.unwrap();
|
||||
if let Ok(data) = thread.join() {
|
||||
self.data.replace(Some(data));
|
||||
}
|
||||
}
|
||||
|
||||
self.data.borrow()
|
||||
}
|
||||
}
|
142
src/helperfunctions.rs
Normal file
142
src/helperfunctions.rs
Normal file
|
@ -0,0 +1,142 @@
|
|||
//! Basic helper functions
|
||||
|
||||
use std::fs;
|
||||
use std::io::ErrorKind;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
|
||||
use std::ffi::CStr;
|
||||
use std::os::raw::c_char;
|
||||
|
||||
use assetpath::AssetPath;
|
||||
use cgmath;
|
||||
use cgmath::One;
|
||||
|
||||
pub fn erase_by_ptr<T>(vector: &mut Vec<T>, object: &T) -> bool {
|
||||
match vector
|
||||
.iter()
|
||||
.position(|t| t as *const T == object as *const T)
|
||||
{
|
||||
Some(i) => {
|
||||
vector.remove(i);
|
||||
true
|
||||
}
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn erase_arc<T: ?Sized>(vector: &mut Vec<Arc<T>>, object: &Arc<T>) -> Option<Arc<T>> {
|
||||
match vector.iter().position(|t| Arc::ptr_eq(t, object)) {
|
||||
Some(i) => Some(vector.remove(i)),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn erase_rc<T: ?Sized>(vector: &mut Vec<Rc<T>>, object: &Rc<T>) -> Option<Rc<T>> {
|
||||
match vector.iter().position(|t| Rc::ptr_eq(t, object)) {
|
||||
Some(i) => Some(vector.remove(i)),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ortho(
|
||||
left: f32,
|
||||
right: f32,
|
||||
bottom: f32,
|
||||
top: f32,
|
||||
z_near: f32,
|
||||
z_far: f32,
|
||||
) -> cgmath::Matrix4<f32> {
|
||||
let mut mat = cgmath::Matrix4::one();
|
||||
|
||||
mat[0][0] = 2.0 / (right - left);
|
||||
mat[1][1] = -2.0 / (top - bottom);
|
||||
mat[2][2] = -2.0 / (z_far - z_near);
|
||||
mat[3][0] = -(right + left) / (right - left);
|
||||
mat[3][1] = -(top + bottom) / (top - bottom);
|
||||
mat[3][2] = -(z_far + z_near) / (z_far - z_near);
|
||||
|
||||
mat
|
||||
}
|
||||
|
||||
pub fn search_dir_recursively(
|
||||
base_dir: &str,
|
||||
suffix: &str,
|
||||
) -> Result<Vec<AssetPath>, std::io::Error> {
|
||||
let mut files = Vec::new();
|
||||
|
||||
// simply return an empty result when the path could not be found
|
||||
// or the user has a lack of permissions
|
||||
let dir_content = match fs::read_dir(base_dir) {
|
||||
Ok(dir) => dir,
|
||||
Err(err) => match err.kind() {
|
||||
ErrorKind::NotFound | ErrorKind::PermissionDenied => return Ok(files),
|
||||
_ => return Err(err),
|
||||
},
|
||||
};
|
||||
|
||||
for fs_object in dir_content {
|
||||
let obj = fs_object?;
|
||||
|
||||
let path = obj.path();
|
||||
|
||||
if path.is_file() {
|
||||
if let Some(os_str) = path.file_name() {
|
||||
if let Some(string) = os_str.to_str() {
|
||||
if string.ends_with(suffix) {
|
||||
files.push(AssetPath::from((base_dir, string)));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if let Some(string) = path.to_str() {
|
||||
let more_files = search_dir_recursively(string, suffix)?;
|
||||
files.extend(more_files);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(files)
|
||||
}
|
||||
|
||||
pub unsafe fn c_char_to_string(cchar: *const c_char) -> String {
|
||||
CStr::from_ptr(cchar).to_str().unwrap().to_string()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn perspective(fov_y: f32, aspect: f32, z_near: f32, z_far: f32) -> cgmath::Matrix4<f32> {
|
||||
debug_assert!(z_near != 0.0);
|
||||
|
||||
let zero = 0.0;
|
||||
let one = 1.0;
|
||||
let two = 2.0;
|
||||
let q = one / (fov_y / two).tan();
|
||||
let a = q / aspect;
|
||||
let b = (z_near + z_far) / (z_near - z_far);
|
||||
let c = (two * z_near * z_far) / (z_near - z_far);
|
||||
|
||||
#[cfg_attr(rustfmt, rustfmt_skip)]
|
||||
cgmath::Matrix4::new(
|
||||
a, zero, zero, zero,
|
||||
zero, -q, zero, zero,
|
||||
zero, zero, b, zero - one,
|
||||
zero, zero, c, zero,
|
||||
)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn rotate_z(v: cgmath::Vector3<f32>, angle: f32) -> cgmath::Vector3<f32> {
|
||||
let mut result = v;
|
||||
let cos = angle.cos();
|
||||
let sin = angle.sin();
|
||||
|
||||
result.x = v.x * cos - v.y * sin;
|
||||
result.y = v.x * sin + v.y * cos;
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn almost_eq(f1: f32, f2: f32) -> bool {
|
||||
(f1 - f2).abs() <= std::f32::EPSILON
|
||||
}
|
17
src/lib.rs
Normal file
17
src/lib.rs
Normal file
|
@ -0,0 +1,17 @@
|
|||
#![deny(rust_2018_idioms)]
|
||||
|
||||
pub mod asyncthread;
|
||||
pub mod random;
|
||||
//pub mod hashvector;
|
||||
pub mod color;
|
||||
pub mod future;
|
||||
pub mod helperfunctions;
|
||||
pub mod prelude;
|
||||
//pub mod closures;
|
||||
|
||||
pub mod try_lock_guard;
|
||||
|
||||
pub mod arc_unique_vec;
|
||||
pub mod rc_unique_vec;
|
||||
|
||||
pub mod unsafe_life_time;
|
29
src/prelude.rs
Normal file
29
src/prelude.rs
Normal file
|
@ -0,0 +1,29 @@
|
|||
// crates
|
||||
pub use cgmath;
|
||||
|
||||
// functions
|
||||
pub use crate::helperfunctions::*;
|
||||
|
||||
// async thread
|
||||
pub use crate::asyncthread::AsyncThread;
|
||||
|
||||
pub use crate::future::Future;
|
||||
|
||||
// Coin
|
||||
pub use crate::random::{Coin, Random};
|
||||
|
||||
// Unique vectors
|
||||
pub use crate::arc_unique_vec::ArcUniqueVec;
|
||||
pub use crate::rc_unique_vec::RcUniqueVec;
|
||||
|
||||
// rand crate
|
||||
pub use rand;
|
||||
|
||||
// color
|
||||
pub use crate::color::*;
|
||||
|
||||
// TryLockGuard
|
||||
pub use crate::try_lock_guard::TryLockGuard;
|
||||
|
||||
// unsafe life time trickery
|
||||
pub use crate::unsafe_life_time::*;
|
43
src/random.rs
Normal file
43
src/random.rs
Normal file
|
@ -0,0 +1,43 @@
|
|||
use rand::Rng;
|
||||
|
||||
pub struct Coin;
|
||||
|
||||
impl Coin {
|
||||
pub fn flip(probability: f32) -> bool {
|
||||
if probability >= 1.0 {
|
||||
return true;
|
||||
}
|
||||
|
||||
if probability <= 0.0 {
|
||||
return false;
|
||||
}
|
||||
|
||||
let random_number = Self::raw();
|
||||
|
||||
probability > random_number
|
||||
}
|
||||
|
||||
pub fn raw() -> f32 {
|
||||
rand::thread_rng().gen_range(0.0..1.0)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Random;
|
||||
|
||||
impl Random {
|
||||
pub fn range(low: u32, high: u32) -> u32 {
|
||||
if low == high {
|
||||
return low;
|
||||
}
|
||||
|
||||
rand::thread_rng().gen_range(low..high)
|
||||
}
|
||||
|
||||
pub fn range_f32(low: f32, high: f32) -> f32 {
|
||||
if low == high {
|
||||
return low;
|
||||
}
|
||||
|
||||
rand::thread_rng().gen_range(low..high)
|
||||
}
|
||||
}
|
59
src/rc_unique_vec.rs
Normal file
59
src/rc_unique_vec.rs
Normal file
|
@ -0,0 +1,59 @@
|
|||
use std::rc::Rc;
|
||||
|
||||
/// Wrapper around a `Vec` if `Rc`,
|
||||
/// that ensures pointer uniqueness of its elements
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct RcUniqueVec<T> {
|
||||
data: Vec<Rc<T>>,
|
||||
}
|
||||
|
||||
impl<T> RcUniqueVec<T> {
|
||||
/// Creates an empty `RcUniqueVec`
|
||||
pub fn new() -> RcUniqueVec<T> {
|
||||
RcUniqueVec { data: Vec::new() }
|
||||
}
|
||||
|
||||
/// Checks for pointer collision while inserting.
|
||||
/// Returns the index for the position of the inserted element.
|
||||
pub fn insert(&mut self, element: Rc<T>) -> usize {
|
||||
match self.data.iter().position(|t| Rc::ptr_eq(t, &element)) {
|
||||
Some(index) => index,
|
||||
None => {
|
||||
let index = self.data.len();
|
||||
self.data.push(element);
|
||||
index
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if the given element is in the vector, then returns true,
|
||||
/// otherwise false.
|
||||
pub fn remove(&mut self, element: &Rc<T>) -> bool {
|
||||
match self.data.iter().position(|t| Rc::ptr_eq(t, element)) {
|
||||
Some(index) => {
|
||||
self.data.remove(index);
|
||||
true
|
||||
}
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if that element is in this `RcUniqueVec`
|
||||
/// and returns its index if possible
|
||||
pub fn get_index(&self, element: &Rc<T>) -> Option<usize> {
|
||||
match self.data.iter().position(|t| Rc::ptr_eq(t, element)) {
|
||||
Some(index) => Some(index),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Clears all elements from this vector
|
||||
pub fn clear(&mut self) {
|
||||
self.data.clear();
|
||||
}
|
||||
|
||||
/// Returns the reference to the internal vector
|
||||
pub fn as_vec(&self) -> &Vec<Rc<T>> {
|
||||
&self.data
|
||||
}
|
||||
}
|
41
src/try_lock_guard.rs
Normal file
41
src/try_lock_guard.rs
Normal file
|
@ -0,0 +1,41 @@
|
|||
use std::sync::{LockResult, Mutex, MutexGuard, PoisonError, TryLockError};
|
||||
|
||||
pub enum TryLockGuard<'a, T> {
|
||||
Lock(MutexGuard<'a, T>),
|
||||
WouldBlock(&'a Mutex<T>),
|
||||
}
|
||||
|
||||
impl<'a, T> TryLockGuard<'a, T> {
|
||||
pub fn try_lock(
|
||||
d: &'a Mutex<T>,
|
||||
) -> Result<TryLockGuard<'a, T>, PoisonError<MutexGuard<'a, T>>> {
|
||||
match d.try_lock() {
|
||||
Ok(lock) => Ok(TryLockGuard::Lock(lock)),
|
||||
Err(try_lock_error) => match try_lock_error {
|
||||
TryLockError::Poisoned(poison_error) => Err(poison_error),
|
||||
TryLockError::WouldBlock => Ok(TryLockGuard::WouldBlock(d)),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn would_block(&self) -> bool {
|
||||
match self {
|
||||
Self::Lock(_) => false,
|
||||
Self::WouldBlock(_) => true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn guard(self) -> Option<MutexGuard<'a, T>> {
|
||||
match self {
|
||||
Self::Lock(guard) => Some(guard),
|
||||
Self::WouldBlock(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lock(self) -> LockResult<MutexGuard<'a, T>> {
|
||||
match self {
|
||||
Self::Lock(guard) => Ok(guard),
|
||||
Self::WouldBlock(mutex) => Ok(mutex.lock()?),
|
||||
}
|
||||
}
|
||||
}
|
7
src/unsafe_life_time.rs
Normal file
7
src/unsafe_life_time.rs
Normal file
|
@ -0,0 +1,7 @@
|
|||
pub unsafe fn remove_life_time_mut<'a, 'b, T>(t: &'a mut T) -> &'b mut T {
|
||||
std::mem::transmute(t as *mut T)
|
||||
}
|
||||
|
||||
pub unsafe fn remove_life_time<'a, 'b, T>(t: &'a T) -> &'b T {
|
||||
std::mem::transmute(t as *const T)
|
||||
}
|
Loading…
Reference in a new issue