Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
P
picodata
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Container Registry
Model registry
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
core
picodata
Commits
e4a77bcf
Commit
e4a77bcf
authored
1 year ago
by
Georgy Moshkin
Browse files
Options
Downloads
Patches
Plain Diff
feat: Introspection::set_field_from_rmpv
parent
89189850
No related branches found
No related tags found
1 merge request
!913
feat: pico.config() now shows sources for provided parameters
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
pico_proc_macro/src/lib.rs
+33
-9
33 additions, 9 deletions
pico_proc_macro/src/lib.rs
src/introspection.rs
+112
-6
112 additions, 6 deletions
src/introspection.rs
with
145 additions
and
15 deletions
pico_proc_macro/src/lib.rs
+
33
−
9
View file @
e4a77bcf
...
...
@@ -48,9 +48,22 @@ pub fn derive_introspection(input: proc_macro::TokenStream) -> proc_macro::Token
},
_
=>
{}
}
let
crate_
=
&
context
.args.crate_
;
let
body_for_field_infos
=
generate_body_for_field_infos
(
&
context
);
let
body_for_set_field_from_yaml
=
generate_body_for_set_field_from_yaml
(
&
context
);
let
body_for_set_field_from_yaml
=
generate_body_for_set_field_from_something
(
&
context
,
&
syn
::
parse2
(
quote!
{
set_field_from_yaml
})
.unwrap
(),
&
syn
::
parse2
(
quote!
{
serde_yaml
::
from_str
})
.unwrap
(),
);
let
body_for_set_field_from_rmpv
=
generate_body_for_set_field_from_something
(
&
context
,
&
syn
::
parse2
(
quote!
{
set_field_from_rmpv
})
.unwrap
(),
&
syn
::
parse2
(
quote!
{
#
crate_
::
introspection
::
from_rmpv_value
})
.unwrap
(),
);
let
body_for_get_field_as_rmpv
=
generate_body_for_get_field_as_rmpv
(
&
context
);
let
crate_
=
&
context
.args.crate_
;
...
...
@@ -61,11 +74,16 @@ pub fn derive_introspection(input: proc_macro::TokenStream) -> proc_macro::Token
#
body_for_field_infos
];
fn
set_field_from_yaml
(
&
mut
self
,
path
:
&
str
,
yaml
:
&
str
)
->
::
std
::
result
::
Result
<
(),
#
crate_
::
introspection
::
IntrospectionError
>
{
fn
set_field_from_yaml
(
&
mut
self
,
path
:
&
str
,
value
:
&
str
)
->
::
std
::
result
::
Result
<
(),
#
crate_
::
introspection
::
IntrospectionError
>
{
use
#
crate_
::
introspection
::
IntrospectionError
;
#
body_for_set_field_from_yaml
}
fn
set_field_from_rmpv
(
&
mut
self
,
path
:
&
str
,
value
:
&
#
crate_
::
introspection
::
RmpvValue
)
->
::
std
::
result
::
Result
<
(),
#
crate_
::
introspection
::
IntrospectionError
>
{
use
#
crate_
::
introspection
::
IntrospectionError
;
#
body_for_set_field_from_rmpv
}
fn
get_field_as_rmpv
(
&
self
,
path
:
&
str
)
->
::
std
::
result
::
Result
<
#
crate_
::
introspection
::
RmpvValue
,
#
crate_
::
introspection
::
IntrospectionError
>
{
use
#
crate_
::
introspection
::
IntrospectionError
;
#
body_for_get_field_as_rmpv
...
...
@@ -105,7 +123,11 @@ fn generate_body_for_field_infos(context: &Context) -> proc_macro2::TokenStream
code
}
fn
generate_body_for_set_field_from_yaml
(
context
:
&
Context
)
->
proc_macro2
::
TokenStream
{
fn
generate_body_for_set_field_from_something
(
context
:
&
Context
,
fn_ident
:
&
syn
::
Ident
,
conversion_fn
:
&
syn
::
Path
,
)
->
proc_macro2
::
TokenStream
{
let
mut
set_non_nestable
=
quote!
{};
let
mut
set_nestable
=
quote!
{};
let
mut
error_if_nestable
=
quote!
{};
...
...
@@ -122,20 +144,22 @@ fn generate_body_for_set_field_from_yaml(context: &Context) -> proc_macro2::Toke
// Handle assigning to a non-nestable field
set_non_nestable
.extend
(
quote!
{
#
name
=>
{
match
serde_yaml
::
from_str
(
yaml
)
{
match
#
conversion_fn
(
value
)
{
Ok
(
v
)
=>
{
self
.#
ident
=
v
;
return
Ok
(());
}
Err
(
error
)
=>
return
Err
(
IntrospectionError
::
FromSerdeYaml
{
field
:
path
.into
(),
error
}),
Err
(
error
)
=>
{
return
Err
(
IntrospectionError
::
ConvertToFieldError
{
field
:
path
.into
(),
error
:
error
.into
()
});
}
}
}
});
}
else
{
// Handle assigning to a nested
sub-
field
// Handle assigning to a nested field
set_nestable
.extend
(
quote!
{
#
name
=>
{
return
self
.#
ident
.
set_field_from_yaml
(
tail
,
yaml
)
return
self
.#
ident
.
#
fn_ident
(
tail
,
value
)
.map_err
(|
e
|
e
.with_prepended_prefix
(
head
));
}
});
...
...
@@ -158,11 +182,11 @@ fn generate_body_for_set_field_from_yaml(context: &Context) -> proc_macro2::Toke
// Handle if a nested path is specified for non-nestable field
let
mut
error_if_non_nestable
=
quote!
{};
if
!
non_nestable_names
.is_empty
()
{
error_if_non_nestable
.extend
(
quote!
{
error_if_non_nestable
=
quote!
{
#
(
#
non_nestable_names
)|
*
=>
{
return
Err
(
IntrospectionError
::
NotNestable
{
field
:
head
.into
()
})
}
}
)
;
};
}
// Actual generated body:
...
...
This diff is collapsed.
Click to expand it.
src/introspection.rs
+
112
−
6
View file @
e4a77bcf
...
...
@@ -46,8 +46,47 @@ pub trait Introspection {
/// s.set_field_from_yaml("text", "hello world").unwrap();
/// s.set_field_from_yaml("nested.sub_field", "3.14").unwrap();
/// ```
// TODO: maybe remove in favour of set_field_from_rmpv
fn
set_field_from_yaml
(
&
mut
self
,
path
:
&
str
,
yaml
:
&
str
)
->
Result
<
(),
IntrospectionError
>
;
/// Assign field of `self` described by `path` to value converted from the
/// provided `value`.
///
/// When using the `#[derive(Introspection)]` derive macro the implementation
/// uses the `rmpv::ext::deserialize_from` to convert to the required type.
/// This may change in the future.
///
/// # Examples:
/// ```
/// use picodata::introspection::Introspection;
/// use rmpv::Value;
///
/// #[derive(Introspection, Default)]
/// #[introspection(crate = picodata)]
/// struct MyStruct {
/// number: i32,
/// text: String,
/// #[introspection(nested)]
/// nested: NestedStruct,
/// }
///
/// #[derive(Introspection, Default)]
/// #[introspection(crate = picodata)]
/// struct NestedStruct {
/// sub_field: f32,
/// }
///
/// let mut s = MyStruct::default();
/// s.set_field_from_rmpv("number", &Value::from(420)).unwrap();
/// s.set_field_from_rmpv("text", &Value::from("hello world")).unwrap();
/// s.set_field_from_rmpv("nested.sub_field", &Value::F32(3.14)).unwrap();
/// ```
fn
set_field_from_rmpv
(
&
mut
self
,
path
:
&
str
,
value
:
&
rmpv
::
Value
,
)
->
Result
<
(),
IntrospectionError
>
;
/// Get field of `self` described by `path` as a generic msgpack value in
/// form of [`rmpv::Value`].
///
...
...
@@ -168,6 +207,17 @@ where
/// A public reimport for use in the derive macro.
pub
use
rmpv
::
Value
as
RmpvValue
;
/// Converts a [`rmpv::Value`] `value` to a generic serde deserializable type.
/// This function is just needed to be called from the derived
/// [`Introspection::set_field_from_rmpv`] implementations.
#[inline(always)]
pub
fn
from_rmpv_value
<
T
>
(
value
:
&
rmpv
::
Value
)
->
Result
<
T
,
Error
>
where
T
:
for
<
'de
>
serde
::
Deserialize
<
'de
>
,
{
rmpv
::
ext
::
deserialize_from
(
value
.as_ref
())
.map_err
(
Error
::
other
)
}
/// Converts a generic serde serializable value to [`rmpv::Value`]. This
/// function is just needed to be called from the derived
/// [`Introspection::get_field_as_rmpv`] implementations.
...
...
@@ -189,9 +239,9 @@ pub enum IntrospectionError {
},
#[error(
"incorrect value for field '{field}': {error}"
)]
FromSerdeYaml
{
ConvertToFieldError
{
field
:
String
,
error
:
serde_yaml
::
Error
,
error
:
Box
<
dyn
std
::
error
::
Error
>
,
},
#[error(
"{expected} '{path}'"
)]
...
...
@@ -250,7 +300,7 @@ impl IntrospectionError {
*
parent
=
format!
(
"{prefix}.{parent}"
);
}
}
Self
::
FromSerdeYaml
{
field
,
..
}
=>
{
Self
::
ConvertToFieldError
{
field
,
..
}
=>
{
*
field
=
format!
(
"{prefix}.{field}"
);
}
Self
::
AssignToNested
{
field
,
..
}
=>
{
...
...
@@ -269,7 +319,7 @@ mod test {
use
super
::
*
;
use
pretty_assertions
::
assert_eq
;
#[derive(Default,
Debug,
Introspection)]
#[derive(Default,
Debug,
Introspection
,
PartialEq
)]
struct
S
{
x
:
i32
,
y
:
f32
,
...
...
@@ -282,7 +332,7 @@ mod test {
ignored
:
serde_yaml
::
Value
,
}
#[derive(Default,
Debug,
Introspection)]
#[derive(Default,
Debug,
Introspection
,
PartialEq
)]
struct
Nested
{
a
:
String
,
b
:
i64
,
...
...
@@ -290,7 +340,7 @@ mod test {
empty
:
Empty
,
}
#[derive(Default,
Debug,
Introspection)]
#[derive(Default,
Debug,
Introspection
,
PartialEq
)]
struct
Empty
{}
#[test]
...
...
@@ -401,6 +451,62 @@ mod test {
assert_eq!
(
s
.r
#
struct
.b
,
0xbbbb
);
}
#[test]
fn
set_field_from_rmpv
()
{
let
mut
s
=
S
::
default
();
//
// Error cases
//
let
e
=
s
.set_field_from_rmpv
(
"x"
,
&
rmpv
::
Value
::
Boolean
(
true
))
.unwrap_err
();
assert_eq!
(
e
.to_string
(),
"incorrect value for field 'x': error while decoding value: invalid type: boolean `true`, expected i32"
);
let
e
=
s
.set_field_from_rmpv
(
"struct.a"
,
&
rmpv
::
Value
::
Nil
)
.unwrap_err
();
assert_eq!
(
e
.to_string
(),
"incorrect value for field 'struct.a': error while decoding value: invalid type: unit value, expected a string"
);
let
e
=
s
.set_field_from_rmpv
(
"struct"
,
&
rmpv
::
Value
::
Nil
)
.unwrap_err
();
assert_eq!
(
e
.to_string
(),
"field 'struct' cannot be assigned directly, must choose a sub-field (for example 'struct.a')"
);
// Other error cases are mostly the same as in case of `set_field_from_yaml`
//
// Success cases
//
s
.set_field_from_rmpv
(
"x"
,
&
rmpv
::
Value
::
from
(
123
))
.unwrap
();
s
.set_field_from_rmpv
(
"y"
,
&
rmpv
::
Value
::
F32
(
3.21
))
.unwrap
();
s
.set_field_from_rmpv
(
"s"
,
&
rmpv
::
Value
::
from
(
"ccc"
))
.unwrap
();
s
.set_field_from_rmpv
(
"v"
,
&
rmpv
::
Value
::
Array
(
vec!
[
rmpv
::
Value
::
from
(
"Vv"
),
rmpv
::
Value
::
from
(
"vV"
)]),
)
.unwrap
();
s
.set_field_from_rmpv
(
"struct.a"
,
&
(
"AaAa"
.into
()))
.unwrap
();
s
.set_field_from_rmpv
(
"struct.b"
,
&
(
0xccc
.into
()))
.unwrap
();
assert_eq!
(
s
,
S
{
x
:
123
,
y
:
3.21
,
s
:
"ccc"
.into
(),
v
:
vec!
[
"Vv"
.into
(),
"vV"
.into
()],
r
#
struct
:
Nested
{
a
:
"AaAa"
.into
(),
b
:
0xccc
,
empty
:
Empty
{},
},
ignored
:
Default
::
default
(),
},
);
}
#[test]
fn
get_field_as_rmpv
()
{
let
s
=
S
{
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment