Skip to content

Add internal types documentations. #82

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Dec 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions phper-doc/doc/_05_internal_types/_01_z_str/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Z Str

> A string is series of characters, where a character is the same as a byte.
>
> Refer: <https://www.php.net/manual/en/language.types.string.php>

The [`&ZStr`](phper::strings::ZStr) and [`ZString`](phper::strings::ZString) are
the wrapper of [`zend_string`](phper::sys::zend_string).

`ZStr` can be converted to `&[u8]`, `&CStr` and `&str`.

`ZString` can be constructed from `impl AsRef<[u8]>`, has pair of `from_raw()`
and `into_raw()`, like in [`Box`].

```rust,no_run
use phper::strings::ZString;

let s = ZString::new("Hello world!");

// Will leak memory.
let ptr = s.into_raw();

// retake pointer.
let ss = unsafe { ZString::from_raw(ptr) };

// `ZString` implements `PartialEq`.
assert_eq!(ss, "Hello world!");
```

`ZString` can be dereferenced to `ZStr`.

```rust,no_run
use phper::strings::ZString;

let s = ZString::new("Hello world!");

// `to_str` is the method of `ZStr`.
assert_eq!(s.to_str(), Ok("Hello world!"));
```

`ZStr` implements `ToOwned`, can upgrade to `ZString` by value copy.

Because `zend_string` is reference counting type, so `ZStr` also implements
[`ToRefOwned`](phper::alloc::ToRefOwned) (just like
[`RefClone`](phper::alloc::RefClone) for [`ZVal`](phper::values::ZVal)), can
upgrade to `ZString` by refcount increment.

```rust,no_run
use phper::sys;
use phper::strings::ZStr;
use phper::alloc::ToRefOwned;

extern "C" {
fn something() -> *mut sys::zend_string;
}

let s = unsafe { ZStr::from_mut_ptr(something()) };

// By value copy.
let _s = s.to_owned();

// By refcount increment.
let _s = s.to_ref_owned();
```

Note that neither `ZStr` nor `ZString` implement `Send` and `Sync`, because PHP
is single-threaded.
83 changes: 83 additions & 0 deletions phper-doc/doc/_05_internal_types/_02_z_arr/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# Z Arr

> An array in PHP is actually an ordered map. A map is a type that associates
> values to keys. This type is optimized for several different uses; it can be
> treated as an array, list (vector), hash table (an implementation of a map),
> dictionary, collection, stack, queue, and probably more. As array values can
> be other arrays, trees and multidimensional arrays are also possible.
>
> Refer: <https://www.php.net/manual/en/language.types.array.php>

*In fact, I don't agree with PHP's practice of mixing list and map. I prefer*
*python to separate list and dictionary as two types. For example, when*
*serializing into json, the serialization function has to judge whether the key*
*of the array starts from 0 and increment by 1 to confirm whether the array is*
*a list. I think it is a waste of performance.*

The [`&ZArr`](phper::arrays::ZArr) and [`ZArray`](phper::arrays::ZArray) are
the wrapper of [`zend_array`](phper::sys::zend_array) (same as `Hashtable`).

[`&ZArr`](phper::arrays::ZArr) acts like [`HashMap`](std::collections::HashMap),
also has api `insert()`, `get()`, `remove()`, but it's key type is
[`Key`](phper::arrays::Key) and value type is [`ZVal`](phper::values::ZVal).

Notice that phper prefer to use [`Symtables`](https://www.phpinternalsbook.com/php5/hashtables/array_api.html#symtables) api `zend_symtable_*`,
so `get(42)` and `get("42")` should be considered the same.

`ZArray` can be dereferenced to `ZArr`.

```rust,no_run
use phper::arrays::{ZArray, InsertKey};
use phper::values::ZVal;

let mut arr = ZArray::new();

arr.insert(InsertKey::NextIndex, ZVal::default());
arr.insert(10, ZVal::from(100));
arr.insert("foo", ZVal::from("bar"));

let _i = arr.get("10");

arr.remove("foo");
```

`ZArr` can be iterated by `iter()`.

```rust,no_run
use phper::arrays::ZArray;
use phper::values::ZVal;

let arr = ZArray::new();

for (_k, _v) in arr.iter() {
}
```

`ZArr` implements `ToOwned`, can upgrade to `ZArray` by value copy via
`zend_array_dup`.

Because `zend_array` is reference counting type, so `ZArr` also implements
[`ToRefOwned`](phper::alloc::ToRefOwned) (just like
[`RefClone`](phper::alloc::RefClone) for [`ZVal`](phper::values::ZVal)), can
upgrade to `ZArray` by refcount increment.

```rust,no_run
use phper::sys;
use phper::arrays::ZArr;
use phper::alloc::ToRefOwned;

extern "C" {
fn something() -> *mut sys::zend_array;
}

let arr = unsafe { ZArr::from_mut_ptr(something()) };

// By value copy.
let _arr = arr.to_owned();

// By refcount increment.
let _arr = arr.to_ref_owned();
```

Note that neither `ZArr` nor `ZArray` implement `Send` and `Sync`, because PHP
is single-threaded.
3 changes: 3 additions & 0 deletions phper-doc/doc/_05_internal_types/_03_z_obj/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Z Obj

TODO
38 changes: 38 additions & 0 deletions phper-doc/doc/_05_internal_types/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Internal types

## DST & Owned Type

In Rust, there are many types that appear in pairs, like [str](str) / [String](String),
[OsStr](std::ffi::OsStr) / [OsString](std::ffi::OsString),
[CStr](std::ffi::CStr) / [CString](std::ffi::CString).

For example:

- [str](str): Dynamically sized type, implements `!Sized`, usually used with reference
notation, as `&str`.
- [String](String): Ownership type, encapsulates a pointer to a heap memory allocation.

PHPER follows this design, there are the following types:

- [ZStr](phper::strings::ZStr) / [ZString](phper::strings::ZString)
- [ZArr](phper::arrays::ZArr) / [ZArray](phper::arrays::ZArray)
- [ZObj](phper::objects::ZObj) / [ZObject](phper::objects::ZObject)

## Mapping relationship

Here is the mapping relationship of Rust type and base PHP type.

| Rust type | PHP type |
| ---------------- | -------- |
| `()` | null |
| `bool` | bool |
| `i64` | long |
| `f64` | double |
| `ZStr / ZString` | string |
| `ZArr / ZArray` | array |
| `ZObj / ZObject` | object |
| `ZRes` | resource |

*Why is there no ZResource? Because Resource is a relatively old type, it*
*is generally replaced by Class now, and the role of ZRes is only compatible*
*with old extension resources.*
3 changes: 3 additions & 0 deletions phper-doc/doc/_06_class_and_object/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Class and object

TODO
3 changes: 3 additions & 0 deletions phper-doc/doc/_07_module/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Module

TODO
14 changes: 7 additions & 7 deletions phper-doc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,23 +32,23 @@ pub mod _03_integrate_with_pecl {}
#[doc = include_str!("../doc/_04_zval/index.md")]
pub mod _04_zval {}

/// TODO
#[doc = include_str!("../doc/_05_internal_types/index.md")]
pub mod _05_internal_types {

/// TODO
#[doc = include_str!("../doc/_05_internal_types/_01_z_str/index.md")]
pub mod _01_z_str {}

/// TODO
#[doc = include_str!("../doc/_05_internal_types/_02_z_arr/index.md")]
pub mod _02_z_arr {}

/// TODO
pub mod _03_z_arr {}
#[doc = include_str!("../doc/_05_internal_types/_03_z_obj/index.md")]
pub mod _03_z_obj {}
}

/// TODO
#[doc = include_str!("../doc/_06_class_and_object/index.md")]
pub mod _06_class_and_object {}

/// TODO
#[doc = include_str!("../doc/_07_module/index.md")]
pub mod _07_module {

/// TODO
Expand Down