Merge pull request #1 from wfly1998/master

完善 README.md,修改部分文档,解决 editable 的问题
dev
Runji Wang 6 years ago committed by GitHub
commit bdf8e75f33
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1 +0,0 @@
docs/src/README.md

@ -0,0 +1,20 @@
# zCore Tutorial
## 仓库目录
* `docs/`: 教学实验指导
* `zcore`: 操作系统代码
## 实验指导
基于 mdBook目前目前已经部署到了 [GitHub Pages](https://rcore-os.github.io/zCore-Tutorial/) 上面。
### 文档本地使用方法
```bash
git clone https://github.com/rcore-os/zCore-Tutorial.git
cd zCore-Tutorial
cargo install mdbook
mdbook serve docs
```

@ -4,3 +4,5 @@ language = "cn"
multilingual = false
src = "src"
title = "简明 zCore 教程"
[output.html.playpen]
editable = true

@ -41,6 +41,7 @@ $ cd zcore
为此我们需要移除对标准库的依赖,使其成为一个不依赖当前 OS 功能的库。在 `lib.rs` 的第一行添加声明:
```rust,noplaypen
// src/lib.rs
#![no_std]
extern crate alloc;
```
@ -67,7 +68,8 @@ Rust 是一门部分面向对象的语言,我们通常用它的 trait 实现
首先创建一个 `KernelObject` trait 作为内核对象的公共接口:
```rust
```rust,noplaypen
// src/object/mod.rs
/// 内核对象公共接口
pub trait KernelObject: Send + Sync {
{{#include ../../zcore/src/object/mod.rs:object}}
@ -86,6 +88,7 @@ pub trait KernelObject: Send + Sync {
接下来我们实现一个最简单的空对象 `DummyObject`,并为它实现 `KernelObject` 接口:
```rust,noplaypen
// src/object/object.rs
{{#include ../../zcore/src/object/object_v1.rs:dummy_def}}
```
@ -109,6 +112,7 @@ pub trait KernelObject: Send + Sync {
然后我们为新对象实现构造函数:
```rust,noplaypen
// src/object/object.rs
{{#include ../../zcore/src/object/object_v1.rs:dummy_new}}
```
@ -120,6 +124,7 @@ ID 类型使用 `u64`,保证了数值空间足够大,在有生之年都不
最后我们为它实现 `KernelObject` 接口:
```rust,noplaypen
// src/object/object.rs
{{#include ../../zcore/src/object/object_v1.rs:dummy_impl}}
```
@ -129,6 +134,7 @@ ID 类型使用 `u64`,保证了数值空间足够大,在有生之年都不
为了证明上面代码的正确性,我们写一个简单的单元测试,替换掉自带的 `it_works` 函数:
```rust,noplaypen
// src/object/object.rs
{{#include ../../zcore/src/object/object_v1.rs:dummy_test}}
```
@ -168,9 +174,10 @@ DummyObject *dummy = dynamic_cast<DummyObject*>(base);
[`Any`]: https://doc.rust-lang.org/std/any/
```rust,editable
#use std::any::Any;
#use std::sync::Arc;
```rust,editable,noplaypen
# use core::any::Any;
# use alloc::sync::Arc;
#
trait KernelObject: Any + Send + Sync {}
fn downcast_v1<T: KernelObject>(object: Arc<dyn KernelObject>) -> Arc<T> {
object.downcast::<T>().unwrap()
@ -190,11 +197,12 @@ fn downcast_v2<T: KernelObject>(object: Arc<dyn KernelObject>) -> Arc<T> {
{{#include ../../zcore/Cargo.toml:downcast}}
```
(题外话:这个库原来是不支持 no_std 的zCore 有这个需求,于是就顺便帮他实现了一把)
(题外话:这个库原来是不支持 `no_std`zCore 有这个需求,于是就顺便帮他实现了一把)
按照它文档的描述,我们要为自己的接口实现向下转换,只需以下修改:
```rust,noplaypen
// src/object/mod.rs
use core::fmt::Debug;
use downcast_rs::{impl_downcast, DowncastSync};
@ -206,6 +214,7 @@ impl_downcast!(sync KernelObject);
`impl_downcast!` 宏用来帮我们自动生成转换函数,然后就可以用 `downcast_arc` 来对 `Arc` 做向下转换了。我们直接来测试一把:
```rust,noplaypen
// src/object/object.rs
{{#include ../../zcore/src/object/object_v1.rs:downcast_test}}
```
@ -244,12 +253,14 @@ test object::tests::dummy_object ... ok
而所谓的内部 struct其实就是我们上面实现的 `DummyObject`。为了更好地体现它的功能,我们给他改个名叫 `KObjectBase`
```rust,noplaypen
// src/object/mod.rs
{{#include ../../zcore/src/object/mod.rs:base_def}}
```
接下来我们把它的构造函数改为实现 `Default` trait并且公共属性和方法都指定为 `pub`
```rust,noplaypen
// src/object/mod.rs
{{#include ../../zcore/src/object/mod.rs:base_default}}
impl KObjectBase {
/// 生成一个唯一的 ID
@ -264,24 +275,29 @@ impl KObjectBase {
最后来写一个魔法的宏!
```rust,noplaypen
// src/object/mod.rs
{{#include ../../zcore/src/object/mod.rs:impl_kobject}}
```
轮子已经造好了!让我们看看如何用它方便地实现一个内核对象,仍以 `DummyObject` 为例:
```rust,noplaypen
// src/object/mod.rs
{{#include ../../zcore/src/object/mod.rs:dummy}}
```
是不是方便了很多?最后按照惯例,用单元测试检验实现的正确性:
```rust,noplaypen
// src/object/mod.rs
{{#include ../../zcore/src/object/mod.rs:dummy_test}}
```
有兴趣的读者可以继续探索使用功能更强大的 **过程宏proc_macro**,进一步简化实现新内核对象所需的模板代码。
有兴趣的读者可以继续探索使用功能更强大的 [**过程宏proc_macro**],进一步简化实现新内核对象所需的模板代码。
如果能把上面的代码块缩小成下面这两行,就更加完美了:
[**过程宏proc_macro**]: https://doc.rust-lang.org/proc_macro/index.html
```rust,noplaypen
#[KernelObject]
pub struct DummyObject;

Loading…
Cancel
Save