Skip to content
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

Update helper macros documentation and examples. #522

Merged
merged 1 commit into from
Nov 27, 2023
Merged
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
142 changes: 107 additions & 35 deletions trustfall_core/src/interpreter/helpers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,10 +135,10 @@ pub fn resolve_coercion_using_schema<
///
/// # Examples
/// ```
/// # use std::rc::Rc;
/// # use trustfall_core::{
/// # field_property,
/// # interpreter::{
/// # AsVertex,
/// # ContextIterator,
/// # ContextOutcomeIterator,
/// # helpers::resolve_property_with,
Expand All @@ -151,13 +151,15 @@ pub fn resolve_coercion_using_schema<
/// // ...
/// }
///
/// // In implementation of `BasicAdapter`
/// fn resolve_property(
/// // &mut self,
/// contexts: ContextIterator<'static, User>,
/// # struct Adapter<'a>(&'a ());
/// # impl<'a> Adapter<'a> {
/// // In implementation of `Adapter`
/// fn resolve_property<V: AsVertex<User> + 'a>(
/// &self,
/// contexts: ContextIterator<'a, User>,
/// type_name: &str,
/// property_name: &str,
/// ) -> ContextOutcomeIterator<'static, User, FieldValue> {
/// ) -> ContextOutcomeIterator<'a, User, FieldValue> {
/// match (type_name, property_name) {
/// ("User", "id") => {
/// resolve_property_with(contexts, field_property!(id)) // Macro used here
Expand All @@ -166,17 +168,19 @@ pub fn resolve_coercion_using_schema<
/// _ => unreachable!()
/// }
/// }
/// # }
/// ```
///
/// Sometimes a vertex may have to be converted to another type before the
/// property can be accessed. To do this, simply pass a conversion method
/// implemented on the `Vertex` type (in this case `as_user`) to the macro like
/// implemented on the `Vertex` type (in this case `as_user()`) to the macro like
/// in the example below.
/// ```
/// # use std::rc::Rc;
/// # use trustfall_core::{
/// # field_property,
/// # interpreter::{
/// # AsVertex,
/// # ContextIterator,
/// # ContextOutcomeIterator,
/// # helpers::resolve_property_with,
Expand Down Expand Up @@ -213,31 +217,93 @@ pub fn resolve_coercion_using_schema<
/// // ...
/// }
///
/// // In implementation of `BasicAdapter`
/// # fn resolve_property(
/// # // &mut self,
/// # contexts: ContextIterator<'static, Vertex>,
/// # type_name: &str,
/// # property_name: &str,
/// # ) -> ContextOutcomeIterator<'static, Vertex, FieldValue> {
/// # match (type_name, property_name) {
/// ("User" | "Bot", "id") => {
/// resolve_property_with(contexts, field_property!(as_user, id)) // Macro used here
/// },
/// # // ...
/// # _ => unreachable!()
/// # }
/// # struct Adapter<'a>(&'a ());
/// # impl<'a> Adapter<'a> {
/// // In implementation of `Adapter`
/// fn resolve_property<V: AsVertex<Vertex> + 'a>(
/// &self,
/// contexts: ContextIterator<'a, Vertex>,
/// type_name: &str,
/// property_name: &str,
/// ) -> ContextOutcomeIterator<'a, Vertex, FieldValue> {
/// match (type_name, property_name) {
/// ("User" | "Bot", "id") => {
/// resolve_property_with(contexts, field_property!(as_user, id)) // Macro used here
/// },
/// // ...
/// _ => unreachable!()
/// }
/// }
/// # }
/// ```
///
/// It is also possible to pass a code block to additionally handle the
/// property.
/// By default, this macro calls `.clone().into()` on the field to convert it
/// to a Trustfall property value. Most often, this is what we want.
/// However, not all types implement `Into<FieldValue>` — some aren't even `Clone`!
///
/// To handle such cases, this macro can take an optional code block that will be called
/// to convert the field's value into a Trustfall property value:
/// ```
/// # use trustfall_core::{
/// # field_property,
/// # interpreter::{
/// # AsVertex,
/// # ContextIterator,
/// # ContextOutcomeIterator,
/// # helpers::resolve_property_with,
/// # },
/// # ir::FieldValue,
/// # };
/// # pub(crate) mod chrono {
/// # #[derive(Debug, Clone)]
/// # pub(crate) struct DateTime;
/// #
/// # impl DateTime {
/// # pub(crate) fn to_rfc3339(&self) -> String {
/// # unimplemented!()
/// # }
/// # }
/// # }
/// #[derive(Debug, Clone)]
/// struct User {
/// created_at: Option<chrono::DateTime>,
/// }
///
/// # struct Adapter<'a>(&'a ());
/// # impl<'a> Adapter<'a> {
/// // Inside implementation of `Adapter`:
/// fn resolve_property<V: AsVertex<User> + 'a>(
/// &self,
/// contexts: ContextIterator<'a, V>,
/// type_name: &str,
/// property_name: &str,
/// ) -> ContextOutcomeIterator<'a, V, FieldValue> {
/// match (type_name, property_name) {
/// ("User", "created_at") => { // \/ Macro used here
/// resolve_property_with(contexts, field_property!(created_at, {
/// // `created_at` in this block refers to the `User.created_at` field.
/// created_at.as_ref().map(|dt| dt.to_rfc3339()).into()
/// }))
/// }
/// // ...
/// _ => unreachable!()
/// }
/// }
/// # }
/// ```
#[macro_export]
macro_rules! field_property {
// If the data is a field directly on the vertex type.
($field:ident) => {
move |vertex| -> $crate::ir::value::FieldValue { vertex.$field.clone().into() }
};
// Field on the vertex type + post-processing block.
($field:ident, $b:block) => {
move |vertex| -> $crate::ir::value::FieldValue {
let $field = &vertex.$field;
$b
}
};
// If we need to call a fallible conversion method
// (such as `fn as_foo() -> Option<&Foo>`) before getting the field.
($conversion:ident, $field:ident) => {
Expand Down Expand Up @@ -272,11 +338,11 @@ macro_rules! field_property {
/// In the following example, `name` would be accessed using a field, but the
/// age is accessed using a function:
/// ```rust
/// # use std::rc::Rc;
/// # use trustfall_core::{
/// # accessor_property,
/// # field_property,
/// # interpreter::{
/// # AsVertex,
/// # ContextIterator,
/// # ContextOutcomeIterator,
/// # helpers::resolve_property_with,
Expand All @@ -297,30 +363,33 @@ macro_rules! field_property {
/// }
/// }
///
/// // In implementation of `BasicAdapter`
/// fn resolve_property(
/// // &mut self,
/// contexts: ContextIterator<'static, User>,
/// # struct Adapter<'a>(&'a ());
/// # impl<'a> Adapter<'a> {
/// // In implementation of `Adapter`:
/// fn resolve_property<V: AsVertex<User> + 'a>(
/// &self,
/// contexts: ContextIterator<'a, User>,
/// type_name: &str,
/// property_name: &str,
/// ) -> ContextOutcomeIterator<'static, User, FieldValue> {
/// ) -> ContextOutcomeIterator<'a, User, FieldValue> {
/// match (type_name, property_name) {
/// ("User", "id") => resolve_property_with(contexts, field_property!(id)),
/// ("User", "age") => resolve_property_with(contexts, accessor_property!(age)),
/// // ...
/// _ => unreachable!()
/// }
/// }
/// # }
/// ```
///
/// If the function to be called requires additional arguments, they can be specified
/// as part of naming the function and the argument values will be moved into the generated closure.
/// ```rust
/// # use std::rc::Rc;
/// # use trustfall_core::{
/// # accessor_property,
/// # field_property,
/// # interpreter::{
/// # AsVertex,
/// # ContextIterator,
/// # ContextOutcomeIterator,
/// # helpers::resolve_property_with,
Expand All @@ -340,19 +409,22 @@ macro_rules! field_property {
/// }
/// }
///
/// // In implementation of `BasicAdapter`
/// fn resolve_property(
/// // &mut self,
/// contexts: ContextIterator<'static, User>,
/// # struct Adapter<'a>(&'a ());
/// # impl<'a> Adapter<'a> {
/// // In implementation of `Adapter`:
/// fn resolve_property<V: AsVertex<User> + 'a>(
/// &self,
/// contexts: ContextIterator<'a, User>,
/// type_name: &str,
/// property_name: &str,
/// ) -> ContextOutcomeIterator<'static, User, FieldValue> {
/// ) -> ContextOutcomeIterator<'a, User, FieldValue> {
/// match (type_name, property_name) {
/// ("User", "age") => resolve_property_with(contexts, accessor_property!(age(2024))),
/// // ...
/// _ => unreachable!()
/// }
/// }
/// # }
/// ```
///
/// The usage of conversion functions and possible extra processing with a code
Expand Down
Loading