Browse Source

new: DowncastArc and its docs (#244)

login 1 year ago
parent
commit
77c928f6ce

+ 63 - 0
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<SystemError> {
+        // posix 错误码是小于0的
+        if errno >= 0 {
+            return None;
+        }
+        return <Self as FromPrimitive>::from_i32(-errno);
+    }
+
+    /// @brief 把系统错误枚举类型转换为负数posix错误码。
+    pub fn to_posix_errno(&self) -> i32 {
+        return -<Self as ToPrimitive>::to_i32(self).unwrap();
+    }
+}
+```
+
+&emsp;&emsp;这两个函数很好的说明了如何使用这两个trait。
+
+## 2. Arc类型转换
+
+### 2.1 从Arc<dyn U>转换为Arc<T>
+
+&emsp;&emsp;当我们需要把一个`Arc<dyn U>`转换为`Arc<T>`的具体类型指针时,我们要为`U`这个trait实现`DowncastArc`trait。这个trait定义在`kernel/src/libs/casting.rs`中。它要求`trait U`实现`Any + Sync + Send`trait.
+
+&emsp;&emsp;为`trait U: Any + Send + Sync`实现`DowncastArc`trait,需要这样做:
+
+```rust
+impl DowncastArc for dyn U {
+    fn as_any_arc(self: Arc<Self>) -> Arc<dyn Any> {
+        return self;
+    }
+}
+```
+
+&emsp;&emsp;使用`DowncastArc`trait,我们可以这样转换:
+
+```rust
+let arc: Arc<dyn U> = ...;
+let arc_t: Arc<T> = arc.downcast_arc::<T>().unwrap();
+```
+
+&emsp;&emsp;如果`arc`的具体类型不是`Arc<T>`,那么`downcast_arc::<T>()`会返回`None`。

+ 1 - 0
docs/kernel/core_api/index.rst

@@ -11,6 +11,7 @@
    kernel_api
    atomic
    data_structures
+   casting
 
 内存管理
 ===================

+ 75 - 0
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<dyn xxx>转换为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<Self>) -> Arc<dyn Any> {
+///         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<dyn Base> = Arc::new(a) as Arc<dyn Base>;
+///     let a_arc2: Option<Arc<A>> = a_arc.downcast_arc::<A>();
+///     assert!(a_arc2.is_some());
+/// }
+/// ```
+trait DowncastArc: Any + Send + Sync {
+    /// 请在具体类型中实现这个函数,返回self
+    fn as_any_arc(self: Arc<Self>) -> Arc<dyn Any>;
+
+    /// @brief 将Arc<dyn xxx>转换为Arc<具体类型>
+    ///
+    /// 如果Arc<dyn xxx>是Arc<具体类型>,则返回Some(Arc<具体类型>),否则返回None
+    ///
+    /// @param self Arc<dyn xxx>
+    fn downcast_arc<T: Any + Send + Sync>(self: Arc<Self>) -> Option<Arc<T>> {
+        let x: Arc<dyn Any> = self.as_any_arc();
+        if x.is::<T>() {
+            // into_raw不会改变引用计数
+            let p = Arc::into_raw(x);
+            let new = unsafe { Arc::from_raw(p as *const T) };
+            return Some(new);
+        }
+        return None;
+    }
+}

+ 1 - 0
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;