Skip to content

Commit

Permalink
1. Adding minor fixes
Browse files Browse the repository at this point in the history
2. Refactoring code
3. Improving examples
4. Improving documentation
  • Loading branch information
denisandroid committed May 12, 2024
1 parent 3f7f950 commit 0a0b214
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 125 deletions.
44 changes: 22 additions & 22 deletions examples/generic.rs
Original file line number Diff line number Diff line change
@@ -1,48 +1,48 @@
use cluFullTransmute::transmute_or_panic;
use core::fmt::Display;

// Implementation of a simple transmutation with a generic parameter inside.
/*
For example, let's write some code with a Drop trait that panics when dropped and
holds some data. We then transmute this data to another similar struct and check
that we have effectively overridden the Drop trait and have a different struct
with some data.
We can also remove the Drop trait altogether or do any number of other things.
*/

/// Struct to panic when dropped
#[derive(Debug)]
#[repr(transparent)]
struct A<T> {
#[allow(dead_code)]
data: T,
}
struct PanicWhenDrop<T>(T);

impl<T> Drop for A<T> {
impl<T> Drop for PanicWhenDrop<T> {
fn drop(&mut self) {
panic!("Invalid beh");
panic!("panic, discovered `drop(PanicWhenDrop);`");
}
}

/// Struct to print value when dropped
#[derive(Debug)]
#[repr(transparent)]
struct B<T>
struct PrintlnWhenDrop<T: Display>(T)
where
T: Display,
{
data: T,
}
T: Display;

impl<T> Drop for B<T>
impl<T> Drop for PrintlnWhenDrop<T>
where
T: Display,
{
fn drop(&mut self) {
println!("{}", self.data);
println!("println: {}", self.0);
}
}

fn main() {
let a: A<u16> = A {
// original and panic when falling
data: 1024,
};
println!("in: {:?}", a);
let a: PanicWhenDrop<u16> = PanicWhenDrop(1024);
println!("in a: {:?}", a);

let b: B<u16> = unsafe { transmute_or_panic(a) };
println!("out: {:?}", b);
let b: PrintlnWhenDrop<u16> = unsafe { transmute_or_panic(a as PanicWhenDrop<u16>) };
println!("out b: {:?}", b);

drop(b); // <--- println!
drop(b); // <--- drop, PrintlnWhenDrop!
}
142 changes: 41 additions & 101 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,136 +17,70 @@
A more complete and extended version of data type conversion without constraint checks.
# Library Features
1. Casting any type A to any type B with generic data without and with data dimension checking.
2. Ability to use transmutation in constant functions in very old versions of rust..
3. Possibility of delayed transmutation through contracts.
4. Ability to work without the standard library.
# !!! ATTENTION !!!
## !!! ATTENTION !!!
1. When converting types without checking the size of the data, you really need to understand what you are doing.
2. You must understand the specifics of the platform you are using.
# Use
### 1. Generic
## Example:
```rust
use core::fmt::Display;
use cluFullTransmute::transmute_or_panic;
use core::fmt::Display;
/// Implementation of a simple transmutation with a generic parameter inside.
/*
For example, let's write some code with a Drop trait that panics when dropped and
holds some data. We then transmute this data to another similar struct and check
that we have effectively overridden the Drop trait and have a different struct
with some data.
We can also remove the Drop trait altogether or do any number of other things.
*/
/// Struct to panic when dropped
#[derive(Debug)]
#[repr(transparent)]
struct A<T> {
#[allow(dead_code)]
data: T
}
struct PanicWhenDrop<T>(T);
impl<T> Drop for A<T> {
impl<T> Drop for PanicWhenDrop<T> {
fn drop(&mut self) {
panic!("Invalid beh");
panic!("panic, discovered `drop(PanicWhenDrop);`");
}
}
/// Struct to print value when dropped
#[derive(Debug)]
#[repr(transparent)]
struct B<T> where T: Display {
data: T,
}
impl<T> Drop for B<T> where T: Display {
struct PrintlnWhenDrop<T: Display>(T)
where
T: Display;
impl<T> Drop for PrintlnWhenDrop<T>
where
T: Display,
{
fn drop(&mut self) {
println!("{}", self.data);
println!("println: {}", self.0);
}
}
fn main() {
let a: A<u16> = A { // original and panic when falling
data: 1024
};
println!("in: {:?}", a);
let a: PanicWhenDrop<u16> = PanicWhenDrop(1024);
println!("in a: {:?}", a);
let b: B<u16> = unsafe { transmute_or_panic(a) };
println!("out: {:?}", b);
let b: PrintlnWhenDrop<u16> = unsafe { transmute_or_panic(a as PanicWhenDrop<u16>) };
println!("out b: {:?}", b);
drop(b); // <--- println!
drop(b); // <--- drop, PrintlnWhenDrop!
}
```
### 2. Contract
```rust
use cluFullTransmute::contract::Contract;
/*
For example, we will sign a contract to convert a String to a Vec<u8>,
although this may not be exactly the case.
## Library Features
Contracts are needed to create more secure APIs using transmutation in
situations where it can't be proven.
*/
///
struct MyData {
data: Contract<&'static str, &'static [u8]>,
}
impl MyData {
#[inline]
const fn new(data: &'static str) -> Self {
let data = unsafe {
// Contract::new_checksize_or_panic
//
// The `new_checksize_or_panic` function can only guarantee equality of data
// dimensions, creating a contract is always unsafe, since the transmutation
// of such data types can only be proven orally. But after signing the
// transmutation contract, all functions for working with the transmuted are
// not marked as unsafe.
//
Contract::new_checksize_or_panic(data)
};
Self {
data,
}
}
#[inline]
pub fn as_data(&self) -> &'static str {
&self.data
}
#[inline]
pub fn as_sliceu8(&self) -> &'static [u8] {
self.data.as_datato()
}
#[inline]
pub fn into(self) -> &'static [u8] {
self.data.into()
}
}
fn main() {
const C_DATA: &'static str = "Test";
// &'static str
let data = MyData::new(C_DATA);
assert_eq!(data.as_data(), C_DATA); // const_readtype: &'static str
assert_eq!(data.as_sliceu8(), C_DATA.as_bytes()); //const_readtype &'static [u8]
//
// &'static u8
let vec = data.into(); // const_transmute: &'static str -> &'static [u8]
assert_eq!(vec, C_DATA.as_bytes());
}
```
1. Casting any type A to any type B with generic data without and with data dimension checking.
2. Ability to use transmutation in constant functions in very old versions of rust..
3. Possibility of delayed transmutation through contracts.
4. Ability to work without the standard library.
*/

Expand All @@ -173,6 +107,8 @@ pub mod mem {
pub use crate::raw::unchecked_transmute;
}

#[cfg_attr(docsrs, doc(cfg(feature = "support_size_check_transmute")))]
#[cfg(any(test, feature = "support_size_check_transmute"))]
pub mod err;
pub mod raw;

Expand All @@ -184,7 +120,11 @@ pub mod to;
#[cfg(any(test, feature = "contract"))]
pub mod contract;

#[cfg_attr(docsrs, doc(cfg(feature = "support_size_check_transmute")))]
#[cfg(any(test, feature = "support_size_check_transmute"))]
use crate::err::TransmuteErr;
#[cfg_attr(docsrs, doc(cfg(feature = "support_size_check_transmute")))]
#[cfg(any(test, feature = "support_size_check_transmute"))]
use crate::err::TransmuteErrKind;
#[cfg_attr(docsrs, doc(cfg(feature = "inline")))]
#[cfg(any(test, feature = "inline"))]
Expand Down
2 changes: 2 additions & 0 deletions tests/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ use core::hash::{Hash, Hasher};
use core::mem::MaybeUninit;
use std::collections::hash_map::DefaultHasher;

#[cfg_attr(docsrs, doc(cfg(feature = "contract")))]
#[cfg(any(test, feature = "contract"))]
#[test]
fn test_maybe_transmute_correct_struct() {
use cluFullTransmute::contract::Contract;
Expand Down
3 changes: 2 additions & 1 deletion tests/struct.rs → tests/drop.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use cluFullTransmute::unchecked_transmute;
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};

Expand Down Expand Up @@ -52,7 +53,7 @@ fn full_transmute_correct() {
hasher.finish()
};

let b: B = unsafe { cluFullTransmute::mem::unchecked_transmute(a) };
let b: B = unsafe { unchecked_transmute(a) };
let b_hash = {
let mut hasher = DefaultHasher::new();
b.hash(&mut hasher);
Expand Down
3 changes: 2 additions & 1 deletion tests/generic.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use cluFullTransmute::unchecked_transmute;
use std::collections::hash_map::DefaultHasher;
use std::hash::Hash;
use std::hash::Hasher;
Expand Down Expand Up @@ -50,7 +51,7 @@ fn easy_full_transmute_correct() {
hasher.finish()
};

let b: B = unsafe { cluFullTransmute::mem::unchecked_transmute(a) };
let b: B = unsafe { unchecked_transmute(a) };
let b_hash = {
let mut hasher = DefaultHasher::new();
b.hash(&mut hasher);
Expand Down

0 comments on commit 0a0b214

Please sign in to comment.