From 7d96ae649f38f40ed22fc7d371d2dacfc989eef0 Mon Sep 17 00:00:00 2001 From: "Luke T. Shumaker" Date: Sat, 11 Jan 2025 23:17:53 -0700 Subject: lib9p: idl.gen: Track min and max object sizes --- lib9p/idl/__init__.py | 89 ++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 85 insertions(+), 4 deletions(-) (limited to 'lib9p/idl') diff --git a/lib9p/idl/__init__.py b/lib9p/idl/__init__.py index ab45ed0..8fd7e25 100644 --- a/lib9p/idl/__init__.py +++ b/lib9p/idl/__init__.py @@ -43,6 +43,12 @@ class Primitive(enum.Enum): def static_size(self) -> int: return self.value + def min_size(self, version: str) -> int: + return self.value + + def max_size(self, version: str) -> int: + return self.value + class Number: name: str @@ -60,6 +66,12 @@ class Number: def static_size(self) -> int: return self.prim.static_size + def min_size(self, version: str) -> int: + return self.static_size + + def max_size(self, version: str) -> int: + return self.static_size + class BitfieldVal: name: str @@ -88,6 +100,12 @@ class Bitfield: def static_size(self) -> int: return self.prim.static_size + def min_size(self, version: str) -> int: + return self.static_size + + def max_size(self, version: str) -> int: + return self.static_size + def bit_is_valid(self, bit: str | int, ver: str | None = None) -> bool: """Return whether the given bit is valid in the given protocol version. @@ -137,7 +155,7 @@ class Expr: class StructMember: # from left-to-right when parsing - cnt: str | None = None + cnt: "StructMember | None" = None name: str typ: "Type" max: Expr @@ -145,12 +163,59 @@ class StructMember: in_versions: set[str] + @property + def min_cnt(self) -> int: + assert self.cnt + if not isinstance(self.cnt.typ, Primitive): + raise ValueError( + f"list count must be an integer type: {repr(self.cnt.name)}" + ) + if self.cnt.val: # TODO: allow this? + raise ValueError(f"list count may not have ,val=: {repr(self.cnt.name)}") + return 0 + + @property + def max_cnt(self) -> int: + assert self.cnt + if not isinstance(self.cnt.typ, Primitive): + raise ValueError( + f"list count must be an integer type: {repr(self.cnt.name)}" + ) + if self.cnt.val: # TODO: allow this? + raise ValueError(f"list count may not have ,val=: {repr(self.cnt.name)}") + if self.cnt.max: + # TODO: be more flexible? + if len(self.cnt.max.tokens) != 1: + raise ValueError( + f"list count ,max= may only have 1 token: {repr(self.cnt.name)}" + ) + match tok := self.cnt.max.tokens[0]: + case ExprLit(): + return tok.val + case ExprSym(name="s32_max"): + return (1 << 31) - 1 + case ExprSym(name="s64_max"): + return (1 << 63) - 1 + case _: + raise ValueError( + f'list count ,max= only allows literal, "s32_max", and "s64_max" tokens: {repr(self.cnt.name)}' + ) + return (1 << (self.cnt.typ.value * 8)) - 1 + @property def static_size(self) -> int | None: if self.cnt: return None return self.typ.static_size + def min_size(self, version: str) -> int: + cnt = self.min_cnt if self.cnt else 1 + return cnt * self.typ.min_size(version) + + def max_size(self, version: str) -> int: + cnt = self.max_cnt if self.cnt else 1 + return cnt * self.typ.max_size(version) + class Struct: name: str @@ -165,12 +230,28 @@ class Struct: def static_size(self) -> int | None: size = 0 for member in self.members: + if member.in_versions < self.in_versions: + return None msize = member.static_size if msize is None: return None size += msize return size + def min_size(self, version: str) -> int: + return sum( + member.min_size(version) + for member in self.members + if (version in member.in_versions) + ) + + def max_size(self, version: str) -> int: + return sum( + member.max_size(version) + for member in self.members + if (version in member.in_versions) + ) + class Message(Struct): @property @@ -289,9 +370,9 @@ def parse_members(ver: str, env: dict[str, Type], struct: Struct, specs: str) -> if cnt := m.group("cnt"): if len(struct.members) == 0 or struct.members[-1].name != cnt: raise ValueError(f"list count must be previous item: {repr(cnt)}") - if not isinstance(struct.members[-1].typ, Primitive): - raise ValueError(f"list count must be an integer type: {repr(cnt)}") - member.cnt = cnt + cnt_mem = struct.members[-1] + member.cnt = cnt_mem + _ = member.max_cnt # force validation if maxstr := m.group("max"): if (not isinstance(member.typ, Primitive)) or member.cnt: -- cgit v1.2.3-2-g168b From 02188436a7cf4efcee88c7b5eed6a621abb19d6d Mon Sep 17 00:00:00 2001 From: "Luke T. Shumaker" Date: Fri, 17 Jan 2025 19:41:51 -0700 Subject: lib9p: idl: 9P2000.e: Don't inherit data limits from 9P2000 --- lib9p/idl/2012-9P2000.e.9p | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'lib9p/idl') diff --git a/lib9p/idl/2012-9P2000.e.9p b/lib9p/idl/2012-9P2000.e.9p index c113618..aba4e66 100644 --- a/lib9p/idl/2012-9P2000.e.9p +++ b/lib9p/idl/2012-9P2000.e.9p @@ -1,6 +1,6 @@ # lib9p/idl/2012-9P2000.e.9p - Definitions of 9P2000.e messages # -# Copyright (C) 2024 Luke T. Shumaker +# Copyright (C) 2024-2025 Luke T. Shumaker # SPDX-License-Identifier: AGPL-3.0-or-later # "9P2000.e" Erlang extension @@ -10,9 +10,12 @@ version "9P2000.e" from ./2002-9P2000.9p import * +# like 9P2000 `d`, but without the s32_max limit +struct d_e = "len[4] len*(dat[1])" + msg Tsession = "size[4,val=end-&size] typ[1,val=150] tag[tag] key[8]" msg Rsession = "size[4,val=end-&size] typ[1,val=151] tag[tag]" msg Tsread = "size[4,val=end-&size] typ[1,val=152] tag[tag] fid[4] nwname[2] nwname*(wname[s])" -msg Rsread = "size[4,val=end-&size] typ[1,val=153] tag[tag] data[d]" -msg Tswrite = "size[4,val=end-&size] typ[1,val=154] tag[tag] fid[4] nwname[2] nwname*(wname[s]) data[d]" +msg Rsread = "size[4,val=end-&size] typ[1,val=153] tag[tag] data[d_e]" +msg Tswrite = "size[4,val=end-&size] typ[1,val=154] tag[tag] fid[4] nwname[2] nwname*(wname[s]) data[d_e]" msg Rswrite = "size[4,val=end-&size] typ[1,val=155] tag[tag] count[4]" -- cgit v1.2.3-2-g168b