[thrift] preliminary Erlang support (initial import)
Summary:
* missing {list,map,set}s, inheritance is spotty
* loose source code, plus everything is one process (application / gen_server behavior is forthcoming)
* codegen is a mess, need t_fp_generator
Test Plan:
* codegen invoked without -erl generates identical code for test/
* calculatorHandler plus 'thrift -erl -r tutorial.thrift' more or less works
Revert Plan: ok
git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@665146 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/lib/erl/src-loose/transport/tBufferedTransport.erl b/lib/erl/src-loose/transport/tBufferedTransport.erl
new file mode 100644
index 0000000..1cc809d
--- /dev/null
+++ b/lib/erl/src-loose/transport/tBufferedTransport.erl
@@ -0,0 +1,34 @@
+-module(tBufferedTransport).
+
+-include("thrift/thrift.hrl").
+-include("thrift/transport/tBufferedTransport.hrl").
+
+-export([new/1, isOpen/1, open/1, close/1, read/2, write_MUTABLE/2, flush_MUTABLE/1]).
+
+new(Transport) ->
+ #tBufferedTransport{transport=Transport, wbuf=""}.
+
+transport(This) -> % local accessor
+ This#tBufferedTransport.transport.
+
+isOpen(This) ->
+ ?M0(transport(This), isOpen).
+
+open(This) ->
+ ?M0(transport(This), open).
+
+close(This) ->
+ ?M0(transport(This), close).
+
+read(This, Sz) ->
+ ?M1(transport(This), read, Sz).
+
+write_MUTABLE(This, Buf) -> % be sure to rebind This to the retval
+ Wbuf = This#tBufferedTransport.wbuf,
+ This#tBufferedTransport{wbuf=Wbuf++Buf}. % TODO: ++ efficiency?
+
+flush_MUTABLE(This) -> % be sure to rebind This to the retval
+ Wbuf = This#tBufferedTransport.wbuf,
+ ?M1(transport(This), write, Wbuf),
+ ?M0(transport(This), flush),
+ This#tBufferedTransport{wbuf=""}. % TODO: ++ efficiency?
diff --git a/lib/erl/src-loose/transport/tBufferedTransport.hrl b/lib/erl/src-loose/transport/tBufferedTransport.hrl
new file mode 100644
index 0000000..d8d71e1
--- /dev/null
+++ b/lib/erl/src-loose/transport/tBufferedTransport.hrl
@@ -0,0 +1 @@
+-record(tBufferedTransport, {transport, wbuf}).
diff --git a/lib/erl/src-loose/transport/tServerSocket.erl b/lib/erl/src-loose/transport/tServerSocket.erl
new file mode 100644
index 0000000..239af6e
--- /dev/null
+++ b/lib/erl/src-loose/transport/tServerSocket.erl
@@ -0,0 +1,44 @@
+-module(tServerSocket).
+-include("tServerSocket.hrl").
+
+-export([new/1, listen_MUTABLE/1, accept_MUTABLE/1, close/1]).
+
+new(Port) ->
+ #tServerSocket{port=Port, handle=nil}.
+
+listen_MUTABLE(This) ->
+ Port = This#tServerSocket.port,
+ Options = [binary, {packet, 0}, {active, false}], % was []
+
+ case gen_tcp:listen(Port, Options) of
+ {ok, ListenSocket} ->
+ This#tServerSocket{handle=ListenSocket}
+ % {error, _} ->
+ % TODO: no error handling in Ruby version?
+ end.
+
+accept_MUTABLE(This) ->
+ if
+ This#tServerSocket.handle /= nil ->
+ case gen_tcp:accept(This#tServerSocket.handle) of
+ {ok, Socket} ->
+ tSocket:setHandle_MUTABLE( tSocket:new(), Socket )
+ % {error, _} ->
+ % TODO: no error handling in Ruby version?
+ end;
+ true ->
+ nil
+ end.
+
+close(This) ->
+ if
+ This#tServerSocket.handle /= nil ->
+ case gen_tcp:close(This#tServerSocket.handle) of
+ ok ->
+ ok
+ % {error, _} ->
+ % TODO: no error handling in Ruby version?
+ end;
+ true ->
+ ok
+ end.
diff --git a/lib/erl/src-loose/transport/tServerSocket.hrl b/lib/erl/src-loose/transport/tServerSocket.hrl
new file mode 100644
index 0000000..34ed320
--- /dev/null
+++ b/lib/erl/src-loose/transport/tServerSocket.hrl
@@ -0,0 +1 @@
+-record(tServerSocket, {port, handle}).
diff --git a/lib/erl/src-loose/transport/tSocket.erl b/lib/erl/src-loose/transport/tSocket.erl
new file mode 100644
index 0000000..850c3b9
--- /dev/null
+++ b/lib/erl/src-loose/transport/tSocket.erl
@@ -0,0 +1,96 @@
+-module(tSocket).
+
+-include("thrift/thrift.hrl").
+-include("thrift/transport/tTransportException.hrl").
+% -include("thrift/transport/tTransport.hrl").
+-include("thrift/transport/tSocket.hrl").
+
+-export([new/0, new/1, new/2, setHandle_MUTABLE/2, open_MUTABLE/1, isOpen/1, write/2, read/2, close_MUTABLE/1, readAll/2]).
+
+new(Host, Port) ->
+ #tSocket{host=Host, port=Port, handle=nil}. % WATCH
+
+new() -> new("localhost", 9090).
+new(Host) -> new(Host, 9090).
+
+setHandle_MUTABLE(This, Handle) ->
+ This#tSocket{handle=Handle}.
+
+open_MUTABLE(This) ->
+ Host = This#tSocket.host,
+ Port = This#tSocket.port,
+ Options = [],
+
+ case gen_tcp:connect(Host, Port, Options) of
+ {error, _} ->
+ throw(tTransportException:new(
+ ?tTransportException_NOT_OPEN,
+ "Could not connect to " ++ Host ++ ":" ++ Port)
+ ),
+ {error, This}; % cpiro not reached?
+ {ok, Socket} ->
+ {ok, This#tSocket{handle=Socket}}
+ end.
+
+handle(This) ->
+ This#tSocket.handle.
+
+isOpen(This) ->
+ handle(This) /= nil.
+
+write(This, Str) ->
+ Val = gen_tcp:send(handle(This), Str),
+
+ %% io:format("WRITE |~p|(~p)~n", [Str,Val]),
+
+ case Val of
+ {error, _} ->
+ throw(tTransportException:new(?tTransportException_NOT_OPEN, "in write"));
+ ok ->
+ ok
+ end.
+
+read(This, Sz) ->
+ case gen_tcp:recv(handle(This), Sz) of
+ {ok, []} ->
+ { Host, Port } = { This#tSocket.host, This#tSocket.port },
+ throw(tTransportException:new(?tTransportException_UNKNOWN, "TSocket: Could not read " ++ Sz ++ "bytes from " ++ Host ++ ":" ++ Port));
+ {ok, Data} ->
+ Data;
+ {error, Error} ->
+ io:format("in tSocket:read/2: gen_tcp:recv(~p, ~p) => {error, ~p}~n",
+ [handle(This), Sz, Error]),
+ throw(tTransportException:new(?tTransportException_NOT_OPEN, "in tSocket:read/2: gen_tcp:recv"))
+ end.
+
+close_MUTABLE(This) ->
+ if
+ This#tSocket.handle == nil ->
+ This;
+ true ->
+ gen_tcp:close(handle(This)),
+ This#tSocket{handle=nil}
+ end.
+
+readAll(This, Sz) ->
+ readAll_loop(This, Sz, "", 0).
+
+readAll_loop(This, Sz, Buff, Have) ->
+ if
+ Have < Sz ->
+ Chunk = ?M1(This, read, Sz - Have),
+
+ %% man gen_tcp:
+ %% exactly Length bytes are returned, or an error;
+ %% possibly discarding less than Length bytes of data when
+ %% the socket gets closed from the other side.
+
+ %% io:format("READ |~p|~n", [Chunk]),
+
+ Have1 = Have + (Sz-Have), % length(Chunk)
+ Buff1 = Buff ++ Chunk, % TODO: ++ efficiency?
+ readAll_loop(This, Sz, Buff1, Have1);
+ true ->
+ Buff
+ end.
+
diff --git a/lib/erl/src-loose/transport/tSocket.hrl b/lib/erl/src-loose/transport/tSocket.hrl
new file mode 100644
index 0000000..dc1cc20
--- /dev/null
+++ b/lib/erl/src-loose/transport/tSocket.hrl
@@ -0,0 +1 @@
+-record(tSocket, {host, port, handle}).
diff --git a/lib/erl/src-loose/transport/tTransport.erl b/lib/erl/src-loose/transport/tTransport.erl
new file mode 100644
index 0000000..91b7228
--- /dev/null
+++ b/lib/erl/src-loose/transport/tTransport.erl
@@ -0,0 +1,4 @@
+-module(tTransport).
+
+-include("thrift/transport/tTransportException.hrl").
+
diff --git a/lib/erl/src-loose/transport/tTransportException.erl b/lib/erl/src-loose/transport/tTransportException.erl
new file mode 100644
index 0000000..b31bb20
--- /dev/null
+++ b/lib/erl/src-loose/transport/tTransportException.erl
@@ -0,0 +1,15 @@
+-module(tTransportException).
+
+-include("thrift/thrift.hrl").
+-include("thrift/transport/tTransportException.hrl").
+
+-export([new/0, new/1, new/2, message/1]).
+
+new(Type, Message) ->
+ #tTransportException{type = Type, message = Message}.
+
+new() -> new(?tTransportException_UNKNOWN, nil). % WATCH
+new(Type) -> new(Type, nil). % WATCH
+
+message(This) ->
+ ?ATTR(message).
diff --git a/lib/erl/src-loose/transport/tTransportException.hrl b/lib/erl/src-loose/transport/tTransportException.hrl
new file mode 100644
index 0000000..fa8554b
--- /dev/null
+++ b/lib/erl/src-loose/transport/tTransportException.hrl
@@ -0,0 +1,7 @@
+-define(tTransportException_UNKNOWN, 0).
+-define(tTransportException_NOT_OPEN, 1).
+-define(tTransportException_ALREADY_OPEN, 2).
+-define(tTransportException_TIMED_OUT, 3).
+-define(tTransportException_END_OF_FILE, 4).
+
+-record(tTransportException, {type, message}).