From 77c928f6ce3192c79ea42ab7bcba2713e289f73b Mon Sep 17 00:00:00 2001 From: login Date: Sun, 16 Apr 2023 20:29:04 +0800 Subject: [PATCH] new: DowncastArc and its docs (#244) --- docs/kernel/core_api/casting.md | 63 +++++++++++++++++++++++++++ docs/kernel/core_api/index.rst | 1 + kernel/src/libs/casting.rs | 75 +++++++++++++++++++++++++++++++++ kernel/src/libs/mod.rs | 1 + 4 files changed, 140 insertions(+) create mode 100644 docs/kernel/core_api/casting.md create mode 100644 kernel/src/libs/casting.rs diff --git a/docs/kernel/core_api/casting.md b/docs/kernel/core_api/casting.md new file mode 100644 index 00000000..9bb98fe2 --- /dev/null +++ b/docs/kernel/core_api/casting.md @@ -0,0 +1,63 @@ +# 类型转换库API + +  内核提供了一些函数来帮助你在不同的类型之间进行转换。包括以下类型: + +- 数值类型转换 (使用`num-traits`库) +- Arc类型转换 + +  上述没有特殊标明的函数,都是在`kernel/src/libs/casting.rs`中实现的。 + + +## 1. 数值类型转换 + +### 1.1. 整数类型与枚举类型之间的转换 + +  您可以使用`num-traits`库提供的宏,实现枚举类型和整数类型之间的转换。 +SystemError枚举类型使用了这种方式,您可以在`kernel/src/syscall/mod.rs`中找到它的用法。 + +  它首先继承了`FromPrimitive, ToPrimitive`两个trait,然后这样转换: + +```rust +impl SystemError { + /// @brief 把posix错误码转换为系统错误枚举类型。 + pub fn from_posix_errno(errno: i32) -> Option { + // posix 错误码是小于0的 + if errno >= 0 { + return None; + } + return ::from_i32(-errno); + } + + /// @brief 把系统错误枚举类型转换为负数posix错误码。 + pub fn to_posix_errno(&self) -> i32 { + return -::to_i32(self).unwrap(); + } +} +``` + +  这两个函数很好的说明了如何使用这两个trait。 + +## 2. Arc类型转换 + +### 2.1 从Arc转换为Arc + +  当我们需要把一个`Arc`转换为`Arc`的具体类型指针时,我们要为`U`这个trait实现`DowncastArc`trait。这个trait定义在`kernel/src/libs/casting.rs`中。它要求`trait U`实现`Any + Sync + Send`trait. + +  为`trait U: Any + Send + Sync`实现`DowncastArc`trait,需要这样做: + +```rust +impl DowncastArc for dyn U { + fn as_any_arc(self: Arc) -> Arc { + return self; + } +} +``` + +  使用`DowncastArc`trait,我们可以这样转换: + +```rust +let arc: Arc = ...; +let arc_t: Arc = arc.downcast_arc::().unwrap(); +``` + +  如果`arc`的具体类型不是`Arc`,那么`downcast_arc::()`会返回`None`。 diff --git a/docs/kernel/core_api/index.rst b/docs/kernel/core_api/index.rst index 2b4a0c5a..71a9f0b8 100644 --- a/docs/kernel/core_api/index.rst +++ b/docs/kernel/core_api/index.rst @@ -11,6 +11,7 @@ kernel_api atomic data_structures + casting 内存管理 =================== diff --git a/kernel/src/libs/casting.rs b/kernel/src/libs/casting.rs new file mode 100644 index 00000000..20c0fc41 --- /dev/null +++ b/kernel/src/libs/casting.rs @@ -0,0 +1,75 @@ +// Copyright (C) DragonOS Community longjin 2023 + +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// Or you can visit https://www.gnu.org/licenses/gpl-2.0.html +#![allow(dead_code)] + +use core::any::Any; + +use alloc::sync::Arc; + +/// @brief 将Arc转换为Arc<具体类型>的trait +/// +/// 用法: +/// +/// ```rust +/// trait Base: Any + Send + Sync + Debug { +/// fn get_name(&self) -> String; +/// } +/// +/// struct A { +/// name: String, +/// } +/// +/// impl DowncastArc for dyn Base { +/// fn as_any_arc(self: Arc) -> Arc { +/// return self; +/// } +/// } +/// +/// impl Base for A { +/// fn get_name(&self) -> String { +/// return self.name.clone(); +/// } +/// } +/// +/// fn test() { +/// let a = A { name: "a".to_string() }; + +/// let a_arc: Arc = Arc::new(a) as Arc; +/// let a_arc2: Option> = a_arc.downcast_arc::(); +/// assert!(a_arc2.is_some()); +/// } +/// ``` +trait DowncastArc: Any + Send + Sync { + /// 请在具体类型中实现这个函数,返回self + fn as_any_arc(self: Arc) -> Arc; + + /// @brief 将Arc转换为Arc<具体类型> + /// + /// 如果Arc是Arc<具体类型>,则返回Some(Arc<具体类型>),否则返回None + /// + /// @param self Arc + fn downcast_arc(self: Arc) -> Option> { + let x: Arc = self.as_any_arc(); + if x.is::() { + // into_raw不会改变引用计数 + let p = Arc::into_raw(x); + let new = unsafe { Arc::from_raw(p as *const T) }; + return Some(new); + } + return None; + } +} diff --git a/kernel/src/libs/mod.rs b/kernel/src/libs/mod.rs index fa3beaa3..ed01fba2 100644 --- a/kernel/src/libs/mod.rs +++ b/kernel/src/libs/mod.rs @@ -1,4 +1,5 @@ pub mod atomic; +pub mod casting; pub mod ffi_convert; pub mod list; pub mod lockref;