protected boolean tryFromObject(TExecutionContext context, ValueSource in, ValueTarget out) {
    if (in.getType().equalsExcludingNullable(out.getType())) {
      ValueTargets.copyFrom(in, out);
      return true;
    }

    UnderlyingType underlyingType = TInstance.underlyingType(in.getType());
    if (underlyingType == UnderlyingType.STRING || underlyingType == UnderlyingType.BYTES)
      return false;
    final String asString;
    switch (underlyingType) {
      case BOOL:
        asString = Boolean.toString(in.getBoolean());
        break;
      case INT_8:
        asString = Byte.toString(in.getInt8());
        break;
      case INT_16:
        asString = Short.toString(in.getInt16());
        break;
      case UINT_16:
        asString = Integer.toString(in.getUInt16());
        break;
      case INT_32:
        asString = Integer.toString(in.getInt32());
        break;
      case INT_64:
        asString = Long.toString(in.getInt64());
        break;
      case FLOAT:
        asString = Float.toString(in.getFloat());
        break;
      case DOUBLE:
        asString = Double.toString(in.getDouble());
        break;
      case BYTES:
      case STRING:
      default:
        throw new AssertionError(underlyingType + ": " + in);
    }
    parser.parse(context, new Value(MString.varcharFor(asString), asString), out);
    return true;
  }
 @Override
 public void fromObject(TExecutionContext context, ValueSource in, ValueTarget out) {
   if (in.isNull()) out.putNull();
   else if (!tryFromObject(context, in, out)) parser.parse(context, in, out);
 }