#!perl

use strict;
use warnings;
use Devel::Leak::Object qw(GLOBAL_bless);
use JavaScript qw(:all);

{
  package ThisObjectWillLeak;

  sub new {
    my($class, $num) = @_;
    return bless { n => $num }, $class;
  }

  sub whoami {
    my $self = shift;
    return "Leaky object #$self->{n}";
  }
}

{
  package ThisObjectWillNotLeak;

  sub new {
    my($class, $num) = @_;
    return bless { n => $num }, $class;
  }

  sub whoami {
    my $self = shift;
    return "Sealed object #$self->{n}";
  }
}

our $rt = JavaScript::Runtime->new;
our $cx = JavaScript::Context->new($rt);

sub dont_leak_an_object {
  my $sealed = ThisObjectWillNotLeak->new(shift);
  $cx->bind_object(sealed => $sealed);
  return;
}

sub leak_an_object {
  my $leaky = ThisObjectWillLeak->new(shift);
  return $leaky;
}

sub write {
  my $msg = shift;
  print "$msg\n";
}

foreach my $i ('ThisObjectWillLeak', 'ThisObjectWillNotLeak') {
  $cx->bind_class(
    name => $i,
    constructor => sub {},
    methods => { whoami => $i->can('whoami') },
    flags => JS_CLASS_NO_INSTANCE,
    package => $i
  );
}

$cx->bind_function(leak_an_object => \&leak_an_object);
$cx->bind_function(dont_leak_an_object => \&dont_leak_an_object);
$cx->bind_function(write => \&write);

foreach my $i (1 .. 10) {
  $cx->eval("leaky = leak_an_object($i)");
  $cx->eval("dont_leak_an_object($i)");
  $cx->eval("write(leaky.whoami())");
  $cx->eval("write(sealed.whoami())");
}

JavaScript::dump_sv_report_used();