Как обрабатывать варагоны с помощью NativeCall

Я пишу привязки для Editline и одной из ее функций, history, выполняет основную часть работы для этой части библиотеки, но имеет несколько возможных подписей:

:(Pointer[Internal], Pointer[Event], int32 --> int32)
:(Pointer[Internal], Pointer[Event], int32, int32 --> int32)
:(Pointer[Internal], Pointer[Event], int32, Str --> int32)
# etc.

Третий аргумент - это флаг, который определяет, какая функция history следует вызывать с заданными аргументами, но поскольку эти символы не экспортируются, я не могу вместо них использовать их. Как я могу найти способ использовать функцию? Я не могу использовать несколько сабвуферов или использовать cglobal бросить его в Pointer, затем к функции с правильной подписью.

Редактировать: я знаю о is symbol, но мне интересно, есть ли лучшие способы сделать это, поскольку есть 9 различных подписей, чтобы написать для

0 ответов

Вы можете обернуть родную функцию функцией Raku:

sub history ( Pointer[Internal] $a, Pointer[Event] $b, int32 $flag, $c? --> int32 ){
  given $flag {
    when 0|2 {
      sub history (Pointer[Internal], Pointer[Event], int32 --> int32) is native(…) {}
      history( $a, $b, $flag )
    }
    when 1|3 {
      sub history (Pointer[Internal], Pointer[Event], int32, int32 --> int32) is native(…) {}
      history( $a, $b, $flag, $c )
    }
    when 4 {
      sub history (Pointer[Internal], Pointer[Event], int32, Str --> int32) is native(…) {}
      history( $a, $b, $flag, $c )
    }
  }
}

Или вы можете обернуть каждую версию в отдельный мульти:

# Note the flag value ---------------------------------------+
#                                                            |
#                                                            V
multi sub history ( Pointer[Internal] $a, Pointer[Event] $b, 0 --> int32 ){
  sub history (Pointer[Internal], Pointer[Event], int32 --> int32) is native(…) {}
  history( $a, $b, 0 )
}
multi sub history ( Pointer[Internal] $a, Pointer[Event] $b, 2 --> int32 ){
  sub history (Pointer[Internal], Pointer[Event], int32 --> int32) is native(…) {}
  history( $a, $b, 2 )
}

multi sub history ( Pointer[Internal] $a, Pointer[Event] $b, int32 $flag where 1|3, int32 $c --> int32 ){
  sub history (Pointer[Internal], Pointer[Event], int32, int32 --> int32) is native(…) {}
  history( $a, $b, $flag, $c )
}

multi sub history ( Pointer[Internal] $a, Pointer[Event] $b, 4, Str:D $c --> int32 ){
  sub history (Pointer[Internal], Pointer[Event], int32, Str --> int32) is native(…) {}
  history( $a, $b, 4, $c )
}

Возможно, вы даже сможете определить правильный флаг на основе аргументов. Это будет работать, только если для каждой подписи будет только один флаг.
(Таким образом, этот следующий пример не следует за приведенным выше, где0 а также 2 иметь такую ​​же подпись.)

multi sub history ( Pointer[Internal] $a, Pointer[Event] $b --> int32 ){
  sub history (Pointer[Internal], Pointer[Event], int32 --> int32) is native(…) {}
  history( $a, $b, 0 )
}

multi sub history ( Pointer[Internal] $a, Pointer[Event] $b, int32 $c --> int32 ){
  sub history (Pointer[Internal], Pointer[Event], int32 --> int32) is native(…) {}
  history( $a, $b, 1, $c )
}

multi sub history ( Pointer[Internal] $a, Pointer[Event] $b, Str:D $c --> int32 ){
  sub history (Pointer[Internal], Pointer[Event], int32, Str --> int32) is native(…) {}
  history( $a, $b, 4, $c )
}

Вы можете писать обертки с разными именами:

sub foo ( Pointer[Internal] $a, Pointer[Event] $b --> int32 ){
  sub history (Pointer[Internal], Pointer[Event], int32 --> int32) is native(…) {}
  history( $a, $b, 0 )
}

sub bar ( Pointer[Internal] $a, Pointer[Event] $b, int32 $c --> int32 ){
  sub history (Pointer[Internal], Pointer[Event], int32 --> int32) is native(…) {}
  history( $a, $b, 1, $c )
}

sub baz ( Pointer[Internal] $a, Pointer[Event] $b, Str:D $c --> int32 ){
  sub history (Pointer[Internal], Pointer[Event], int32, Str --> int32) is native(…) {}
  history( $a, $b, 4, $c )
}

Вы можете сделать это без обертки, используя is symbol.

sub foo (Pointer[Internal], Pointer[Event], int32        --> int32) is native(…) is symbol<history> {}
sub bar (Pointer[Internal], Pointer[Event], int32, int32 --> int32) is native(…) is symbol<history> {}
sub baz (Pointer[Internal], Pointer[Event], int32, Str   --> int32) is native(…) is symbol<history> {}

Вы также можете использовать nativecast и сгенерированный объект Signature в вашей функции-оболочке:

sub history ( Pointer[Internal] $a, Pointer[Event] $b, int32 $flag, $c? --> int32 ){
  my \I32 = Parameter.new( type => int32 );
  my \PI  = Parameter.new( type => Pointer[Internal] );
  my \PE  = Parameter.new( type => Pointer[Event] );
  my \STR = Parameter.new( type => Str );

  my @params = ( PI, PE, I32 );
  given $flag {
    when 0|2 {
    }
    when 1|3 {
      @params.push( I32 );
    }
    when 4 {
      @params.push( STR );
    }
  }

  my \signature = Signature.new( params => @params.List, returns => int32 );

  # fill this out -----------V
  my \history-ptr = cglobal( …, 'history', Pointer );

  my &history = nativecast( signature, history-ptr );

  history( $a, $b, $flag, ($c if +@params == 4) );
}

Вот как можно написать обертку для C printf или scanf.


Независимо от того, что из вышеперечисленного вы используете, вам нужен способ определить, какой вариант вам нужно вызвать.

Даже в C должен быть способ определения количества и типа аргументов на основе текущего или предыдущего аргумента.

В printf количество и тип аргументов основаны на первом аргументе, который является форматом.

Функция A C может определять количество аргументов, имея в конце нулевой аргумент. В таком случае ты должен сказать об этом Раку.

Независимо от того, как базовая внешняя функция обрабатывает va_args, вы должны скопировать этот алгоритм в Raku в той или иной форме. Это не может просто угадать.

Если у вас есть несколько сторонних функций, которые работают одинаково, вы можете создать для них генератор оболочки.

Другие вопросы по тегам