aboutsummaryrefslogblamecommitdiffstats
path: root/lib/protocols/Handle.ml
blob: c45afb02d1bab48e13805cf42d7e37bbe3cac9f8 (plain) (tree)
1
2
3
4
5
6
7
8
9
10

                  


                         


                                                                                                        

   


                         
                                  
                           














                                                         
                                                         








                                              

                               






                             


                                                                   

                               

                                         



                                      
 
                                                                                           
type protocol = ..

module Error = struct
  open Concepts.Condition

  let unimplemented_protocol obj_name =
    condition "unimplemented-protocol" "A required protocol was not implemented by the specified object"
      ("object" |=| Concepts.Value.String obj_name)
end

class type obj = object
  method reference : bool
  method release : unit
  method hash : Concepts.Hash.hash
  method to_string : string
  method protocols : protocol list
end

type t = { valid : bool ref; refers_to : obj }

type 'a interface = { handle : t; interface : 'a }

let object_of { valid; refers_to } =
  if !valid then
    refers_to
  else
    failwith "Attempt to dereference an invalid handle!"

let interface_of handle interface = { handle; interface }

let make o = { valid = ref true; refers_to = (o :> obj) }

let into handle f =
  List.find_map f (object_of handle)#protocols
  |> Option.map (interface_of handle)

let invoke { handle; interface } f =
  let _ = object_of handle in
  f interface

let from { handle; _ } = handle

let copy handle =
  let o = object_of handle in
  if o#reference then
    Some (make o)
  else
    None

let equal h1 h2 =
  Concepts.Hash.hash_equals (object_of h1)#hash (object_of h2)#hash

let hash h = (object_of h)#hash

let to_string h = (object_of h)#to_string

let release ({ valid; _ } as handle) =
  let o = object_of handle in
  valid := false;
  o#release

let require f h = Option.to_result ~none:(Error.unimplemented_protocol (to_string h)) (f h)