5 releases (3 breaking)

0.8.0 Jun 7, 2024
0.7.2 May 31, 2024
0.7.0 May 29, 2024
0.6.1 May 28, 2024
0.5.0 May 24, 2024

#76 in #uri


Used in 2 crates

BSD-3-Clause

38KB
728 lines

XAPI Oxidized Derive

This crate defines the magic behind the URI build mappings found in oxinate_core and the root crate, oxinat. Primarily this crate is used in the core library to generate relevant methods that eventually result in the URI building system in oxinat.

At this time, the derive macros do not support unit structs at the top-level of structural definitions, but does support for regular structs and enumerations.

use oxinat_derive::UriBuilder;

#[derive(Clone, Debug, Default, UriBuilder)]
#[match_path(path = "some/uri")]
#[match_path(path = "some/uri/{some_parameter}")]
struct SomeUriBuilder {
    #[param]
    some_parameter: Option<String>
}

Attribute Directives

As briefly described above, there are several attribute modifiers used to more deeply define how, at build-time, a URI may be constructed. It is important to know that match arms are constructed in order of each #[match_path] declaration.

Match Path

The first, and most important directive, will be the #[match_path] macro. This tells oxinat_derive how to construct build the resulting build method that will be defined at compile time. It comes with two attributes, path and requires (optional).

  • path is required. This allows oxinat_derive to know what and how pattern(s) should be constructed for the builder.
  • requires is an optional attribute. It accepts a string of some boolean expression (e.g. "2+2 == 4"). This modifies the match arm to only be valid on the condition. NOTE: At this scope, the attribute will match at the 'self' level of the builder.

Parent and Param

Both #[parent] and #[param] behave effectively the same way when constructing match arms for the eventual build method. However, there are differences when constructing certain methods that allow for pre-build customization.

All-in-all, it will look the same on the surface. Before URI construction, methods will be implemented for these fields which allow a user to set the inner values.

For example:

use oxinat_derive::UriBuilder;

#[derive(Clone, Debug, Default, UriBuilder)]
#[match_path(path = "{parent}/some/uri")]
#[match_path(path = "{parent}/some/uri/{some_parameter}")]
struct SomeUriBuilder {
    #[param]
    some_parameter: Option<String>
    #[parent]
    parent: Option<String>
}

// Under the hood, these methods will be implemented.
impl SomeUriBuilder {
    pub fn with_some_parameter(mut self, value: String) -> Self {
        ...
    }

    pub fn with_parent(mut self, value: String) -> Self {
        ...
    }
}

In addition to generating methods, declaring fields as either a parent or a param allows for some customization with additional attributes.

  • requires works similar to how it behaves at the #[match_path] level, but instead at the parameter level.
  • map_from allows for specific formatting/manipulation of a value during build-time of the URI.

Both of these directives behave the same as #[match_path(requires = "..")]. This means that it will accept a stringed boolean expression, such as a closure, function or macro.

Dependencies

~1–1.5MB
~29K SLoC