1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
// Copyright (C) 2024 Philipp Benner
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the “Software”), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
use std::io::{self, BufRead, BufReader, BufWriter, Write};
use crate::granges::GRanges;
/* -------------------------------------------------------------------------- */
impl GRanges {
/// Prints the contents of the `GRanges` instance in a pretty-printed format to the provided writer.
///
/// This method formats the `GRanges` data into a human-readable string and writes it to the specified
/// output stream. It calculates the maximum widths of each column to ensure proper alignment in the output.
///
/// # Arguments
/// - `writer`: A mutable reference to a writer that implements the `Write` trait, where the formatted output will be written.
/// - `n`: The maximum number of rows to print. This allows for controlling the output size and is useful for
/// displaying a limited number of rows.
///
/// # Returns
/// An `io::Result<()>`, which will be `Ok(())` if the operation succeeds or an error if the writing fails.
fn print_pretty<W: Write>(&self, writer: &mut W, n: usize) -> io::Result<()> {
let meta_str = format!("{}", self.meta);
let mut meta_reader = BufReader::new(meta_str.as_bytes());
let mut widths : [usize; 5] = [1, 8, 1, 1, 6];
for i in 0..self.num_rows() {
update_max_widths(self, i, &mut widths);
}
let widths_row = [widths[0], widths[1], widths[2], widths[3], widths[4]];
let widths_header = [widths[0], widths[1], widths[2] + widths[3] + 4, widths[4]];
write_header(self, writer, &mut meta_reader, &widths_header)?;
write_all (self, writer, &mut meta_reader, &widths_header, &widths_row, n)?;
Ok(())
}
/// Formats the contents of the `GRanges` instance into a pretty-printed string.
///
/// This method collects the formatted representation of the `GRanges` data into a string, which can be
/// useful for displaying or logging purposes. It internally calls `print_pretty` to handle the formatting.
///
/// # Arguments
/// - `n`: The maximum number of rows to include in the formatted output.
///
/// # Returns
/// An `io::Result<String>` containing the formatted string if successful, or an error if the formatting fails.
pub fn format_pretty(&self, n: usize) -> io::Result<String> {
let mut buffer = Vec::new();
{
let mut writer = BufWriter::new(&mut buffer);
self.print_pretty(&mut writer, n)?;
writer.flush().unwrap();
}
let s = match String::from_utf8(buffer) {
Ok (v) => v,
Err(_) => panic!("internal error")
};
Ok(s)
}
}
/* -------------------------------------------------------------------------- */
fn update_max_width(widths: &mut [usize], j: usize, args: String) {
let width = args.len();
if width > widths[j] {
widths[j] = width;
}
}
fn update_max_widths(granges: &GRanges, i: usize, widths: &mut [usize; 5]) {
update_max_width(widths, 0, (i + 1) .to_string());
update_max_width(widths, 1, granges.seqnames[i] .to_string());
update_max_width(widths, 2, granges.ranges [i].from.to_string());
update_max_width(widths, 3, granges.ranges [i].to .to_string());
update_max_width(widths, 4, granges.strand [i] .to_string());
}
fn write_meta_row<W: Write>(granges: &GRanges, writer: &mut W, reader: &mut dyn BufRead) -> io::Result<()> {
if granges.meta.num_cols() > 0 {
write!(writer, " |")?;
let mut line = String::new();
reader.read_line(&mut line)?;
write!(writer, "{}", line.trim_end_matches('\n'))?;
}
Ok(())
}
fn write_header<W: Write>(granges: &GRanges, writer: &mut W, meta_reader: &mut dyn BufRead, widths: &[usize]) -> io::Result<()> {
write!(writer,
"{:width0$} {:width1$} {:width2$} {:width3$}",
"", "seqnames", "ranges", "strand",
width0=widths[0], width1=widths[1], width2=widths[2], width3=widths[3])?;
write_meta_row(granges, writer, meta_reader)?;
Ok(())
}
fn write_row<W: Write>(granges: &GRanges, writer: &mut W, meta_reader: &mut dyn BufRead, widths: &[usize], i: usize) -> io::Result<()> {
writeln!(writer)?;
write!(writer,
"{:width0$} {:width1$} [{:width2$}, {:width3$}) {:width4$}",
i + 1, granges.seqnames[i], granges.ranges[i].from, granges.ranges[i].to, granges.strand[i],
width0=widths[0], width1=widths[1], width2=widths[2], width3=widths[3], width4=widths[4])?;
write_meta_row(granges, writer, meta_reader)?;
Ok(())
}
fn write_all<W: Write>(granges: &GRanges, writer: &mut W, meta_reader: &mut dyn BufRead, widths_header : &[usize], widths_row: &[usize], n: usize) -> io::Result<()> {
if granges.num_rows() <= n + 1 {
for i in 0..granges.num_rows() {
write_row(granges, writer, meta_reader, &widths_row, i)?;
}
} else {
// Print first n/2 rows
for i in 0..n / 2 {
write_row(granges, writer, meta_reader, &widths_row, i)?;
}
// Print gap
writeln!(writer)?;
write!(writer,
"{:width0$} {:width1$} {:width2$} {:width3$}",
"", "...", "...", "",
width0=widths_header[0], width1=widths_header[1], width2=widths_header[2], width3=widths_header[3])?;
write_meta_row(granges, writer, meta_reader)?;
// Print last n/2 rows
for i in granges.num_rows() - n / 2..granges.num_rows() {
write_row(granges, writer, meta_reader, &widths_row, i)?;
}
}
Ok(())
}