Description
Fix marshaling
-
I don't like JniMarshalInfo; it's too convoluted, makes the simple cases hard.
-
Do in conjunction w/ Java.Interop.Dynamic
-
Need to permit use of custom attributes on return types, parameter types, "inline" into marshal methods.
-
Need to use System.Linq.Expressions/etc. to "merge"/do the work of monodroid/tools/generator, so that Java.Interop.Export can support value types, etc.
-
Use case: Android.Graphics.Color, which is marshaled from JNI as an
int
but to managed as an Android.Graphics.Color struct, and vice-versa. -
Should probably split JniMarshalInfo into separate "to managed" and "from managed" types?
- No; needless added complexity, and when it comes to System.Linq.Expressions many of the type information will be shared between them.
-
"New" marshaling support should try to leverage
Expression<TDelegate>
to make it easier to write marshalers:public class JnIValueMarshaler<TJni, TManaged> : JniValueMarshaler { public sealed override Expression<Func<JniValueMarshalerContext, TJni, TManaged>> JniTypeToManagedType (JniValueMarshalerContext context, Expression jniSourceValue, Expression manageDestinationdValue); public abstract Expression<Func<JniValueMarshaler, TJni, TManaged> JniTypeToManagedType (); } class Int32Marshaler : JniValueMarshaler<int, int> { public override Expression<Func<JniValueMarshalerContext, TJni, TManaged>> JniTypeToManagedType (JniValueMarshalerContext context, Expression jniSourceValue, Expression manageDestinationdValue) { return (c, jni) => jni; } }
-
With such a system in place, we'll need to be able to "rebind" the Expression<Func<...>> parameters with the generated parameters
http://stackoverflow.com/questions/8610506/binding-parameter-in-expression-trees
class MyVisitor : ExpressionVisitor { ParameterExpression[] old, cur; public MyVisitor(ParameterExpression[] old, ParameterExpression[] cur) { this.old = old; this.cur = cur; } protected override Expression VisitParameter(ParameterExpression node) { for (int i = 0; i < old.Length; ++i) { if (old [i].Name == node.Name && old [i].Type == node.Type) return cur [i]; } return node; } }
With
MyVisitor
, we can then convert the result ofInt32Marshaler.JniTypeToManagedType()
:var p = Expression.Parameter (typeof (int), "p"); var c = Expression.Parameter (typeof (JniValueMarshalerContext), "c"); var e = new Int32Marshaler ().JniValueMarshalerContext (); var v = new MyVisitor (e.Parameters, new[]{c, p}); var e = Expression.Lambda<Func<JniValueMarshalerContext, int, int>>(v.Visit (e.Body), new[]{c, p});
Probably related: JniMarshalInfoAttribute
, a custom attribute to control marshaling behavior?
We'll also need similar custom attributes to control parameter and return type marshaling, via the above Expression architecture.