summaryrefslogtreecommitdiffstats
path: root/src/shared/varlink-idl.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/shared/varlink-idl.h')
-rw-r--r--src/shared/varlink-idl.h158
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);