Change-Id: Iab7e00cc26a4f9727d3ab98691ef379921a33052 Reviewed-on: https://cl.tvl.fyi/c/depot/+/5240 Tested-by: BuildkiteCI Reviewed-by: kanepyork <rikingcoding@gmail.com> Reviewed-by: Profpatsch <mail@profpatsch.de> Reviewed-by: grfn <grfn@gws.fyi> Reviewed-by: tazjin <tazjin@tvl.su>
		
			
				
	
	
		
			72 lines
		
	
	
	
		
			1.8 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			72 lines
		
	
	
	
		
			1.8 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
// Go's defer in Rust, with error value return.
 | 
						|
 | 
						|
use std::rc::Rc;
 | 
						|
use std::sync::RwLock;
 | 
						|
 | 
						|
struct Defer<F: Fn()> {
 | 
						|
    f: F,
 | 
						|
}
 | 
						|
 | 
						|
impl<F: Fn()> Drop for Defer<F> {
 | 
						|
    fn drop(&mut self) {
 | 
						|
        (self.f)()
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
// Only added this for Go-syntax familiarity ;-)
 | 
						|
fn defer<F: Fn()>(f: F) -> Defer<F> {
 | 
						|
    Defer { f }
 | 
						|
}
 | 
						|
 | 
						|
// Convenience type synonym. This is a reference-counted smart pointer to
 | 
						|
// a shareable, mutable variable.
 | 
						|
// Rust does not allow willy-nilly mutation of shared variables, so explicit
 | 
						|
// write-locking must be performed.
 | 
						|
type ErrorHandle<T> = Rc<RwLock<Option<T>>>;
 | 
						|
 | 
						|
///////////////////
 | 
						|
// Usage example //
 | 
						|
///////////////////
 | 
						|
 | 
						|
#[derive(Debug)] // Debug trait for some default way to print the type.
 | 
						|
enum Error {
 | 
						|
    DropError,
 | 
						|
}
 | 
						|
 | 
						|
fn main() {
 | 
						|
    // Create a place to store the error.
 | 
						|
    let drop_err: ErrorHandle<Error> = Default::default(); // create empty error
 | 
						|
 | 
						|
    // Introduce an arbitrary scope block (so that we still have control after
 | 
						|
    // the defer runs):
 | 
						|
    {
 | 
						|
        let mut i = 1;
 | 
						|
 | 
						|
        // Rc types are safe to clone and share for multiple ownership.
 | 
						|
        let err_handle = drop_err.clone();
 | 
						|
 | 
						|
        // Call defer and let the closure own the cloned handle to the error:
 | 
						|
        let token = defer(move || {
 | 
						|
            // do something!
 | 
						|
            println!("Value is: {}", i);
 | 
						|
 | 
						|
            // ... oh no, it went wrong!
 | 
						|
            *err_handle.write().unwrap() = Some(Error::DropError);
 | 
						|
        });
 | 
						|
 | 
						|
        i += 1;
 | 
						|
        println!("Value is: {}", i);
 | 
						|
 | 
						|
        // token goes out of scope here - drop() is called.
 | 
						|
    }
 | 
						|
 | 
						|
    match *drop_err.read().unwrap() {
 | 
						|
        Some(ref err) => println!("Oh no, an error occured: {:?}!", err),
 | 
						|
        None => println!("Phew, everything went well."),
 | 
						|
    };
 | 
						|
}
 | 
						|
 | 
						|
// Prints:
 | 
						|
// Value is: 2
 | 
						|
// Value is: 1
 | 
						|
// Oh no, an error occured: DropError!
 |