-module(baselib). -export([loop/1]). -record(state,{data=dict:new(),proto='SELF'}). %% this is the only export - it acts as the main loop for the base %% instances, and is started by the basedb server. loop(S) -> receive {look,Req,Ref,From} -> spawn( fun() -> do_look(Req,Ref,From,S) end), loop(S); {ask,Req,Ref,From} -> {Reply,NewS} = safewrap( fun() -> handle(Req,S) end, {{error_with,Req},S}), reply(From,Ref,Reply), loop(NewS); {tell,Req} -> {_,NewS} = safewrap( fun() -> handle(Req,S) end, {none,S}), loop(NewS); Got -> io:format("got message: ~p~n",[Got]), loop(S) end. do_look(Req,Ref,From,S) -> {Reply,_} = safewrap( fun() -> handle(Req,S) end, {{error_with,Req},none}), reply(From,Ref,Reply). reply(From,Ref,Reply) -> From ! {Ref,Reply}, ok. safewrap(Fun,Default) -> case catch Fun() of {'EXIT',E} -> io:format("Error: ~p~n",[E]), Default; Return -> Return end. handle({data,NewData},S) -> {{ok,S#state.data},S#state{data=NewData}}; handle(data,S) -> {{ok,S#state.data},S}; handle(attributes,#state{data=Data,proto=P}=S) -> case P of 'SELF' -> {dict:fetch_keys(Data),S}; _Ob -> {dict:fetch_keys(Data) ++ P:attributes(),S} end; handle({select,List},S) -> {selection(List,S),S}; handle({insert,List},S) -> {ok,insertion(List,S)}; handle(proto,S) -> {S#state.proto,S}; handle({proto,ProtoId},S) -> case ProtoId of 'SELF' -> {{ok,S#state.proto},S#state{proto='SELF'}}; _ -> NewProto = base:new(ProtoId), {{ok,S#state.proto},S#state{proto=NewProto}} end. insertion([],S) -> S; insertion([{K,V}|More],#state{data=Data}=S) -> NewData = dict:append(K,V,Data), insertion(More,S#state{data=NewData}). selection(Keys,S) -> selection(Keys,S,[]). selection([],_,Vals) -> lists:reverse(Vals); selection([K|Keys],#state{data=Data,proto=Proto}=S,Vals) -> Val = %error when proto is 'SELF' and the key is not found case dict:find(K,Data) of error when Proto /= 'SELF' -> [Ret] = Proto:select([K]), Ret; {ok,List} -> lists:last(List) end, selection(Keys,S,[Val|Vals]).