I'm revisiting my include_dir crate to give it a proper include_dir!()
macro with proc_macro_hack
and encountered an interesting cyclic generics problem.
Basically, I want include_dir!()
to expand to some Dir
which includes the bytes of each file via include_bytes!()
as a &'static [u8]
. However, for simplicity of implementation I'd like to use the same Dir
type except with all the fields backed by a Vec
so I can update a Dir
in-place while writing the macro. In theory, this is exactly the use case for Cow<'a, [File<'a>]>
.
#[derive(Debug, Clone, PartialEq)]
pub struct Dir<'a> {
path: Cow<'a, Path>,
files: Cow<'a, [File<'a>]>,
dirs: Cow<'a, [Dir<'a>]>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct File<'a> {
pub path: Cow<'a, Path>,
pub contents: Cow<'a, [u8]>,
}
Trying to compile results in an error because resolving Dir<'a>: ToOwned
requires checking [Dir<'a>]: ToOwned
, which in turn requires Dir<'a>: ToOwned
.
error[E0275]: overflow evaluating the requirement `<[dir::Dir<'_>] as std::borrow::ToOwned>::Owned`
|
= note: required because it appears within the type `dir::Dir<'_>`
= note: required because of the requirements on the impl of `std::borrow::ToOwned` for `[dir::Dir<'_>]`
= note: required because it appears within the type `dir::Dir<'_>`
error: aborting due to previous error
Does anyone have any ideas on what I can do to fix the cycle in trait resolution? I could always create two parallel sets of File
and Dir
, one for compile time which stores its data on the heap and another which is 'static
, but I'd prefer not to if possible.
The end goal is being able to generate something like this:
static Foo: Dir<'static> = Dir {
path: "foo/bar/",
files: Cow::Borrowed(&'static [
File {
path: "foo/bar/baz.txt",
contents: Cow::Borrowed(&'static [1, 2, 3, 4, ... ]),
},
...
]),
dirs: Cow::Borrowed(&[ ... ]),
};