package Wasm::Wasmtime::Caller;

use strict;
use warnings;
use 5.008004;
use FFI::Platypus::Buffer ();
use Wasm::Wasmtime::FFI;
use Wasm::Wasmtime::Extern;
use base qw( Exporter );

our @EXPORT = qw( wasmtime_caller );

$ffi_prefix = 'wasmtime_caller_';

# ABSTRACT: Wasmtime caller interface
our $VERSION = '0.24'; # VERSION


our @callers;

sub wasmtime_caller (;$)
{
  $callers[$_[0]||0]
}


sub new
{
  my($class, $ptr, $store) = @_;
  bless {
    ptr   => $ptr,
    store => $store,
  }, $class;
}


sub store { shift->{store} }

$ffi->attach( export_get => ['opaque','opaque','size_t','wasmtime_extern_t'] => 'bool' => sub {
  my $xsub = shift;
  my $self = shift;
  return undef unless $self->{ptr};
  my $name = shift;
  $name = defined $name ? "$name" : "";
  my($nptr, $nlen) = FFI::Platypus::Buffer::scalar_to_buffer($name);
  my $extern = Wasm::Wasmtime::ExternData->new;
  return undef unless $xsub->($self->{ptr}, $nptr, $nlen, $extern);
  my $obj = Wasm::Wasmtime::Extern->from_extern($extern, $self->{store});
  $extern->free;
  $obj;
});

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Wasm::Wasmtime::Caller - Wasmtime caller interface

=head1 VERSION

version 0.24

=head1 SYNOPSIS

 use Wasm::Wasmtime;
 use Wasm::Wasmtime::Caller qw( wasmtime_caller );
 
 {
   # this just uses Platypus to create a utility function
   # to convert a pointer to a C string into a Perl string.
   use FFI::Platypus 2.00;
   my $ffi = FFI::Platypus->new( api => 2 );
   $ffi->attach_cast( 'cstring' => 'opaque' => 'string' );
 }
 
 sub print_wasm_string
 {
   my $ptr = shift;
   my $caller = wasmtime_caller;
   my $memory = $caller->export_get('memory');
   print cstring($ptr + $memory->data);
 }
 
 my $store = Wasm::Wasmtime::Store->new;
 my $instance = Wasm::Wasmtime::Instance->new(
   Wasm::Wasmtime::Module->new($store->engine, wat => q{
     (module
       (import "" "print_wasm_string" (func $print_wasm_string (param i32)))
       (func (export "run")
         i32.const 0
         call $print_wasm_string
       )
       (memory (export "memory") 1)
       (data (i32.const 0) "Hello, world!\n\00")
     )
   }),
   $store,
   [\&print_wasm_string],
 );
 
 $instance->exports->run->();

=head1 DESCRIPTION

This class represents the caller's context when calling a Perl L<Wasm::Wasmtime::Func> from
WebAssembly.  The primary purpose of this structure is to provide access to the caller's
exported memory.

=head1 FUNCTIONS

=head2 wasmtime_caller

 my $caller = wasmtime_caller;
 my $caller = wasmtime_caller $index;

Returns the current caller context (an instance of L<Wasm::Wasmtime::Caller>), or
C<undef> if the current Perl code wasn't called from WebAssembly.  C<$index>
indicates how many WebAssembly call frames to go back.

This function is exported by default.

=head1 METHODS

=head2 export_get

 my $extern = $caller->export_get($name);

Returns the L<Wasm::Wasmtime::Extern> for the named export C<$name>.  As of this
writing only L<Wasm::Wasmtime::Memory> exports are supported by Wasmtime here.

=head2 store

 my $store = $caller->store;

Returns the L<Wasm::Wasmtime::Store> the caller belongs to.

=head1 SEE ALSO

=over 4

=item L<Wasm>

=item L<Wasm::Wasmtime>

=back

=head1 AUTHOR

Graham Ollis <plicease@cpan.org>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2020-2026 by Graham Ollis.

This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.

=cut
