Created
October 22, 2018 13:57
-
-
Save xiaoniu-578fa6bff964d005/e5c8a70080dc881cbd6ae838993825bb to your computer and use it in GitHub Desktop.
Is it possible to unchecked unwrap Option with safety?
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
mod approach5 { | |
mod variance { | |
use std::marker::PhantomData; | |
use std::fmt; | |
use std::hash::{Hash, Hasher}; | |
use std::cmp::Ordering; | |
/// A marker for forcing T to be considered invariant. | |
// *mut T is invariant in T | |
pub struct Invariant<T>(PhantomData<*mut T>); | |
impl<T> Invariant<T> { | |
/// Create a new Invariant marker instance. | |
/// | |
/// All instances of Invariant with the same T are equivalent. | |
#[inline] | |
pub fn new() -> Self { Invariant(PhantomData) } | |
} | |
impl<T> Default for Invariant<T> { | |
#[inline] | |
fn default() -> Self { Invariant::new() } | |
} | |
impl<T> Copy for Invariant<T> {} | |
impl<T> Clone for Invariant<T> { | |
#[inline] | |
fn clone(&self) -> Self { Invariant::new() } | |
} | |
impl<T> fmt::Debug for Invariant<T> { | |
#[inline] | |
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
f.write_str("Invariant Type Marker") | |
} | |
} | |
impl<T> PartialEq<Invariant<T>> for Invariant<T> { | |
#[inline] | |
fn eq(&self, _: &Self) -> bool { true } | |
#[inline] | |
fn ne(&self, _: &Self) -> bool { false } | |
} | |
impl<T> PartialOrd<Invariant<T>> for Invariant<T> { | |
#[inline] | |
fn partial_cmp(&self, _: &Self) -> Option<Ordering> { | |
Some(Ordering::Equal) | |
} | |
#[inline] | |
fn lt(&self, _: &Self) -> bool { false } | |
#[inline] | |
fn le(&self, _: &Self) -> bool { true } | |
#[inline] | |
fn gt(&self, _: &Self) -> bool { false } | |
#[inline] | |
fn ge(&self, _: &Self) -> bool { true } | |
} | |
impl<T> Eq for Invariant<T> {} | |
impl<T> Ord for Invariant<T> { | |
#[inline] | |
fn cmp(&self, _: &Self) -> Ordering { Ordering::Equal } | |
} | |
impl<T> Hash for Invariant<T> { | |
#[inline] | |
fn hash<H: Hasher>(&self, state: &mut H) { | |
().hash(state) | |
} | |
} | |
} | |
#[macro_use] | |
mod fixobj { | |
// extern crate variance; | |
// use self::variance::Invariant; | |
use super::variance::Invariant; | |
/// solidify the lifetime. | |
pub struct FixRange<'a,T: 'a> (Invariant<&'a T>); | |
impl<'a,T: 'a> FixRange<'a, T> { | |
pub fn new(_: &'a &'a T) -> Self { | |
FixRange(Invariant::new()) | |
} | |
} | |
impl<'a, T> Copy for FixRange<'a, T> {} | |
impl<'a, T> Clone for FixRange<'a, T> { | |
#[inline] | |
fn clone(&self) -> Self { FixRange(Invariant::new()) } | |
} | |
/// ensure that value don't change in lifetiem 'a | |
pub struct FixObj<'a,T: 'a> (&'a T, FixRange<'a, T>); | |
impl<'a,T: 'a> FixObj<'a, T> { | |
pub fn new(c: &'a &'a T) -> Self { FixObj(c, FixRange::new(c)) } | |
pub fn get<'b>(&'b self) -> &'b T where 'a: 'b{ self.0 } | |
pub fn get_range<'b>(&'b self) -> FixRange<'a, T> { self.1 } | |
} | |
impl<'a, T> Copy for FixObj<'a, T> {} | |
impl<'a, T> Clone for FixObj<'a, T> { | |
#[inline] | |
fn clone(&self) -> Self { FixObj(self.0,self.1) } | |
} | |
#[macro_export] | |
macro_rules! fix { ($x:ident, $f:ident) => (let reference = &$x; let $f = FixObj::new(&reference);) } | |
} | |
mod prechecked_option { | |
use super::fixobj::*; | |
/// T should be an Option<U> | |
/// In the range of Fix<'a, T>, guarantee the T is not empty. | |
#[derive(Clone, Copy)] | |
pub struct OptionNotNonProof<'a, T: 'a> (FixRange<'a, T>); | |
pub fn check<'a, U: 'a>(fx: FixObj<'a, Option<U>>) -> Option<OptionNotNonProof<'a, Option<U>>> { | |
match fx.get() { | |
Some(_) => Some(OptionNotNonProof(fx.get_range())), | |
None => None, | |
} | |
} | |
pub fn prechecked_unwrap<'a: 'b, 'b, U>(fx: &'b FixObj<'a, Option<U>>, proof: OptionNotNonProof<'a, Option<U>>) -> &'b U { | |
match fx.get() { | |
Some(x) => x, | |
None => unreachable!(), | |
} | |
} | |
} | |
pub fn test() { | |
test1(); | |
test2(); | |
} | |
fn test1() { | |
println!("test FixObj."); | |
use self::fixobj::*; | |
let a: u8 = 1; | |
/// one liner to define fixobj. | |
fix!(a,fa); | |
/// another way to define it. | |
let ra = &a; | |
let mut fa = FixObj::new(&ra); | |
let ra2 = &a; | |
let mut fa2 = FixObj::new(&ra2); | |
// both won't compile | |
// fa2 = fa; | |
// fa = fa2; | |
/// However can be crack with group bind. | |
let (a,b) = (42 as u8, 1 as u8); | |
let (ra, rb) = (&a, &b); | |
let (mut fa, mut fb) = (FixObj::new(&ra),FixObj::new(&rb)); | |
fa = fb; | |
// fix about x cannot be forged with &x. | |
// fn fix<'a: 'b, 'b, T: 'a>(x: &'a T) -> FixObj<'b, T> { FixObj::new(&x) } | |
} | |
fn test2() { | |
println!("Prechecked Unwrap."); | |
use std::mem; | |
use self::fixobj::*; | |
use self::prechecked_option::*; | |
let b: Option<u8> = None; | |
fix!(b,fb); | |
let a: Option<u8> = Some(42); | |
fix!(a,fa); | |
let z = check(fa); | |
if let Some(proof) = z { | |
println!("Got proof."); | |
println!("proof size: {}", mem::size_of_val(&proof)); | |
// Do something... | |
println!("unwrap with proof: {}", prechecked_unwrap(&fa,proof)); | |
// The proof is for fa only, and cannot be used for fb. | |
// println!("unwrap with proof: {}", prechecked_unwrap(&fb,proof)); | |
} else { | |
println!("No proof."); | |
} | |
// Not possible to forge proof. | |
// field is private. | |
// let proof = OptionNotNonProof{0:fa.get_range()}; | |
/// Crack with group bind. | |
let (a,b)=(Some(42),None); | |
let (ra, rb) = (&a, &b); | |
let (mut fa, mut fb) = (FixObj::new(&ra),FixObj::new(&rb)); | |
let z = check(fa); | |
if let Some(proof) = z { | |
println!("Got proof."); | |
println!("unwrap with proof: {}", prechecked_unwrap(&fb,proof)); | |
} else { | |
println!("No proof."); | |
} | |
} | |
// extern crate variance; | |
// use self::variance::InvariantLifetime; | |
// use std::marker::PhantomData; | |
// use self::variance::Invariant; | |
} | |
fn main() { | |
use approach5::*; | |
test(); | |
println!("Hello, world!"); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment