From f12cc437edb393c63d8d24ce56dc6f88f1edfb4c Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 13 Dec 2023 12:00:41 -0500 Subject: [PATCH] Add something to be explicit about things that never die in a process. --- src/immortal.rs | 73 +++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + 2 files changed, 74 insertions(+) create mode 100644 src/immortal.rs diff --git a/src/immortal.rs b/src/immortal.rs new file mode 100644 index 0000000..f9e7103 --- /dev/null +++ b/src/immortal.rs @@ -0,0 +1,73 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * (c) ZeroTier, Inc. + * https://www.zerotier.com/ + */ + +use std::ops::Deref; + +/// Container for an object that never dies, by design (leaks on drop) +/// +/// This is used when you want an object that lives for the duration of a running process, but +/// don't want to use a static variable so that e.g. you can have more than one of them. +/// It's useful in cases such as async code with complex interdependencies where an Arc<> would +/// ordinarily be used but where using one leads to situations that would leak. Using this +/// instead explicitly documents in your code that the object in question is immortal and will +/// leak if dropped. +/// +/// Semantics are similar to Arc<> in that only non-mutable references can be obtained and +/// the object can be cloned. These can also be copied, as they are just pointers. +#[derive(Clone, Copy)] +pub struct Immortal(*mut T); + +impl Immortal { + #[inline(always)] + pub fn new(obj: T) -> Self { + Self(Box::into_raw(Box::new(obj))) + } +} + +impl AsRef for Immortal { + #[inline(always)] + fn as_ref(&self) -> &T { + unsafe { &*self.0 } + } +} + +impl Deref for Immortal { + type Target = T; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + unsafe { &*self.0 } + } +} + +unsafe impl Sync for Immortal where T: Sync {} +unsafe impl Send for Immortal where T: Send {} + +// Unit tests generated with CodeLlama-Instruct-34B +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_new() { + let immortal = Immortal::new(10); + assert_eq!(*immortal.as_ref(), 10); + } + + #[test] + fn test_deref() { + let immortal = Immortal::new(10); + assert_eq!(*immortal, 10); + } + + #[test] + fn test_as_ref() { + let immortal = Immortal::new(10); + assert_eq!(*immortal.as_ref(), 10); + } +} diff --git a/src/lib.rs b/src/lib.rs index 05590e0..0dbc8ec 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,6 +16,7 @@ pub mod error; pub mod exitcode; pub mod gate; pub mod hex; +pub mod immortal; pub mod inetaddress; pub mod io; pub mod memory;