Struct ThingBuilder

Source
pub struct ThingBuilder<Other, Status>
where Other: ExtendableThing,
{ pub other: Other, /* private fields */ }
Expand description

A builder for a Thing

A ThingBuilder can be created using ThingBuilder::new or Thing::builder, and after all the customization, ThingBuilder::build needs to be called in order to create a Thing.

Fields§

§other: Other

Thing extension.

Implementations§

Source§

impl<Other> ThingBuilder<Other, ToExtend>
where Other: ExtendableThing,

Source

pub fn new(title: impl Into<String>) -> ThingBuilder<Other, ToExtend>
where Other: Default,

Create a new default builder with a specified title, using a default extension

Source

pub fn new_empty( title: impl Into<String>, ) -> ThingBuilder<<Other as Extendable>::Empty, ToExtend>
where Other: Extendable, <Other as Extendable>::Empty: ExtendableThing,

Create a new default builder with a specified title, using an empty extension

Source

pub fn finish_extend(self) -> ThingBuilder<Other, Extended>

Finalize the set of extensions that must be populated

Moves the builder status from ToExtend to Extended. From this point is not possible to add further extensions to the builder.

See ThingBuilder::ext.

§Example
let thing = Thing::builder("Thing name")
    .id("thing-id-1234")
    .finish_extend()
    .property("first-property", |prop_builder| {
        prop_builder
            .finish_extend_data_schema()
            .observable(true)
            .bool()
    })
    .build()
    .unwrap();
Source

pub fn ext_with<F, T>( self, f: F, ) -> ThingBuilder<<Other as Extend<T>>::Target, ToExtend>
where F: FnOnce() -> T, Other: Extend<T>, <Other as Extend<T>>::Target: ExtendableThing,

Extends the Thing, passing a closure that returns T.

§Example
let thing = Thing::builder("Thing name")
    .ext_with(|| ThingExtension {
        a_field: "hello world".to_string(),
        another_field: 42,
    })
    .finish_extend()
    .build()
    .unwrap();

assert_eq!(
    serde_json::to_value(thing).unwrap(),
    json!({
        "@context": "https://www.w3.org/2022/wot/td/v1.1",
        "title": "Thing name",
        "a_field": "hello world",
        "another_field": 42,
        "security": [],
        "securityDefinitions": {},
    })
);
Source

pub fn ext<T>( self, t: T, ) -> ThingBuilder<<Other as Extend<T>>::Target, ToExtend>
where Other: Extend<T>, <Other as Extend<T>>::Target: ExtendableThing,

Extend the ThingBuilder with a ExtendableThing

§Example
let thing = Thing::builder("Thing name")
    .ext(ThingExtension {
        a_field: "hello world".to_string(),
        another_field: 42,
    })
    .finish_extend()
    .build()
    .unwrap();

assert_eq!(
    serde_json::to_value(thing).unwrap(),
    json!({
        "@context": "https://www.w3.org/2022/wot/td/v1.1",
        "title": "Thing name",
        "a_field": "hello world",
        "another_field": 42,
        "security": [],
        "securityDefinitions": {},
    })
);
Source§

impl<Other, Status> ThingBuilder<Other, Status>
where Other: ExtendableThing,

Source

pub fn build(self) -> Result<Thing<Other>, Error>

Consume the builder to produce the configured Thing

This step will perform the final validation of the builder state.

Source

pub fn id(self, value: impl Into<String>) -> ThingBuilder<Other, Status>

Sets the value of the id field.

Source

pub fn description( self, value: impl Into<String>, ) -> ThingBuilder<Other, Status>

Sets the value of the description field.

Source

pub fn version( self, value: impl Into<VersionInfo>, ) -> ThingBuilder<Other, Status>

Sets the value of the version field.

Source

pub fn created( self, value: impl Into<OffsetDateTime>, ) -> ThingBuilder<Other, Status>

Sets the value of the created field.

Source

pub fn modified( self, value: impl Into<OffsetDateTime>, ) -> ThingBuilder<Other, Status>

Sets the value of the modified field.

Source

pub fn support(self, value: impl Into<String>) -> ThingBuilder<Other, Status>

Sets the value of the support field.

Source

pub fn base(self, value: impl Into<String>) -> ThingBuilder<Other, Status>

Sets the value of the base field.

Source

pub fn context<S>(self, value: S) -> ThingBuilder<Other, Status>
where S: Into<String> + AsRef<str>,

Add a new JSON-LD @context in the default namespace

Source

pub fn context_map<F>(self, f: F) -> ThingBuilder<Other, Status>

Add a new JSON-LD @context with a custom namespace

§Example
let thing = Thing::builder("Thing name")
    .context_map(|builder| {
        builder
            .context("custom_context1", "hello")
            .context("custom_context2", "world")
    })
    .build()
    .unwrap();

assert_eq!(
    serde_json::to_value(thing).unwrap(),
    json!({
        "title": "Thing name",
        "@context": [
            "https://www.w3.org/2022/wot/td/v1.1",
            {
                "custom_context1": "hello",
                "custom_context2": "world",
            }
        ],
        "security": [],
        "securityDefinitions": {},
    }),
);
Source

pub fn attype(self, value: impl Into<String>) -> ThingBuilder<Other, Status>

Add a JSON-LD @type to the thing

Source

pub fn titles<F>(self, f: F) -> ThingBuilder<Other, Status>

Set multi-language titles

§Examples
let thing = Thing::builder("Thing name")
    .titles(|builder| {
        builder
            .add("en", "English title")
            .add("it", "Italian title")
    })
    .build()
    .unwrap();

assert_eq!(
    serde_json::to_value(thing).unwrap(),
    json!({
        "title": "Thing name",
        "@context": "https://www.w3.org/2022/wot/td/v1.1",
        "titles": {
            "en": "English title",
            "it": "Italian title",
        },
        "security": [],
        "securityDefinitions": {},
    })
);

Creating a title using an invalid language tag is going to return an error when Thing::build is called:

let error = Thing::builder("Thing name")
    .titles(|builder| builder.add("e!n", "Invalid title"))
    .build()
    .unwrap_err();

assert_eq!(error, Error::InvalidLanguageTag("e!n".to_string()));
Source

pub fn descriptions<F>(self, f: F) -> ThingBuilder<Other, Status>

Set multi-language descriptions

See ThingBuilder::titles for examples.

Add an additional link to the Thing Description

Add an additional link to the Thing Description, with specified optional fields.

§Example
let thing = Thing::builder("Thing name")
    .link_with(|builder| {
        builder
            .href("https://localhost")
            .rel("icon")
            .sizes("16x16 24x24 32x32")
    })
    .build()
    .unwrap();

assert_eq!(
    serde_json::to_value(thing).unwrap(),
    json!({
        "title": "Thing name",
        "@context": "https://www.w3.org/2022/wot/td/v1.1",
        "links": [{
            "href": "https://localhost",
            "rel": "icon",
            "sizes": "16x16 24x24 32x32",
        }],
        "security": [],
        "securityDefinitions": {},
    })
);
Source

pub fn security<F, T>(self, f: F) -> ThingBuilder<Other, Status>

Add a security definition and, eventually, a required security

§Example
let thing = Thing::builder("Thing name")
    .security(|builder| {
        builder
            .basic()
            .with_key("my_basic_sec")
            .name("basic_sec_name")
    })
    .security(|builder| builder.apikey())
    .build()
    .unwrap();

assert_eq!(
    serde_json::to_value(thing).unwrap(),
    json!({
        "title": "Thing name",
        "@context": "https://www.w3.org/2022/wot/td/v1.1",
        "security": [],
        "securityDefinitions": {
            "my_basic_sec": {
                "scheme": "basic",
                "name": "basic_sec_name",
                "in": "header",
            },
            "apikey": {
                "scheme": "apikey",
                "in": "query",
            }
        },
    })
);
Source

pub fn profile(self, value: impl Into<String>) -> ThingBuilder<Other, Status>

Adds a new item to the profile field.

Source§

impl<Other> ThingBuilder<Other, Extended>
where Other: ExtendableThing, <Other as ExtendableThing>::Form: Extendable,

Source

pub fn form<F>(self, f: F) -> ThingBuilder<Other, Extended>
where F: FnOnce(FormBuilder<Other, (), <<Other as ExtendableThing>::Form as Extendable>::Empty>) -> FormBuilder<Other, String, <Other as ExtendableThing>::Form>,

Add a Thing-level form

§Notes
  • It must explicitly state its operation
  • It must use an all operation
§Examples
let thing = Thing::builder("Thing name")
    // Needs to _finish_ extending the thing before calling `.form`
    .finish_extend()
    .form(|builder| {
        builder
            .href("form_href")
            .op(FormOperation::ReadAllProperties)
    })
    .build()
    .unwrap();

assert_eq!(
    serde_json::to_value(thing).unwrap(),
    json!({
        "title": "Thing name",
        "@context": "https://www.w3.org/2022/wot/td/v1.1",
        "forms": [
            {
                "href": "form_href",
                "op": ["readallproperties"],
            }
        ],
        "security": [],
        "securityDefinitions": {},
    })
);

Thing-level forms must explicitly specify the operation, otherwise ThingBuilder::build returns an error:

let error = Thing::builder("Thing name")
    .finish_extend()
    .form(|builder| builder.href("form_href"))
    .build()
    .unwrap_err();

assert_eq!(error, Error::MissingOpInForm);

Furthermore, Thing-level form operations must be one or more of the following FormOperations:

  • ReadAllProperties
  • WriteAllProperties
  • ObserveAllProperties
  • UnobserveAllProperties
  • SubscribeAllEvents
  • UnsubscribeAllEvents
  • QueryAllActions

If any other FormOperation is specified, ThingBuilder::build returns an error:

let error = Thing::builder("Thing name")
    .finish_extend()
    .form(|builder| builder.href("form_href").op(FormOperation::ReadProperty))
    .build()
    .unwrap_err();

assert_eq!(
    error,
    Error::InvalidOpInForm {
        context: FormContext::Thing,
        operation: FormOperation::ReadProperty,
    }
);
Source§

impl<Other> ThingBuilder<Other, Extended>
where Other: ExtendableThing,

Source

pub fn uri_variable<F, T>( self, name: impl Into<String>, f: F, ) -> ThingBuilder<Other, Extended>

Adds a new URI variable.

It takes a function that accepts a DataSchema builder and must return a type convertible into a DataSchema.

See DataSchemaBuilder for more information about how the underlying builder works.

§Examples
let thing = Thing::builder("Thing name")
    .finish_extend()
    .uri_variable("var", |builder| builder.finish_extend().number())
    .build()
    .unwrap();

assert_eq!(
    serde_json::to_value(thing).unwrap(),
    json!({
        "title": "Thing name",
        "@context": "https://www.w3.org/2022/wot/td/v1.1",
        "uriVariables": {
            "var": {
                "type": "number",
                "readOnly": false,
                "writeOnly": false,
            },
        },
        "security": [],
        "securityDefinitions": {},
    })
);
Source

pub fn property<F, T>( self, name: impl Into<String>, f: F, ) -> ThingBuilder<Other, Extended>

Adds a new property affordance.

It takes a function that accepts a PropertyAffordance builder and must return a type convertible into an usable PropertyAffordance builder.

See PropertyAffordanceBuilder for more information about how the underlying builder works.

Source

pub fn action<F, T>( self, name: impl Into<String>, f: F, ) -> ThingBuilder<Other, Extended>

Adds a new action affordance.

It takes a function that accepts a ActionAffordance builder and must return a type convertible into an usable ActionAffordance builder.

See ActionAffordanceBuilder for more information about how the underlying builder works.

Source

pub fn event<F, T>( self, name: impl Into<String>, f: F, ) -> ThingBuilder<Other, Extended>

Adds a new event affordance.

It takes a function that accepts an EventAffordance builder and must return a type convertible into an usable EventAffordance builder.

See EventAffordanceBuilder for more information about how the underlying builder works.

Source

pub fn schema_definition<F, T>( self, name: impl Into<String>, f: F, ) -> ThingBuilder<Other, Extended>

Adds a new schema definition.

It takes the name for the schema definition and a function that takes a DataSchema builder and must return a type convertible into an unchecked DataSchema.

See DataSchemaBuilder for more information about how the underlying builder works.

Trait Implementations§

Source§

impl<O> BuildServient for ThingBuilder<O, Extended>
where O: ExtendableThing + Holder<ServientExtension> + Serialize, <O as ExtendableThing>::Form: Holder<Form>,

Source§

fn build_servient( self, ) -> Result<Servient<<ThingBuilder<O, Extended> as BuildServient>::Other>, Box<dyn Error>>

Build the configured Servient

Source§

type Other = O

Extension type for the Servient and underlying Thing.
Source§

impl<O> ServientSettings for ThingBuilder<O, Extended>
where O: ExtendableThing + Holder<ServientExtension>,

Source§

fn http_bind(self, addr: SocketAddr) -> ThingBuilder<O, Extended>

Bind the http server to addr
Source§

fn thing_type(self, ty: ThingType) -> ThingBuilder<O, Extended>

Set the thing type to be advertised.
Source§

fn http_disable_permissive_cors(self) -> ThingBuilder<O, Extended>

Disable the default CORS settings.

Auto Trait Implementations§

§

impl<Other, Status> Freeze for ThingBuilder<Other, Status>
where Other: Freeze,

§

impl<Other, Status> RefUnwindSafe for ThingBuilder<Other, Status>

§

impl<Other, Status> Send for ThingBuilder<Other, Status>

§

impl<Other, Status> Sync for ThingBuilder<Other, Status>

§

impl<Other, Status> Unpin for ThingBuilder<Other, Status>

§

impl<Other, Status> UnwindSafe for ThingBuilder<Other, Status>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more