dbusjs / node-dbus-next

🚌 The next great dbus library for node
https://www.npmjs.com/package/dbus-next
155 stars 52 forks source link

automatic (de)serialization to Variant dicts #104

Open mikelpr opened 2 years ago

mikelpr commented 2 years ago

I wrote the following for myself as I wanted to use D-Bus natives and not send JSON all over the place and I didn't see the library provide anything for using them Variants

import {Variant} from "dbus-next";

export function serialize(obj: any): Variant<any> | undefined {
  if (obj === undefined) return undefined;
  if (typeof obj == 'function') throw new Error("can't serialize function");
  const signature = (({
    'object': () => obj === null? 'o':(Array.isArray(obj)? 'av':'a{sv}'),
    'string': () => 's',
    'number': () => 'd',
   'boolean': () => 'b',
    'symbol': () => 's',
    'bigint': () => 'x'
  } as any)[typeof obj]) ();

  let _ = obj;
  if (typeof obj == 'object') {
    if (obj === null) _ = '/dev/null';
    else {
      _ = Array.isArray(obj)? []:{};
      for (const k in obj) {
        if (obj[k] !== undefined) _[k] = serialize(obj[k]);
      }
    }
  }

  return new Variant(signature, _);
};

type Key = string | number | symbol;
export function deserialize(v: Variant): any {
  const sig = v.signature.slice(0, 2);
  if (sig == 'av') return v.value.map(deserialize);
  else if (sig == 'a{') {
    if (sig[4] !== '}') throw new Error("invalid variant signature");
    //const kt = sig[2]; // unused
    const vt = sig[3];
    return Object.entries(v.value).reduce(
      (acc: {[x: Key]: any}, [key, value]: [Key, any]) =>
        ({...acc, [key]: vt === 'v'? deserialize(value):value}), {}
    );
  }
  else if (sig == 'o') return v.value === '/dev/null'? null:v.value;
  else return v.value;
}

but like, would be cool if the library did this automatically. convert param objects and returns into a{sv} and variant type arrays into av. so for example you could

someObj = {};
@property({signature: 'v'}) // or just @property({})
get Configuration() {return someObj}
set Configuration(newObj) {someObj = newObj}

instead of having to

someObj = {};
@property({signature: 'v'}) // or just @property({})
get Configuration() {return serialize(someObj)}
set Configuration(newObj) {someObj = deserialize(newObj)}