-
Notifications
You must be signed in to change notification settings - Fork 79
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Revamp Filter API #301
Comments
@Goncalerta I might do Step 1 of this issue as part of my effort to start to lock down |
This is a step towards cobalt-org#301 and takes us one step further to `liquid-compiler` being "stable". BREAKING CHANGE: Things moved all over the place.
Got #302 in which takes care of Step 1 and expanded on some of my ideas for Step 2. Still in rough shape. |
I'm thinking about |
Before I weigh in, I'd be interested to know what is leading to the idea of a Also, at this point, would you like to be added as a maintainer on github. if nothing else, it will let you edit the original issue. |
If I understood correctly how
It seemed to me that a struct would be more appropriate for this:
Because every member would be a static constant, the whole structure could then be itself a static constant passed in during the registration of the filter. It just felt more "right" to me, at least at a first glance. However, to be honest I'm not really sure exactly where and how you intend to use the information from
Well, I'd be glad to. Thank you! |
I think I did it correctly. I've not messed with permissions too much before |
So I'm going to go in priority order, even if some things are only tangentially related. Ideally, the information we use to generate the reflection is also used by a macro to code-generate the mapping from the user's parameters (positional and keyword) to named parameter It also seems like it'd be "convenient" if tags, filters, and blocks all included their names. Then a user only needs to pass one thing in to register them. The upside for blocks is we'd then have a The last is due to Liquid's flexibility. Cobalt will be using the |
That is true that it is all static which does lower the value. I'll step you through some of my thought process on this. tl;drThe trade offs are very minor. See "Future Compatibility" for why I think I have a slight aesthetic bias towards a trait but would be interested in your thoughts after reading this. Future CompatibilityWe can go two directions with our struct, For Getters/setters end up having a bit of boiler plate. Since you mentioned the struct being static / const, both routes are dependent on function calls and so all of this is dependent on the status of the One benefit of a trait (and getters get this as well) is that we can provide default implementations of some things, including implementing them in terms of other functions ("inherent trait functions"). Ease of useFor some weird reason, I lean slightly towards a trait on this. Not sure why. One of our goals is to simplify the common case with macros. I'd love for our existing filters to not need too much of a change from how they look today though I expect that'd be a lot of complex macro work that might not be worth it and we might need a compromise between the ideal and no macros. On the other hand, it'd be really nice if we provide macros that compose so that if someone doesn't want all of our built-in logic, they can easily customize it. For example, they might want a macro for parsing parameters into a struct and evaluating the struct. On the other hand, they might want a configurable filter. They have to bypass our optimizations (struct of function pointers) and instead have a So with that in mind, some design considerations. As a user of macros, one of the things I find annoying is when they generate hidden code I need to access (enums, structs, fns). Implementing a trait is easy because you can just point someone to the trait to describe what will be implemented. I think this is even true for your struct idea because I don't think the user would need to access the generated struct at all since we'll have a generated trait to do that for them. Implementation costSo the above reminded me of the "struct of function pointers" optimization we use to avoid the cost of PerformanceOur priorities for performance
And the remaining bits that I'm unsure how much or if we care about Getting the For getting the name, since we don't need to reuse the lookup, it turns into a vtable call vs a vtable + struct lookup which there isn't really a difference there and is all unnoticeable anyways within our application. |
Just added the goal I forgot about "Offload argument-list parsing error handling from the user". |
Goals
Steps
1. Get filters out of runtime
Modify
FilterCall
to capture the relevant filter, avoiding the need to do this in the runtime2. Change filter APIs
Like tags/blocks, we'll make filters a two-trait process. The first trait replaces the FilterCall and processes the arguments into the order desired by the filter, erroring if needed. The second trait is generated by this and is captured into the FilterChain.
We'll also have an introspection trait that reports name, description, and each argument with name, description, and whether it is required, optional, positional only, or keyword only.
Rough sketches
Open Questions
Making things simple
We'll have a derive macro that takes a Parameters struct and generates an Arguments struct and helpers for taking the arguments and parsing them into the Arguments struct.
We also want to keep the current optimization for when a Filter has no configuration (100% of filters today; in the future some filters like a
markdown
filter could have state).Rough sketch
#[parameter(rename="")]
in case the member's name is insufficient#[parameter(positional=true)]
and#[parameter(keyword=true)]
This generates
self
) functions onSliceParameters
relevant forFilterReflection
FilterParser::parse
's parameters into aSliceParameter
SliceParameters
toSliceArguments
The reason for the static methods is to allow us to maintain our current optimization wherein a struct will be full of a functions points and implement
FilterParser
, allowing a non-BoxedCopy
variant.TODO Anything more we can help with
The text was updated successfully, but these errors were encountered: