------------------------------------------------------------------------------
--                                                                          --
--                         GNAT COMPILER COMPONENTS                         --
--                                                                          --
--                           S Y S T E M . R P C                            --
--                                                                          --
--                                 S p e c                                  --
--                                                                          --
--                            $Revision: 1.11 $                             --
--                                                                          --
-- This specification is adapted from the Ada Reference Manual for use with --
-- GNAT.  In accordance with the copyright of that document, you can freely --
-- copy and modify this specification,  provided that if you redistribute a --
-- modified version,  any changes that you have made are clearly indicated. --
--                                                                          --
------------------------------------------------------------------------------

with Ada.Streams;
with System.Storage_Elements;

package System.RPC is

   type Partition_ID is range 0 .. 63; --  temporary declaration

   Communication_Error : exception;

   type Params_Stream_Type
     (Initial_Size : Ada.Streams.Stream_Element_Count) is new
       Ada.Streams.Root_Stream_Type with private;

   procedure Read
     (Stream : in out Params_Stream_Type;
      Item   : out Ada.Streams.Stream_Element_Array;
      Last   : out Ada.Streams.Stream_Element_Offset);

   procedure Write
     (Stream : in out Params_Stream_Type;
      Item   : in Ada.Streams.Stream_Element_Array);

   --  Synchronous call

   procedure Do_RPC
     (Partition  : in Partition_ID;
      Params     : access Params_Stream_Type;
      Result     : access Params_Stream_Type);

   --  Asynchronous call

   procedure Do_APC
     (Partition  : in Partition_ID;
      Params     : access Params_Stream_Type);

   --  The handler for incoming RPCs.

   type RPC_Receiver is
     access procedure
       (Params     : access Params_Stream_Type;
        Result     : access Params_Stream_Type);

   procedure Establish_RPC_Receiver (
      Partition : in Partition_ID;
      Receiver  : in RPC_Receiver);

private

   Std_Length : constant Ada.Streams.Stream_Element_Count := 1024;

   type Packet_Type (Length : Ada.Streams.Stream_Element_Count) is
      record
         Content : aliased Ada.Streams.Stream_Element_Array (1 .. Length);
         First   : Ada.Streams.Stream_Element_Offset := 1;
         Last    : Ada.Streams.Stream_Element_Offset := 0;
      end record;
   --  Each packet has a content and two indexes, First and Last.
   --  First and Last are used by Read and Write to know
   --  (resp.) where to start to read and where to start to write

   type Tmp_Packet_Type (Length : Ada.Streams.Stream_Element_Count) is
      record
         Tmp : Packet_Type (Length);
      end record;
   --  Sorry for that : Gnat bug

   type Packet_Node;
   type Packet_Node_Access is access Packet_Node;
   type Packet_Node is
      record
         Packet : Packet_Type (Std_Length);
         Next   : Packet_Node_Access;
      end record;

   type Packet_List_Type is
      record
         Head     : Packet_Node_Access;
         Tail     : Packet_Node_Access;
      end record;

   type Initial_Stream_Access is access Tmp_Packet_Type;

   type Params_Stream_Type
     (Initial_Size : Ada.Streams.Stream_Element_Count) is new
       Ada.Streams.Root_Stream_Type with
       record
          Initial : Initial_Stream_Access;
          Extra   : Packet_List_Type;
       end record;
   --  Two kinds of storage in a stream :
   --   o an initial storage initialized during the declaration
   --   o an extra storage with a linked list of fixed size packets
   --     used during execution when the initial storage is not sufficient

   procedure Head_Node
     (Index  :    out Packet_Node_Access;
      Stream : in     Params_Stream_Type);
   --  Set index to the first packet of the extra storage

   procedure Tail_Node
     (Index  :    out Packet_Node_Access;
      Stream : in     Params_Stream_Type);
   --  Set index to the last packet of the extra storage

   function Null_Node
     (Index : Packet_Node_Access)
     return Boolean;
   --  True if null

   procedure Delete_Head_Node
     (Stream : in out Params_Stream_Type);
   --  Delete the first node and free it

   procedure Next_Node
     (Node : in out Packet_Node_Access);
   --  Node is set to the next node
   --  If not possible, Stream_Error is raised

   procedure Append_New_Node
     (Stream : in out Params_Stream_Type);
   --  Create a new node at the end of the extra storage

end System.RPC;
