The root of the problem in the example is that this bound
T: for<'a> TryConvertValue<'a>,
can never be satisfied for the non-static-argument case like &str, because you need something more like
for<'a> &'a str: TryConvertValue<'a>
Thus, I suspect you're going to need to generalize over static arguments and lifetime-carrying arguments:
// Gat like helper for potential lifetime type constructors
trait ArgRepr<'a> {
type Arg: 'a + TryConvertValue<'a>;
}
// Static args implement the trait themselves: <T as ArgRepr<'_>>::Arg == T
impl<T: 'static + for<'any> TryConvertValue<'any>> ArgRepr<'_> for T {
type Arg = T;
}
// Non-static args need a represenative. Since we've only implemented the above
// for sized types, references to unsized types can be represented by the unsized
// type.
//
// You'll need one of these per reference arg, and if it's sized, you'll need
// a dummy type represenative.
impl<'a> ArgRepr<'a> for str {
type Arg = &'a str;
}
So your bound can be
T: for<'a> ArgRepr<'a> // implies...
// for<'a> <T as ArgRepr<'a>>::Arg: TryConvert<'a>
Which works for both static sized args, and for representatives of lifetime carrying args like str.
Then build up from that, perhaps with a single lifetime version of CallbackTrait that you then use to build the higher-ranked actual CallbackTrait.
The next challenge may be that generic implementations that hit all cases with the ArgRepr abstraction will defeat inference. In that case you can perhaps restore some inference by implementing for the static arguments in a blanket fashion, and then for each lifetime-carrying arg via it's for<'a> ArgRepr<'a> represenative (str for &str, ...).
I don't think I have time to hash it out today, but see here for a walkthrough of what I believe is a related problem.