@@ -26,6 +26,7 @@ def __init__(self, data_iter):
2626 self .data_iter = data_iter
2727 self .i = 0
2828 self .chunk = b""
29+ self .last_char = None
2930
3031 def read (self ):
3132 """Read the next character from the stream."""
@@ -39,16 +40,23 @@ def read(self):
3940 self .i += 1
4041 return char
4142
42- def fast_forward (self , closer ):
43+ def fast_forward (self , closer , buffer = None ):
4344 """Read through the stream until the character is ``closer``, ``]``
4445 (ending a list) or ``}`` (ending an object.) Intermediate lists and
4546 objects are skipped."""
47+
4648 closer = ord (closer )
4749 close_stack = [closer ]
4850 count = 0
4951 while close_stack :
5052 char = self .read ()
5153 count += 1
54+ if buffer :
55+ if count == len (buffer ):
56+ new_buffer = bytearray (len (buffer ) + 32 )
57+ new_buffer [: len (buffer )] = buffer
58+ buffer = new_buffer
59+ buffer [count ] = char
5260 if char == close_stack [- 1 ]:
5361 close_stack .pop ()
5462 elif char == ord ('"' ):
@@ -63,6 +71,9 @@ def fast_forward(self, closer):
6371 close_stack .append (ord ("}" ))
6472 elif char == ord ("[" ):
6573 close_stack .append (ord ("]" ))
74+ if buffer :
75+ value_string = bytes (memoryview (buffer )[: count + 1 ]).decode ("utf-8" )
76+ return json .loads (value_string )
6677 return False
6778
6879 def next_value (self , endswith = None ):
@@ -77,10 +88,10 @@ def next_value(self, endswith=None):
7788 except EOFError :
7889 char = endswith
7990 if not in_string and (char == endswith or char in (ord ("]" ), ord ("}" ))):
91+ self .last_char = char
8092 if len (buf ) == 0 :
8193 return None
8294 value_string = bytes (buf ).decode ("utf-8" )
83- # print(f"{repr(value_string)}, {endswith=}")
8495 return json .loads (value_string )
8596 if char == ord ("{" ):
8697 return TransientObject (self )
@@ -94,40 +105,60 @@ def next_value(self, endswith=None):
94105 buf .append (char )
95106
96107
97- class Transient : # pylint: disable=too-few-public-methods
108+ class Transient :
98109 """Transient object representing a JSON object."""
99110
100- # This is helpful for checking that something is a TransientList or TransientObject.
101-
102-
103- class TransientList (Transient ):
104- """Transient object that acts like a list through the stream."""
105-
106111 def __init__ (self , stream ):
112+ self .active_child = None
107113 self .data = stream
108114 self .done = False
109- self .active_child = None
115+ self .has_read = False
116+ self .finish_char = ""
117+ self .start_char = ""
110118
111119 def finish (self ):
112120 """Consume all of the characters for this list from the stream."""
113121 if not self .done :
114122 if self .active_child :
115123 self .active_child .finish ()
116124 self .active_child = None
117- self .data .fast_forward ("]" )
125+ self .data .fast_forward (self . finish_char )
118126 self .done = True
119127
128+ def as_object (self ):
129+ """Consume all of the characters for this list from the stream and return as an object."""
130+ if self .has_read :
131+ raise BufferError ("Object has already been partly read." )
132+
133+ buffer = bytearray (32 )
134+ buffer [0 ] = ord (self .start_char )
135+ self .done = True
136+ return self .data .fast_forward (self .finish_char , buffer )
137+
138+
139+ class TransientList (Transient ):
140+ """Transient object that acts like a list through the stream."""
141+
142+ def __init__ (self , stream ):
143+ super ().__init__ (stream )
144+ self .finish_char = "]"
145+ self .start_char = "["
146+
120147 def __iter__ (self ):
121148 return self
122149
123150 def __next__ (self ):
151+ self .has_read = True
152+
124153 if self .active_child :
125154 self .active_child .finish ()
126155 self .done = self .data .fast_forward ("," )
127156 self .active_child = None
128157 if self .done :
129158 raise StopIteration ()
130159 next_value = self .data .next_value ("," )
160+ if self .data .last_char == ord ("]" ):
161+ self .done = True
131162 if next_value is None :
132163 self .done = True
133164 raise StopIteration ()
@@ -140,42 +171,34 @@ class TransientObject(Transient):
140171 """Transient object that acts like a dictionary through the stream."""
141172
142173 def __init__ (self , stream ):
143- self .data = stream
144- self .done = False
145- self .buf = array .array ("B" )
146-
147- self .active_child = None
148-
149- def finish (self ):
150- """Consume all of the characters for this object from the stream."""
151- if not self .done :
152- if self .active_child :
153- self .active_child .finish ()
154- self .active_child = None
155- self .data .fast_forward ("}" )
156- self .done = True
174+ super ().__init__ (stream )
175+ self .finish_char = "}"
176+ self .start_char = "{"
157177
158178 def __getitem__ (self , key ):
179+ self .has_read = True
180+
159181 if self .active_child :
160182 self .active_child .finish ()
161183 self .done = self .data .fast_forward ("," )
162184 self .active_child = None
163185 if self .done :
164- raise KeyError ()
186+ raise KeyError (key )
165187
166- while True :
188+ while not self . done :
167189 current_key = self .data .next_value (":" )
168190 if current_key is None :
169- # print("object done", self)
170191 self .done = True
171192 break
172193 if current_key == key :
173194 next_value = self .data .next_value ("," )
195+ if self .data .last_char in [ord ("}" ), ord ("]" )]:
196+ self .done = True
174197 if isinstance (next_value , Transient ):
175198 self .active_child = next_value
176199 return next_value
177- self .data .fast_forward ("," )
178- raise KeyError ()
200+ self .done = self . data .fast_forward ("," )
201+ raise KeyError (key )
179202
180203
181204def load (data_iter ):
0 commit comments