@@ -13,6 +13,7 @@ use std::{
1313 cell:: RefCell ,
1414 collections:: BTreeMap ,
1515 fs:: { self , read_to_string} ,
16+ io:: Write ,
1617 path:: PathBuf ,
1718 rc:: Rc ,
1819 vec,
@@ -133,15 +134,15 @@ impl Default for CompilerMissingParams {
133134/// Typestate representing compiler that is ready to compile
134135pub struct CompilerReady {
135136 sources : Vec < AsnSource > ,
136- output_path : PathBuf ,
137+ output_mode : OutputMode ,
137138}
138139
139- /// Typestate representing compiler that has the output path set, but is missing ASN1 sources
140+ /// Typestate representing compiler that has the output mode set, but is missing ASN1 sources
140141pub struct CompilerOutputSet {
141- output_path : PathBuf ,
142+ output_mode : OutputMode ,
142143}
143144
144- /// Typestate representing compiler that knows about ASN1 sources, but doesn't have an output path set
145+ /// Typestate representing compiler that knows about ASN1 sources, but doesn't have an output mode set
145146pub struct CompilerSourcesSet {
146147 sources : Vec < AsnSource > ,
147148}
@@ -254,19 +255,26 @@ impl<B: Backend> Compiler<B, CompilerMissingParams> {
254255 }
255256 }
256257
257- /// Set the output path for the generated rust representation.
258- /// * `output_path` - path to an output file or directory, if path indicates
259- /// a directory, the output file is named `rasn_generated.rs`
258+ /// Set the output path for the generated bindings.
259+ /// * `output_path` - path to an output file or directory, if path indicates a directory, the
260+ /// output file is named `generated` with the extension used by the Backend.
261+ #[ deprecated = "Use `Self::set_output_mode` instead" ]
260262 pub fn set_output_path (
261263 self ,
262264 output_path : impl Into < PathBuf > ,
263265 ) -> Compiler < B , CompilerOutputSet > {
264- let mut path: PathBuf = output_path. into ( ) ;
265- if path. is_dir ( ) {
266- path. set_file_name ( "rasn_generated.rs" ) ;
266+ Compiler {
267+ state : CompilerOutputSet {
268+ output_mode : OutputMode :: SingleFile ( output_path. into ( ) ) ,
269+ } ,
270+ backend : self . backend ,
267271 }
272+ }
273+
274+ /// Set the output destination for the generated bindings.
275+ pub fn set_output_mode ( self , output_mode : OutputMode ) -> Compiler < B , CompilerOutputSet > {
268276 Compiler {
269- state : CompilerOutputSet { output_path : path } ,
277+ state : CompilerOutputSet { output_mode } ,
270278 backend : self . backend ,
271279 }
272280 }
@@ -279,7 +287,7 @@ impl<B: Backend> Compiler<B, CompilerOutputSet> {
279287 Compiler {
280288 state : CompilerReady {
281289 sources : vec ! [ AsnSource :: Path ( path_to_source. into( ) ) ] ,
282- output_path : self . state . output_path ,
290+ output_mode : self . state . output_mode ,
283291 } ,
284292 backend : self . backend ,
285293 }
@@ -296,7 +304,7 @@ impl<B: Backend> Compiler<B, CompilerOutputSet> {
296304 sources : paths_to_sources
297305 . map ( |p| AsnSource :: Path ( p. into ( ) ) )
298306 . collect ( ) ,
299- output_path : self . state . output_path ,
307+ output_mode : self . state . output_mode ,
300308 } ,
301309 backend : self . backend ,
302310 }
@@ -315,7 +323,7 @@ impl<B: Backend> Compiler<B, CompilerOutputSet> {
315323 Compiler {
316324 state : CompilerReady {
317325 sources : vec ! [ AsnSource :: Literal ( literal. into( ) ) ] ,
318- output_path : self . state . output_path ,
326+ output_mode : self . state . output_mode ,
319327 } ,
320328 backend : self . backend ,
321329 }
@@ -369,15 +377,26 @@ impl<B: Backend> Compiler<B, CompilerSourcesSet> {
369377 }
370378 }
371379
372- /// Set the output path for the generated rust representation .
373- /// * `output_path` - path to an output file or directory, if path points to
374- /// a directory, the compiler will generate a file for every ASN.1 module .
375- /// If the path points to a file, all modules will be written to that file.
380+ /// Set the output path for the generated bindings .
381+ /// * `output_path` - path to an output file or directory, if path indicates a directory, the
382+ /// output file is named `generated` with the extension used by the Backend .
383+ # [ deprecated = "Use `Self::set_output_mode` instead" ]
376384 pub fn set_output_path ( self , output_path : impl Into < PathBuf > ) -> Compiler < B , CompilerReady > {
377385 Compiler {
378386 state : CompilerReady {
379387 sources : self . state . sources ,
380- output_path : output_path. into ( ) ,
388+ output_mode : OutputMode :: SingleFile ( output_path. into ( ) ) ,
389+ } ,
390+ backend : self . backend ,
391+ }
392+ }
393+
394+ /// Set the output destination for the generated bindings.
395+ pub fn set_output_mode ( self , output_mode : OutputMode ) -> Compiler < B , CompilerReady > {
396+ Compiler {
397+ state : CompilerReady {
398+ sources : self . state . sources ,
399+ output_mode,
381400 } ,
382401 backend : self . backend ,
383402 }
@@ -387,64 +406,9 @@ impl<B: Backend> Compiler<B, CompilerSourcesSet> {
387406 /// Returns a Result wrapping a compilation result:
388407 /// * _Ok_ - tuple containing the stringified bindings for the ASN1 spec as well as a vector of warnings raised during the compilation
389408 /// * _Err_ - Unrecoverable error, no bindings were generated
390- pub fn compile_to_string ( mut self ) -> Result < CompileResult , CompilerError > {
391- self . internal_compile ( ) . map ( CompileResult :: fmt :: < B > )
392- }
393-
394- fn internal_compile ( & mut self ) -> Result < CompileResult , CompilerError > {
395- let mut generated_modules = vec ! [ ] ;
396- let mut warnings = Vec :: < CompilerError > :: new ( ) ;
397- let mut modules: Vec < ToplevelDefinition > = vec ! [ ] ;
398- for src in & self . state . sources {
399- let stringified_src = match src {
400- AsnSource :: Path ( p) => read_to_string ( p) . map_err ( LexerError :: from) ?,
401- AsnSource :: Literal ( l) => l. clone ( ) ,
402- } ;
403- modules. append (
404- & mut asn_spec ( & stringified_src) ?
405- . into_iter ( )
406- . flat_map ( |( header, tlds) | {
407- let header_ref = Rc :: new ( RefCell :: new ( header) ) ;
408- tlds. into_iter ( ) . map ( move |mut tld| {
409- tld. apply_tagging_environment ( & header_ref. borrow ( ) . tagging_environment ) ;
410- tld. set_module_header ( header_ref. clone ( ) ) ;
411- tld
412- } )
413- } )
414- . collect ( ) ,
415- ) ;
416- }
417- let ( valid_items, mut validator_errors) = Validator :: new ( modules) . validate ( ) ?;
418- let modules = valid_items. into_iter ( ) . fold (
419- BTreeMap :: < String , Vec < ToplevelDefinition > > :: new ( ) ,
420- |mut modules, tld| {
421- let key = tld
422- . get_module_header ( )
423- . map_or ( <_ >:: default ( ) , |module| module. borrow ( ) . name . clone ( ) ) ;
424- match modules. entry ( key) {
425- std:: collections:: btree_map:: Entry :: Vacant ( v) => {
426- v. insert ( vec ! [ tld] ) ;
427- }
428- std:: collections:: btree_map:: Entry :: Occupied ( ref mut e) => {
429- e. get_mut ( ) . push ( tld)
430- }
431- }
432- modules
433- } ,
434- ) ;
435- for ( _, module) in modules {
436- let mut generated_module = self . backend . generate_module ( module) ?;
437- if let Some ( m) = generated_module. generated {
438- generated_modules. push ( m) ;
439- }
440- warnings. append ( & mut generated_module. warnings ) ;
441- }
442- warnings. append ( & mut validator_errors) ;
443-
444- Ok ( CompileResult {
445- generated : generated_modules. join ( "\n " ) ,
446- warnings,
447- } )
409+ pub fn compile_to_string ( self ) -> Result < CompileResult , CompilerError > {
410+ self . set_output_mode ( OutputMode :: NoOutput )
411+ . compile_to_string ( )
448412 }
449413}
450414
@@ -456,7 +420,7 @@ impl<B: Backend> Compiler<B, CompilerReady> {
456420 sources. push ( AsnSource :: Path ( path_to_source. into ( ) ) ) ;
457421 Compiler {
458422 state : CompilerReady {
459- output_path : self . state . output_path ,
423+ output_mode : self . state . output_mode ,
460424 sources,
461425 } ,
462426 backend : self . backend ,
@@ -474,7 +438,7 @@ impl<B: Backend> Compiler<B, CompilerReady> {
474438 Compiler {
475439 state : CompilerReady {
476440 sources,
477- output_path : self . state . output_path ,
441+ output_mode : self . state . output_mode ,
478442 } ,
479443 backend : self . backend ,
480444 }
@@ -494,7 +458,7 @@ impl<B: Backend> Compiler<B, CompilerReady> {
494458 sources. push ( AsnSource :: Literal ( literal. into ( ) ) ) ;
495459 Compiler {
496460 state : CompilerReady {
497- output_path : self . state . output_path ,
461+ output_mode : self . state . output_mode ,
498462 sources,
499463 } ,
500464 backend : self . backend ,
@@ -505,43 +469,121 @@ impl<B: Backend> Compiler<B, CompilerReady> {
505469 /// Returns a Result wrapping a compilation result:
506470 /// * _Ok_ - tuple containing the stringified bindings for the ASN1 spec as well as a vector of warnings raised during the compilation
507471 /// * _Err_ - Unrecoverable error, no bindings were generated
508- pub fn compile_to_string ( self ) -> Result < CompileResult , CompilerError > {
509- Compiler {
510- state : CompilerSourcesSet {
511- sources : self . state . sources ,
512- } ,
513- backend : self . backend ,
514- }
515- . compile_to_string ( )
472+ pub fn compile_to_string ( mut self ) -> Result < CompileResult , CompilerError > {
473+ self . internal_compile ( ) . map ( CompileResult :: fmt :: < B > )
516474 }
517475
518476 /// Runs the rasn compiler command.
519477 /// Returns a Result wrapping a compilation result:
520478 /// * _Ok_ - Vector of warnings raised during the compilation
521479 /// * _Err_ - Unrecoverable error, no bindings were generated
522- pub fn compile ( self ) -> Result < Vec < CompilerError > , CompilerError > {
523- let result = Compiler {
524- state : CompilerSourcesSet {
525- sources : self . state . sources ,
480+ pub fn compile ( mut self ) -> Result < Vec < CompilerError > , CompilerError > {
481+ let result = self . internal_compile ( ) ?. fmt :: < B > ( ) ;
482+
483+ self . output_generated ( & result. generated ) ?;
484+
485+ Ok ( result. warnings )
486+ }
487+
488+ fn internal_compile ( & mut self ) -> Result < CompileResult , CompilerError > {
489+ let mut generated_modules = vec ! [ ] ;
490+ let mut warnings = Vec :: < CompilerError > :: new ( ) ;
491+ let mut modules: Vec < ToplevelDefinition > = vec ! [ ] ;
492+ for src in & self . state . sources {
493+ let stringified_src = match src {
494+ AsnSource :: Path ( p) => read_to_string ( p) . map_err ( LexerError :: from) ?,
495+ AsnSource :: Literal ( l) => l. clone ( ) ,
496+ } ;
497+ modules. append (
498+ & mut asn_spec ( & stringified_src) ?
499+ . into_iter ( )
500+ . flat_map ( |( header, tlds) | {
501+ let header_ref = Rc :: new ( RefCell :: new ( header) ) ;
502+ tlds. into_iter ( ) . map ( move |mut tld| {
503+ tld. apply_tagging_environment ( & header_ref. borrow ( ) . tagging_environment ) ;
504+ tld. set_module_header ( header_ref. clone ( ) ) ;
505+ tld
506+ } )
507+ } )
508+ . collect ( ) ,
509+ ) ;
510+ }
511+ let ( valid_items, mut validator_errors) = Validator :: new ( modules) . validate ( ) ?;
512+ let modules = valid_items. into_iter ( ) . fold (
513+ BTreeMap :: < String , Vec < ToplevelDefinition > > :: new ( ) ,
514+ |mut modules, tld| {
515+ let key = tld
516+ . get_module_header ( )
517+ . map_or ( <_ >:: default ( ) , |module| module. borrow ( ) . name . clone ( ) ) ;
518+ match modules. entry ( key) {
519+ std:: collections:: btree_map:: Entry :: Vacant ( v) => {
520+ v. insert ( vec ! [ tld] ) ;
521+ }
522+ std:: collections:: btree_map:: Entry :: Occupied ( ref mut e) => {
523+ e. get_mut ( ) . push ( tld)
524+ }
525+ }
526+ modules
526527 } ,
527- backend : self . backend ,
528+ ) ;
529+ for ( _, module) in modules {
530+ let mut generated_module = self . backend . generate_module ( module) ?;
531+ if let Some ( m) = generated_module. generated {
532+ generated_modules. push ( m) ;
533+ }
534+ warnings. append ( & mut generated_module. warnings ) ;
528535 }
529- . internal_compile ( ) ?
530- . fmt :: < B > ( ) ;
531-
532- let output_file = if self . state . output_path . is_dir ( ) {
533- self . state
534- . output_path
535- . join ( format ! ( "generated{}" , B :: FILE_EXTENSION ) )
536- } else {
537- self . state . output_path
538- } ;
539- fs:: write ( output_file, result. generated ) . map_err ( |e| GeneratorError {
540- top_level_declaration : None ,
541- details : e. to_string ( ) ,
542- kind : GeneratorErrorType :: IO ,
543- } ) ?;
536+ warnings. append ( & mut validator_errors) ;
544537
545- Ok ( result. warnings )
538+ Ok ( CompileResult {
539+ generated : generated_modules. join ( "\n " ) ,
540+ warnings,
541+ } )
546542 }
543+
544+ fn output_generated ( & self , generated : & str ) -> Result < ( ) , GeneratorError > {
545+ match & self . state . output_mode {
546+ OutputMode :: SingleFile ( path) => {
547+ let path = if path. is_dir ( ) {
548+ & path. join ( format ! ( "generated{}" , B :: FILE_EXTENSION ) )
549+ } else {
550+ path
551+ } ;
552+ fs:: write ( path, generated) . map_err ( |e| {
553+ GeneratorError :: new (
554+ None ,
555+ & format ! (
556+ "Failed to write generated bindings to {}: {e}" ,
557+ path. display( )
558+ ) ,
559+ GeneratorErrorType :: IO ,
560+ )
561+ } )
562+ }
563+ OutputMode :: Stdout => {
564+ std:: io:: stdout ( )
565+ . write_all ( generated. as_bytes ( ) )
566+ . map_err ( |err| {
567+ GeneratorError :: new (
568+ None ,
569+ & format ! ( "Failed to write generated bindings to stdout: {err}" ) ,
570+ GeneratorErrorType :: IO ,
571+ )
572+ } )
573+ }
574+ OutputMode :: NoOutput => Ok ( ( ) ) ,
575+ }
576+ }
577+ }
578+
579+ /// Where the [Compiler] output should go.
580+ #[ derive( Debug ) ]
581+ pub enum OutputMode {
582+ /// Write all compiled modules to a single file. Uses a default filename if path is a
583+ /// directory.
584+ SingleFile ( PathBuf ) ,
585+ /// Write all compiled modules to stdout.
586+ Stdout ,
587+ /// Do not write anything, only check.
588+ NoOutput ,
547589}
0 commit comments