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 a design/goals document to detail guidelines for the project #99

Open
wants to merge 5 commits into
base: develop
Choose a base branch
from

Conversation

prokopyl
Copy link
Member

With the departure of @Janonard as a maintainer, and new contributors coming in, I thought this might be a good time to write down all of my ideas and goals for the lv2 crate(s). This way less time can be spent teaching contributors and users what this crate is and isn't supposed to do.

I created a GOALS.md file detailing all of this (Rendered), and there is also a DESIGN.md file (Rendered) detailing guidelines for API design, although it is still a WIP for now.

As of right now, I do not consider those as final at all. Those are my ideas for now, but any other ideas or discussions about those in the document are welcome to debate and discuss in depth in this PR. 🙂

@prokopyl prokopyl added 👋 Help wanted Extra attention is needed 🗨️ Discussion An exchange of opinions about a topic 📖 Documentation An effort to improve the documentation labels Aug 16, 2021
@prokopyl prokopyl self-assigned this Aug 16, 2021
Copy link
Contributor

@PieterPenninckx PieterPenninckx left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with most of the contents of this document. My strongest concern is that implementing the LV2 specifications fully is maybe too ambitious for the resources we have.

are usually user-written, and writing them incorrectly is likely to trigger Undefined Behavior, in both the plugin and
the host.

Higher-level, more specialized libraries and frameworks that rely on LV2 should probably auto-generate those files based on
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would consider what other crates do to be out-of-scope of this document. I would write "Higher-level libraries and frameworks that rely on LV2 can probably auto-generate those files based on plugin code and metadata."

if that makes it less practical to use for direct users of the `lv2` crates.

## No restrictions coming from C

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Supporting every single possibility of the LV2 specification is a nice goal. I would also like to take into account that we probably don't have a lot of (developer) resources to build and maintain this crate. So I think it would be good to prioritize features based on demand, host support and "contributor eagerness". Also, I'm not sure if we really need everything before version 1.0. E.g. deprecated specifications like Event are something I would not put any effort in. Also, the LV2 specification is a moving target, so it may not be feasible to have every feature implemented and to keep this crate on par with the LV2 specification.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, yes, I absolutely agree there. I should make this more clear, but this is more of a vision/design goals document, not a roadmap or prioritization document.

This means that while I probably won't push for the less-demanded (or supported) features before a little while (read: some years), I will still accept contributions for them.

Deprecated specifications should probably be implemented at least for hosts (when we support them properly), if they want to be compatible with older plugins. However, I agree this is not really a priority for now.

I agree that ideally, we should only need a viable library before reaching 1.0, and we could add the remaining specs on top of it afterwards. However, I've many times had the experience where adding an extra spec breaks many invariants and assumptions that other specs rely on, and require making breaking changes.

For instance, implementing Option requires a refactor of Atom to be actually usable, Instance Access and Data Access break both the single-threadedness and exclusivity invariants of lv2_core (basically requiring plugins to be Sync instead of just Send, and preventing any form of &mut reference to ever exist on a plugin instance), and implementing UI will probably break something that I haven't seen coming yet. 🙃

I will add those clarifications to the document. 🙂

GOALS.md Show resolved Hide resolved
cannot do what they want. Examples of work LV2 plugins should defer to the host are I/O buffers and communication, state
serialization (i.e., presets / session loading and saving), asynchronous processing, or UI communication.

In that aspect, LV2 plugins and hosts share very similar behaviors with Rust's own
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not familiar with futures and executors (i didn't ), so I don't fully understand this section. Would it be possible to reword this section so that people can understand it without knowledge about futures and executors?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, re-reading this I realize this is a bit more of me rambling about LV2's API (compared to others like VST) more than anything else. I will reword (if not completely remove), as it's more of an example to illustrate the rest of this section.

is definitely Undefined Behavior.

In this case, this ergonomic helper is necessary to produce safe code, and is not considered optional: the
`PortCollection` abstraction cannot be bypassed.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the PortCollection abstraction can in fact be bypassed: it can be implemented outside of the lv2 crate. For rsynth, this is in fact desirable, otherwise it's hard to abstract over different API's.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is an unclear wording issue. The PortCollection trait itself cannot be bypassed: the Plugin trait (among others) rely heavily on it. However, the PortCollection derive macro can be bypassed, and you can implement PortCollection however you like outside of the lv2 crate, which, as you say, is useful if you want to make your own abstraction.

In that specific case, I consider the PortCollection trait to be necessary for safe operation, and the PortCollection derive macro to be the optional syntax sugar layer on top (like all derive macros in rust-lv2 are).

Will fix this as well. 🙂

## Extra ergonomics and sugar
Also, while ergonomics and extra utilities are nice to have in this library sometimes, they *must* be optional to use.
Indeed, because of the goal to be a low-level library, we must not prevent the user from doing custom things themselves
at the cost of complexity. At least, as long as it is safe for them to do so.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A safe abstraction usually introduces some ergonomics, so I wouldn't say that this must be optional.

I think designing safe abstractions will very often come with hard choices: a more complicated API, some runtime overhead (see previous section for that), something that is hard to maintain or exposing unsafe methods or traits.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, what I meant here was ergonomic*-only* APIs should be optional (like the derive macros cited in the other comment), not all APIs that happen to be more ergonomic that raw LV2's.

Pretty much all safe APIs are more ergonomic than LV2's anyway. 🙃

I agree that API design comes with hard choices. I forgot to make it explicit in the DESIGN document (which isn't completed anyway), but this is what it is about: the list at the beginning is in order of most important to least important.

For example, when it comes to the lv2 crate, Memory Safety will be chosen in favored of C Parity or Performance, all of which are considered more important than Ergonomics (which is quite low the list).

Again, will fix that. Thanks a lot for your remarks, they are quite helpful! 🙂

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
📖 Documentation An effort to improve the documentation 🗨️ Discussion An exchange of opinions about a topic 👋 Help wanted Extra attention is needed
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants