Expand description

Tag is a dynamically typed data structure used to encode extra properties about a type in its layout constant.

Comparison semantics

Tags don’t use strict equality when doing layout checking , here is an exhaustive list on what is considered compatible for each variant in the interface:

  • Null: A Tag which is compatible with any other one. Note that Nulls are stripped from arrays,set,and map keys.

  • Integers/bools/strings: They must be strictly equal.

  • Arrays: They must have the same length, and have elements that compare equal.

  • Sets/Maps: The set/map in the interface must be a subset of the implementation,

Examples

Declaring a unit type with a tag.


use abi_stable::{tag,StableAbi};

#[repr(C)]
#[derive(StableAbi)]
#[sabi( tag = tag!("WAT"))]
struct UnitType;



Emulating const generics for strings

This emulates a const NAME:&'static str parameter, which is checked as being the same between the interface and implementation.

use abi_stable::{tag,StableAbi,marker_type::UnsafeIgnoredType};


trait Name{
    const NAME:&'static str;
}

///
/// The layout of `StringParameterized<S>` is determined by `<S as Name>::NAME`,
/// allowing the interface crate to have a different `S`
/// type parameter than the implementation crate,
/// so long as they have the same associated `&'static str`.
///
/// StringParameterized<Foo> has the "same" layout as StringParameterized<Bar>.
///
/// StringParameterized<Foo> has a "different" layout to StringParameterized<Boor>.
///
#[repr(C)]
#[derive(StableAbi)]
#[sabi(
    bound(S:Name),
    tag = tag!( S::NAME ),
)]
struct StringParameterized<S>{
    _marker:UnsafeIgnoredType<S>
}

#[repr(C)]
#[derive(StableAbi)]
struct Foo;

impl Name for Foo{
    const NAME:&'static str="Hello, World!";
}


#[repr(C)]
#[derive(StableAbi)]
struct Bar;

impl Name for Bar{
    const NAME:&'static str="Hello, Helloooooo!";
}


#[repr(C)]
#[derive(StableAbi)]
struct Boor;

impl Name for Boor{
    const NAME:&'static str="This is a different string!";
}

Declaring each variant.

use abi_stable::{
    rslice,tag,
    type_layout::Tag,
};

const NULL:Tag=Tag::null();


const BOOL_MACRO:Tag=tag!( false );
const BOOL_FN   :Tag=Tag::bool_(false);


const INT_MACRO_0:Tag=tag!(  100 );
const INT_FN_0   :Tag=Tag::int(100);

const INT_MACRO_1:Tag=tag!( -100 );
const INT_FN_1   :Tag=Tag::int(-100);


// This can only be declared using the function for now.
const UINT:Tag=Tag::uint(100);


const STR_0_MACRO:Tag=tag!("Hello,World!");
const STR_0_FN:Tag=Tag::str("Hello,World!");

const ARR_0_MACRO:Tag=tag![[ 0,1,2,3 ]];
const ARR_0_FN:Tag=Tag::arr(rslice![
    Tag::int(0),
    Tag::int(1),
    Tag::int(2),
    Tag::int(3),
]);


const SET_0_MACRO:Tag=tag!{{ 0,1,2,3 }};
const SET_0_FN:Tag=Tag::set(rslice![
    Tag::int(0),
    Tag::int(1),
    Tag::int(2),
    Tag::int(3),
]);


const MAP_0_MACRO:Tag=tag!{{
    0=>"a",
    1=>"b",
    2=>false,
    3=>100,
}};
const MAP_0_FN:Tag=Tag::map(rslice![
    Tag::kv( Tag::int(0), Tag::str("a")),
    Tag::kv( Tag::int(1), Tag::str("b")),
    Tag::kv( Tag::int(2), Tag::bool_(false)),
    Tag::kv( Tag::int(3), Tag::int(100)),
]);

Creating a complex data structure.

use abi_stable::{
    tag,
    type_layout::Tag,
};

const TAG:Tag=tag!{{
    // This must match exactly,
    // adding required traits on the interface or the implementation
    // would be a breaking change.
    "required"=>tag![[
        "Copy",
    ]],
     
    "requires at least"=>tag!{{
        "Debug",
        "Display",
    }},


    "maps"=>tag!{{
        0=>"Zero",
        1=>"One",
    }}
}};

Structs

  • A tag that can be checked for compatibility with another tag.
  • Used to convert many types to Tag.
  • A key-value pair,used when constructing a map.
  • Tag is a dynamically typed data structure used to encode extra properties about a type in its layout constant.
  • The error produced when checking CheckableTags.

Enums

  • The possible variants of CheckableTag.
  • The primitive types of a variant,which do not contain other nested tags.
  • All the Tag variants.