pub struct CardRequestV1 {Show 44 fields
pub units: CardUnits,
pub muzzle_velocity: f64,
pub ballistic_coefficient: f64,
pub mass: f64,
pub diameter: f64,
pub drag_model: DragModelV1,
pub sight_height: f64,
pub zero_distance: f64,
pub zero_poi_vertical: f64,
pub zero_poi_horizontal: f64,
pub sight_offset_lateral: f64,
pub temperature: Option<f64>,
pub pressure: Option<f64>,
pub humidity: f64,
pub altitude: f64,
pub wind_speed: f64,
pub wind_direction_deg: f64,
pub start: f64,
pub end: f64,
pub step: f64,
pub distance_unit: Option<CardDistanceUnit>,
pub velocity_unit: Option<CardVelocityUnit>,
pub mass_unit: Option<CardMassUnit>,
pub diameter_unit: Option<CardDiameterUnit>,
pub sight_height_unit: Option<CardLinearUnit>,
pub drop_unit: Option<CardLinearUnit>,
pub wind_speed_unit: Option<CardWindSpeedUnit>,
pub temperature_unit: Option<CardTemperatureUnit>,
pub pressure_unit: Option<CardPressureUnit>,
pub energy_unit: Option<CardEnergyUnit>,
pub altitude_unit: Option<CardAltitudeUnit>,
pub adjustment_unit: AdjustmentUnit,
pub windage_unit: Option<AdjustmentUnit>,
pub elevation_click_value: Option<String>,
pub windage_click_value: Option<String>,
pub elevation_cf: f64,
pub windage_cf: f64,
pub zero_set_elevation_bias_mil: f64,
pub zero_set_windage_bias_mil: f64,
pub wind_speeds: Vec<f64>,
pub wind_angles_deg: Vec<f64>,
pub bc_segments: Option<Vec<CardBcSegmentV1>>,
pub bc5d_table_path: Option<String>,
pub pdf: Option<PdfCardOptionsV1>,
}Expand description
Everything the three card surfaces share: load, zero, atmosphere, display axes.
Field values are in this request’s PER-DIMENSION units: each dimensional field names the
*_unit field that denominates it, and each of those falls back to what units implies
when it is absent (see the module docs). Stating none of them is the pre-MBA-1519 shape
and reproduces the pre-MBA-1519 card exactly.
§Adding a field here is additive on the WIRE and breaking in RUST
This is a deserialization target: the supported way to build one is
serde_json::from_str/from_value on a JSON document, which is what the bridge and every
binding do, and an optional new field costs such a caller nothing. A downstream Rust crate
that constructs it with a struct literal has no such luck — every added field is an
E0063: missing fields against code that compiled before, which is exactly what MBA-1519’s
eleven fields do to a crate written against 0.39.x. The remedy is one line per field
(altitude_unit: None, and so on for the rest); the intended path is to deserialize.
#[non_exhaustive] was considered and NOT applied. It would break the same callers in the
same release, and — with no Default and no builder on this type — it would leave a
downstream crate no way to construct the request at all, trading one fixable compile error
for a permanent one. So the breakage is stated in the CHANGELOG for the release that causes
it rather than encoded in the type, and a future field will be stated the same way.
Fields§
§units: CardUnitsThe preset that fills in every *_unit field below that this request leaves absent.
muzzle_velocity: f64Muzzle speed, in velocity_unit.
ballistic_coefficient: f64§mass: f64Bullet weight, in mass_unit.
diameter: f64Bullet diameter, in diameter_unit.
drag_model: DragModelV1§sight_height: f64Sight height over bore, in sight_height_unit; CLI default 1.5 in.
zero_distance: f64Zero range, in distance_unit.
zero_poi_vertical: f64Deliberate POI offset at the zero range, in drop_unit — it is a displacement on
the target, which is the dimension the drop column reports; 0 = zeroed dead-on.
zero_poi_horizontal: f64Deliberate lateral POI offset at the zero range, in drop_unit.
sight_offset_lateral: f64Lateral sight-to-bore mount offset, in sight_height_unit — it is rifle geometry
measured beside the sight height, not a figure read off a target.
temperature: Option<f64>Station temperature, in temperature_unit.
pressure: Option<f64>Station pressure, in pressure_unit.
humidity: f64Relative humidity, percent. Dimensionless, so no unit field governs it.
altitude: f64Site elevation, in altitude_unit — which defaults to METRES whatever units says.
wind_speed: f64§wind_direction_deg: f64§start: f64§end: f64§step: f64§distance_unit: Option<CardDistanceUnit>Unit of zero_distance, start, end, step and every row’s range.
Default: yards (imperial) / metres (metric).
Distance is the dimension where reinterpreting the number does the most damage the most quietly: “300” yards and “300” metres are targets 9.36% apart, and a stored zero, a DOPE row and a target-size hold are all attached to a PHYSICAL distance rather than to a unit-free label. So a card’s distance unit is stated, never inferred from a neighbouring dimension.
velocity_unit: Option<CardVelocityUnit>Unit of muzzle_velocity, the bc_segments band edges and the velocity column.
Default: fps (imperial) / m/s (metric).
mass_unit: Option<CardMassUnit>Unit of mass. Default: grains (imperial) / grams (metric).
diameter_unit: Option<CardDiameterUnit>Unit of diameter. Default: inches (imperial) / mm (metric). Those two values and no
others — see CardDiameterUnit.
sight_height_unit: Option<CardLinearUnit>Unit of sight_height and sight_offset_lateral — the sight-to-bore geometry.
Default: inches (imperial) / mm (metric).
This is a dimension the design’s table does not contain, added deliberately rather
than by oversight: without it, the only home for the sight height would be
drop_unit, and then asking for a drop column in centimetres would silently reread a
1.5-inch sight height as 1.5 cm. It is a twelfth field on a deny_unknown_fields
contract that cannot be withdrawn without a breaking change, which is the cost being
accepted here.
Separate from drop_unit on purpose. They are the same unit today only because both
presets happen to give them the same value; they are different measurements (one is
taken on the rifle with calipers, the other is read off a target downrange), and
folding them together would mean a caller who asks for a drop column in centimetres
silently reinterprets a 1.5-inch sight height as 1.5 cm.
drop_unit: Option<CardLinearUnit>Unit of the drop_linear / wind_linear columns and of zero_poi_vertical /
zero_poi_horizontal. Default: inches (imperial) / mm (metric).
The ANGULAR half of the design’s drop dimension is adjustment_unit /
windage_unit, which have always been separate fields; this is the linear half, and
cm is available here because a metric card prints 250 cm of drop, not 2500 mm.
wind_speed_unit: Option<CardWindSpeedUnit>Unit of wind_speed, of every entry in wind_speeds, and of pdf.target_speed.
Default: mph (imperial) / m/s (metric).
temperature_unit: Option<CardTemperatureUnit>Unit of temperature and of the temperature default. Default: °F (imperial) / °C
(metric).
pressure_unit: Option<CardPressureUnit>Unit of pressure and of the pressure default. Default: inHg (imperial) / hPa
(metric).
energy_unit: Option<CardEnergyUnit>Unit of the energy column. Default: ft-lb (imperial) / J (metric).
altitude_unit: Option<CardAltitudeUnit>Unit of altitude. Default: metres, whatever units says — this is the one
dimension whose fallback is not the preset’s.
altitude has ignored the units scalar since this module was written: it is passed
to AtmosphericConditions unconverted, and that field is documented metres, so an
imperial card’s altitude has always been metres too (the PDF header divides it by
0.3048 regardless of units for exactly that reason). Letting the imperial preset
start filling this with feet would therefore not be additive: every stored imperial
card carrying altitude: 1000 would silently become a card shot at 304.8 m instead
of 1000 m, which is a different density altitude and a different trajectory.
So the preset does not reach this field. A caller that wants feet says "feet", and
gets the first way this request has ever had to express one.
adjustment_unit: AdjustmentUnit§windage_unit: Option<AdjustmentUnit>Windage axis unit; defaults to the elevation axis.
elevation_click_value: Option<String>Turret graduations as suffixed strings (“0.1mil”, “0.25moa”); required when
the corresponding axis unit is clicks. Windage falls back to elevation.
windage_click_value: Option<String>§elevation_cf: f64Scope tracking correction factors (MBA-1358); 1.0 = tracks true.
windage_cf: f64§zero_set_elevation_bias_mil: f64Selected zero set’s dial corrections, true angular MIL (MBA-1360).
zero_set_windage_bias_mil: f64§wind_speeds: Vec<f64>Wind card only: the sweep of wind speeds, each in wind_speed_unit (so km/h and
knots are available here too), one output column each.
wind_angles_deg: Vec<f64>Wind card only: wind-FROM angles in degrees; default [90] (full-value from
the right), matching the CLI.
bc_segments: Option<Vec<CardBcSegmentV1>>Explicit velocity-banded BC schedule, mirroring the CLI’s repeatable
--bc-segment VMIN:VMAX:BC. Velocities are in the request’s velocity_unit,
exactly like the CLI flag. When supplied it
wins over bc5d_table_path, and — CLI parity — the scalar
ballistic_coefficient remains the interior-gap fallback unchanged. The
schedule feeds BOTH the zero solve and every sampled trajectory.
Bands may be listed in any order and may touch or leave gaps, but must not overlap; at
most crate::solve_json::MAX_BC_SEGMENTS_V1 bands; each bc within 0.0001..=100, the
bound solve-json puts on a BC. [] and null mean no ladder (MBA-1600).
bc5d_table_path: Option<String>Filesystem path to a caliber-specific BC5D correction table
(bc5d_<caliber>.bin, the exact format the CLI’s --bc-table-dir
consumes). The table is CRC-verified, a velocity-keyed BC schedule is
generated for this load (same ladder as the CLI), and the scalar BC gets the
table’s muzzle correction as the interior-gap fallback. Ignored when
bc_segments is supplied. Not available on wasm32 builds (no filesystem);
there it is rejected with an invalid-request error.
pdf: Option<PdfCardOptionsV1>Presentation-only options for the printable PDF dope card (card.pdf). Nothing in
here touches the ballistics: the numbers in the PDF are the rows
range_table_v1 returns, computed by the same call.
It lives on the shared request — rather than in a card.pdf-only wrapper type — so
an app stores ONE CardRequestV1 per saved card and replays that exact document
against either surface: card.range_table for the screen, card.pdf for the
printout. The on-screen commands ignore this block.
Deliberately NOT #[cfg(feature = "pdf")], even though everything that consumes it
is: CardRequestV1 denies unknown fields, so gating the field would make a
pdf-less build REJECT a stored request that carries it, breaking exactly the
round-trip the field exists to support. A pdf-less build parses it and never reads
it; only the card.pdf command itself disappears.
Trait Implementations§
Source§impl Clone for CardRequestV1
impl Clone for CardRequestV1
Source§fn clone(&self) -> CardRequestV1
fn clone(&self) -> CardRequestV1
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for CardRequestV1
impl Debug for CardRequestV1
Source§impl<'de> Deserialize<'de> for CardRequestV1
impl<'de> Deserialize<'de> for CardRequestV1
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
Auto Trait Implementations§
impl Freeze for CardRequestV1
impl RefUnwindSafe for CardRequestV1
impl Send for CardRequestV1
impl Sync for CardRequestV1
impl Unpin for CardRequestV1
impl UnwindSafe for CardRequestV1
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
§impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
§fn to_subset(&self) -> Option<SS>
fn to_subset(&self) -> Option<SS>
self from the equivalent element of its
superset. Read more§fn is_in_subset(&self) -> bool
fn is_in_subset(&self) -> bool
self is actually part of its subset T (and can be converted to it).§fn to_subset_unchecked(&self) -> SS
fn to_subset_unchecked(&self) -> SS
self.to_subset but without any property checks. Always succeeds.§fn from_subset(element: &SS) -> SP
fn from_subset(element: &SS) -> SP
self to the equivalent element of its superset.