Skip to content

Commit c8c4856

Browse files
committed
generate get_width for structures/unions
1 parent 2a3ec08 commit c8c4856

3 files changed

Lines changed: 208 additions & 0 deletions

File tree

xdr_codegen/src/codegen/deserialize.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,34 @@ impl ValidatedUnionEnumBody {
163163
}
164164

165165
impl ValidatedStruct {
166+
pub fn offset_to_string(off: &DeclarationOfset) -> String {
167+
Self::offset_to_string_with_unwrapper(off, "?")
168+
}
169+
170+
pub fn offset_to_string_infallible(off: &DeclarationOfset) -> String {
171+
Self::offset_to_string_with_unwrapper(off, ".unwrap()")
172+
}
173+
174+
pub fn offset_to_string_with_unwrapper(off: &DeclarationOfset, unwrapper: &str) -> String {
175+
let code = off
176+
.deps
177+
.iter()
178+
.map(|v| format!("self.get_{}_width(){}", v, unwrapper))
179+
.chain(
180+
vec![format!("{}", off.known)]
181+
.into_iter()
182+
.filter(|v| v != "0"),
183+
)
184+
.collect::<Vec<String>>()
185+
.join(" + ");
186+
187+
if code.is_empty() {
188+
"0".to_string()
189+
} else {
190+
code.clone()
191+
}
192+
}
193+
166194
pub(super) fn deserialize_definition(&self, buf: &mut CodeBuf, tab: &ValidatedSymbolTable) {
167195
buf.code_block(DESERIALIZE_SIGNATURE, |buf| {
168196
for (decl, _) in self.members.iter() {

xdr_codegen/src/codegen/mod.rs

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,80 @@ impl NamedDeclaration {
294294
DeclarationKind::Optional(o) => o.optional_default_value(tab),
295295
}
296296
}
297+
298+
fn is_varlen_reader(&self, tab: &ValidatedSymbolTable) -> bool {
299+
match &self.kind {
300+
DeclarationKind::Scalar(ty) | DeclarationKind::Optional(ty) => {
301+
ty.is_reader(tab) && ty.size(tab).is_none()
302+
}
303+
_ => false,
304+
}
305+
}
306+
307+
fn is_self_referential(&self, tab: &ValidatedSymbolTable) -> bool {
308+
match &self.kind {
309+
DeclarationKind::Scalar(xdr_type) | DeclarationKind::Optional(xdr_type) => {
310+
xdr_type.self_referential_optional(tab)
311+
}
312+
DeclarationKind::Array(_) => false,
313+
}
314+
}
315+
316+
fn get_width(&self, buf: &mut CodeBuf, name: &str, tab: &ValidatedSymbolTable) {
317+
match &self.kind {
318+
DeclarationKind::Scalar(t) => t.get_width(buf, name, tab),
319+
DeclarationKind::Array(array) => match &array.kind {
320+
ArrayKind::Byte | ArrayKind::Ascii => {
321+
buf.add_line(&format!("xdr_lib::padding_4byte({}.len())", name))
322+
}
323+
ArrayKind::UserType(xdr_type) => {
324+
let elem_size = xdr_type.size(tab);
325+
if let Some(elem_size) = elem_size {
326+
buf.add_line(&format!(
327+
"xdr_lib::padding_4byte({}.len() * {})",
328+
name, elem_size
329+
));
330+
} else {
331+
let count_addition = if let ArraySize::Fixed(_) = &array.size {
332+
""
333+
} else {
334+
"4usize + "
335+
};
336+
buf.block_with_trailer(
337+
&format!(
338+
"{count_addition}xdr_lib::padding_4byte({}.iter().map(|_v|",
339+
name
340+
),
341+
").sum::<usize>())",
342+
|buf| {
343+
xdr_type.get_width(buf, "_v", tab);
344+
},
345+
);
346+
}
347+
}
348+
},
349+
DeclarationKind::Optional(xdr_type) => {
350+
if self.is_self_referential(tab) {
351+
buf.block_with_trailer(
352+
&format!("4usize + xdr_lib::padding_4byte({}.iter().map(|_v|", name),
353+
").sum::<usize>())",
354+
|buf| {
355+
buf.code_block("4usize +", |buf| {
356+
xdr_type.get_width(buf, "_v", tab);
357+
});
358+
},
359+
);
360+
} else {
361+
buf.code_block(&format!("4usize + match &{}", name), |buf| {
362+
buf.add_line("None => 0,");
363+
buf.code_block("Some(_val) =>", |buf| {
364+
xdr_type.get_width(buf, "_val", tab);
365+
});
366+
})
367+
}
368+
}
369+
}
370+
}
297371
}
298372

299373
impl ValidatedUnion {
@@ -308,6 +382,8 @@ impl ValidatedUnion {
308382
}
309383
buf.add_line("");
310384
self.deserialize_definition(buf, tab);
385+
buf.add_line("");
386+
self.width_getter(buf, tab);
311387
});
312388
buf.add_line("");
313389
}
@@ -326,6 +402,44 @@ impl ValidatedUnion {
326402
})
327403
});
328404
}
405+
fn width_getter(&self, buf: &mut CodeBuf, tab: &ValidatedSymbolTable) {
406+
buf.code_block("pub fn get_width(&self) -> usize", |buf| match &self.body {
407+
ValidatedUnionBody::Bool(validated_union_bool_body) => {
408+
buf.code_block("4usize + match &self.inner", |buf| {
409+
buf.add_line("None => 0,");
410+
buf.code_block("Some(_val) =>", |buf| {
411+
validated_union_bool_body
412+
.true_arm
413+
.get_width(buf, "_val", tab);
414+
});
415+
})
416+
}
417+
ValidatedUnionBody::Enum(e) => {
418+
buf.code_block("4usize + match &self", |buf| {
419+
for arm in e.arms.iter() {
420+
let name = ValidatedUnionEnumBody::arm_name(&arm.0);
421+
match &arm.1 {
422+
Declaration::Void => buf.add_line(&format!("Self::{name} => 0,")),
423+
Declaration::Named(n) => {
424+
buf.code_block(&format!("Self::{name}(_val) =>"), |buf| {
425+
n.get_width(buf, "_val", tab);
426+
});
427+
}
428+
};
429+
}
430+
match &e.default_arm {
431+
Some(Declaration::Void) => buf.add_line("Self::Default => 0,"),
432+
Some(Declaration::Named(n)) => {
433+
buf.code_block("Self::Default(_val) =>", |buf| {
434+
n.get_width(buf, "_val", tab);
435+
});
436+
}
437+
None => {}
438+
}
439+
});
440+
}
441+
});
442+
}
329443
}
330444

331445
impl ValidatedUnionBoolBody {
@@ -545,10 +659,45 @@ impl ValidatedStruct {
545659
}
546660
buf.add_line("");
547661
self.deserialize_definition(buf, tab);
662+
buf.add_line("");
663+
self.width_getters(buf, tab);
548664
});
549665
buf.add_line("");
550666
}
551667

668+
fn width_getters(&self, buf: &mut CodeBuf, tab: &ValidatedSymbolTable) {
669+
let varlen_members = self.get_variable_width_members(tab);
670+
671+
for name in varlen_members {
672+
let (member, _) = self.members.iter().find(|val| val.0.name == *name).unwrap();
673+
674+
buf.code_block(&format!("fn get_{}_width(&self) -> usize", name), |buf| {
675+
member.get_width(buf, &format!("self.{}", name), tab)
676+
});
677+
}
678+
679+
buf.code_block("pub fn get_width(&self) -> usize", |buf| {
680+
if let Some((last, last_off)) = self.members.last() {
681+
let last_size = last.size(tab);
682+
let mut overall_definition_size = DefinitionSize {
683+
known: last_off.known + last_size.unwrap_or(0),
684+
deps: last_off.deps.clone(),
685+
};
686+
687+
if last_size.is_none() {
688+
overall_definition_size.deps.push(last.name.clone());
689+
}
690+
691+
buf.add_line(&Self::offset_to_string_with_unwrapper(
692+
&overall_definition_size,
693+
"",
694+
));
695+
} else {
696+
buf.add_line("0");
697+
}
698+
});
699+
}
700+
552701
fn definition(&self, buf: &mut CodeBuf, tab: &ValidatedSymbolTable) {
553702
buf.type_header();
554703
buf.code_block(&format!("pub struct {}", self.name), |buf| {
@@ -786,6 +935,33 @@ impl XdrType {
786935
}
787936
.to_string()
788937
}
938+
939+
fn get_width(&self, buf: &mut CodeBuf, name: &str, tab: &ValidatedSymbolTable) {
940+
match self {
941+
XdrType::Name(n) => {
942+
let found = tab.lookup_definition(n);
943+
944+
let defsize = found.size(tab);
945+
946+
if defsize.is_determinate() {
947+
buf.add_line(&format!("{}", defsize.known));
948+
} else {
949+
match found {
950+
ValidatedDefinition::Const(_) => unreachable!(),
951+
ValidatedDefinition::TypeDef(td) => td.decl.get_width(buf, name, tab),
952+
ValidatedDefinition::Struct(_) => {
953+
buf.add_line(&format!("{name}.get_width()"));
954+
}
955+
ValidatedDefinition::Enum(_) => buf.add_line("4"),
956+
ValidatedDefinition::Union(_) => {
957+
buf.add_line(&format!("{name}.get_width()"));
958+
}
959+
}
960+
}
961+
}
962+
_ => buf.add_line(&format!("{}", self.size(tab).unwrap())),
963+
}
964+
}
789965
}
790966

791967
struct CodeBuf {

xdr_lib/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@ pub fn serialize_bool(src: &bool) -> [u8; 4] {
6868
}
6969
}
7070

71+
pub fn padding_4byte(len: usize) -> usize {
72+
(len + 3) & !(0b11usize)
73+
}
74+
7175
pub fn encode_padding(offset: usize, buf: &mut [u8]) -> usize {
7276
let padded_offset: usize = (offset + 3) & !(0b11usize);
7377
buf[offset..padded_offset].fill(0u8);

0 commit comments

Comments
 (0)