Skip to content

Commit 8c60c8d

Browse files
authored
Refactor errors and exceptions. (#84)
1 parent d4b0858 commit 8c60c8d

File tree

24 files changed

+660
-472
lines changed

24 files changed

+660
-472
lines changed

examples/complex/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ fn say_hello(arguments: &mut [ZVal]) -> phper::Result<String> {
2828
}
2929

3030
fn throw_exception(_: &mut [ZVal]) -> phper::Result<()> {
31-
Err(phper::Error::other("I am sorry"))
31+
Err(phper::Error::Boxed("I am sorry".into()))
3232
}
3333

3434
#[php_get_module]

examples/http-client/src/client.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ pub fn make_client_builder_class() -> StatefulClass<ClientBuilder> {
3232
let state = this.as_mut_state();
3333
let builder: ClientBuilder = take(state);
3434
*state = builder.timeout(Duration::from_millis(ms as u64));
35-
Ok::<_, HttpClientError>(this.to_ref_owned())
35+
Ok::<_, phper::Error>(this.to_ref_owned())
3636
})
3737
.argument(Argument::by_val("ms"));
3838

@@ -43,20 +43,20 @@ pub fn make_client_builder_class() -> StatefulClass<ClientBuilder> {
4343
let state = this.as_mut_state();
4444
let builder: ClientBuilder = take(state);
4545
*state = builder.cookie_store(enable);
46-
Ok::<_, HttpClientError>(this.to_ref_owned())
46+
Ok::<_, phper::Error>(this.to_ref_owned())
4747
})
4848
.argument(Argument::by_val("enable"));
4949

5050
// Inner call the `ClientBuilder::build`, and wrap the result `Client` in
5151
// Object.
5252
class.add_method("build", Visibility::Public, |this, _arguments| {
5353
let state = take(this.as_mut_state());
54-
let client = ClientBuilder::build(state)?;
54+
let client = ClientBuilder::build(state).map_err(HttpClientError::Reqwest)?;
5555
let mut object = ClassEntry::from_globals(HTTP_CLIENT_CLASS_NAME)?.init_object()?;
5656
unsafe {
5757
*object.as_mut_state() = Some(client);
5858
}
59-
Ok::<_, HttpClientError>(object)
59+
Ok::<_, phper::Error>(object)
6060
});
6161

6262
class
@@ -76,7 +76,7 @@ pub fn make_client_class() -> StatefulClass<Option<Client>> {
7676
unsafe {
7777
*object.as_mut_state() = Some(request_builder);
7878
}
79-
Ok::<_, HttpClientError>(object)
79+
Ok::<_, phper::Error>(object)
8080
})
8181
.argument(Argument::by_val("url"));
8282

@@ -89,7 +89,7 @@ pub fn make_client_class() -> StatefulClass<Option<Client>> {
8989
unsafe {
9090
*object.as_mut_state() = Some(request_builder);
9191
}
92-
Ok::<_, HttpClientError>(object)
92+
Ok::<_, phper::Error>(object)
9393
})
9494
.argument(Argument::by_val("url"));
9595

examples/http-client/src/errors.rs

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,25 @@
88
// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
99
// See the Mulan PSL v2 for more details.
1010

11-
use phper::classes::{ClassEntry, StatefulClass};
11+
use phper::{
12+
classes::{ClassEntry, StatefulClass},
13+
errors::{exception_class, Throwable},
14+
};
1215

1316
/// The exception class name of extension.
1417
const EXCEPTION_CLASS_NAME: &str = "HttpClient\\HttpClientException";
1518

16-
/// The struct implemented `phper::Throwable` will throw php Exception
17-
/// when return as `Err(e)` in extension functions.
18-
#[derive(Debug, thiserror::Error, phper::Throwable)]
19-
#[throwable_class(EXCEPTION_CLASS_NAME)]
20-
pub enum HttpClientError {
21-
/// Generally, implement `From` for `phper::Error`.
22-
#[error(transparent)]
23-
#[throwable(transparent)]
24-
Phper(#[from] phper::Error),
19+
pub fn make_exception_class() -> StatefulClass<()> {
20+
let mut exception_class = StatefulClass::new(EXCEPTION_CLASS_NAME);
21+
// The `extends` is same as the PHP class `extends`.
22+
exception_class.extends("Exception");
23+
exception_class
24+
}
2525

26+
#[derive(Debug, thiserror::Error)]
27+
pub enum HttpClientError {
2628
#[error(transparent)]
27-
Reqwest(#[from] reqwest::Error),
29+
Reqwest(reqwest::Error),
2830

2931
#[error("should call '{method_name}()' before call 'body()'")]
3032
ResponseAfterRead { method_name: String },
@@ -33,9 +35,14 @@ pub enum HttpClientError {
3335
ResponseHadRead,
3436
}
3537

36-
pub fn make_exception_class() -> StatefulClass<()> {
37-
let mut exception_class = StatefulClass::new(EXCEPTION_CLASS_NAME);
38-
// The `extends` is same as the PHP class `extends`.
39-
exception_class.extends("Exception");
40-
exception_class
38+
impl Throwable for HttpClientError {
39+
fn get_class(&self) -> &ClassEntry {
40+
ClassEntry::from_globals(EXCEPTION_CLASS_NAME).unwrap_or_else(|_| exception_class())
41+
}
42+
}
43+
44+
impl From<HttpClientError> for phper::Error {
45+
fn from(e: HttpClientError) -> Self {
46+
phper::Error::throw(e)
47+
}
4148
}

examples/http-client/src/request.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@
99
// See the Mulan PSL v2 for more details.
1010

1111
use crate::{errors::HttpClientError, response::RESPONSE_CLASS_NAME};
12-
use phper::classes::{ClassEntry, StatefulClass, Visibility};
12+
use phper::{
13+
classes::{ClassEntry, StatefulClass, Visibility},
14+
errors::ThrowObject,
15+
};
1316
use reqwest::blocking::RequestBuilder;
1417
use std::mem::take;
1518

@@ -23,12 +26,14 @@ pub fn make_request_builder_class() -> StatefulClass<Option<RequestBuilder>> {
2326

2427
class.add_method("send", Visibility::Public, |this, _arguments| {
2528
let state = take(this.as_mut_state());
26-
let response = state.unwrap().send()?;
27-
let mut object = ClassEntry::from_globals(RESPONSE_CLASS_NAME)?.new_object([])?;
29+
let response = state.unwrap().send().map_err(HttpClientError::Reqwest)?;
30+
let mut object = ClassEntry::from_globals(RESPONSE_CLASS_NAME)
31+
.map_err(ThrowObject::from_throwable)?
32+
.new_object([])?;
2833
unsafe {
2934
*object.as_mut_state() = Some(response);
3035
}
31-
Ok::<_, HttpClientError>(object)
36+
Ok::<_, phper::Error>(object)
3237
});
3338

3439
class

examples/http-client/src/response.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,9 @@ pub fn make_response_class() -> StatefulClass<Option<Response>> {
2424

2525
class.add_method("body", Visibility::Public, |this, _arguments| {
2626
let response = take(this.as_mut_state());
27-
let body = response
28-
.ok_or(HttpClientError::ResponseHadRead)
29-
.and_then(|response| response.bytes().map_err(Into::into))?;
30-
Ok::<_, HttpClientError>(body.to_vec())
27+
let response = response.ok_or(HttpClientError::ResponseHadRead)?;
28+
let body = response.bytes().map_err(HttpClientError::Reqwest)?;
29+
Ok::<_, phper::Error>(body.to_vec())
3130
});
3231

3332
class.add_method("status", Visibility::Public, |this, _arguments| {

examples/http-server/src/errors.rs

Lines changed: 17 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -8,36 +8,28 @@
88
// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
99
// See the Mulan PSL v2 for more details.
1010

11-
use hyper::header::{InvalidHeaderName, InvalidHeaderValue};
12-
use phper::classes::{ClassEntry, StatefulClass};
13-
use std::{net::AddrParseError, str::Utf8Error};
11+
use phper::{
12+
classes::{ClassEntry, StatefulClass},
13+
errors::{exception_class, Throwable},
14+
};
15+
use std::error::Error;
1416

1517
const EXCEPTION_CLASS_NAME: &str = "HttpServer\\HttpServerException";
1618

17-
#[derive(Debug, thiserror::Error, phper::Throwable)]
18-
#[throwable_class(EXCEPTION_CLASS_NAME)]
19-
pub enum HttpServerError {
20-
#[error(transparent)]
21-
#[throwable(transparent)]
22-
Phper(#[from] phper::Error),
19+
#[derive(Debug, thiserror::Error)]
20+
#[error(transparent)]
21+
pub struct HttpServerError(pub Box<dyn Error>);
2322

24-
#[error(transparent)]
25-
Utf8Error(#[from] Utf8Error),
26-
27-
#[error(transparent)]
28-
AddrParse(#[from] AddrParseError),
29-
30-
#[error(transparent)]
31-
Io(#[from] std::io::Error),
32-
33-
#[error(transparent)]
34-
Hyper(#[from] hyper::Error),
35-
36-
#[error(transparent)]
37-
InvalidHeaderName(#[from] InvalidHeaderName),
23+
impl Throwable for HttpServerError {
24+
fn get_class(&self) -> &ClassEntry {
25+
ClassEntry::from_globals(EXCEPTION_CLASS_NAME).unwrap_or_else(|_| exception_class())
26+
}
27+
}
3828

39-
#[error(transparent)]
40-
InvalidHeaderValue(#[from] InvalidHeaderValue),
29+
impl From<HttpServerError> for phper::Error {
30+
fn from(e: HttpServerError) -> Self {
31+
phper::Error::throw(e)
32+
}
4133
}
4234

4335
pub fn make_exception_class() -> StatefulClass<()> {

examples/http-server/src/response.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,15 @@ pub fn make_response_class() -> StatefulClass<Response<Body>> {
2222

2323
class
2424
.add_method("header", Visibility::Public, |this, arguments| {
25+
let name = arguments[0].expect_z_str()?.to_bytes();
26+
let value = arguments[1].expect_z_str()?.to_bytes();
27+
2528
let response: &mut Response<Body> = this.as_mut_state();
2629
response.headers_mut().insert(
27-
HeaderName::from_bytes(arguments[0].as_z_str().unwrap().to_bytes())?,
28-
HeaderValue::from_bytes(arguments[1].as_z_str().unwrap().to_bytes())?,
30+
HeaderName::from_bytes(name).map_err(|e| HttpServerError(Box::new(e)))?,
31+
HeaderValue::from_bytes(value).map_err(|e| HttpServerError(Box::new(e)))?,
2932
);
30-
Ok::<_, HttpServerError>(())
33+
Ok::<_, phper::Error>(())
3134
})
3235
.argument(Argument::by_val("data"));
3336

examples/http-server/src/server.rs

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ use hyper::{
2020
use phper::{
2121
alloc::{EBox, RefClone, ToRefOwned},
2222
classes::{ClassEntry, StatefulClass, Visibility},
23-
errors::Error::Throw,
2423
functions::Argument,
2524
values::ZVal,
2625
};
@@ -48,12 +47,17 @@ pub fn make_server_class() -> StatefulClass<Option<Builder<AddrIncoming>>> {
4847
.add_method("__construct", Visibility::Public, |this, arguments| {
4948
let host = arguments[0].expect_z_str()?;
5049
let port = arguments[1].expect_long()?;
50+
5151
this.set_property("host", host.to_owned());
5252
this.set_property("port", port);
53-
let addr = format!("{}:{}", host.to_str()?, port).parse::<SocketAddr>()?;
53+
54+
let addr = format!("{}:{}", host.to_str()?, port)
55+
.parse::<SocketAddr>()
56+
.map_err(|e| HttpServerError(Box::new(e)))?;
5457
let builder = Server::bind(&addr);
5558
*this.as_mut_state() = Some(builder);
56-
Ok::<_, HttpServerError>(())
59+
60+
Ok::<_, phper::Error>(())
5761
})
5862
.arguments([Argument::by_val("host"), Argument::by_val("port")]);
5963

@@ -73,7 +77,7 @@ pub fn make_server_class() -> StatefulClass<Option<Builder<AddrIncoming>>> {
7377

7478
let make_svc = make_service_fn(move |_conn| async move {
7579
Ok::<_, Infallible>(service_fn(move |_: Request<Body>| async move {
76-
match async move {
80+
let fut = async move {
7781
let handle = unsafe { HANDLE.load(Ordering::SeqCst).as_mut().unwrap() };
7882

7983
let request =
@@ -85,21 +89,16 @@ pub fn make_server_class() -> StatefulClass<Option<Builder<AddrIncoming>>> {
8589
let response_val = response.to_ref_owned();
8690
let response_val = ZVal::from(response_val);
8791

88-
match handle.call([request, response_val]) {
89-
Err(Throw(ex)) => {
90-
let state = unsafe { response.as_mut_state::<Response<Body>>() };
91-
*state.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
92-
*state.body_mut() = ex.to_string().into();
93-
}
94-
Err(e) => return Err(e.into()),
95-
_ => {}
96-
}
92+
if let Err(err) = handle.call([request, response_val]) {
93+
let state = unsafe { response.as_mut_state::<Response<Body>>() };
94+
*state.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
95+
*state.body_mut() = err.to_string().into();
96+
};
9797

9898
let response = replace_and_get(unsafe { response.as_mut_state() });
99-
Ok::<Response<Body>, HttpServerError>(response)
100-
}
101-
.await
102-
{
99+
Ok::<Response<Body>, phper::Error>(response)
100+
};
101+
match fut.await {
103102
Ok(response) => Ok::<Response<Body>, Infallible>(response),
104103
Err(e) => {
105104
let mut response = Response::new("".into());
@@ -112,9 +111,11 @@ pub fn make_server_class() -> StatefulClass<Option<Builder<AddrIncoming>>> {
112111
});
113112

114113
let server = builder.serve(make_svc);
115-
Handle::current().block_on(server)?;
114+
Handle::current()
115+
.block_on(server)
116+
.map_err(|e| HttpServerError(Box::new(e)))?;
116117

117-
Ok::<_, HttpServerError>(())
118+
Ok::<_, phper::Error>(())
118119
});
119120

120121
class

examples/logging/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ license = { workspace = true }
2121
crate-type = ["lib", "cdylib"]
2222

2323
[dependencies]
24-
anyhow = "1.0.66"
2524
phper = { version = "0.7.0", path = "../../phper" }
2625

2726
[dev-dependencies]

examples/logging/src/lib.rs

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
99
// See the Mulan PSL v2 for more details.
1010

11-
use anyhow::Context;
1211
use phper::{
1312
deprecated, echo, error, functions::Argument, modules::Module, notice, php_get_module,
1413
values::ZVal, warning,
@@ -25,7 +24,11 @@ pub fn get_module() -> Module {
2524
module
2625
.add_function("log_say", |params: &mut [ZVal]| -> phper::Result<()> {
2726
params[0].convert_to_string();
28-
let message = params[0].as_z_str().unwrap().to_str().context("to str")?;
27+
let message = params[0]
28+
.as_z_str()
29+
.unwrap()
30+
.to_str()
31+
.map_err(phper::Error::boxed)?;
2932
echo!("Hello, {}!", message);
3033
Ok(())
3134
})
@@ -34,7 +37,11 @@ pub fn get_module() -> Module {
3437
module
3538
.add_function("log_notice", |params: &mut [ZVal]| -> phper::Result<()> {
3639
params[0].convert_to_string();
37-
let message = params[0].as_z_str().unwrap().to_str().context("to str")?;
40+
let message = params[0]
41+
.as_z_str()
42+
.unwrap()
43+
.to_str()
44+
.map_err(phper::Error::boxed)?;
3845
notice!("Something happened: {}", message);
3946
Ok(())
4047
})
@@ -43,7 +50,11 @@ pub fn get_module() -> Module {
4350
module
4451
.add_function("log_warning", |params: &mut [ZVal]| -> phper::Result<()> {
4552
params[0].convert_to_string();
46-
let message = params[0].as_z_str().unwrap().to_str().context("to str")?;
53+
let message = params[0]
54+
.as_z_str()
55+
.unwrap()
56+
.to_str()
57+
.map_err(phper::Error::boxed)?;
4758
warning!("Something warning: {}", message);
4859
Ok(())
4960
})
@@ -52,7 +63,10 @@ pub fn get_module() -> Module {
5263
module
5364
.add_function("log_error", |params: &mut [ZVal]| -> phper::Result<()> {
5465
params[0].convert_to_string();
55-
let message = params[0].as_z_str().unwrap().to_str().context("to str")?;
66+
let message = params[0]
67+
.expect_z_str()?
68+
.to_str()
69+
.map_err(phper::Error::boxed)?;
5670
error!("Something gone failed: {}", message);
5771
Ok(())
5872
})
@@ -63,7 +77,10 @@ pub fn get_module() -> Module {
6377
"log_deprecated",
6478
|params: &mut [ZVal]| -> phper::Result<()> {
6579
params[0].convert_to_string();
66-
let message = params[0].as_z_str().unwrap().to_str().context("to str")?;
80+
let message = params[0]
81+
.expect_z_str()?
82+
.to_str()
83+
.map_err(phper::Error::boxed)?;
6784
deprecated!("Something deprecated: {}", message);
6885
Ok(())
6986
},

0 commit comments

Comments
 (0)