@@ -20,10 +20,11 @@ use crate::{BBIReadError, BigBedRead, ChromInfo};
2020 long_about = "Converts an input bigBed to a bed. Can be multi-threaded for substantial speedups. Note for roughly each core, one temporary file will be opened."
2121) ]
2222pub struct BigBedToBedArgs {
23- /// the bigbed to get convert to bed
23+ /// The bigbed to get convert to bed.
2424 pub big_bed : String ,
2525
26- /// the path of the bed to output to
26+ /// The path of the bed to output to.
27+ /// Specifying `-` will write to `stdout`.
2728 pub bed : String ,
2829
2930 /// If set, restrict output to given chromosome
@@ -65,7 +66,6 @@ pub fn bigbedtobed(args: BigBedToBedArgs) -> Result<(), Box<dyn Error>> {
6566 let nthreads = args. nthreads ;
6667
6768 let bigbed = BigBedRead :: open_file ( & bigbedpath) ?;
68- let bed = File :: create ( bedpath) ?;
6969
7070 if ( args. start . is_some ( ) || args. end . is_some ( ) ) && args. chrom . is_none ( ) {
7171 eprintln ! ( "Cannot specify --start or --end without specifying --chrom." ) ;
@@ -79,30 +79,62 @@ pub fn bigbedtobed(args: BigBedToBedArgs) -> Result<(), Box<dyn Error>> {
7979
8080 match args. overlap_bed {
8181 Some ( overlap_bed) => {
82- if !Path :: exists ( & Path :: new ( & overlap_bed) ) {
82+ if !Path :: new ( & overlap_bed) . exists ( ) {
8383 eprintln ! ( "Overlap bed file does not exist." ) ;
8484 return Ok ( ( ) ) ;
8585 }
8686 let overlap_bed = File :: open ( overlap_bed) ?;
87- write_bed_from_bed ( bigbed, bed, overlap_bed) ?;
87+ match bedpath. as_str ( ) {
88+ "-" => {
89+ let stdout = io:: stdout ( ) . lock ( ) ;
90+ write_bed_from_bed ( bigbed, stdout, overlap_bed) ?;
91+ }
92+ _ => {
93+ let file = File :: create ( bedpath) ?;
94+ write_bed_from_bed ( bigbed, file, overlap_bed) ?;
95+ }
96+ }
8897 }
8998 None => {
9099 // Right now, we don't offload decompression to separate threads,
91100 // so specifying `chrom` effectively means single-threaded
92101 if nthreads == 1 || args. chrom . is_some ( ) || args. zoom . is_some ( ) {
93- write_bed_singlethreaded ( bigbed, bed, args. chrom , args. start , args. end , args. zoom ) ?;
102+ match bedpath. as_str ( ) {
103+ "-" => {
104+ let stdout = io:: stdout ( ) . lock ( ) ;
105+ write_bed_singlethreaded (
106+ bigbed, stdout, args. chrom , args. start , args. end , args. zoom ,
107+ ) ?;
108+ }
109+ _ => {
110+ let file = File :: create ( bedpath) ?;
111+ write_bed_singlethreaded (
112+ bigbed, file, args. chrom , args. start , args. end , args. zoom ,
113+ ) ?;
114+ }
115+ }
94116 } else {
95- write_bed ( bigbed, bed, args. inmemory , nthreads) ?;
117+ match bedpath. as_str ( ) {
118+ "-" => {
119+ // FIXME: would be nice to refactor so that each write doesn't need to lock individually
120+ let stdout = io:: stdout ( ) ;
121+ write_bed ( bigbed, stdout, args. inmemory , nthreads) ?;
122+ }
123+ _ => {
124+ let out_file = File :: create ( bedpath) ?;
125+ write_bed ( bigbed, out_file, args. inmemory , nthreads) ?;
126+ }
127+ }
96128 }
97129 }
98130 }
99131
100132 Ok ( ( ) )
101133}
102134
103- pub fn write_bed_singlethreaded < R : Reopen + SeekableRead > (
135+ pub fn write_bed_singlethreaded < R : Reopen + SeekableRead , O : Write > (
104136 mut bigbed : BigBedRead < R > ,
105- out_file : File ,
137+ writer : O ,
106138 chrom : Option < String > ,
107139 start : Option < u32 > ,
108140 end : Option < u32 > ,
@@ -121,7 +153,7 @@ pub fn write_bed_singlethreaded<R: Reopen + SeekableRead>(
121153 } else {
122154 bigbed. chroms ( ) . to_vec ( )
123155 } ;
124- let mut writer = io:: BufWriter :: with_capacity ( 32 * 1000 , out_file ) ;
156+ let mut writer = io:: BufWriter :: with_capacity ( 32 * 1000 , writer ) ;
125157 let mut buf: String = String :: with_capacity ( 50 ) ; // Estimate
126158 if let Some ( zoom) = zoom {
127159 if bigbed
@@ -182,9 +214,9 @@ pub fn write_bed_singlethreaded<R: Reopen + SeekableRead>(
182214 Ok ( ( ) )
183215}
184216
185- pub fn write_bed < R : Reopen + SeekableRead + Send + ' static > (
217+ pub fn write_bed < R : Reopen + SeekableRead + Send + ' static , O : Write + Send + ' static > (
186218 bigbed : BigBedRead < R > ,
187- mut out_file : File ,
219+ mut writer : O ,
188220 inmemory : bool ,
189221 nthreads : usize ,
190222) -> Result < ( ) , BBIReadError > {
@@ -196,10 +228,10 @@ pub fn write_bed<R: Reopen + SeekableRead + Send + 'static>(
196228 let mut remaining_chroms = bigbed. chroms ( ) . to_vec ( ) ;
197229 remaining_chroms. reverse ( ) ;
198230
199- async fn file_future < R : SeekableRead + ' static > (
231+ async fn file_future < R : SeekableRead + ' static , O : Write + Send + ' static > (
200232 mut bigbed : BigBedRead < R > ,
201233 chrom : ChromInfo ,
202- mut writer : io:: BufWriter < TempFileBufferWriter < File > > ,
234+ mut writer : io:: BufWriter < TempFileBufferWriter < O > > ,
203235 ) -> Result < ( ) , BBIReadError > {
204236 let mut buf: String = String :: with_capacity ( 50 ) ; // Estimate
205237 for raw_val in bigbed. get_interval ( & chrom. name , 0 , chrom. length ) ? {
@@ -232,7 +264,7 @@ pub fn write_bed<R: Reopen + SeekableRead + Send + 'static>(
232264 } ;
233265
234266 let bigbed = bigbed. reopen ( ) ?;
235- let ( buf, file) : ( TempFileBuffer < File > , TempFileBufferWriter < File > ) =
267+ let ( buf, file) : ( TempFileBuffer < O > , TempFileBufferWriter < O > ) =
236268 TempFileBuffer :: new ( inmemory) ;
237269 let writer = io:: BufWriter :: new ( file) ;
238270 let handle = tokio:: task:: spawn ( file_future ( bigbed, chrom, writer) ) ;
@@ -259,24 +291,24 @@ pub fn write_bed<R: Reopen + SeekableRead + Send + 'static>(
259291 return Ok :: < _ , BBIReadError > ( ( ) ) ;
260292 } ;
261293
262- buf. switch ( out_file ) ;
294+ buf. switch ( writer ) ;
263295 while !buf. is_real_file_ready ( ) {
264296 tokio:: task:: yield_now ( ) . await ;
265297 }
266- out_file = buf. await_real_file ( ) ;
298+ writer = buf. await_real_file ( ) ;
267299 }
268300 } ) ?;
269301
270302 Ok ( ( ) )
271303}
272304
273- pub fn write_bed_from_bed < R : Reopen + SeekableRead + Send + ' static > (
305+ pub fn write_bed_from_bed < R : Reopen + SeekableRead , O : Write > (
274306 mut bigbed : BigBedRead < R > ,
275- out_file : File ,
307+ writer : O ,
276308 bed : File ,
277309) -> Result < ( ) , BBIReadError > {
278310 let mut bedstream = StreamingLineReader :: new ( BufReader :: new ( bed) ) ;
279- let mut writer = io:: BufWriter :: new ( out_file ) ;
311+ let mut writer = io:: BufWriter :: new ( writer ) ;
280312
281313 let mut buf = String :: with_capacity ( 50 ) ; // Estimate
282314 while let Some ( line) = bedstream. read ( ) {
0 commit comments