Зависимость циклического пакета при реализации макроса proc - PullRequest
0 голосов
/ 08 января 2019

Я пытаюсь реализовать proc_macro Dump, который похож на serdes Serialize.

Для этой цели у меня есть ящик foo, который содержит мои "примитивные" структуры (в данном случае P1 и P2), которые должны быть только сбрасываемыми.

Далее у меня есть ящик foo_derive, который содержит сам процедурный макрос.

Поскольку я хочу поддерживать несколько форматов, у меня есть третий ящик foo_dump, который содержит определение черты Dump (например, эта структура может быть выгружена) и Dumper (это то, что должен реализовать бэкэнд). Очень прямо до этого момента.

Когда я теперь хочу его скомпилировать, я получаю эту ошибку:

$ cargo build
error: cyclic package dependency: package `foo v0.1.0 (/tmp/tmp.u34pI5J6qd/example/foo)` depends on itself. Cycle:
package `foo v0.1.0 (/tmp/tmp.u34pI5J6qd/example/foo)`
    ... which is depended on by `foo_dump v0.1.0 (/tmp/tmp.u34pI5J6qd/example/foo_dump)`
    ... which is depended on by `foo_derive v0.1.0 (/tmp/tmp.u34pI5J6qd/example/foo_derive)`

Я не знаю, как правильно, как использовать зависимости в этом ящике. Мой текущий:

dependencies

и это, конечно, невозможно.

Чего мне не хватает? Что мне нужно сделать, чтобы разорвать круг зависимости?


( mcve @ GitHub )

/ Cargo.toml

[workspace]
members = [ 
    "foo",
    "foo_derive",
    "foo_dump",
]

/ Foo / Cargo.toml

[package]
name = "foo"
version = "0.1.0"
edition = "2018"

[dependencies]
foo_derive = { path = "../foo_derive" }

/ Foo / SRC / lib.rs

use foo_derive::Dump;

struct P1;
struct P2;

#[derive(Dump)]
struct Bar {
    primitive_one: P1,
    primitive_two: P2,
}

/ foo_dump / Cargo.toml

[package]
name = "foo_dump"
version = "0.1.0"
edition = "2018"

[dependencies]
foo = { path = "../foo" }

/ foo_dump / SRC / lib.rs

use foo::{P1, P2};

pub trait Dumper {
    fn dump_p1(&mut self, value: &P1);
    fn dump_p2(&mut self, value: &P2);
}

pub trait Dump {
    fn dump<D: Dumper>(&self, d: D);
}

impl Dump for P1 {
    fn dump<D: Dumper>(&self, d: D) {
        d.dump_p1(self);
    }
}

impl Dump for P2 {
    fn dump<D: Dumper>(&self, d: D) {
        d.dump_p2(self);
    }
}

/ foo_derive / Cargo.toml

[package]
name = "foo_derive"
version = "0.1.0"
edition = "2018"

[lib]
proc-macro = true

[dependencies]
syn = "*"
quote = "*"
foo_dump = { path = "../foo_dump" }

/ foo_derive / SRC / lib.rs

extern crate proc_macro;

use quote::quote;
use proc_macro::TokenStream;
use syn::DeriveInput;

#[proc_macro_derive(Dump)]
pub fn derive_dump(input: TokenStream) -> TokenStream {
    let input = syn::parse_macro_input!(input as DeriveInput);
    let name = &input.ident;

    quote!(
        impl foo_dump::Dump for #name {
            fn dump<D: foo_dump::Dumper>(&self, d: D) {
                unimplemented!()
            }
        }
    ).into()
}

1 Ответ

0 голосов
/ 08 января 2019

Благодаря @ Boiethious комментарию и его помощи в чате Мне удалось найти решение, которое подразумевает введение нового ящика foo_core, который содержит структуры P1 и P2.

Итак, что я сделал:

  • Извлечение P1 и P2 из foo и помещение их в foo_core
  • Удаление зависимости foo_dump из foo_derive, поэтому она зависит только от syn и quote больше
  • Добавление foo_core в качестве зависимости в foo и foo_dump
  • Добавление зависимости foo_dump к foo

(полный список изменений можно посмотреть в истории git ).

Последняя цепочка зависимостей теперь выглядит так:

depency graph

...