Skip to content

Commit bd84f28

Browse files
Added ext-php-rs guide (#52)
* Started work on guide, added types * Rewrite argument parser to allow referencs Primarly so that `&str` is a valid parameter type. * Remove generic `Into<String>` conversion to exception * Worked on guide, added macros * Build guide when building docs * Allow manual trigger of docs build * `cargo fmt`
1 parent 81dacc8 commit bd84f28

39 files changed

+1062
-249
lines changed

.github/workflows/docs.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
name: Deploy documentation
22
on:
3+
workflow_dispatch:
34
push:
45
branches:
56
- master
@@ -32,13 +33,22 @@ jobs:
3233
with:
3334
version: ${{ matrix.llvm }}
3435
directory: ${{ runner.temp }}/llvm-${{ matrix.llvm }}
36+
- name: Install mdbook
37+
uses: actions-rs/install@v0.1
38+
with:
39+
crate: mdbook
40+
version: latest
3541
- name: Build docs
3642
uses: actions-rs/cargo@v1
3743
env:
3844
LIBCLANG_PATH: ${{ runner.temp }}/llvm-${{ matrix.llvm }}/lib
3945
with:
4046
command: doc
4147
args: --release
48+
- name: Build guide
49+
run: |
50+
mdbook build guide
51+
mv guide/book target/doc/guide
4252
- name: Create index redirect
4353
run: |
4454
echo '<meta http-equiv=refresh content=0;url=/ext-php-rs/ext_php_rs>' > target/doc/index.html

README.md

Lines changed: 41 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22

33
[<img align="right" src="https://discord.com/api/guilds/115233111977099271/widget.png?style=banner2">](https://discord.gg/dphp)
44

5-
Bindings and abstractions for the Zend API to build PHP extensions natively in Rust.
5+
Bindings and abstractions for the Zend API to build PHP extensions natively in
6+
Rust.
67

78
## Example
89

@@ -31,30 +32,43 @@ var_dump(hello_world("David")); // string(13) "Hello, David!"
3132

3233
## Features
3334

34-
- **Easy to use:** The built-in macros can abstract away the need to interact with the Zend API, such as Rust-type function parameter abstracting away interacting with Zend values.
35-
- **Lightweight:** You don't have to use the built-in helper macros. It's possible to write your own glue code around your own functions.
36-
- **Extensible:** Implement `IntoZval` and `FromZval` for your own custom types, allowing the type to be used as function parameters and return types.
35+
- **Easy to use:** The built-in macros can abstract away the need to interact
36+
with the Zend API, such as Rust-type function parameter abstracting away
37+
interacting with Zend values.
38+
- **Lightweight:** You don't have to use the built-in helper macros. It's
39+
possible to write your own glue code around your own functions.
40+
- **Extensible:** Implement `IntoZval` and `FromZval` for your own custom types,
41+
allowing the type to be used as function parameters and return types.
3742

3843
## Goals
3944

4045
Our main goal is to **make extension development easier.**
4146

42-
- Writing extensions in C can be tedious, and with the Zend APIs limited documentation can be intimidating.
43-
- Rust's modern language features and feature-full standard library are big improvements on C.
44-
- Abstracting away the raw Zend APIs allows extensions to be developed faster and with more confidence.
45-
- Abstractions also allow us to support future (and potentially past) versions of PHP without significant changes to extension code.
47+
- Writing extensions in C can be tedious, and with the Zend APIs limited
48+
documentation can be intimidating.
49+
- Rust's modern language features and feature-full standard library are big
50+
improvements on C.
51+
- Abstracting away the raw Zend APIs allows extensions to be developed faster
52+
and with more confidence.
53+
- Abstractions also allow us to support future (and potentially past) versions
54+
of PHP without significant changes to extension code.
4655

4756
## Documentation
4857

49-
The project is documented in-line, so viewing the `cargo` documentation is the best resource at the moment.
58+
The project is documented in-line, so viewing the `cargo` documentation is the
59+
best resource at the moment.
5060

51-
We are currently unable to deploy our documentation to `docs.rs` due to the crate requiring PHP 8.0, which is unavailable in the default Ubuntu repositories.
52-
Documentation can be viewed [here](https://davidcole1340.github.io/ext-php-rs/). It is generated from the latest `master` branch. Documentation will be moved to `docs.rs` when Ubuntu updates its repositories to PHP 8.0.
61+
We are currently unable to deploy our documentation to `docs.rs` due to the
62+
crate requiring PHP 8.0, which is unavailable in the default Ubuntu
63+
repositories. Documentation can be viewed
64+
[here](https://davidcole1340.github.io/ext-php-rs/). It is generated from the
65+
latest `master` branch. Documentation will be moved to `docs.rs` when Ubuntu
66+
updates its repositories to PHP 8.0.
5367

5468
## Requirements
5569

5670
- PHP 8.0 or later
57-
- No support is planned for lower versions.
71+
- No support is planned for lower versions.
5872
- Linux or Darwin-based OS
5973
- Rust - no idea which version
6074
- Clang 3.9 or greater
@@ -64,20 +78,26 @@ See the following links for the dependency crate requirements:
6478
- [`cc`](https://github.com/alexcrichton/cc-rs#compile-time-requirements)
6579
- [`bindgen`](https://rust-lang.github.io/rust-bindgen/requirements.html)
6680

67-
6881
## Usage
6982

70-
This project only works for PHP >= 8.0 (for now). Due to the fact that the PHP extension system relies heavily on C macros (which cannot be exported to Rust easily), structs have to be hard coded in.
83+
This project only works for PHP >= 8.0 (for now). Due to the fact that the PHP
84+
extension system relies heavily on C macros (which cannot be exported to Rust
85+
easily), structs have to be hard coded in.
7186

7287
Check out one of the example projects:
7388

74-
- [ext-skel](example/skel) - Testbed for testing the library. Check out previous commits as well to see what else is possible.
75-
- [anonaddy-sequoia](https://gitlab.com/willbrowning/anonaddy-sequoia) - Sequoia encryption PHP extension.
76-
- [opus-php](https://github.com/davidcole1340/opus-php/tree/rewrite_rs) - Work-in-progress extension to use the Opus library in PHP.
89+
- [ext-skel](example/skel) - Testbed for testing the library. Check out previous
90+
commits as well to see what else is possible.
91+
- [anonaddy-sequoia](https://gitlab.com/willbrowning/anonaddy-sequoia) - Sequoia
92+
encryption PHP extension.
93+
- [opus-php](https://github.com/davidcole1340/opus-php/tree/rewrite_rs) -
94+
Work-in-progress extension to use the Opus library in PHP.
7795

7896
## Contributions
7997

80-
Contributions are very much welcome. I am a novice Rust developer and any suggestions are wanted and welcome. Feel free to file issues and PRs through Github.
98+
Contributions are very much welcome. I am a novice Rust developer and any
99+
suggestions are wanted and welcome. Feel free to file issues and PRs through
100+
Github.
81101

82102
Contributions welcome include:
83103

@@ -98,9 +118,8 @@ dual licensed as above, without any additional terms or conditions.
98118

99119
Licensed under either of
100120

101-
* Apache License, Version 2.0
102-
([LICENSE_APACHE](LICENSE_APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
103-
* MIT license
104-
([LICENSE_MIT](LICENSE_MIT) or http://opensource.org/licenses/MIT)
121+
- Apache License, Version 2.0 ([LICENSE_APACHE](LICENSE_APACHE) or
122+
http://www.apache.org/licenses/LICENSE-2.0)
123+
- MIT license ([LICENSE_MIT](LICENSE_MIT) or http://opensource.org/licenses/MIT)
105124

106125
at your option.

example/skel/src/lib.rs

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
mod allocator;
22

3-
use std::collections::HashMap;
3+
use std::{collections::HashMap, convert::TryFrom};
44

55
use allocator::PhpAllocator;
66
use ext_php_rs::{
@@ -127,11 +127,23 @@ pub fn skeleton_array(
127127
Ok(new)
128128
}
129129

130-
#[php_function]
131-
pub fn test_array() -> Vec<i32> {
130+
#[php_function(optional = "i", defaults(i = 5))]
131+
pub fn test_array(i: i32, b: Option<i32>) -> Vec<i32> {
132+
dbg!(i, b);
132133
vec![1, 2, 3, 4]
133134
}
134135

136+
#[php_function(optional = "offset", defaults(offset = 0))]
137+
pub fn rust_strpos(haystack: &str, needle: &str, offset: i64) -> Option<usize> {
138+
let haystack = haystack.chars().skip(offset as usize).collect::<String>();
139+
haystack.find(needle)
140+
}
141+
142+
#[php_function]
143+
pub fn example_exception() -> Result<i32, &'static str> {
144+
Err("Bad here")
145+
}
146+
135147
#[php_function]
136148
pub fn skel_unpack<'a>(
137149
mut arr: HashMap<String, String>,
@@ -149,6 +161,16 @@ pub fn test_extern() -> i32 {
149161
0
150162
}
151163

164+
#[php_function]
165+
pub fn test_lifetimes<'a>() -> ZendHashTable<'a> {
166+
ZendHashTable::try_from(&HashMap::<String, String>::new()).unwrap()
167+
}
168+
169+
#[php_function]
170+
pub fn test_str(input: &str) -> &str {
171+
input
172+
}
173+
152174
#[no_mangle]
153175
pub extern "C" fn php_module_info(_module: *mut ModuleEntry) {
154176
info_table_start!();

ext-php-rs-derive/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,5 @@ darling = "0.12"
1717
quote = "1.0.9"
1818
proc-macro2 = "1.0.26"
1919
lazy_static = "1.4.0"
20+
regex = "1.5"
21+
anyhow = "1.0"

ext-php-rs-derive/src/class.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
use crate::{error::Result, STATE};
1+
use crate::STATE;
2+
use anyhow::{bail, Result};
23
use proc_macro2::{Ident, Span, TokenStream};
34
use quote::quote;
45
use syn::DeriveInput;
@@ -47,18 +48,17 @@ pub fn parser(input: DeriveInput) -> Result<TokenStream> {
4748
}
4849
};
4950

50-
let mut state = STATE.lock()?;
51+
let mut state = STATE.lock();
5152

5253
if state.built_module {
53-
return Err("The `#[php_module]` macro must be called last to ensure functions and classes are registered.".into());
54+
bail!("The `#[php_module]` macro must be called last to ensure functions and classes are registered.");
5455
}
5556

5657
if state.classes.contains_key(&class_name) {
57-
return Err(format!(
58+
bail!(
5859
"A class has already been registered with the name `{}`.",
5960
class_name
60-
)
61-
.into());
61+
);
6262
}
6363

6464
state.classes.insert(class_name, Default::default());

ext-php-rs-derive/src/constant.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1+
use anyhow::{bail, Result};
12
use darling::ToTokens;
23
use proc_macro2::{Ident, Literal, TokenStream};
34
use quote::quote;
45
use syn::ItemConst;
56

6-
use crate::{error::Result, STATE};
7+
use crate::STATE;
78

89
#[derive(Debug)]
910
pub struct Constant {
@@ -13,10 +14,10 @@ pub struct Constant {
1314
}
1415

1516
pub fn parser(input: ItemConst) -> Result<TokenStream> {
16-
let mut state = STATE.lock()?;
17+
let mut state = STATE.lock();
1718

1819
if state.startup_function.is_some() {
19-
return Err("Constants must be declared before you declare your startup function and module function.".into());
20+
bail!("Constants must be declared before you declare your startup function and module function.");
2021
}
2122

2223
state.constants.push(Constant {

ext-php-rs-derive/src/error.rs

Lines changed: 0 additions & 36 deletions
This file was deleted.

ext-php-rs-derive/src/extern_.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
1+
use anyhow::{anyhow, bail, Result};
12
use proc_macro2::TokenStream;
23
use quote::quote;
34
use syn::{punctuated::Punctuated, ForeignItemFn, ItemForeignMod, ReturnType, Signature, Token};
45

5-
use crate::error::Result;
6-
76
pub fn parser(input: ItemForeignMod) -> Result<TokenStream> {
87
input
98
.items
109
.into_iter()
1110
.map(|item| match item {
1211
syn::ForeignItem::Fn(func) => parse_function(func),
13-
_ => Err("Only `extern` functions are supported by PHP.".into()),
12+
_ => bail!("Only `extern` functions are supported by PHP."),
1413
})
1514
.collect::<Result<Vec<_>>>()
1615
.map(|vec| quote! { #(#vec)* })
@@ -36,7 +35,9 @@ fn parse_function(mut func: ForeignItemFn) -> Result<TokenStream> {
3635
_ => None,
3736
})
3837
.collect::<Option<Punctuated<_, Token![,]>>>()
39-
.ok_or("`self` parameters are not permitted inside `#[php_extern]` blocks.")?;
38+
.ok_or_else(|| {
39+
anyhow!("`self` parameters are not permitted inside `#[php_extern]` blocks.")
40+
})?;
4041
let ret = build_return(&name, &sig.output, params);
4142

4243
Ok(quote! {

0 commit comments

Comments
 (0)