Skip to main content

Module doc_ref_attrs

Module doc_ref_attrs 

Source
Expand description

Reference: Attributes supported by the tor_config macro

§Top-level attributes

These attributes can be provided at the top-level, right after derive_deftly(TorConfig) and before pub struct FooConfig.

§deftly(tor_config(no_serialize_trait)) — Don’t derive Serialize for the builder struct

By default, the generated Builder will derive serde::Serialize. This attribute suppresses that behavior.

§deftly(tor_config(no_deserialize_trait)) — Don’t derive Deserialize for the builder struct

By default, the generated Builder will implement serde::Deserialize. This attribute suppresses that behavior.

Using this option will prevent your type from participating directly in the Arti configuration system.

§deftly(tor_config(no_flattenable_trait)) — Don’t derive Flattenable for the builder struct

By default, the generated Builder will derive Flattenable. This attribute suppresses that behavior.

§deftly(tor_config(no_extendbuilder_trait)) — Don’t derive ExtendBuilder for the builder struct

By default, the generated Builder will derive ExtendBuilder. This attribute suppresses that behavior.

§deftly(tor_config(no_default_trait)) — Don’t derive Default for the config struct

By default, the macro will derive Default on the configuration type by creating a default builder, and constructing the configuration type with it.

§deftly(tor_config(no_test_default)) — Don’t test Default for the config struct

By default, the macro will implement a test to make sure that its generated Default implementation produces the same result as deserializing an empty configuration builder, and building it. This attribute prevents that test from being generated.

The test is also omitted when no_default_trait or no_deserialize_trait is given.

Note: You must specify this option if the configuration type has any generic parameters. Otherwise, it’s best to avoid this attribute.

TODO: We should remove this limitation if we can.

§deftly(tor_config(no_builder_trait)) — Don’t derive Builder for the builder struct

By default, the builder will implement tor_config::load::Builder. This attribute suppresses that behavior.

This attribute’s name ends with _trait to remind the caller that the Builder struct itself will still be implemented.

§deftly(tor_config(no_buildable_trait)) — Don’t derive Buildable for the config struct

By default, the configuration struct will implement tor_config::load::Buildable. This attribute suppresses that behavior.

§deftly(tor_config(attr = "..")) — Apply an attribute to the builder struct

This attribute passes its contents through to a new attribute on the derived builder struct. For example, you can make the builder derive PartialOrd by saying

#[deftly(tor_config(attr= "derive(PartialOrd)"))]

(See also attr for fields.)

§deftly(tor_config(pre_build = "..")) — Call a function before building

This attribute makes the generated build() method call a validation function on itself before it builds the configuration. The function must take &FooBuilder as an argument, and return Result<(),ConfigBuildError>. If the function returns an error, then the build method fails with that error.

Example:

#[derive(Clone,Debug,PartialEq,Deftly)]
#[derive_deftly(TorConfig)]
#[deftly(tor_config(pre_build="Self::must_be_odd"))]
pub struct FavoriteOddNumber {
    #[deftly(tor_config(default="23"))]
    my_favorite: u32,
}

impl FavoriteOddNumberBuilder {
    fn must_be_odd(&self) -> Result<(), ConfigBuildError> {
        let Some(fav) = self.my_favorite else { return Ok(()); };
        if fav % 2 != 1 {
            return Err(ConfigBuildError::Invalid {
                field: "my_favorite".to_string(),
                problem: format!("{fav} was not an odd number")
            })
        }
        Ok(())
    }
}

See also post_build.

§deftly(tor_config(post_build = "..")) — Call a function after building

This attribute makes the generated build() method call a validation function on the configuration after it is built. The function must take the configuration by value as an argument, and Result<(the configuration),ConfigBuildError>. If the function returns an error, then the build method fails with that error.

Example:

#[derive(Clone,Debug,PartialEq,Deftly)]
#[derive_deftly(TorConfig)]
#[deftly(tor_config(post_build="FavoriteEvenNumber::must_be_even"))]
pub struct FavoriteEvenNumber {
    #[deftly(tor_config(default="86"))]
    my_favorite: u32,
}

impl FavoriteEvenNumber {
    fn must_be_even(self) -> Result<Self, ConfigBuildError> {
        if self.my_favorite % 2 != 0 {
            return Err(ConfigBuildError::Invalid {
                field: "my_favorite".to_string(),
                problem: format!("{} was not an even number", self.my_favorite)
            })
        }
        Ok(self)
    }
}

Note: You can also use this attribute to clean up or normalize the configuration object.

§deftly(tor_config(vis = "..")) — Change visibility of the builder

By default, the builder struct is generated with the same visibility as the configuration struct. You can use this attribute to change its visibility.

§deftly(tor_config(build_fn(name = ".."))) — Change name of the build method

By default, the generated build method is called build. You can use this attribute to change its name.

§deftly(tor_config(build_fn(vis = ".."))) — Change visibility of the build method

By default, the build() method has the same visibility as the builder struct. You can use this attribute to change its visibility.

See also:

§deftly(tor_config(build_fn(error = ".."))) — Change return error type of the build method.

By default, the build() method returns [ConfigBuildError on failure. You can change the error type with this attribute.

You will probably need to use this attribute along with build_fn(missing_field), if any of your fields are mandatory.

§deftly(tor_config(build_fn(missing_field = ".."))) — Code to generate a missing field error.

By default, when a required field is not set, the build() method returns Err(E::MissingField { field: "field_name".to_string() }), where E is ConfigBuildError or the type configured with build_fn(error). You can use this attribute to override this behavior. Its value should be an expression evaluating to a closure of type FnOnce(&str) -> E.

For compatibility with derive_builder’s version of `build_fn(error)``, you can say:

#[build_fn(error="SomeError",
           missing_field=
    r#"|fname| derive_builder::UninitializedFieldError(
                                 fname.to_string()
               ).into()"
)]

§Field-level attributes

§deftly(tor_config(default))) — Use Default::default() when no value is provided

When this attribute is provided, if the given field is absent in the builder, the build() method will set its value to Default::default().

For each field, you must specify exactly one of default, default =, no_default, build, try_build, or sub_builder.

§deftly(tor_config(default = ".."))) — Use a given value when no value is provided

When this attribute is provided, if the given field is absent in the builder, the build() method will set its value to the value of the provided expression. The expression may invoke a function, but cannot use self.

For each field, you must specify exactly one of default, default =, no_default, build, try_build, or sub_builder.

§deftly(tor_config(no_default)) — Do not provide a default for this field.

When this attribute is provided, if the given field is absent in the builder, the build() method will fail with an error.

For each field, you must specify exactly one of default, default =, no_default, build, try_build, or sub_builder.

When you set this attribute on a field, you must also set the top-level no_default_trait attribute, since there will not be a meaningful value for the configuration struct.

Don’t use this option on any config struct that’s always present with a multiplicity of one, or else the empty configuration will become invalid.

§deftly(tor_config(build = "..")) — Call a function to build this field.

When this attribute is provided, you can completely override the way that this field is constructed. The expression must evaluate to a function taking &Builder as an argument, and returning the type of the field.

For each field, you must specify exactly one of default, default =, no_default, build, try_build, or sub_builder.

Be careful with this attribute: it can lead to counterintuitive behavior for the end user.

Example:

#[derive(Clone,Debug,PartialEq,Deftly)]
#[derive_deftly(TorConfig)]
pub struct LowercaseExample {
    #[deftly(tor_config(build="Self::build_lc"))]
    lc: String,
}
impl LowercaseExampleBuilder {
    fn build_lc(&self) -> String {
        let s = self.lc.as_ref().map(String::as_str).unwrap_or("");
        s.to_lowercase()
    }
}

§deftly(tor_config(try_build = "..")) — Call a fallible function to build this field.

When this attribute is provided, you can completely override the way that this field is constructed. The expression must evaluate to a function taking &Builder as an argument, and returning Result<T, ConfigBuildError>, where T is the type of the field.

For each field, you must specify exactly one of default, default =, no_default, build, try_build, or sub_builder.

Be careful with this attribute: it can lead to counterintuitive behavior for the end user.

Example:

#[derive(Clone,Debug,PartialEq,Deftly)]
#[derive_deftly(TorConfig)]
pub struct SqrtExample {
    #[deftly(tor_config(try_build="Self::build_sqrt"))]
    val: f64,
}
impl SqrtExampleBuilder {
    fn build_sqrt(&self) -> Result<f64, ConfigBuildError> {
        let v = self.val.unwrap_or(0.0).sqrt();
        if v.is_nan() {
            return Err(ConfigBuildError::Invalid {
                field: "val".to_string(),
                problem: format!("{v} was negative")
            })
        }
        Ok(v)
    }
}

§deftly(tor_config(sub_builder)) — Declare a field to contain a nested configuration

This attribute is what allows configuration structures to nest. When you set this attribute on a field of type InnerCfg, the builder structure will contain a field of type InnerCfgBuilder. In order to construct the field, the build() method will call InnerCfgBuilder::build().

For each field, you must specify exactly one of default, default =, no_default, build, try_build, or sub_builder.

§deftly(tor_config(sub_builder(build_fn = "..."))) — Call a different function on this sub-builder

By default, when sub_builder is in use, the build() method is used to generate the inner configuration object. This attribute changes the name of the function that is called on the inner builder.

§deftly(tor_config(no_sub_builder)) — Allow a Buildable field without a sub_builder.

By default, the TorConfig macro inserts code to checks whether each field implements Buildable, and causes a compile-time error if any such field does not have an explicit sub_builder, build, try_build, or no_magic declaration. This attribute overrides this check, and allows you to have a field implementing Buildable without using the sub_builder pattern.

§deftly(tor_config(list)) — Declare a field to contain a nested list of items.

This attribute should be used on every field containing a Vec, BTreeSet, HashSet, or similar. It causes the an appropriate list-builder and set of accessors to be generated.

When using this attribute, you must also provide a default = producing a Vec of the builder type, and either list(element(build)) or list(element(clone)).

Examples:

// The builder and the constructed list will both contain u32.
#[deftly(tor_config(list(element(clone)), default = "vec![7]"))]
integers: Vec<u32>,

// The builder will contain a Vec<MyTypeBuilder>;.
#[deftly(tor_config(list(), (element(build)), default = "vec![]"))]
objects: Vec<MyType>

§deftly(tor_config(list(listtype = ...)))

Usually, the name of the list type alias and builder object based on the struct and the field name. You can provide a different name for the list type alias using this attribute, as in listtype = "TypeName". The list builder will then be constructed with the list type name, suffixed with Builder.

§deftly(tor_config(list(element(build))) — Declare that the list builder contains sub-builders.

Used along with list, and indicates the elements of the built list should be constructed via builders themselves. When this attribute is used, the builder structure will contain a Vec of builders for the list’s elements.

If this attribute is given a value, it will be used as the name of the “build” method for the list elements.

§deftly(tor_config(list(element(clone))) — Declare that the list builder objects should be cloned directly.

Used along with list, and indicates the elements of the built list should be cloned directly from those in the builder. When this attribute is used, the builder structure will contain a Vec whose elements are the same type as those of the genated list.

§deftly(tor_config(map)) — Use a map-builder pattern.

This attribute should be used on every field containing a HashMap or BTreeMap whose key is a String, and whose value type is a Buildable. It causes the template to generate a map builder type and corresponding accessor functions. The map builder behaves like a map from String to the builder type.

If a value is provided for this attribute, it is used as the name of the map type alias, and suffixed with Builder to get the name for the builder type. Otherwise, the map type alias is derived from the name of the struct and the field.

The default = attribute is mandatory with this attribute.

For more information on the generated code, see define_map_builder.

§deftly(tor_config(list(maptype = ...)))

Usually, the name of the map type alias and builder object based on the struct and the field name. You can provide a different name for the map type alias using this attribute, as in maptype = "TypeName". The map builder will then be constructed with the map type name, suffixed with Builder.

§deftly(tor_config(setter(name = ".."))) — Change the name of the setter function

By default, the setter function for a field has the same name as its field. You can provide a different name in this attribute.

§deftly(tor_config(setter(vis = ".."))) — Change the visibility of the setter function

By default, the setter function for a field has the same visibility as the builder type. You can provide a different visibility in this attribute.

§deftly(tor_config(setter(skip))) — Do not generate a setter function

By default, the builder generates a setter function for every field. You can tell it not to do so for a single field by providing this attribute.

§deftly(tor_config(setter(into))) — Have the setter function accept impl Into<T>

By default, the setter function expects an argument of type T, where T is the same type of the field. When this option is provided, the setter instead expects an argument of type impl Into<T>, and calls Into::into on it to set the field.

§deftly(tor_config(setter(try_into))) — Have the setter function accept impl TryInto<T>

By default, the setter function expects an argument of type T, where T is the same type of the field. When this option is provided, the setter instead expects an argument of type impl TryInto<T>, and calls TryInto::try_into on it to set the field. If try_into returns an error, the setter function returns that error.

§deftly(tor_config(setter(strip_option))) — Have the setter for Option<T> accept T

This attribute requires that the field itself have type Option<T> for some T. Instead of taking Option<T> as an argument, the setter now accepts T.

§deftly(tor_config(field(ty = ".."))) — Change the type of a field in the builder

By default, for every field of type T in the configuration, the builder has a field of type Option<T>. This attribute changes the type of the field in the builder to the provided type.

This attribute has no effect on the generated setter or builder code. Therefore, you will typically need to use it along with the setter(skip), build, and extend_with field attributes.

Example:

#[derive(Clone,Debug,PartialEq)]
pub struct ParsedValue {
   // ...
}
impl std::str::FromStr for ParsedValue {
    type Err = String;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        // ...
    }
}

#[derive(Clone,Debug,PartialEq,Deftly)]
#[derive_deftly(TorConfig)]
pub struct MyConfig {
    #[deftly(tor_config(
        try_build = r#"Self::try_build_behavior"#,
        field(ty = "Option<String>"),
        setter(skip)
    ))]
    behavior: ParsedValue,
}

impl MyConfigBuilder {
    pub fn behavior(&mut self, s: impl AsRef<str>) -> &mut Self {
        self.behavior = Some(s.as_ref().to_string());
        self
    }
    fn try_build_behavior(&self) -> Result<ParsedValue, ConfigBuildError> {
        self.behavior
            .as_ref()
            .map(String::as_str)
            .unwrap_or("Leave the macro processor. Take the cannoli.")
            .parse()
            .map_err(|problem| ConfigBuildError::Invalid {
                field: "behavior".to_string(),
                problem,
            })
    }
}

§deftly(tor_config(field(vis = ".."))) — Change the visibility of a field in the builder

By default, fields in the builder are private. This attribute changes their visibility to the one provided.

§deftly(tor_config(skip)) — Do not generate the field in the builder

If this attribute is present, no field is generated in the builder for this field. Implies setter(skip). Requires build.

§deftly(tor_config(attr = ".."))) — Apply an attribute to the field in the builder

Any attribute provided here is applied to the declared field in the builder.

Example:

#[deftly(tor_config(attr = "allow(deprecated)"))]
x: SomeDeprecatedType,

See also the cfg and serde attributes.

§deftly(tor_config(serde = ".."))) — Apply a serde attribute to the field in the builder

Any serde attribute provided here is applied to the declared field in the builder.

Example:

#[deftly(tor_config(serde = r#"alias = "old_name_of_field" "#))]
current_name_of_field: String,

Attributes applied with serde apply after any specified with attr instead.

This is a convenience attribute; you could just use attr instead.

§deftly(tor_config(extend_with = "")) — Change the ExtendBuilder behavior for a field.

Unless you specify no_extendbuilder_trait, the builder type will implement ExtendBuilder, and will need a way to replace or extend every field in the builder with the value from another builder. This attribute lets you override the default behavior for a single field. It expects an expression that evaluates to type FnOnce(&mut T, T, ExtendStrategy), where T is the type of the field in the builder.

§deftly(tor_config(cfg = ".."))) — Mark a field as conditionally present

This option causes a field in the builder to be conditionally present or absent at compile time, similar to the ordinary cfg attribute. However, unlike with the ordinary cfg attribute, if the user provides any configuration values for this field when it is disabled, the generated build() code will emit a warning via tracing at runtime telling them what feature they would need to turn on.

If an error is more appropriate than a warning, additionally use cfg_reject.

Note that you cannot use this along with a regular cfg attribute, since a regular cfg attribute would suppress the field altogether. Therefore, the field will still be present in the configuration struct even when the cfg condition is false. To work around this limitation, it’s conventional to arrange for the type of the field to be () when the cfg condition is false.

The tor_config(cfg_desc) attribute is mandatory to use along with cfg. It should contain a short prepositional phrase describing how the program needs to be built with in order to make this feature present. Examples might be “with RPC support” or “for Windows”.

Example:

#[cfg(feature = "rpc")]
pub type RpcOptionType = String;

#[cfg(not(feature = "rpc"))]
type RpcOptionType = ();

#[derive(Clone,Debug,PartialEq,Deftly)]
#[derive_deftly(TorConfig)]
pub struct OnionSoupConfig {
    #[deftly(tor_config(cfg = r#" feature="rpc" "#, cfg_desc = "with RPC support"))]
    #[deftly(tor_config(default))]
    rpc_option: RpcOptionType,
}

§deftly(tor_config(cfg_reject)) — Reject the configuration when a feature is missing.

Used alongside tor_config(cfg); see also that attribute’s documentation.

Usually, tor_config(cfg) causes a warning if values are provided for a compiled-out configuration option. When this attribute is present, then tor_config(cfg) causes an error instead.

§deftly(tor_config(cfg_desc = ".."))) — Description of when a field is present.

Used along with tor_config(cfg); see that attribute’s documentation.

§deftly(tor_config(no_magic))) — Disable magic handling based on a field’s type

This attribute disables type-based magic behavior for the current field.