/* This file is part of DarkFi (https://dark.fi) * * Copyright (C) 2020-2023 Dyne.org foundation * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ use std::sync::{Arc, OnceLock, Weak}; /// Sometimes you need a parent-child relationship which results in code like: /// ```rust /// struct Parent { /// child: Mutex>> /// } /// impl Parent { /// fn new() -> Arc { /// let self_ = Arc::new(Self { /// child: Mutex::new(None) /// }; /// let parent = Arc::downgrade(&self_); /// *self_.child.lock().await = Some(Child::new(parent)); /// self_ /// } /// } /// struct Child { /// parent: Weak /// } /// impl Child { /// fn new(parent: Weak) -> Self { /// Self { parent } /// } /// fn upgrade(&self) -> Arc { /// self.parent.upgrade().unwrap() /// } /// } /// ``` /// This class simplifies the above code by allowing us instead to do: /// ```rust /// struct Parent { /// child: Arc /// } /// impl Parent { /// fn new() -> Arc { /// let self_ = Arc::new(Self { /// child: Child::new() /// }; /// self_.child.parent.init(self_.clone()); /// self_ /// } /// } /// struct Child { /// parent: LazyWeak /// } /// impl Child { /// fn new() -> Self { /// Self { parent: LazyWeak::new() } /// } /// fn upgrade(&self) -> Arc { /// self.parent.upgrade() /// } /// } /// ``` pub struct LazyWeak(OnceLock>); impl LazyWeak { /// Create an empty `LazyWeak`, which must immediately be followed by `weak.init()`. pub fn new() -> Self { Self(OnceLock::new()) } /// Must be called within the same scope as `new()`. pub fn init(&self, parent: Arc) { assert!(self.0.get().is_none()); let parent = Arc::downgrade(&parent); self.0.set(parent).unwrap(); } /// Access the `Arc` pointer pub fn upgrade(&self) -> Arc { self.0.get().unwrap().upgrade().unwrap() } } impl Default for LazyWeak { fn default() -> Self { Self::new() } }