docs: private MethodHandle buildProcessor(FunctionManager functionManager, Type fromType, Type toType, boolean isKey)
      {
          MethodHandle getter = nativeValueGetter(fromType);
  
          // Adapt cast that takes ([ConnectorSession,] ?) to one that takes (?, ConnectorSession), where ? is the return type of getter.
          ScalarFunctionImplementation castImplementation = functionManager.getScalarFunctionImplementation(functionManager.lookupCast(CastType.CAST, fromType.getTypeSignature(), toType.getTypeSignature()));
          MethodHandle cast = castImplementation.getMethodHandle();
          if (cast.type().parameterArray()[0] != ConnectorSession.class) {
              cast = MethodHandles.dropArguments(cast, 0, ConnectorSession.class);
          }
          cast = permuteArguments(cast, methodType(cast.type().returnType(), cast.type().parameterArray()[1], cast.type().parameterArray()[0]), 1, 0);
          MethodHandle target = compose(cast, getter);
  
          // If the key cast function is nullable, check the result is not null.
          if (isKey && castImplementation.isNullable()) {
              target = compose(nullChecker(target.type().returnType()), target);
          }
  
          MethodHandle writer = nativeValueWriter(toType);
          writer = permuteArguments(writer, methodType(void.class, writer.type().parameterArray()[1], writer.type().parameterArray()[0]), 1, 0);
  
          return compose(writer, target.asType(methodType(unwrap(target.type().returnType()), target.type().parameterArray())));
      }