diff options
Diffstat (limited to 'src/shared/varlink-idl.h')
-rw-r--r-- | src/shared/varlink-idl.h | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/src/shared/varlink-idl.h b/src/shared/varlink-idl.h new file mode 100644 index 0000000..140b937 --- /dev/null +++ b/src/shared/varlink-idl.h @@ -0,0 +1,158 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include <errno.h> +#include <stdbool.h> +#include <stdio.h> + +#include "json.h" +#include "macro.h" + +/* This implements the Varlink Interface Definition Language ("Varlink IDL"), + * i.e. https://varlink.org/Interface-Definition + * + * Primarily allows encoding static interface definitions in C code, that can be converted to the textual IDL + * format on-the-fly. Can also parse the textual format back to C structures. Validates the interface + * definitions for internal consistency and validates JSON objects against the interface definitions. */ + +typedef enum VarlinkSymbolType { + VARLINK_ENUM_TYPE, + VARLINK_STRUCT_TYPE, + VARLINK_METHOD, + VARLINK_ERROR, + _VARLINK_SYMBOL_TYPE_MAX, + _VARLINK_SYMBOL_TYPE_INVALID = -EINVAL, +} VarlinkSymbolType; + +typedef enum VarlinkFieldType { + _VARLINK_FIELD_TYPE_END_MARKER = 0, /* zero type means: this is the last entry in the fields[] array of VarlinkSymbol */ + VARLINK_STRUCT, + VARLINK_ENUM, + VARLINK_NAMED_TYPE, + VARLINK_BOOL, + VARLINK_INT, + VARLINK_FLOAT, + VARLINK_STRING, + VARLINK_OBJECT, + VARLINK_ENUM_VALUE, + _VARLINK_FIELD_TYPE_MAX, + _VARLINK_FIELD_TYPE_INVALID = -EINVAL, +} VarlinkFieldType; + +typedef enum VarlinkFieldDirection { + VARLINK_REGULAR, + VARLINK_INPUT, + VARLINK_OUTPUT, + _VARLINK_FIELD_DIRECTION_MAX, + _VARLINK_FIELD_DIRECTION_INVALID = -EINVAL, +} VarlinkFieldDirection; + +typedef enum VarlinkFieldFlags { + VARLINK_ARRAY = 1 << 0, + VARLINK_MAP = 1 << 1, + VARLINK_NULLABLE = 1 << 2, + _VARLINK_FIELD_FLAGS_MAX = (1 << 3) - 1, + _VARLINK_FIELD_FLAGS_INVALID = -EINVAL, +} VarlinkFieldFlags; + +typedef struct VarlinkField VarlinkField; +typedef struct VarlinkSymbol VarlinkSymbol; +typedef struct VarlinkInterface VarlinkInterface; + +/* Fields are the components making up symbols */ +struct VarlinkField { + const char *name; + VarlinkFieldType field_type; + VarlinkFieldFlags field_flags; + VarlinkFieldDirection field_direction; /* in case of method call fields: whether input or output argument */ + const VarlinkSymbol *symbol; /* VARLINK_STRUCT, VARLINK_ENUM: anonymous symbol that carries the definitions, VARLINK_NAMED_TYPE: resolved symbol */ + const char *named_type; /* VARLINK_NAMED_TYPE */ +}; + +/* Symbols are primary named concepts in an interface, and are methods, errors or named types (either enum or struct). */ +struct VarlinkSymbol { + const char *name; /* most symbols have a name, but sometimes they are created on-the-fly for fields, in which case they are anonymous */ + VarlinkSymbolType symbol_type; + VarlinkField fields[]; +}; + +/* An interface definition has a name and consist of symbols */ +struct VarlinkInterface { + const char *name; + const VarlinkSymbol *symbols[]; +}; + +#define VARLINK_DEFINE_FIELD(_name, _field_type, _field_flags) \ + { .name = #_name, .field_type = (_field_type), .field_flags = (_field_flags) } + +#define VARLINK_DEFINE_FIELD_BY_TYPE(_name, _named_type, _field_flags) \ + { .name = #_name, .field_type = VARLINK_NAMED_TYPE, .named_type = #_named_type, .symbol = &vl_type_ ## _named_type, .field_flags = (_field_flags) } + +#define VARLINK_DEFINE_INPUT(_name, _field_type, _field_flags) \ + { .name = #_name, .field_type = (_field_type), .field_flags = (_field_flags), .field_direction = VARLINK_INPUT } + +#define VARLINK_DEFINE_INPUT_BY_TYPE(_name, _named_type, _field_flags) \ + { .name = #_name, .field_type = VARLINK_NAMED_TYPE, .named_type = #_named_type, .symbol = &vl_type_ ## _named_type, .field_flags = (_field_flags), .field_direction = VARLINK_INPUT } + +#define VARLINK_DEFINE_OUTPUT(_name, _field_type, _field_flags) \ + { .name = #_name, .field_type = (_field_type), .field_flags = (_field_flags), .field_direction = VARLINK_OUTPUT } + +#define VARLINK_DEFINE_OUTPUT_BY_TYPE(_name, _named_type, _field_flags) \ + { .name = #_name, .field_type = VARLINK_NAMED_TYPE, .named_type = #_named_type, .symbol = &vl_type_ ## _named_type, .field_flags = (_field_flags), .field_direction = VARLINK_OUTPUT } + +#define VARLINK_DEFINE_ENUM_VALUE(_name) \ + { .name = #_name, .field_type = VARLINK_ENUM_VALUE } + +#define VARLINK_DEFINE_METHOD(_name, ...) \ + const VarlinkSymbol vl_method_ ## _name = { \ + .name = #_name, \ + .symbol_type = VARLINK_METHOD, \ + .fields = { __VA_ARGS__ __VA_OPT__(,) {}}, \ + } + +#define VARLINK_DEFINE_ERROR(_name, ...) \ + const VarlinkSymbol vl_error_ ## _name = { \ + .name = #_name, \ + .symbol_type = VARLINK_ERROR, \ + .fields = { __VA_ARGS__ __VA_OPT__(,) {}}, \ + } + +#define VARLINK_DEFINE_STRUCT_TYPE(_name, ...) \ + const VarlinkSymbol vl_type_ ## _name = { \ + .name = #_name, \ + .symbol_type = VARLINK_STRUCT_TYPE, \ + .fields = { __VA_ARGS__ __VA_OPT__(,) {}}, \ + } + +#define VARLINK_DEFINE_ENUM_TYPE(_name, ...) \ + const VarlinkSymbol vl_type_ ## _name = { \ + .name = #_name, \ + .symbol_type = VARLINK_ENUM_TYPE, \ + .fields = { __VA_ARGS__ __VA_OPT__(,) {}}, \ + } + +#define VARLINK_DEFINE_INTERFACE(_name, _full_name, ...) \ + const VarlinkInterface vl_interface_ ## _name = { \ + .name = (_full_name), \ + .symbols = { __VA_ARGS__ __VA_OPT__(,) NULL}, \ + } + +int varlink_idl_dump(FILE *f, int use_colors, const VarlinkInterface *interface); +int varlink_idl_format(const VarlinkInterface *interface, char **ret); + +int varlink_idl_parse(const char *text, unsigned *ret_line, unsigned *ret_column, VarlinkInterface **ret); +VarlinkInterface* varlink_interface_free(VarlinkInterface *interface); +DEFINE_TRIVIAL_CLEANUP_FUNC(VarlinkInterface*, varlink_interface_free); + +bool varlink_idl_field_name_is_valid(const char *name); +bool varlink_idl_symbol_name_is_valid(const char *name); +bool varlink_idl_interface_name_is_valid(const char *name); + +int varlink_idl_consistent(const VarlinkInterface *interface, int level); + +const VarlinkSymbol* varlink_idl_find_symbol(const VarlinkInterface *interface, VarlinkSymbolType type, const char *name); +const VarlinkField* varlink_idl_find_field(const VarlinkSymbol *symbol, const char *name); + +int varlink_idl_validate_method_call(const VarlinkSymbol *method, JsonVariant *v, const char **bad_field); +int varlink_idl_validate_method_reply(const VarlinkSymbol *method, JsonVariant *v, const char **bad_field); +int varlink_idl_validate_error(const VarlinkSymbol *error, JsonVariant *v, const char **bad_field); |