Skip to content

Value Marshaling with Expressions #8

Closed
@jonpryor

Description

@jonpryor

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 of Int32Marshaler.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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions