This issue is meant to track the status of patching methods, as well as a public idea board. This is sectioned mainly into two achievements: associated functions and methods. NOTE methods will get their own tracking issue; this will be closed when associated functions are done.
TODO items for associated functions:
[x] Get a real demo working
[x] Integrate for everything in lib
[x] Fix with macros
[x] Module aware expansions for imports
[x] Test with imports
[x] Import macros
[x] Test for backwards compatibility
[x] Docs!
[x] Error checking to deny actual methods (temporary)
Associated Functions
Prior to filing this issue, a method of patchable associated functions was discovered. The final implementation syntax is as follows:
It is (roughly) implemented internally as follows:
struct Foo {}
static __hotpatch_implgen_Foo_bar: hotpatch::Patchable<(Self, i32), ()> =
hotpatch::Patchable::__new( ||
// macro passthrough from the initial implementation
);
fn __hotpatch_staticwrap_0_bar() -> &'static Patchable<(Self, i32), ()> {
&__hotpatch_implgen_Foo_bar
}
impl Foo {
pub const bar: hotpatch::MutConst<Patchable<(Self, i32), ()>> =
hotpatch::MutConst::new(__hotpatch_staticwrap_0_bar);
// where MutConst is a const reference to a static variable
// It's pretty much an associated static with extra steps (they aren't supported)
}
Problem: Because the implementation must be separated from the impl block, this cannot support a self parameter (in any form).
Problem: Self is not available. I have yet to find a workaround, but I suspect one exists using dummy consts.
Methods
Recently I discovered a way of making patchable methods. The main holdup was declaring a way of having some associated static holding a function pointer with a self parameter. And the only way to get a self parameter to work is with a method directly in an impl block.
Or at least, I thought so. Traits perfectly achieve this. Combining this with the fact that there can be multiple struct associations under the same name if they're in a trait and of different types yields a perfect solution. The working syntax is as follows:
struct Foo {}
#[patchable]
impl Foo {
fn bar(&self) {}
}
fn main() {
let foo = Foo::new(); // new defined elsewhere
foo.bar(); // works
// hotpatched as the following:
Foo::bar.hotpatch_fn(|| unimplemented!());
// Yet the following does NOT work for hotpatching:
foo.bar.hotpatch_fn(|| unimplemented!());
// This is GREAT for cleanliness
}
The macro-expanded implementation is still being figured out. However, the following is a working demo of making Foo::bar different from foo.bar:
struct Foo {
data: i32,
}
impl Foo {
fn new(data: i32) -> Self {
Self{data}
}
}
// begin macro generated content
// macro input:
// #[patchable]
// impl Foo {
// fn bar(self) {
// println!("hello from bar! This foo object has data: {}", self.data);
// }
// }
impl Foo {
#[allow(non_upper_case_globals)]
const bar: i32 = 0;
}
trait FnTrait { // final implementation will use mangled names
fn bar(self);
}
impl FnTrait for Foo {
fn bar(self) {
println!("hello from bar! This foo object has data: {}", self.data);
}
}
// end macro generated content
// test
fn main() {
let foo = Foo::new(100); // just gives foo some instance data
foo.bar(); // Has access to self, and the data -^-----------^
println!("{:?}", Foo::bar); // Foo::bar is a const i32; totally different!
}
I really like the fact that foo.bar is actually a method, and that foo.bar.hotpatch isn't allowed. Forcing the use of Foo::bar.hotpatch cements the idea that the method is patched for all instances.
Problem: trait associated functions (without self) are not privy to the same non-competition rules. This may mean a macro may need to decide whether to use the associated function implementation or the method implementation. This feels like a rustc bug to me.
Took a sidequest for fn_ptr branch. This fixes an intermediate issue I was having with incorrect lifetime elision on patchable types. This should be good to go next.
This issue is meant to track the status of patching methods, as well as a public idea board. This is sectioned mainly into two achievements: associated functions and methods. NOTE methods will get their own tracking issue; this will be closed when associated functions are done.
TODO items for associated functions:
Associated Functions
Prior to filing this issue, a method of patchable associated functions was discovered. The final implementation syntax is as follows:
It is (roughly) implemented internally as follows:
Problem: Because the implementation must be separated from the
impl
block, this cannot support aself
parameter (in any form).Problem:
Self
is not available. I have yet to find a workaround, but I suspect one exists using dummyconst
s.Methods
Recently I discovered a way of making patchable methods. The main holdup was declaring a way of having some associated static holding a function pointer with a
self
parameter. And the only way to get aself
parameter to work is with a method directly in animpl
block.Or at least, I thought so. Traits perfectly achieve this. Combining this with the fact that there can be multiple struct associations under the same name if they're in a trait and of different types yields a perfect solution. The working syntax is as follows:
The macro-expanded implementation is still being figured out. However, the following is a working demo of making
Foo::bar
different fromfoo.bar
:I really like the fact that
foo.bar
is actually a method, and thatfoo.bar.hotpatch
isn't allowed. Forcing the use ofFoo::bar.hotpatch
cements the idea that the method is patched for all instances.Problem: trait associated functions (without
self
) are not privy to the same non-competition rules. This may mean a macro may need to decide whether to use the associated function implementation or the method implementation. This feels like a rustc bug to me.