[−][src]Crate gvariant
A pure-rust implementation of the GVariant serialisation format intended for fast reading of in-memory buffers.
let data = b"It works!\0"; let string = gv!("s").cast(data.as_aligned()).to_bytes(); assert_eq!(string, b"It works!");
This library operates by reinterpreting byte buffers as a GVariant type. It doesn't do any of its own allocations. As a result proper alignment of byte buffers is the responsibility of the user. See "Alignment of data" below.
It's intended to conform to the GVariant specification and match the behaviour of the [GLib implementation]. Exceptions to this are described in "Deviations from the Specification" below.
This library assumes you know the types of the data you are dealing with at compile time. This is in contrast to the GLib implementation where you could construct a GVariant type string dynamically. This allows for a much smaller and faster implementation, more in line with Alexander Larsson's [GVariant Schema Compiler]. As a result GVariant structs are supported through use of code generation via macros. See the gvariant-macro subdirectory.
The library is intended to be sound and safe to run on untrusted input,
although the implementation does include use of unsafe
. See "Use of
unsafe
" below. Help with validating the unsafe portions of the library
would be gratefully received.
This library works Rust stable. As a result we can't use const-generics, which would make some of the code much more streightforward. A future version of this library may use const-generics, once they are available in stable rust.
[GLib implementation]: https://developer.gnome.org/glib/stable/glib-GVariant.html [GVariant Schema Compiler]: https://gitlab.gnome.org/alexl/variant-schema-compiler/
Status
- Support for all GVariant types is implemented apart from dictionary entries.
- Serialisation is not currently supported, but may be implemented in a future version, or possibly as a seperate crate.
TODO
- Implement support for dict items
- Correct handling of non-normal structs
- Add no-std and no-alloc support
- Fuzz testing - compare against the GLib version
Deviations from the Specification
Maximum size of objects
The spec says:
2.3.6 Framing Offsets
There is no theoretical upper limit in how large a framing offset can be. This fact (along with the absence of other limitations in the serialisation format) allows for values of arbitrary size.
In this implementation the maximum size of an object is usize (typically 64-bits). This should not be a problem in practice on 64-bit machines.
Equality of Variant v type for non-normal form data
See note under Variant
.
Design
The intention is to build abstractions that are transparent to the compiler,
such that they compile down to simple memory accesses, like reading the
fields of a struct. For many of the GVariant types rust already has a type
with the same representation (such as i32
for i or [u8]
for ay).
For other types this library defines such types (such as gvariant::Str
for
s or gvariant::NonFixedWidthArray<[i32]>
for aai). For structure
types this library provides a macro gv!
to generate the code for struct
types.
If we have a type with the same representation as the underlying bytes we
can just cast the data to the appropriate type and then read it. The macro
gv!
maps from GVariant typestrs to compatible Rust types returning a
Marker
. This Marker
can then be used to cast data into that type by
calling Marker::cast
.
So typically code might look like:
let mut buf = alloc_aligned(4096); let len = file.read(buf)? let data = <gv!("a(sia{sv})")>::from_aligned_bytes(&buf[..len]);
For casting data to be valid and safe the byte buffer must be aligned...
Use of unsafe
I've tried to concentrate almost all of the unsafe in aligned_bytes
and
casting
to make it easier to review. I also take advantage of the
ref_cast
crate to avoid some unsafe casting that I'd otherwise require.
A review of the use of unsafe
, or advice on how the amount of unsafe could
be reduced would be greatly appreciated.
Comparison to and relationship with other projects
-
[GVariant Schema Compiler] - Similar to this project the GSC generates code at compile time to represent the types the user is interested in. GSC targets the C language. Unlike this project the types are generated from schema files, allowing structures to have named fields. In gvariant-rs we generate our code just from the plain GVariant type strings using macros. This makes the build process simpler - there are no external tools, and it makes it easier to get started - there is no new schema format to learn. The cost is that the user is responsible for remember which field means what and what endianness should be used to interpret the data.
It might make sense in the future to extend GSC to generate rust code as well
- in which case the generated code may depend on this library.
-
gtk-rs glib::variant - This is a binding to the GLib GVariant implementation in C, so depends on glib. It's currently incomplete. The docs say "Although
GVariant
supports arbitrarily complex types, this binding is currently limited to the basic ones:bool
,u8
,i16
,u16
,i32
,u32
,i64
,u64
,f64
and&str
/String
." -
zvariant - Implements the similar DBus serialisation format rather than GVariant. Docs say: "GVariant ... will be supported by a future version of this crate."
-
serde_gvariant - Implements the same format, but for serde integration. Described as WIP and not published on crates.io
Modules
aligned_bytes | Byte slices with statically guaranteed alignment |
casting | Safe casting |
Macros
gv | Maps from GVariant typestrs to compatible Rust types returning a |
Structs
Bool | Type with same representation as GVariant "b" type |
MaybeFixedSize | Type with same representation as GVariant "mX" type where X is any fixed size type |
MaybeNonFixedSize | Type with same representation as GVariant "mX" type where X is any non-fixed size type |
NonFixedWidthArray | Type with same representation as GVariant "aX" type where X is any non-fixed size type |
NonFixedWidthArrayIterator | A iterator over the items of a |
Str | Type with same representation as GVariant "s", "o" and "g" types |
Variant | The GVariant Variant v type |
Traits
Cast | |
Marker | This is the return type of the |
Structure | A trait that all generated structure types implement |