1+
2+ /// Note that the included codec file and the data file further below
3+ /// are generated through SBE's gradle tooling. `./gradlew generateRustCodecs`
4+ include ! ( "car_example_generated_codec.rs" ) ;
5+
6+ use std:: fs:: File ;
7+ use std:: io:: prelude:: * ;
8+ use std:: io:: Write ;
9+
10+ pub fn main ( ) {
11+ :: std:: process:: exit ( match run_car_example ( ) {
12+ Ok ( _) => 0 ,
13+ Err ( e) => {
14+ writeln ! ( :: std:: io:: stderr( ) , "error: {:?}" , e) . unwrap ( ) ;
15+ 1
16+ }
17+ } ) ;
18+ }
19+
20+ fn read_sbe_file_generated_from_java_example ( ) -> IoResult < Vec < u8 > > {
21+ // Generated by the generateCarExampleDataFile gradle task.
22+ let mut f = File :: open ( "car_example_data.sbe" ) ?;
23+ let mut buffer = Vec :: new ( ) ;
24+ f. read_to_end ( & mut buffer) ?;
25+ Ok ( buffer)
26+ }
27+
28+ fn run_car_example ( ) -> IoResult < ( ) > {
29+ let reference_example_bytes = read_sbe_file_generated_from_java_example ( ) ?;
30+ decode_car_and_assert_expected_content ( & reference_example_bytes) ?;
31+ let bytes_encoded_from_rust = encode_car_from_scratch ( ) ?;
32+ assert_eq ! ( reference_example_bytes, bytes_encoded_from_rust) ;
33+ decode_car_and_assert_expected_content ( & bytes_encoded_from_rust) ?;
34+ Ok ( ( ) )
35+ }
36+
37+ fn decode_car_and_assert_expected_content ( buffer : & [ u8 ] ) -> IoResult < ( ) > {
38+ let ( h, dec_fields) = start_decoding_car ( & buffer) . header ( ) ?;
39+ assert_eq ! ( 49u16 , h. block_length) ;
40+ assert_eq ! ( 1u16 , h. template_id) ;
41+ assert_eq ! ( 1u16 , h. schema_id) ;
42+ assert_eq ! ( 0u16 , h. version) ;
43+ println ! ( "Header read" ) ;
44+
45+
46+ let mut found_fuel_figures = Vec :: < FuelFigure > :: with_capacity ( EXPECTED_FUEL_FIGURES . len ( ) ) ;
47+
48+ let ( fields, dec_fuel_figures_header) = dec_fields. car_fields ( ) ?;
49+ assert_eq ! ( 1234 , fields. serial_number) ;
50+ assert_eq ! ( 2013 , fields. model_year) ;
51+ assert_eq ! ( BooleanType :: T , fields. available) ;
52+ assert_eq ! ( [ 97_i8 , 98 , 99 , 100 , 101 , 102 ] , fields. vehicle_code) ; // abcdef
53+ assert_eq ! ( [ 0_u32 , 1 , 2 , 3 , 4 ] , fields. some_numbers) ;
54+
55+ let dec_perf_figures_header = match dec_fuel_figures_header. fuel_figures_individually ( ) ? {
56+ Either :: Left ( mut dec_ff_members) => {
57+ println ! ( "Got some fuel figure members" ) ;
58+ let mut decoder_after_group = None ;
59+ loop {
60+ let ( ff_fields, dec_usage_description) = dec_ff_members. next_fuel_figures_member ( ) ?;
61+ let ( usage_description, next_step) = dec_usage_description. usage_description ( ) ?;
62+ let usage_str = std:: str:: from_utf8 ( usage_description) . unwrap ( ) ;
63+ println ! ( "Fuel Figure: Speed: {0}, MPG: {1}, Usage: {2}" ,
64+ ff_fields. speed,
65+ ff_fields. mpg,
66+ usage_str) ;
67+ found_fuel_figures. push ( FuelFigure {
68+ speed : ff_fields. speed ,
69+ mpg : ff_fields. mpg ,
70+ usage_description : usage_str,
71+ } ) ;
72+ match next_step {
73+ Either :: Left ( more_members) => dec_ff_members = more_members,
74+ Either :: Right ( done_with_group) => {
75+ decoder_after_group = Some ( done_with_group) ;
76+ break ;
77+ }
78+ }
79+ }
80+ decoder_after_group. unwrap ( )
81+ }
82+ Either :: Right ( next_decoder) => next_decoder,
83+ } ;
84+ assert ! ( EXPECTED_FUEL_FIGURES
85+ . iter( )
86+ . zip( found_fuel_figures. iter( ) )
87+ . all( |( exp, found) | exp == found) ,
88+ "fuel figures should match expected values" ) ;
89+
90+ let dec_manufacturer = match dec_perf_figures_header. performance_figures_individually ( ) ? {
91+ Either :: Left ( mut dec_pf_members) => {
92+ let mut decoder_after_pf_group = None ;
93+ println ! ( "Got some performance figure members" ) ;
94+ loop {
95+ let ( pf_fields, dec_acceleration_header) = dec_pf_members
96+ . next_performance_figures_member ( ) ?;
97+ println ! ( "Performance Figure Fixed Fields: Octane Rating: {0}" ,
98+ pf_fields. octane_rating) ;
99+ let ( accel_slice, next_step) = dec_acceleration_header. acceleration_as_slice ( ) ?;
100+ for accel_fields in accel_slice {
101+ println ! ( "Acceleration: MPH: {0}, Seconds: {1}" ,
102+ accel_fields. mph,
103+ accel_fields. seconds) ;
104+ }
105+ match next_step {
106+ Either :: Left ( more_members) => dec_pf_members = more_members,
107+ Either :: Right ( done_with_group) => {
108+ decoder_after_pf_group = Some ( done_with_group) ;
109+ break ;
110+ }
111+ }
112+ }
113+ decoder_after_pf_group. unwrap ( )
114+ }
115+ Either :: Right ( next_decoder) => next_decoder,
116+ } ;
117+ let ( manufacturer, dec_model) = dec_manufacturer. manufacturer ( ) ?;
118+ let manufacturer = std:: str:: from_utf8 ( manufacturer) . unwrap ( ) ;
119+ println ! ( "Manufacturer: {}" , manufacturer) ;
120+ assert_eq ! ( "Honda" , manufacturer) ;
121+
122+ let ( model, dec_activation_code) = dec_model. model ( ) ?;
123+ let model = std:: str:: from_utf8 ( model) . unwrap ( ) ;
124+ println ! ( "Model: {}" , model) ;
125+ assert_eq ! ( "Civic VTi" , model) ;
126+
127+ let ( activation_code, dec_done) = dec_activation_code. activation_code ( ) ?;
128+ let activation_code = std:: str:: from_utf8 ( activation_code) . unwrap ( ) ;
129+ println ! ( "Activation Code: {}" , activation_code) ;
130+ assert_eq ! ( "abcdef" , activation_code) ;
131+
132+ let ( position, buffer_back) = dec_done. unwrap ( ) ;
133+ println ! ( "Finished decoding. Made it to position {0} out of {1}" ,
134+ position,
135+ buffer_back. len( ) ) ;
136+ Ok ( ( ) )
137+ }
138+
139+ fn encode_car_from_scratch ( ) -> IoResult < Vec < u8 > > {
140+ let mut buffer = vec ! [ 0u8 ; 256 ] ;
141+ let used_pos = {
142+ let enc_header = start_encoding_car ( & mut buffer) ;
143+ let enc_fields = enc_header
144+ . header_copy ( & CarMessageHeader :: default ( ) . message_header ) ?;
145+ println ! ( "encoded header" ) ;
146+ let ( fields, enc_fuel_figures_header) = enc_fields. car_fields ( ) ?;
147+ fields. serial_number = 1234 ;
148+ fields. model_year = 2013 ;
149+ fields. available = BooleanType :: T ;
150+ fields. code = Model :: A ;
151+ fields. vehicle_code = [ 97_i8 , 98 , 99 , 100 , 101 , 102 ] ; // abcdef
152+ fields. some_numbers = [ 0_u32 , 1 , 2 , 3 , 4 ] ;
153+ fields. extras = OptionalExtras ( 6 ) ;
154+ fields. engine = Engine {
155+ capacity : 2000 ,
156+ num_cylinders : 4 ,
157+ manufacturer_code : [ 49 , 50 , 51 ] , // 123
158+ efficiency : 35 ,
159+ booster_enabled : BooleanType :: T ,
160+ booster : Booster {
161+ boost_type : BoostType :: NITROUS ,
162+ horse_power : 200 ,
163+ } ,
164+ } ;
165+ println ! ( "encoded top level fields" ) ;
166+ let mut enc_fuel_figures = enc_fuel_figures_header. fuel_figures_individually ( ) ?;
167+ let mut fuel_figure_scratch = CarFuelFiguresMember { speed : 0 , mpg : 0.0 } ;
168+ for ff in EXPECTED_FUEL_FIGURES {
169+ fuel_figure_scratch. speed = ff. speed ;
170+ fuel_figure_scratch. mpg = ff. mpg ;
171+ //fuel_figure_scratch.usage_description = ff.mpg;
172+ let enc_usage = enc_fuel_figures
173+ . next_fuel_figures_member ( & fuel_figure_scratch) ?;
174+ enc_fuel_figures = enc_usage
175+ . usage_description ( ff. usage_description . as_bytes ( ) ) ?;
176+ }
177+ let enc_perf_figures_header = enc_fuel_figures. done_with_fuel_figures ( ) ?;
178+ println ! ( "encoded fuel figures" ) ;
179+ let mut perf_figure_member_scratch = CarPerformanceFiguresMember { octane_rating : 0 } ;
180+ let mut enc_perf_figures = enc_perf_figures_header. performance_figures_individually ( ) ?;
181+ for pf in EXPECTED_PERF_FIXTURES {
182+ perf_figure_member_scratch. octane_rating = pf. octane_rating ;
183+ let enc_accel = enc_perf_figures
184+ . next_performance_figures_member ( & perf_figure_member_scratch) ?;
185+ enc_perf_figures = enc_accel. acceleration_from_slice ( & pf. acceleration ) ?;
186+ }
187+ let enc_manufacturer = enc_perf_figures. done_with_performance_figures ( ) ?;
188+ println ! ( "encoded perf figures" ) ;
189+ let enc_model = enc_manufacturer. manufacturer ( "Honda" . as_bytes ( ) ) ?;
190+ let enc_activation_code = enc_model. model ( "Civic VTi" . as_bytes ( ) ) ?;
191+ let done = enc_activation_code. activation_code ( "abcdef" . as_bytes ( ) ) ?;
192+ let ( pos, _) = done. unwrap ( ) ;
193+ pos
194+ } ;
195+ println ! ( "encoded up to position {}" , used_pos) ;
196+ buffer. truncate ( used_pos) ;
197+
198+ Ok ( buffer)
199+ }
200+
201+ #[ derive( Debug , PartialEq ) ]
202+ struct FuelFigure < ' d > {
203+ speed : u16 ,
204+ mpg : f32 ,
205+ usage_description : & ' d str ,
206+ }
207+
208+ const EXPECTED_FUEL_FIGURES : & ' static [ FuelFigure ] = & [ FuelFigure {
209+ speed : 30 ,
210+ mpg : 35.9 ,
211+ usage_description : "Urban Cycle" ,
212+ } ,
213+ FuelFigure {
214+ speed : 55 ,
215+ mpg : 49.0 ,
216+ usage_description : "Combined Cycle" ,
217+ } ,
218+ FuelFigure {
219+ speed : 75 ,
220+ mpg : 40.0 ,
221+ usage_description : "Highway Cycle" ,
222+ } ] ;
223+
224+ struct PerfFigure {
225+ octane_rating : u8 ,
226+ acceleration : [ CarPerformanceFiguresAccelerationMember ; 3 ] ,
227+ }
228+
229+ const EXPECTED_PERF_FIXTURES : & ' static [ PerfFigure ] = & [ PerfFigure {
230+ octane_rating : 95 ,
231+ acceleration : [ CarPerformanceFiguresAccelerationMember {
232+ mph : 30 ,
233+ seconds : 4.0 ,
234+ } ,
235+ CarPerformanceFiguresAccelerationMember {
236+ mph : 60 ,
237+ seconds : 7.5 ,
238+ } ,
239+ CarPerformanceFiguresAccelerationMember {
240+ mph : 100 ,
241+ seconds : 12.2 ,
242+ } ] ,
243+ } ,
244+ PerfFigure {
245+ octane_rating : 99 ,
246+ acceleration : [ CarPerformanceFiguresAccelerationMember {
247+ mph : 30 ,
248+ seconds : 3.8 ,
249+ } ,
250+ CarPerformanceFiguresAccelerationMember {
251+ mph : 60 ,
252+ seconds : 7.1 ,
253+ } ,
254+ CarPerformanceFiguresAccelerationMember {
255+ mph : 100 ,
256+ seconds : 11.8 ,
257+ } ] ,
258+ } ] ;
0 commit comments