Hello,
I’m working on a data type for which certain invariants need to be observed upon construction. I have written a macro that ensures this statically. Is there a way to allow users of my crate to use this macro, but disallow them constructing that type otherwise? I believe that this is not possible, because a macro just expands to some code, but perhaps I’m overseeing something. Or perhaps there is another solution to my problem?
What follows is a detailed description.
The data type is supposed to efficiently represent a sequence of subsequences of symbols. The symbols are dumb and pointer-sized, so that in order to represent the subsequence “a, b” followed by the subsequence “c” the following representation in memory seems appropriate: “2, a, b, 1, c”. (The numbers are the lengths of the subsequences.)
My motivation for this representation is keeping all the bits together in memory.
Let’s say that I have a macro that when used like this
let in = seqofseq![a b; c];
expands to
let in = SeqOfSeq([
Element { len: 2 },
Element {
symbol: Symbol::new("a"),
},
Element {
symbol: Symbol::new("b"),
},
Element { len: 1 },
Element {
symbol: Symbol::new("c"),
},
]);
where Element
is either a symbol, or the length of a subsequence
pub union Element {
symbol: Symbol,
len: usize,
}
and SeqOfSeq
is a slice of Elements
pub struct SeqOfSeq<T>(T)
where
T: ?Sized,
T: AsRef<[Element]>;
All of this works within a single module. The macro uses some magic to count the lengths of the subsequences, so that seqofseq![a b; c]
compiles down to a static literal, or at least something simple and efficient.
But if I make that macro available outside of the defining module, I also have to allow the literal to which it expands. But then I can no longer ensure that the lengths will be correct and the whole thing becomes unsafe.
The alternative seems to be to provide a safe API for construction of such sequences-of-sequences. But I do not see how to do this in an efficient and convenient (for the user) way.
Thanks!