CardRequestV1

Struct CardRequestV1 

Source
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: CardUnits

The preset that fills in every *_unit field below that this request leaves absent.

§muzzle_velocity: f64

Muzzle speed, in velocity_unit.

§ballistic_coefficient: f64§mass: f64

Bullet weight, in mass_unit.

§diameter: f64

Bullet diameter, in diameter_unit.

§drag_model: DragModelV1§sight_height: f64

Sight height over bore, in sight_height_unit; CLI default 1.5 in.

§zero_distance: f64

Zero range, in distance_unit.

§zero_poi_vertical: f64

Deliberate 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: f64

Deliberate lateral POI offset at the zero range, in drop_unit.

§sight_offset_lateral: f64

Lateral 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: f64

Relative humidity, percent. Dimensionless, so no unit field governs it.

§altitude: f64

Site 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: f64

Scope tracking correction factors (MBA-1358); 1.0 = tracks true.

§windage_cf: f64§zero_set_elevation_bias_mil: f64

Selected 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

Source§

fn clone(&self) -> CardRequestV1

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for CardRequestV1

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<'de> Deserialize<'de> for CardRequestV1

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
§

impl<SS, SP> SupersetOf<SS> for SP
where SS: SubsetOf<SP>,

§

fn to_subset(&self) -> Option<SS>

The inverse inclusion map: attempts to construct self from the equivalent element of its superset. Read more
§

fn is_in_subset(&self) -> bool

Checks if self is actually part of its subset T (and can be converted to it).
§

fn to_subset_unchecked(&self) -> SS

Use with care! Same as self.to_subset but without any property checks. Always succeeds.
§

fn from_subset(element: &SS) -> SP

The inclusion map: converts self to the equivalent element of its superset.
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,