-
Notifications
You must be signed in to change notification settings - Fork 2
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
Idea: Support for global substitutions, and for generating items once / starting a new akin
context
#1
Comments
Thank you for making this issue, I'm happy someone uses So, the code would end up looking like this: let &ident = [ null, bool, array, /* ... */ ];
let &Type = [
{ () },
{ bool },
{ Vec<Value> },
// ...
];
let &trait_fn = {
fn into_~*ident(self) -> Result<*Type, Self>;
};
let &impl_fn = {
fn into_~*ident(self) -> Result<*Type, Self> {
todo!()
}
};
trait JsonValueExt {
*trait_fn
}
impl JsonValueExt for serde_json::Value {
*impl_fn
} This way, both Regarding the global substitutions, I don't quite understand their purpose, could you make a more elaborate example? |
@LyonSyonII: Thank you! Somehow I missed / didn't realize that it works this way. I was able to get the simple
I'm not 100% sure, but this might already work with the same approach. Here is an example from the documentation of #[duplicate_item(
typ1 [Some<Complex<()>, Type<WeDont<Want, To, Repeat>>>];
typ2 [Some<Other, Complex<Type<(To, Repeat)>>>];
)]
fn some_func(arg1: typ1, arg2: typ2) -> (typ1, typ2){
...
} If this is already possible, then this issue can be closed, from my side. That being said, I think the In case anybody who stumbles upon this issue is interested in it, here is a full implementation of the pub struct JsonValueConversionError(serde_json::Value);
akin::akin! {
let &ident = [ bool, number, string, array, object ];
let &Variant = [ Bool, Number, String, Array, Object ];
let &Type = [
{ bool },
{ serde_json::value::Number },
{ String },
{ Vec<serde_json::Value> },
{ serde_json::value::Map<String, serde_json::Value> },
];
let &trait_fn = {
fn into_~*ident(self) -> Result<*Type, JsonValueConversionError>;
};
let &impl_fn = {
fn into_~*ident(self) -> Result<*Type, JsonValueConversionError> {
if let serde_json::Value::*Variant(v) = self {
return Ok(v)
}
Err(JsonValueConversionError(self))
}
};
trait JsonValueExt {
fn into_null(self) -> Result<(), JsonValueConversionError>;
*trait_fn
}
impl JsonValueExt for serde_json::Value {
fn into_null(self) -> Result<(), JsonValueConversionError> {
if let serde_json::Value::Null = self {
return Ok(())
}
Err(JsonValueConversionError(self))
}
*impl_fn
}
} |
I was able to figure out what the problem was. In case anyone gets the same error, the following code demonstrates the problem: struct Foo;
akin::akin! {
let &into = [u8, u16];
let &stuff = [a, b, c];
let &foo_impl_fn = {
fn other_~*stuff(self) {}
};
impl Foo {
*foo_impl_fn
}
impl Into<*into> for Foo {
fn into(self) -> *into { *into::MIN }
}
} This leads to 'duplicate definitions with name The solution is, to put the struct Foo;
akin::akin! {
let &into = [u8, u16];
let &stuff = [a, b, c];
let &foo_impl_fn = {
fn other_~*stuff(self) {}
};
// Assign `Into` trait implementation to code variable:
let &foo_into_impl = {
impl Into<*into> for Foo {
fn into(self) -> *into { *into::MIN }
}
};
// Add trait implementation:
*foo_into_impl
impl Foo {
*foo_impl_fn
}
} So basically "code variables" are like contexts, and it's probably a good idea to put every independent part into such a variable.
Damn, I missed this part... @LyonSyonII: Yes, I think It probably would also make I think my issue was, that I thought that every top level item (type definitions, implementations, etc.) gets treated separately. Maybe it would make sense to add an example with several top level items? |
Thanks for posting the correction!
|
Sounds good 👍 |
Hi @LyonSyonII,
First of all, thanks for creating
akin
. I like the approach quit a lot.I'm wondering if global substitutions, and generating items only once can be added to
akin
.An example describes the use case best:
Imagine we would like to create an extension trait for serde_json::Value that adds methods like
into_xy
methods that return owned values.I'd create and implement a trait like this:
Instead of writing all of this by hand, I'd like to use
akin
to generate the trait and the trait implementation:But of course this doesn't work (
JsonValueExt
is defined several times).I'm wondering if this use case somehow can be supported.
For example via something like this:
#[akin(context)]
would tellakin
to generate the decorated item only once, and substitute within the item (similar to how$($ident)+
works formacro_rules
macros). Something likeakin_context! { /* new context */ }
probably also would be useful, for cases where attributes can't be used.My first idea for a name of the new attribute was
inner
, but I think that wouldn't be ideal, because it should be possible to substitute things within the trait definition itself (e.g. for generic traits). Maybe there is a better name thancontext
, however.Similarly, the
duplicate
crate has a nice feature to define global substitutions, which often come in handy.I'm wondering if this can be supported via something like:
...which would expand to just one
println!("Hello, world!")
.Using
const
here would be perfect semantically, I believe.These features would make
akin
useful in even more cases.Currently, I have created an additional
macro_rules
macro to generate the trait definition (duplicating the&Type
and&ident
definitions), which works but is not really ideal.Would it be possible to add these features?
Currently, I haven't learned how to use procedural macros, so I currently can't add these features myself. But if you don't want to add this yourself, but would accept a PR, I could do this when I learn procedural macros at some point (however, that would most likely be at least several months into the future, if not more).
Thanks again for creating
akin
!The text was updated successfully, but these errors were encountered: