lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


It was thus said that the Great 云风 Cloud Wu once stated:

> >  Also, I don't think I'm following your API there.  I have this structure:
> >
> >         typedef union sockaddr_all
> >         {
> >           struct sockaddr     sa;
> >           struct sockaddr_in  sin;
> >           struct sockaddr_in6 sin6;
> >           struct sockaddr_un  ssun;
> >         } sockaddr_all__t;
> >
> > which I'm using for a userdata.  I have a custom __index method associated
> > with this that gives me the following "fields":
> >
> >         addr            - text representation of IPv4/IPv6 address
> >         daddr           - other text representation of IPv4/IPv6 address
> >         addrbits        - The raw binary bits that make up an IPv4/IPv6 address
> >         port            - port number
> >         family          - string, either 'ip', 'ip6' or 'unix'.
> >         display         - textual representation of address and port.
> >
> >   How would your system with with that?
> 
> You can use 1 for sa, 2 for sin, 3 for sin6 , and 4 for ssun. 0 means the
> sockaddr_all.

  Well, that was a bad exaple, as sockaddr_all__t is a union, not a
structure.  And its use goes something like:

	> net = require "org.conman.net"
	> a = net.address("192.168.1.10",'tcp',80)
	> b = net.address("fc00::1",'tcp',25)
	> print(a.family)
	ip
	> print(a.addr)
	192.168.1.10
	> print(a.daddr)
	192.168.1.10
	> print(a:display())
	192.168.1.10:80
	> print(b.addr)
	fc00::1
	> print(b.daddr)
	[fc00::1]
	> print(b:display())
	[fc00::1]:25
	> print(b.family)
	ip6
	> print(b.port)
	25

  But, if I'm reading you correctly, let's try another example, and this one
is from work.  I wrapped a rather large structure (44K in size) in Lua. 
Here's a cut down example of that structure:

	#define MAX ... 

	typedef struct
	{
	  time_t  update;
	  char   *name;
	  bool    capable;
	  bool    licensed;
	} entry__s;

	typedef struct
	{
	  uint32_t serial;
	  size_t   lru[MAX];
	  entry__s entries[MAX];
	} cache_data__s;
	  
	typedef struct       
	{
	  time_t        update;
	  cache_data__s cache;
	  bool          dirty;
	} record__s;

Nowhere near 44K in size, but it does go to the same depth as the original. 
In Lua, this would be referenced something as:

	first = record.cache.lru[1]
	if record.cache.entries[first].licensed then
	  display(record.cache.entries[first].name)
	end

As it currently stands, when this structure (which is normally stored on
disk) is shoved into Lua, I convert the entire thing to Lua primitive values
(tables, numbers, strings, etc) with nary a userdata in sight.  But there's
quite a bit of code to do that (around 700 lines of C code).  So let me try
your approach to this.

  I begin with registering an __index method for my userdata:

	static int recordlua___index(lua_State *L)
	{
	  record__s *rec = luaL_checkudata(L,1,TYPE_RECORD);
	  ... um ... 
	}

  I think I lost you.  Hold on ... let me think.  Oh wait, I think I see it
now:

	static int record_lua___index(lua_State *L)
	{
	  record__s *rec   = luaL_checkudata(L,1,TYPE_RECORD);
	  int        slice = lua_getuserslice(L,1);
	
	  switch(slice)
	  {
	    case REC_CACHE:
	    case REC_UPDATE:
	    case REC_UPDATE_2:
	    ...
	  }
	  return 1;
	}

and then lua_getuserslice() somehow knows what function to call back to to
... well ... your example just doesn't make sense here.

> How to implement these by new api lua_getuserslice and lua_setuserslice ?
> 
> #define SOCKADDR 0
> #define SOCKADDR_SIN 1
> #define SOCKADDR_SIN6 2
> #define SOCKADDR_UN 3

  Okay, that I followed.

> int sa_root_index(lua_State *L) {
>   const char * f = luaL_checkstring(L, 2);
>   int slice = 0;
>   if (strcmp(f, "sin")== 0)
>     slice = 1;
>   else  if (strcmp(f, "sin6") == 0)
>     slice = 2;
>   else if (strcmp(f, "un") == 0)
>     slice = 3;
>   else
>     return luaL_error(L, "never here");
>   lua_settop(L,1);
>   lua_setuserslice(L,1,slice);
>   return 1;
> }

  Okay, just a mapping of strings to integers.  No problem there. 
luaL_checkoption() could be used for this:

	int sa_root_index(lua_State *L)
	{
	  static const char *const options[] = 
	  {
	    "sin",
	    "sin6",
	    "un",
	    NULL
	  };
	
	  lua_setuserslice(L,1,luaL_checkoption(L,2,NULL,options));
	  return 1;
	}

> int sa_sin_index(lua_State *L) {
>   const char * f = luaL_checkstring(L, 2);
>   sockaddr_all_t *obj = lua_touserdata(L,1);
>   if (strcmp(f, "port") == 0)
>     lua_pushinteger(L, obj->sin.sin_port);
>   else {
>     // todo: supoort sin.sin_family ... etc
>   }
>   return 1;
> }

  Okay, that's pretty straight forward to follow ... 

> int sockaddr_index(lua_State *L) {
>   // todo: do more type check
>   sockaddr_all_t *obj = lua_touserdata(L,1);
>   int slice = lua_getuserslice(L,1);

  Umm ... wait ...

>   switch (slice) {
>   case SOCKADDR :
>     return sa_root_index(L);

doesn't sa_root_index() *set* the userslice?  You can call
lua_getuserslice() *before* you set it?  This is where I'm lost.  I'm not
following this code at all.

  -spc (but I think I see where you are trying to go to ... )