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
158
159
160
161
162
163
164
//! Why a command could not be run: its command line refused, its input not read, or its
//! output not written.
use brodo::field::ValueType;
use brodo::slice::Axis;
use std::path::PathBuf;
use brodo::error::{
CacheError, FieldError, FormatError, SliceError, TreeError, VdbError, VtkError,
};
/// Why a command could not be run.
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum MestoloError {
/// No argument is given, so no command.
#[error("no command is given")]
NoCommand,
/// The first argument names no command.
#[error("there is no command {0:?}")]
UnknownCommand(String),
/// An option the command does not take.
#[error("{0:?} is not an option of this command")]
UnknownOption(String),
/// An option given twice.
#[error("{0:?} is given twice")]
Repeated(String),
/// What the command needs and was not given, named.
#[error("{0} is missing")]
Missing(&'static str),
/// An argument beyond the input file.
#[error("{0:?} is an argument too many: the input file is given once")]
Extra(String),
/// An option's value it does not take.
#[error("{option} does not take {value:?}")]
BadValue {
/// The option.
option: &'static str,
/// The value given.
value: String,
},
/// An argument that is not UTF-8 where only text is taken, named.
#[error("{0} is not UTF-8")]
NotText(&'static str),
/// The input's first bytes are those of no file mestolo reads.
#[error("{0:?} is not a cache file, an archive or a .vdb")]
UnknownKind(PathBuf),
/// The input is a bare frozen grid, which brodo gives no public way to read.
#[error("{0:?} is a bare frozen grid, which is not read")]
BareGrid(PathBuf),
/// Thawing a cache file's or an archive's grids would make more than the limit, counted
/// as ADR-0050 states.
#[error("thawing the grids would make {counted} bytes or more, more than the limit of {limit}")]
TooMuchToThaw {
/// What was counted when the count passed the limit.
counted: u64,
/// The limit.
limit: u64,
},
/// A grid's values are of a type this build of mestolo does not know, one brodo added
/// after it.
#[error("values of type {0} are not read by this build")]
ValueType(ValueType),
/// The file holds no grid of the name given.
#[error("the file holds no grid named {0:?}")]
NoGrid(String),
/// The file holds a number of grids other than one, and none was named.
#[error("the file holds {0} grids: name one with --grid")]
WhichGrid(usize),
/// The grid has no leaf or tile, so there is nothing to draw.
#[error("grid {0:?} has no leaf or tile to draw")]
EmptyGrid(String),
/// A slice's plane lies beyond the grid's leaves and tiles along its axis.
#[error("grid {grid:?} spans {min} to {max} along {}, so there is no plane at {at}", axis_name(*.axis))]
OutsideGrid {
/// The grid's name.
grid: String,
/// The axis the slice is perpendicular to.
axis: Axis,
/// The plane asked for.
at: i32,
/// The least voxel coordinate of the grid's leaves and tiles along the axis.
min: i32,
/// The greatest.
max: i32,
},
/// A slice of a grid whose values are not scalars.
#[error("a slice of {0} values is not drawn: they are not scalars")]
NotScalar(ValueType),
/// A slice's image would be larger than mestolo draws.
#[error("the slice would be {width} × {height} pixels, more than {most}")]
ImageTooLarge {
/// Its width.
width: i64,
/// Its height.
height: i64,
/// The most pixels drawn.
most: i64,
},
/// The output's name ends in no format mestolo writes, and `--as` names none.
#[error("{0:?} ends in neither .vdb nor .vtu: name the format with --as")]
OutputKind(PathBuf),
/// The grids whose value types `.vdb` does not hold, each its name and value type, in
/// the file's order.
#[error(".vdb does not hold the values of {}", not_written(.0))]
NotWritten(Vec<(String, ValueType)>),
/// A file is at the output's path, and `--force` was not given.
#[error("{0:?} exists: give --force to replace it")]
Exists(PathBuf),
/// Reading or writing a file failed.
#[error(transparent)]
Io(#[from] std::io::Error),
/// A cache file or an archive was refused.
#[error(transparent)]
Cache(#[from] CacheError),
/// A grid's frozen buffer was refused.
#[error(transparent)]
Format(#[from] FormatError),
/// A `.vdb` was refused, or could not be written.
#[error(transparent)]
Vdb(#[from] VdbError),
/// A field did not belong to its topology.
#[error(transparent)]
Field(#[from] FieldError),
/// A topology refused a lookup.
#[error(transparent)]
Tree(#[from] TreeError),
/// A slice could not be drawn or encoded.
#[error(transparent)]
Slice(#[from] SliceError),
/// A `.vtu` could not be written.
#[error(transparent)]
Vtk(#[from] VtkError),
}
impl MestoloError {
/// Whether the command line was refused, rather than the command failing.
pub fn is_usage(&self) -> bool {
matches!(
self,
Self::NoCommand
| Self::UnknownCommand(_)
| Self::UnknownOption(_)
| Self::Repeated(_)
| Self::Missing(_)
| Self::Extra(_)
| Self::BadValue { .. }
| Self::NotText(_)
)
}
}
fn axis_name(axis: Axis) -> &'static str {
match axis {
Axis::X => "x",
Axis::Y => "y",
Axis::Z => "z",
}
}
/// Each grid as `"name" (type)`, joined by commas.
fn not_written(grids: &[(String, ValueType)]) -> String {
grids.iter().map(|(name, t)| format!("{name:?} ({t})")).collect::<Vec<_>>().join(", ")
}