64355afc143cb3bedba7873aa8f47ea221eec84a
[scpubgit/Object-Remote.git] / lib / Object / Remote.pm
1 package Object::Remote;
2
3 use Object::Remote::MiniLoop;
4 use Object::Remote::Proxy;
5 use Scalar::Util qw(weaken blessed);
6 use Module::Runtime qw(use_module);
7 use Moo;
8
9 sub new::on {
10   my ($class, $on, @args) = @_;
11   __PACKAGE__->new(
12     connection => $on,
13     class => $class,
14     args => \@args
15   )->proxy;
16 }
17
18 has connection => (
19   is => 'ro', required => 1,
20   coerce => sub {
21     blessed($_[0])
22       ? $_[0]
23       : use_module('Object::Remote::Connection')->new_from_spec($_[0])
24   },
25 );
26
27 has id => (is => 'rwp');
28
29 has disarmed_free => (is => 'rwp');
30
31 sub disarm_free { $_[0]->_set_disarmed_free(1); $_[0] }
32
33 sub proxy {
34   bless({ remote => $_[0], method => 'call' }, 'Object::Remote::Proxy');
35 }
36
37 sub BUILD {
38   my ($self, $args) = @_;
39   unless ($self->id) {
40     die "No id supplied and no class either" unless $args->{class};
41     ref($_) eq 'HASH' and $_ = [ %$_ ] for $args->{args};
42     $self->_set_id(
43       $self->_await(
44         $self->connection->send(
45           class_call => $args->{class}, 0,
46           $args->{constructor}||'new', @{$args->{args}||[]}
47         )
48       )->{remote}->disarm_free->id
49     );
50   }
51   $self->connection->register_remote($self);
52 }
53
54 sub current_loop {
55   our $Current_Loop ||= Object::Remote::MiniLoop->new
56 }
57
58 sub call {
59   my ($self, $method, @args) = @_;
60   $self->_await(
61     $self->connection->send(call => $self->id, wantarray, $method, @args)
62   );
63 }
64
65 sub call_discard {
66   my ($self, $method, @args) = @_;
67   $self->connection->send_discard(call => $self->id, $method, @args);
68 }
69
70 sub call_discard_free {
71   my ($self, $method, @args) = @_;
72   $self->disarm_free;
73   $self->connection->send_discard(call_free => $self->id, $method, @args);
74 }
75
76 sub _await {
77   my ($self, $future) = @_;
78   my $loop = $self->current_loop;
79   $future->on_ready(sub { $loop->stop });
80   $loop->run;
81   wantarray ? $future->get : ($future->get)[0];
82 }
83
84 sub DEMOLISH {
85   my ($self, $gd) = @_;
86   return if $gd or $self->disarmed_free;
87   $self->connection->send_free($self->id);
88 }
89
90 1;