Macros
The six macros of berm-lang: what each is written on, what it accepts, what it generates and what it refuses at compile time.
| Macro | On | Generates |
|---|---|---|
#[tool] |
a free function | the berm_tool_<name> export the host calls, and the tool's record in the image |
#[derive(Schema)] |
a struct or an enum | the type's JSON Schema, and its serde Serialize and Deserialize |
#[event] |
a struct | a Schema type, an Event impl, and the event's record in the image |
emit! |
an #[event] value |
a log under the event's name |
#[error_code] |
an enum | message(), and From<_> for berm_lang::Error |
declare_service! |
another service's name | a module of its types and typed calls, from its IDL |
A record is JSON the build reads out of the image without running it: the service's interface, which callers see as its IDL and a redeploy is checked against. See Changing an interface.
#[tool]
/// Forecast a city's weather.
#[tool]
pub fn forecast(
/// The city, as its name.
city: String,
/// Days ahead, 1 when absent.
days: Option<u32>,
) -> Result<Forecast> { … }Syntax: #[tool], or #[tool(…)] with any of the flags below, comma-separated. cron, stripe and webhook exclude each other.
| Flag | |
|---|---|
query |
Read-only: writes, logs and wakes are refused while it runs, in every call it makes. A host may serve it over GET. |
cron |
The host calls it when its schedule fires. See Crons and wakes. |
stripe |
The host calls it with each Stripe event for the service, the event object as its arguments. A service has at most one. |
webhook |
The host calls it with each verified webhook for this tool, the body as its arguments. See Webhooks. |
Applies to a free function anywhere in the crate. The function's name is the tool's name. #[deprecated] on it marks the tool deprecated in the record.
Generates:
- the function, unchanged but for its parameters' doc comments;
pub extern "C" fn berm_tool_<name>(), the export the host calls: it deserializes the arguments object into the parameters, calls the function, and writesTas JSON, or nothing for();- the tool's record: its name, its doc comment as its description, its parameters as a JSON Schema object with each parameter's doc comment as its description, its result's schema, and its flags. A tool with no parameters takes any object.
Refused at compile time:
| Message | |
|---|---|
| No doc comment on the function | a tool needs a doc comment |
A self parameter |
a tool is a free function |
| A pattern as a parameter | a tool's parameter is a plain name |
A return type other than Result<T> |
a tool returns berm_lang::Result<T> |
More than one of cron, stripe and webhook |
a tool is at most one of cron, stripe and webhook |
A cron tool with parameters |
a cron tool is called with no arguments |
| Any other flag | unknown option |
Every parameter and the result implement Schema. An Option parameter may be absent from the arguments. Who may call the tool is access in its [tools] table of crab.toml, not an option of the macro; a cron, stripe or webhook tool takes none. A deploy refuses an image that exports no tool, or a tool compiled in a crate other than the service's.
#[derive(Schema)]
/// What `forecast` answers.
#[derive(Schema)]
pub struct Forecast {
/// Degrees Celsius.
pub high: f64,
pub sky: Sky,
pub note: Option<String>,
}
#[derive(Schema)]
pub enum Sky { Clear, PartlyCloudy, Rain }Applies to a struct with named fields, or an enum of unit variants.
Generates:
impl berm_lang::Schema, its JSON Schema: a struct is an object titled by its name, each field's doc comment its description, every field but anOptionrequired; an enum is a string, each variant insnake_case, as"partly_cloudy".impl Serializeandimpl Deserializethat read and write that schema, through serde's remote derive, so the type carries no serde attributes of its own. An absentOptionfield is left out of the JSON, never written asnull.
Schema is implemented for String, bool, f32, f64, every integer type, Vec<T>, Option<T> and BTreeMap<String, T>. An Option<T> result may be null; its schema uses anyOf for T and null. Optional object fields may be omitted.
Refused at compile time: generic or lifetime parameters, a tuple or unit struct, an enum variant carrying data, and a union.
#[event]
/// A forecast was served.
#[event]
pub struct Served {
pub city: String,
}Applies to a struct with named fields. #[deprecated] on it marks the event deprecated in the record.
Generates #[derive(Schema)] on the struct, impl berm_lang::Event with NAME the struct's name, and the event's record: its name, its doc comment as its description, and its fields' schema.
Refused at compile time: no doc comment, and anything #[derive(Schema)] refuses.
emit!
berm_lang::emit!(Served { city })?;emit!(event) emits the #[event] value as one log, under the topic of its name and its data the value as JSON. It answers Result<usize, CallError>, the bytes of the data. berm_lang::emit(topics, data) is the untyped form. Logs, their limits and who reads them: Logs.
#[error_code]
#[berm_lang::error_code]
pub enum NoteError {
#[msg("that note does not exist")]
Missing,
}
return Err(NoteError::Missing.into());Applies to an enum whose every variant is a unit variant with #[msg("…")].
Generates pub fn message(&self) -> &'static str, answering each variant's message, and impl From<NoteError> for berm_lang::Error, so ? and .into() fail the tool with it. The caller reads the message.
Refused at compile time: a variant carrying data, and a variant without #[msg].
declare_service!
berm_lang::declare_service!(hn);
let top = hn::calls::top(Some(10))?;declare_service!(hn) reads idls/hn.json, the IDL crab idl alice/hn writes, from the crate's directory or the nearest ancestor that has an idls/, and generates:
pub mod hn {
/// What the service is deployed as, which every call names.
pub const NAME: &str = "alice/hn";
/// Every titled object and string enum in its tools' arguments and results.
pub mod types { … }
/// One function per tool: its arguments in the IDL's key order, an
/// optional one as an `Option`, answering `Result<T, CallError>`.
pub mod calls { … }
}- Each call is a
berm_lang::callwith typed arguments and result;()for a tool with no result. A tool the IDL marks deprecated is generated#[deprecated]. - The crate rebuilds when the IDL file changes, and the IDL changes only when
crab idlwrites it again. - Generated calls retain the IDL's account and deployment name. No
callsmanifest declaration is needed. See Other services.
Refused at compile time: no idls/hn.json found, a file that is not JSON, and an IDL without name or tools.