4

I want to be able to use a double pointer in a class with REPR CStruct/CPointer:

typedef struct CipherContext {
          void    *cipher;
    const uint8_t *key;
          size_t   key_len;
    const uint8_t *path;
          size_t   path_len;
          size_t   block_size;
          void    *handle;

          int      (*cipher_init)(void **, const uint8_t *, size_t);
          int      (*cipher_encode)(void *, const uint8_t *, uint8_t *, size_t);
          int      (*cipher_decode)(void *, const uint8_t *, uint8_t *, size_t);
          void     (*cipher_free)(void *);
    const uint8_t *(*cipher_strerror)(int);
} CipherContext;

      int            cipher_context_init(CipherContext **, const uint8_t *, size_t, const uint8_t *, size_t, size_t);
      int            cipher_context_encode(CipherContext *, const uint8_t *, uint8_t *, size_t);
      int            cipher_context_decode(CipherContext *, const uint8_t *, uint8_t *, size_t);
      void           cipher_context_free(CipherContext *);
const uint8_t       *cipher_context_strerror(int);

Perl 6 code:

method new(Blob :$key!, Str :$path!, Int :$block-size!) {
    my Pointer[::?CLASS]     $ptr     .= new;
    my Int                   $err      = cipher_context_init($ptr, $key, $key.elems, $path, $path.codes, $block-size);
    return $ptr.deref unless $err;

    my Str $errstr = cipher_context_strerror($err) || do {
        my &cipher-strerror = nativecast(:(int32 --> Str), $!cipher-strerror);
        cipher-strerror($err)
    };
    die "Failed to initialize cipher context: $errstr";
}

submethod DESTROY() {
    cipher_context_free(self)
}

Short golf:

use v6.d;
use Nativecall;

class Foo is repr('CPointer') { 
    my Pointer[::?CLASS] $foo .= nw;
}

Only I can't figure out how to do it due to a bug in Rakudo. Is there a better way I could be handling errors in the C portion of the code (which is why I'm writing it like this)?

Kaiepi
  • 3,230
  • 7
  • 27
  • Please provide much more information. "bug in Rakudo"? What did you try? How did it fail? Also please try to avoid the impression that this is not a programming question, i.e. that it is a question on using an editor feature. – Yunnosch Feb 05 '19 at 20:14
  • You want to use "using a double pointer in cipher_context_init and returning an int" to align code in an editor? – Yunnosch Feb 05 '19 at 20:15
  • My bad @Yunnosch, i'll include more information – Kaiepi Feb 05 '19 at 20:16
  • I made an issue about this. It provides much more information as to what the problem is https://github.com/rakudo/rakudo/issues/2673 – Kaiepi Feb 05 '19 at 20:22
  • 1
    So the problem is a bug which you already reported to the appropriate person. What is it you want here? A workaround for a bug? Also questions on StackOverflow are expected to contain all needed information. A link is considered a weakness because of the risk that it becomes unavailable. Also all info should be in the question itself and not hidden in comments. – Yunnosch Feb 05 '19 at 20:25
  • Sorry about the haphazardness in the question. I'm looking for a workaround for the bug – Kaiepi Feb 05 '19 at 20:27
  • Simplify the example as much as possible. Would a single struct member and a single function demonstrate the issue? I'm still trying to figure out with all of that exactly what the question is. – Curt Tilmes Feb 05 '19 at 21:02
  • 1
    A 'double pointer' is just a Pointer that happens to point to a Pointer. You can usually just tell Perl 6 it is a Pointer and just make sure you set its value correctly. – Curt Tilmes Feb 05 '19 at 21:03
  • Difficult to say without more detail, but perhaps `cipher_context_init()` wants a pointer to a pointer that it will then set to point to some memory it allocates for you? You can usually do that with a `Pointer is rw`. – Curt Tilmes Feb 05 '19 at 21:06
  • I was using `Pointer[::?CLASS] is rw`. The question's been updated – Kaiepi Feb 05 '19 at 21:26

1 Answers1

5

That fails for the same reason this fails:

class Foo {...}

BEGIN Foo ~~ Bool; # <------

class Foo{
}

Part of the problem seems to be that Foo isn't composed yet when the Pointer.^parameterize method gets called.

So it isn't a subtype of Any yet. (or even Mu)

A workaround is to add a .^compose call in a BEGIN phaser before you use Pointer[::?CLASS].

class Foo is repr('CPointer') {
  BEGIN ::?CLASS.^compose;

  my Pointer[::?CLASS] $foo .= new;
}

My guess is that the real fix will be to change the Bool.ACCEPTS(Bool:U: \topic) candidate to Bool.ACCEPTS(Bool:U: Mu \topic).

The reason I think that is because this also fails with basically the same error:

Mu ~~ Bool
Brad Gilbert
  • 33,846
  • 11
  • 78
  • 129