okami.mom/albedo
git clone https://git.nkp.pet/okami.mom/albedo
448d7dc
main
1"""Values crossing a kernel connection; process and reference ownership stay with callers.""" 2 3from __future__import annotations 4 5import base64 6import dataclasses 7import importlib 8from typing import Any 9 10import albedo_api 11 12 13class InvalidValue (ValueError ): 14"""A peer supplied an invalid encoded value.""" 15 16 17class Unencodable (Exception ): 18"""The value cannot cross the connection; it stays a live remote reference.""" 19 20 21def encode (value :object ,depth :int = 0 )-> object : 22"""One value as connection-crossable JSON; Unencodable means a live reference. 23 24Dataclasses and list subclasses carry their class so the owner rebuilds the 25real object and remote results read exactly like local ones. 26""" 27if depth > 32 : 28raise Unencodable 29if value is None or isinstance (value , (bool ,int ,float ,str )): 30return value 31if isinstance (value , (bytes ,bytearray ,memoryview )): 32return {"__bytes__" :base64 .b64encode (bytes (value )).decode ("ascii" )} 33if isinstance (value ,dict )and type (value )is dict : 34return {str (key ):encode (item ,depth + 1 )for key ,item in value .items ()} 35if isinstance (value ,albedo_api .Record ): 36cls = type (value ) 37return { 38"__record__" :cls .__module__ + "." + cls .__qualname__ , 39"fields" : { 40str (key ):encode (item ,depth + 1 )for key ,item in value .items () 41 }, 42 } 43if isinstance (value , (list ,tuple )): 44try : 45if type (value )is not list : 46cls = type (value ) 47return { 48"__list__" :cls .__module__ + "." + cls .__qualname__ , 49"items" : [encode (item ,depth + 1 )for item in value ], 50 } 51except Unencodable : 52raise 53except (TypeError ,ValueError ): 54raise Unencodable from None 55return [encode (item ,depth + 1 )for item in value ] 56if dataclasses .is_dataclass (value )and not isinstance (value ,type ): 57cls = type (value ) 58try : 59return { 60"__class__" :cls .__module__ + "." + cls .__qualname__ , 61"fields" : { 62field .name :encode (getattr (value ,field .name ),depth + 1 ) 63for field in dataclasses .fields (value ) 64 }, 65 } 66except (TypeError ,ValueError ,AttributeError ): 67raise Unencodable from None 68raise Unencodable 69 70 71def _load_class (marker :str )-> type : 72"""The class a wire marker names; both bundles are identical, so it exists.""" 73module ,_ ,qualified = marker .rpartition ("." ) 74obj :Any = importlib .import_module (module ) 75for part in qualified .split ("." ): 76obj = getattr (obj ,part ) 77return obj 78 79 80def decode (value :Any )-> Any : 81"""Rebuild real objects from wire values, so remote results read like local ones.""" 82if isinstance (value ,dict ): 83if set (value )== {"__bytes__" }and isinstance (value .get ("__bytes__" ),str ): 84try : 85return base64 .b64decode (value ["__bytes__" ],validate = True ) 86except ValueError as error : 87raise InvalidValue ("invalid remote byte encoding" )from error 88if set (value )== {"__class__" ,"fields" }and isinstance ( 89value .get ("__class__" ),str 90 ): 91try : 92return _load_class (value ["__class__" ])( 93** {key :decode (item )for key ,item in value ["fields" ].items ()} 94 ) 95except Exception : 96return {key :decode (item )for key ,item in value ["fields" ].items ()} 97if set (value )== {"__record__" ,"fields" }and isinstance ( 98value .get ("__record__" ),str 99 ): 100fields = {key :decode (item )for key ,item in value ["fields" ].items ()} 101try : 102return _load_class (value ["__record__" ])(fields ) 103except Exception : 104return fields 105if set (value )== {"__list__" ,"items" }and isinstance ( 106value .get ("__list__" ),str 107 ): 108items = [decode (item )for item in value ["items" ]] 109try : 110return _load_class (value ["__list__" ])(items ) 111except Exception : 112return items 113return {key :decode (item )for key ,item in value .items ()} 114if isinstance (value ,list ): 115return [decode (item )for item in value ] 116return value