#line 1508 "/home/travis/build/felix-lang/felix/src/packages/io.fdoc"
  
  
  module Faio_win32 {
  requires package "demux";
  requires package "faio";
  // contains windows overlapped/iocp io & copipes. no stream wrapper yet.
  open C_hack;
  open Faio;
  open Demux;
  
  header '#include "faio_winio.hpp"'; // this has everything (includes asyncio.h)
  
  // ------------ core file and socket definitions ----------------
  // I could just use HANDLEs everywhere, but I want to see how this goes
  type WFILE = 'HANDLE';
  typedef fd_t = WFILE;
  
  const INVALID_HANDLE_VALUE: WFILE = 'INVALID_HANDLE_VALUE';
  fun == : WFILE*WFILE -> bool = '($1 == $2)';
  
  type SOCKET = "SOCKET";
  typedef socket_t = SOCKET;
  
  instance Str[socket_t] {
     fun str: socket_t -> string = "::flx::rtl::strutil::str<int>($1)" requires package "flx_strutil";
  }
  
  // --------------------------------------------------------------
  
  // useful windows function
  fun GetLastError: 1 -> int = 'GetLastError()';
  
  // maybe don't use this - let the socket be passed in already associated
  // with an IOCP. do I have to make this explicitly overlapped? If we
  // want async io I think I'll need to associate this with the iocp.
  fun cmk_socket : unit -> SOCKET = '::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)';
  
  // well that didn't help.
  //fun cmk_socket : unit -> SOCKET = 'WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED)';
  // must associate with iocp to do overlapped io with s (WSASend/Recv)
  proc mk_socket(s: &SOCKET)
  {
      *s = cmk_socket();
      associate_with_iocp(*s);                // associate with iocp (errors?).
  }
  
  
  type wasync_accept = "flx::faio::wasync_accept";
  
  fun mk_accept: demuxer *  SOCKET*SOCKET -> wasync_accept = 'flx::faio::wasync_accept($a)';
  // make this a parameterised type
  fun get_success[t]: t -> bool = '$1.success';
  
  // this feels silly
  const INVALID_SOCKET: SOCKET = 'INVALID_SOCKET';
  // oops, no good if we can't check against it
  fun eq : SOCKET*SOCKET -> bool = '($1 == $2)';
  
  // windows style accept. accepted is an already created socket, unbound
  proc Accept(success: &bool, listener: SOCKET, accepted: SOCKET)
  {
      var acc = mk_accept(sys_demux,listener, accepted);
      faio_req$ &acc;    // causes AcceptEx to be called
      *success = get_success(acc);
  }
  
  type connect_ex="flx::faio::connect_ex";
  fun mk_connect_ex: demuxer * SOCKET*+char*int -> connect_ex = 'flx::faio::connect_ex($a)';
  
  // for use on sockets you make yourself, who knows, maybe you want to
  // reuse them
  proc Connect(s: SOCKET, addr: +char, port: int, err: &int)
  {
      var con = mk_connect_ex(sys_demux,s, addr, port);
      faio_req$ &con;    // causes ConnectEx to be called
      var success = get_success(con);
      err <- if success then 0 else -1 endif;
  }
  
  proc Connect(s: &SOCKET, addr: +char, port: int, err: &int)
  {
      mk_socket s;            // error handling?
      Connect(*s, addr, port, err);
  }
  
  // listens on all interfaces, I guess
  proc cmk_listener: &SOCKET*&int*int
      = '*$1 = flx::demux::create_listener_socket($2, $3);';
  
  proc mk_listener(listener: &SOCKET, port: &int, backlog: int)
  {
      cmk_listener(listener,port, backlog);
      associate_with_iocp(*listener);
  }
  
  // ignores return value
  proc closesocket: SOCKET = 'closesocket($1);';
  
  const SD_RECEIVE:int = 'SD_RECEIVE';
  const SD_SEND:int = 'SD_SEND';
  const SD_BOTH:int = 'SD_BOTH';
  
  proc shutdown: SOCKET*int = 'shutdown($1, $2);';
  
  type wasync_transmit_file = "flx::faio::wasync_transmit_file";
  
  // hacked for ro atm. the 0 means exclusive (not good, but I haven't deciphered
  // the flags yet. NULL for non inheritable security attributes.
  // OPEN_EXISTING is to make sure it doesn't create the file
  // Geez, FILE_ATTRIBUTE_NORMAL? not hidden, not temp, etc.
  // final NULL is for template file. not sure what it does, but I don't want it.
  // notice that it's opened for SHARED reading
  gen OpenFile: string -> WFILE =
    '''CreateFile($1.c_str(), FILE_READ_DATA, FILE_SHARE_READ, NULL,
      OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL)''';
  
  // basically for windows named pipes
  gen OpenFileDuplex: string -> WFILE =
    '''CreateFile($1.c_str(), FILE_READ_DATA | FILE_WRITE_DATA,
       FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
       FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL)''';
  
  proc CloseFile: WFILE = '''if(!CloseHandle($1))
    fprintf(stderr, "CloseHandle(WFILE) failed: %i\\n", GetLastError());''';
  
  // error handling?
  // proc CloseFile: WFILE = 'CloseHandle($1);';
  
  fun mk_transmit_file : demuxer * SOCKET*WFILE -> wasync_transmit_file
      = 'flx::faio::wasync_transmit_file($a)';
  
  // toylike interface for now, but still fun
  proc TransmitFile(s: SOCKET, f: WFILE)
  {
      var tf = mk_transmit_file(sys_demux,s, f);
      faio_req$ &tf;
  }
  
  // by passing special flags to TransmitFile we can transform a connected
  // socket into a socket ready for use with AcceptEx. DisconnectEx explicitly
  // does this and without the warning that accept-style & connect-style sockets
  // cannot be reused as the other type (which isn't a problem for my use)
  // however I already have TransmitFile code in place.
  fun mk_reuse_socket : demuxer * SOCKET -> wasync_transmit_file
      = 'flx::faio::wasync_transmit_file($a)';
  
  proc ReuseSocket(s: SOCKET)
  {
      var tf = mk_reuse_socket(sys_demux,s);
      faio_req$ &tf;
  }
  
  type wsa_socketio = "flx::faio::wsa_socketio";
  gen mk_wsa_socketio: demuxer * SOCKET*sel_param_ptr*bool->wsa_socketio = 'flx::faio::wsa_socketio($a)';
  
  private fun to_ptr : sel_param -> sel_param_ptr = '&$1';
  
  
  proc WSARecv(s: SOCKET, len: &int, buf: address, eof: &bool)
  {
      var pb: sel_param;
      init_pb(pb, buf, *len);
      var ppb: sel_param_ptr = to_ptr pb;
  
      var rev = mk_wsa_socketio(sys_demux,s, ppb, true);  // reading
      faio_req$ &rev;
  // we do have a success flag
      calc_eof(ppb, len, eof);
  }
  
  proc WSASend(s: SOCKET, len: &int, buf: address, eof: &bool)
  {
      var pb: sel_param;
      init_pb(pb, buf, *len);
      var ppb: sel_param_ptr = to_ptr pb;
  
      var rev = mk_wsa_socketio(sys_demux,s, ppb, false); // writing
      faio_req$ &rev;
      calc_eof(ppb, len, eof);
  }
  
  type winfile_io = "flx::faio::winfile_io";
  
  fun mk_winfile_io: demuxer * WFILE*address*int*bool->winfile_io = 'flx::faio::winfile_io($a)';
  
  // no offset - just for streams now. write probably doesn't work
  fun get_pb: winfile_io -> sel_param_ptr = '&$1.pb';
  
  proc ReadFile(f: WFILE, len: &int, buf: address, eof: &bool)
  {
      var io = mk_winfile_io(sys_demux, f, buf, *len, true); // reading
      faio_req$ &io;
  // we do have a success flag
      calc_eof(io.get_pb, len, eof);
  }
  
  proc WriteFile(f: WFILE, len: &int, buf: address, eof: &bool)
  {
      var io = mk_winfile_io(sys_demux, f, buf, *len, false);    // writing
      faio_req$ &io;
      calc_eof(io.get_pb, len, eof);
  }
  
  
  // general request for addition of socket to iocp. might be better to
  // just create them that way.
  type iocp_associator = "flx::faio::iocp_associator";
  fun mk_iocp_associator: demuxer * SOCKET -> iocp_associator = 'flx::faio::iocp_associator($a)';
  
  // this ends up just casting to a handle, so I should be able to use
  // this for other HANDLEs. Note that the user cookie is not settable
  // via this interface.
  proc associate_with_iocp(s: SOCKET)
  {
      // results? err code?
      var req = mk_iocp_associator(sys_demux, s);
      faio_req$ &req;
  }
  
  } // module win32_faio