@@ -52,11 +52,13 @@ use crate::{extension::ExtensionRegistry, package::Package};
52
52
use header:: EnvelopeHeader ;
53
53
use std:: io:: BufRead ;
54
54
use std:: io:: Write ;
55
+ use std:: str:: FromStr ;
55
56
56
57
#[ allow( unused_imports) ]
57
58
use itertools:: Itertools as _;
58
59
59
60
use crate :: import:: ImportError ;
61
+ use crate :: { import:: import_package, Extension } ;
60
62
61
63
/// Read a HUGR envelope from a reader.
62
64
///
@@ -219,6 +221,16 @@ pub enum EnvelopeError {
219
221
/// The source error.
220
222
source : hugr_model:: v0:: binary:: WriteError ,
221
223
} ,
224
+ /// Error reading a HUGR model payload.
225
+ ModelTextRead {
226
+ /// The source error.
227
+ source : hugr_model:: v0:: ast:: ParseError ,
228
+ } ,
229
+ /// Error reading a HUGR model payload.
230
+ ModelTextResolve {
231
+ /// The source error.
232
+ source : hugr_model:: v0:: ast:: ResolveError ,
233
+ } ,
222
234
}
223
235
224
236
/// Internal implementation of [`read_envelope`] to call with/without the zstd decompression wrapper.
@@ -233,6 +245,9 @@ fn read_impl(
233
245
EnvelopeFormat :: Model | EnvelopeFormat :: ModelWithExtensions => {
234
246
decode_model ( payload, registry, header. format )
235
247
}
248
+ EnvelopeFormat :: ModelText | EnvelopeFormat :: ModelTextWithExtensions => {
249
+ decode_model_ast ( payload, registry, header. format )
250
+ }
236
251
}
237
252
}
238
253
@@ -248,7 +263,6 @@ fn decode_model(
248
263
extension_registry : & ExtensionRegistry ,
249
264
format : EnvelopeFormat ,
250
265
) -> Result < Package , EnvelopeError > {
251
- use crate :: { import:: import_package, Extension } ;
252
266
use hugr_model:: v0:: bumpalo:: Bump ;
253
267
254
268
if format. model_version ( ) != Some ( 0 ) {
@@ -262,7 +276,7 @@ fn decode_model(
262
276
let model_package = hugr_model:: v0:: binary:: read_from_reader ( & mut stream, & bump) ?;
263
277
264
278
let mut extension_registry = extension_registry. clone ( ) ;
265
- if format. append_extensions ( ) {
279
+ if format == EnvelopeFormat :: ModelWithExtensions {
266
280
let extra_extensions: Vec < Extension > =
267
281
serde_json:: from_reader :: < _ , Vec < Extension > > ( stream) ?;
268
282
for ext in extra_extensions {
@@ -273,6 +287,54 @@ fn decode_model(
273
287
Ok ( import_package ( & model_package, & extension_registry) ?)
274
288
}
275
289
290
+ /// Read a HUGR model text payload from a reader.
291
+ ///
292
+ /// Parameters:
293
+ /// - `stream`: The reader to read the envelope from.
294
+ /// - `extension_registry`: An extension registry with additional extensions to use when
295
+ /// decoding the HUGR, if they are not already included in the package.
296
+ /// - `format`: The format of the payload.
297
+ fn decode_model_ast (
298
+ mut stream : impl BufRead ,
299
+ extension_registry : & ExtensionRegistry ,
300
+ format : EnvelopeFormat ,
301
+ ) -> Result < Package , EnvelopeError > {
302
+ use crate :: import:: import_package;
303
+ use hugr_model:: v0:: bumpalo:: Bump ;
304
+
305
+ if format. model_version ( ) != Some ( 0 ) {
306
+ return Err ( EnvelopeError :: FormatUnsupported {
307
+ format,
308
+ feature : None ,
309
+ } ) ;
310
+ }
311
+
312
+ let mut extension_registry = extension_registry. clone ( ) ;
313
+ if format == EnvelopeFormat :: ModelTextWithExtensions {
314
+ let deserializer = serde_json:: Deserializer :: from_reader ( & mut stream) ;
315
+ // Deserialize the first json object, leaving the rest of the reader unconsumed.
316
+ let extra_extensions = deserializer
317
+ . into_iter :: < Vec < Extension > > ( )
318
+ . next ( )
319
+ . unwrap_or ( Ok ( vec ! [ ] ) ) ?;
320
+ for ext in extra_extensions {
321
+ extension_registry. register_updated ( ext) ;
322
+ }
323
+ }
324
+
325
+ // Read the package into a string, then parse it.
326
+ //
327
+ // Due to how `to_string` works, we cannot append extensions after the package.
328
+ let mut buffer = String :: new ( ) ;
329
+ stream. read_to_string ( & mut buffer) ?;
330
+ let ast_package = hugr_model:: v0:: ast:: Package :: from_str ( & buffer) ?;
331
+
332
+ let bump = Bump :: default ( ) ;
333
+ let model_package = ast_package. resolve ( & bump) ?;
334
+
335
+ Ok ( import_package ( & model_package, & extension_registry) ?)
336
+ }
337
+
276
338
/// Internal implementation of [`write_envelope`] to call with/without the zstd compression wrapper.
277
339
fn write_impl < ' h > (
278
340
writer : impl Write ,
@@ -283,7 +345,10 @@ fn write_impl<'h>(
283
345
match config. format {
284
346
#[ allow( deprecated) ]
285
347
EnvelopeFormat :: PackageJson => package_json:: to_json_writer ( hugrs, extensions, writer) ?,
286
- EnvelopeFormat :: Model | EnvelopeFormat :: ModelWithExtensions => {
348
+ EnvelopeFormat :: Model
349
+ | EnvelopeFormat :: ModelWithExtensions
350
+ | EnvelopeFormat :: ModelText
351
+ | EnvelopeFormat :: ModelTextWithExtensions => {
287
352
encode_model ( writer, hugrs, extensions, config. format ) ?
288
353
}
289
354
}
@@ -307,11 +372,27 @@ fn encode_model<'h>(
307
372
} ) ;
308
373
}
309
374
375
+ // Prepend extensions for binary model.
376
+ if format == EnvelopeFormat :: ModelTextWithExtensions {
377
+ serde_json:: to_writer ( & mut writer, & extensions. iter ( ) . collect_vec ( ) ) ?;
378
+ }
379
+
310
380
let bump = Bump :: default ( ) ;
311
381
let model_package = export_package ( hugrs, extensions, & bump) ;
312
- write_to_writer ( & model_package, & mut writer) ?;
313
382
314
- if format. append_extensions ( ) {
383
+ match format {
384
+ EnvelopeFormat :: Model | EnvelopeFormat :: ModelWithExtensions => {
385
+ write_to_writer ( & model_package, & mut writer) ?;
386
+ }
387
+ EnvelopeFormat :: ModelText | EnvelopeFormat :: ModelTextWithExtensions => {
388
+ let model_package = model_package. as_ast ( ) . unwrap ( ) ;
389
+ writeln ! ( writer, "{model_package}" ) ?;
390
+ }
391
+ _ => unreachable ! ( ) ,
392
+ }
393
+
394
+ // Apend extensions for binary model.
395
+ if format == EnvelopeFormat :: ModelWithExtensions {
315
396
serde_json:: to_writer ( writer, & extensions. iter ( ) . collect_vec ( ) ) ?;
316
397
}
317
398
@@ -418,34 +499,24 @@ pub(crate) mod test {
418
499
}
419
500
420
501
#[ rstest]
421
- //#[case::empty(Package::default())] // Not currently supported
422
- #[ case:: simple( simple_package( ) ) ]
423
- //#[case::multi(multi_module_package())] // Not currently supported
424
- fn module_exts_roundtrip ( #[ case] package : Package ) {
502
+ // Empty packages
503
+ #[ case:: empty_model( Package :: default ( ) , EnvelopeFormat :: Model ) ]
504
+ #[ case:: empty_model_exts( Package :: default ( ) , EnvelopeFormat :: ModelWithExtensions ) ]
505
+ #[ case:: empty_text( Package :: default ( ) , EnvelopeFormat :: ModelText ) ]
506
+ #[ case:: empty_text_exts( Package :: default ( ) , EnvelopeFormat :: ModelTextWithExtensions ) ]
507
+ // Single hugrs
508
+ #[ case:: simple_bin( simple_package( ) , EnvelopeFormat :: Model ) ]
509
+ #[ case:: simple_bin_exts( simple_package( ) , EnvelopeFormat :: ModelWithExtensions ) ]
510
+ #[ case:: simple_text( simple_package( ) , EnvelopeFormat :: ModelText ) ]
511
+ #[ case:: simple_text_exts( simple_package( ) , EnvelopeFormat :: ModelTextWithExtensions ) ]
512
+ // Multiple hugrs
513
+ #[ case:: multi_bin( multi_module_package( ) , EnvelopeFormat :: Model ) ]
514
+ #[ case:: multi_bin_exts( multi_module_package( ) , EnvelopeFormat :: ModelWithExtensions ) ]
515
+ #[ case:: multi_text( multi_module_package( ) , EnvelopeFormat :: ModelText ) ]
516
+ #[ case:: multi_text_exts( multi_module_package( ) , EnvelopeFormat :: ModelTextWithExtensions ) ]
517
+ fn model_roundtrip ( #[ case] package : Package , #[ case] format : EnvelopeFormat ) {
425
518
let mut buffer = Vec :: new ( ) ;
426
- let config = EnvelopeConfig {
427
- format : EnvelopeFormat :: ModelWithExtensions ,
428
- zstd : None ,
429
- } ;
430
- package. store ( & mut buffer, config) . unwrap ( ) ;
431
- let ( decoded_config, new_package) =
432
- read_envelope ( BufReader :: new ( buffer. as_slice ( ) ) , & PRELUDE_REGISTRY ) . unwrap ( ) ;
433
-
434
- assert_eq ! ( config. format, decoded_config. format) ;
435
- assert_eq ! ( config. zstd. is_some( ) , decoded_config. zstd. is_some( ) ) ;
436
- assert_eq ! ( package, new_package) ;
437
- }
438
-
439
- #[ rstest]
440
- //#[case::empty(Package::default())] // Not currently supported
441
- #[ case:: simple( simple_package( ) ) ]
442
- //#[case::multi(multi_module_package())] // Not currently supported
443
- fn module_roundtrip ( #[ case] package : Package ) {
444
- let mut buffer = Vec :: new ( ) ;
445
- let config = EnvelopeConfig {
446
- format : EnvelopeFormat :: Model ,
447
- zstd : None ,
448
- } ;
519
+ let config = EnvelopeConfig { format, zstd : None } ;
449
520
package. store ( & mut buffer, config) . unwrap ( ) ;
450
521
451
522
let ( decoded_config, new_package) =
0 commit comments