summaryrefslogtreecommitdiffstats
path: root/internals/src/utils/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'internals/src/utils/mod.rs')
-rw-r--r--internals/src/utils/mod.rs138
1 files changed, 138 insertions, 0 deletions
diff --git a/internals/src/utils/mod.rs b/internals/src/utils/mod.rs
new file mode 100644
index 0000000..55e27df
--- /dev/null
+++ b/internals/src/utils/mod.rs
@@ -0,0 +1,138 @@
+//! Some more general utilities.
+//!
+//! Or with other words, thinks which
+//! (currently) have no other place to
+//! be placed in.
+use std::any::TypeId;
+use std::cell::RefCell;
+use std::mem;
+use std::fmt::{self, Debug};
+
+
+/// Helper for implementing debug for an iterable think where the think on itself is irrelevant.
+pub struct DebugIterableOpaque<I> {
+ one_use_inner: RefCell<I>
+}
+
+impl<I> DebugIterableOpaque<I> {
+ pub fn new(one_use_inner: I) -> Self {
+ let one_use_inner = RefCell::new(one_use_inner);
+ DebugIterableOpaque { one_use_inner }
+ }
+}
+impl<I> Debug for DebugIterableOpaque<I>
+ where I: Iterator, I::Item: Debug
+{
+ fn fmt(&self, fter: &mut fmt::Formatter) -> fmt::Result {
+ let mut borrow = self.one_use_inner.borrow_mut();
+ fter.debug_list().entries(&mut *borrow).finish()
+ }
+}
+
+
+//FIXME[rust/fat pointer cast]: make it ?Sized once it's supported by rust
+///
+/// Used to undo type erasure in a generic context,
+/// roughly semantically eqivalent to creating a `&Any`
+/// type object from the input and then using `downcast_ref::<EXP>()`,
+/// except that it does not require the cration of a
+/// trait object as a step inbetween.
+///
+/// Note:
+/// This function can be used for some form of specialisation,
+/// (not just in a performence sense) but all "specialization path"
+/// have to be known when writing the unspeciallized version and
+/// it is easy to make functions behave in a unexpected (but safe)
+/// way so use with care.
+///
+///
+#[inline(always)]
+pub fn uneraser_ref<GOT: 'static, EXP: 'static>(inp: &GOT ) -> Option<&EXP> {
+ if TypeId::of::<GOT>() == TypeId::of::<EXP>() {
+ //SAFE: the GOT type is exact the same as the EXP type,
+ // the compiler just does not know this due to type erasure wrt.
+ // generic types
+ let res: &EXP = unsafe { mem::transmute::<&GOT, &EXP>(inp) };
+ Some( res )
+ } else {
+ None
+ }
+}
+
+
+//FIXME[rust/fat pointer cast]: make it ?Sized once it's supported by rust
+#[doc(hidden)]
+#[inline(always)]
+pub fn uneraser_mut<GOT: 'static, EXP: 'static>(inp: &mut GOT ) -> Option<&mut EXP> {
+ if TypeId::of::<GOT>() == TypeId::of::<EXP>() {
+ //SAFE: the GOT type is exact the same as the EXP type,
+ // the compiler just does not know this due to type erasure wrt.
+ // generic types
+ let res: &mut EXP = unsafe { mem::transmute::<&mut GOT, &mut EXP>(inp) };
+ Some( res )
+ } else {
+ None
+ }
+}
+
+//FIXME: only works if the rust compiler get's a bit more clever or a bit less (either is fine)
+//#[inline(always)]
+//pub fn uneraser<GOT: 'static, EXP: 'static>( inp: GOT ) -> Result<EXP, GOT> {
+// if TypeId::of::<GOT>() == TypeId::of::<EXP>() {
+// //SAFE: the GOT type is exact the same as the EXP type,
+// // the compiler just does not know this due to type erasure wrt.
+// // generic types
+// Ok( unsafe { mem::transmute::<GOT, EXP>( inp ) } )
+// } else {
+// Err( inp )
+// }
+//}
+
+//fn get_flat_byte_repr<T>(val: &T) -> Vec<u8> {
+// let count = mem::size_of::<T>();
+// let mut out = Vec::with_capacity(count);
+// let byte_ptr = val as *const T as *const u8;
+// for offset in 0..count {
+// out.push( unsafe {
+// *byte_ptr.offset(offset as isize)
+// })
+// }
+// out
+//}
+
+
+
+/// returns true if this a not first byte from a multi byte utf-8
+///
+/// This will return false:
+/// - on all us-ascii chars (as u8)
+/// - on the first byte of a multi-byte utf-8 char
+///
+pub fn is_utf8_continuation_byte(b: u8) -> bool {
+ // all additional bytes (and only them) in utf8 start with 0b10xxxxxx so while
+ (b & 0b11000000) == 0b10000000
+}
+
+/// Faster insertion of byte slices into a byte vector.
+pub fn vec_insert_bytes(target: &mut Vec<u8>, idx: usize, source: &[u8]) {
+ use std::ptr::copy;
+
+ let old_len = target.len();
+ let insertion_len = source.len();
+ let source_ptr = source.as_ptr();
+ let insertion_point = unsafe { target.as_mut_ptr().offset(idx as isize) };
+ let moved_data_len = old_len - idx;
+
+ target.reserve(insertion_len);
+
+ unsafe {
+ copy(/*src*/insertion_point,
+ /*dest*/insertion_point.offset(insertion_len as isize),
+ /*count*/moved_data_len);
+
+ copy(source_ptr, insertion_point, insertion_len);
+
+ //3. set the new len for the vec
+ target.set_len(old_len + insertion_len)
+ }
+} \ No newline at end of file