Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit8a16647

Browse files
authored
Merge pull request#1011 from schungx/master
Handle Option fields in CustomType derive
2 parents7138710 +8c07d41 commit8a16647

File tree

6 files changed

+95
-11
lines changed

6 files changed

+95
-11
lines changed

‎CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@ Enhancements
1515
-----------
1616

1717
*`CustomType` derive macro now supports generic types (thanks[`@ProphetOSpam`](https://github.com/ProphetOSpam)[#999](https://github.com/rhaiscript/rhai/pull/999)). The`rhai_codegen` crate dependency is bumped to`3.0.0` or later.
18+
*`CustomType` derive macro now handles`Option` fields (thanks[`@agersant`](https://github.com/agersant)[#1005](https://github.com/rhaiscript/rhai/pull/1005)).
1819
*`Engine::eval_binary_op` is added to quickly compare two`Dynamic` values.
19-
* Better handling for 32-bit architectures.
20+
* Better handling for 32-bit architectures and enhanced safety by replacing casts with`try_from` (thanks[`@therealprof`](https://github.com/therealprof)[#1009](https://github.com/rhaiscript/rhai/pull/1009)).
2021

2122

2223
Version 1.22.2

‎Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ num-traits = { version = "0.2.14", default-features = false }
2525
once_cell = {version ="1.20.1",default-features =false,features = ["race","portable-atomic","alloc"] }
2626
bitflags = {version ="2.3.3",default-features =false }
2727
smartstring = {version ="1.0.0",default-features =false }
28-
rhai_codegen = {version ="3.0.0",path ="codegen" }
28+
rhai_codegen = {version ="3.1.0",path ="codegen" }
2929

3030
no-std-compat = {git ="https://gitlab.com/jD91mZM2/no-std-compat.git",version ="0.4.1",default-features =false,features = ["alloc"],optional =true }
3131
libm = {version ="0.2.0",default-features =false,optional =true }

‎codegen/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name ="rhai_codegen"
3-
version ="3.0.0"
3+
version ="3.1.0"
44
edition ="2018"
55
resolver ="2"
66
authors = ["jhwgh1968","Stephen Chung"]

‎codegen/src/custom_type.rs

Lines changed: 83 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,51 @@ pub fn derive_custom_type_impl(input: DeriveInput) -> TokenStream {
183183
}
184184
}
185185

186+
// Code lifted from: https://stackoverflow.com/questions/55271857/how-can-i-get-the-t-from-an-optiont-when-using-syn
187+
fnextract_type_from_option(ty:&syn::Type) ->Option<&syn::Type>{
188+
use syn::{GenericArgument,Path,PathArguments,PathSegment};
189+
190+
fnextract_type_path(ty:&syn::Type) ->Option<&Path>{
191+
match*ty{
192+
syn::Type::Path(ref type_path)if type_path.qself.is_none() =>Some(&type_path.path),
193+
_ =>None,
194+
}
195+
}
196+
197+
// TODO store (with lazy static) the vec of string
198+
// TODO maybe optimization, reverse the order of segments
199+
fnextract_option_segment(path:&Path) ->Option<&PathSegment>{
200+
let idents_of_path = path
201+
.segments
202+
.iter()
203+
.into_iter()
204+
.fold(String::new(), |mut acc, v|{
205+
acc.push_str(&v.ident.to_string());
206+
acc.push('|');
207+
acc
208+
});
209+
vec!["Option|","std|option|Option|","core|option|Option|"]
210+
.into_iter()
211+
.find(|s|&idents_of_path ==*s)
212+
.and_then(|_| path.segments.last())
213+
}
214+
215+
extract_type_path(ty)
216+
.and_then(|path|extract_option_segment(path))
217+
.and_then(|path_seg|{
218+
let type_params =&path_seg.arguments;
219+
// It should have only on angle-bracketed param ("<String>"):
220+
match*type_params{
221+
PathArguments::AngleBracketed(ref params) => params.args.first(),
222+
_ =>None,
223+
}
224+
})
225+
.and_then(|generic_arg|match*generic_arg{
226+
GenericArgument::Type(ref ty) =>Some(ty),
227+
_ =>None,
228+
})
229+
}
230+
186231
fnscan_fields(fields:&[&Field],accessors:&mutVec<TokenStream>,errors:&mutVec<TokenStream>){
187232
for(i,&field)in fields.iter().enumerate(){
188233
letmut map_name =None;
@@ -314,21 +359,54 @@ fn scan_fields(fields: &[&Field], accessors: &mut Vec<TokenStream>, errors: &mut
314359
quote!{ #index}
315360
};
316361

362+
// Handle `Option` fields
363+
let option_type =extract_type_from_option(&field.ty);
364+
317365
// Override functions
318-
let get =match(get_mut_fn, get_fn){
366+
367+
let get_impl =match(get_mut_fn, get_fn){
319368
(Some(func), _) => func,
320369
(None,Some(func)) =>quote!{ |obj:&mutSelf| #func(&*obj)},
321-
(None,None) =>quote!{ |obj:&mutSelf| obj.#field_name.clone()},
370+
(None,None) =>{
371+
ifletSome(_) = option_type{
372+
quote!{ |obj:&mutSelf| obj.#field_name.clone().map_or(Dynamic::UNIT,Dynamic::from)}
373+
}else{
374+
quote!{ |obj:&mutSelf| obj.#field_name.clone()}
375+
}
376+
}
322377
};
323378

324-
let set = set_fn.unwrap_or_else(||quote!{ |obj:&mutSelf, val| obj.#field_name = val});
379+
let set_impl = set_fn.unwrap_or_else(||{
380+
ifletSome(typ) = option_type{
381+
quote!{
382+
|obj:&mutSelf, val:Dynamic|{
383+
if val.is_unit(){
384+
obj.#field_name =None;
385+
Ok(())
386+
} elseifletSome(x) = val.read_lock::<#typ>(){
387+
obj.#field_name =Some(x.clone());
388+
Ok(())
389+
} else{
390+
Err(Box::new(EvalAltResult::ErrorMismatchDataType(
391+
stringify!(#typ).to_string(),
392+
val.type_name().to_string(),
393+
Position::NONE
394+
)))
395+
}
396+
}
397+
}
398+
}else{
399+
quote!{ |obj:&mutSelf, val| obj.#field_name = val}
400+
}
401+
});
402+
325403
let name = map_name.unwrap_or_else(||quote!{ stringify!(#field_name)});
326404

327405
accessors.push({
328406
let method =if readonly{
329-
quote!{ builder.with_get(#name, #get)}
407+
quote!{ builder.with_get(#name, #get_impl)}
330408
}else{
331-
quote!{ builder.with_get_set(#name, #get, #set)}
409+
quote!{ builder.with_get_set(#name, #get_impl, #set_impl)}
332410
};
333411

334412
#[cfg(feature ="metadata")]

‎codegen/tests/test_custom_type.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use rhai::{CustomType,Engine,TypeBuilder,INT};
1+
use rhai::{CustomType,Dynamic,Engine,EvalAltResult,Position,TypeBuilder,INT};
22

33
// Sanity check to make sure everything compiles
44

@@ -21,6 +21,7 @@ pub struct Foo {
2121
pub(crate)baz:String,
2222
#[rhai_type(set =Self::set_qux)]
2323
pubqux:Vec<INT>,
24+
pubmaybe:Option<INT>,
2425
}
2526

2627
implFoo{

‎tests/build_type.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#![cfg(not(feature ="no_object"))]
2-
use rhai::{CustomType,Engine,EvalAltResult,Position,TypeBuilder,INT};
2+
use rhai::{CustomType,Dynamic,Engine,EvalAltResult,Position,TypeBuilder,INT};
33
use std::cmp::Ordering;
44

55
#[test]
@@ -170,6 +170,7 @@ fn test_build_type_macro() {
170170
baz:bool,
171171
#[rhai_type(set =Self::set_hello)]
172172
hello:String,
173+
maybe:Option<bool>,
173174
}
174175

175176
implFoo{
@@ -191,6 +192,7 @@ fn test_build_type_macro() {
191192
bar:5,
192193
baz:false,
193194
hello:"hey".to_string(),
195+
maybe:None,
194196
});
195197
}
196198
}
@@ -207,6 +209,7 @@ fn test_build_type_macro() {
207209
foo.hello = "world!";
208210
foo.emphasize = true;
209211
foo.hello = "yo";
212+
foo.maybe = true;
210213
foo
211214
"#
212215
)
@@ -215,7 +218,8 @@ fn test_build_type_macro() {
215218
dummy:0,
216219
bar:5,
217220
baz:true,
218-
hello:"world!yo!!!!!".into()
221+
hello:"world!yo!!!!!".into(),
222+
maybe:Some(true),
219223
}
220224
);
221225
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp