Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add derive macros for Dispatch, ExtensionDispatch #98

Merged
merged 4 commits into from
Mar 25, 2024

Conversation

robin-nitrokey
Copy link
Member

@robin-nitrokey robin-nitrokey commented Feb 10, 2023

Please don’t look at the macro implementation yet, it’s quite messy at the moment. Instead look at the diff for tests/backend.rs and tests/serde_extensions.rs to see the derive macros in action. The current syntax is:

#[derive(Default, trussed::backend::Dispatch)]
#[dispatch(backend_id = "Backend")]
struct Dispatch {
    test: TestBackend,
}

#[derive(Default, ExtensionDispatch)]
#[dispatch(backend_id = "Backend", extension_id = "Extension")]
#[extensions(Test = "TestExtension", Sample = "SampleExtension")]  // maps the extension ID to the type
pub struct Backends {
    #[extensions("Test")]  // declares the extensions supported by this backend
    test: TestBackend,
    #[extensions("Test", "Sample")]
    sample: SampleBackend,
}

What do you think?


Missing features:

  • providing different sets of extensions for the same backend with the different IDs
  • having multiple extensions attributes to simplify conditional compilation
  • warn if an extension is declared but not implemented

@robin-nitrokey
Copy link
Member Author

@daringer @sosthene-nitrokey Any thoughts on the syntax? I think it would make it much easier to maintain the dispatch implementations.

@daringer
Copy link
Member

This hides a lot of redundant code, I love it! especially here: https://github.com/trussed-dev/trussed/pull/98/files#diff-203bd1efad2e5b766e73f7058bc930bc35004df65aeb5088a6c5845f662bdd43L383 lot of boilerplate stuff just gone... +1

@sosthene-nitrokey
Copy link
Contributor

sosthene-nitrokey commented Mar 22, 2024

My main concern is whether it can do what we do with the Manage extensions, that have a specific Backend ID to be used, so that an app with access to the StagingBackend or the Se050Backend cannot access it (and instead needs the StagingManage and Se050Manage backend Ids configured.

Other than that, i would put the extensions into the dispatch attribute so that only one "attribute namespace" is used.

#[derive(Default, trussed::backend::Dispatch)]
#[dispatch(backend_id = "Backend")]
struct Dispatch {
    test: TestBackend,
}

#[derive(Default, ExtensionDispatch)]
#[dispatch(backend_id = "Backend", extension_id = "Extension")]
#[dispatch(extensions(Test = "TestExtension", Sample = "SampleExtension"))]  // maps the extension ID to the type
pub struct Backends {
    #[dispatch(extensions("Test"))]  // declares the extensions supported by this backend
    test: TestBackend,
    #[dispatch(extensions("Test", "Sample"))]
    sample: SampleBackend,
}

@robin-nitrokey
Copy link
Member Author

robin-nitrokey commented Mar 22, 2024

My main concern is whether it can do what we do with the Manage extensions, that have a specific Backend ID to be used, so that an app with access to the StagingBackend or the Se050Backend cannot access it

I don’t see a problem with that. We can just use fields with different names but the same type. I think something like this should already work with the current implementation:

#[derive(Default, ExtensionDispatch)]
#[dispatch(backend_id = "Backend", extension_id = "Extension")]
#[extensions(Test = "TestExtension", Special = "SpecialExtension", Sample = "SampleExtension")]
pub struct Backends {
    #[extensions("Test")]
    test: TestBackend,
    #[extensions("Test", "Special")]
    test_special: TestBackend,
    #[extensions("Test", "Sample")]
    sample: SampleBackend,
}

Other than that, i would put the extensions into the dispatch attribute so that only one "attribute namespace" is used.

I also thought about that, but on the other hand, it just adds more boilerplate code without real benefit. And looking at the most popular derive crates, using multiple attributes is quite common. For example, clap uses multiple attributes to group options logically.

@robin-nitrokey
Copy link
Member Author

If we don’t want to duplicate the backend, we could probably use a special attribute like:

#[derive(Default, ExtensionDispatch)]
#[dispatch(backend_id = "Backend", extension_id = "Extension")]
#[extensions(Test = "TestExtension", Special = "SpecialExtension", Sample = "SampleExtension")]
pub struct Backends {
    #[extensions("Test")]
    test: TestBackend,

    #[extensions("Test", "Special")]
    #[dispatch(delegate_to = "test")]
    test_special: TestBackend,

    #[extensions("Test", "Sample")]
    sample: SampleBackend,
}

@sosthene-nitrokey
Copy link
Contributor

If we don’t want to duplicate the backend, we could probably use a special attribute like:

#[derive(Default, ExtensionDispatch)]
#[dispatch(backend_id = "Backend", extension_id = "Extension")]
#[extensions(Test = "TestExtension", Special = "SpecialExtension", Sample = "SampleExtension")]
pub struct Backends {
    #[extensions("Test")]
    test: TestBackend,

    #[extensions("Test", "Special")]
    #[dispatch(delegate_to = "test")]
    test_special: TestBackend,

    #[extensions("Test", "Sample")]
    sample: SampleBackend,
}

Would that work for a #[derive] macro? I think test_special would still be a member of the struct at the end since derive macros can't change the struct definition itself.

@robin-nitrokey
Copy link
Member Author

Hmm, then we could change the type to (). Anyway, I would suggest to first merge a version without duplicate backends. We can then add that feature in a second step.

@sosthene-nitrokey
Copy link
Contributor

Yes

@robin-nitrokey robin-nitrokey changed the title [wip] Add derive macros for Dispatch, ExtensionDispach Add derive macros for Dispatch, ExtensionDispatch Mar 24, 2024
@robin-nitrokey robin-nitrokey marked this pull request as ready for review March 24, 2024 13:31
@robin-nitrokey
Copy link
Member Author

Updated:

  • Rebased onto main.
  • Upated syn dependency to v2.
  • Made the implementation more robust and improved error messages.
  • Added examples.

@robin-nitrokey
Copy link
Member Author

Updated:

  • Made the extensions attribute optional for backends in ExtensionDispatch.
  • Added an ExtensionId derive macro that implements From<T> for u8 and TryFrom<u8> for T.

This patch adds a new derive crate that can be used to derive
implementations of the trussed::backend::Dispatch and
trussed::serde_extensions::ExtensionDispatch traits.
Backends may only implement core requests and no extensions, therefore
the extensions attribute should not be required for backends.
This patch adds the ExtensionId derive macro to trussed-derive that
implements From<T> for u8 and TryFrom<u8> for T.
This makes it easier to select the supported extensions using
conditional compilation (cfg_attr).
@robin-nitrokey robin-nitrokey merged commit 9ca8866 into trussed-dev:main Mar 25, 2024
2 checks passed
@robin-nitrokey robin-nitrokey deleted the derive branch March 25, 2024 13:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants