switchback_codec_pb/convert/
mod.rs1mod contract;
5mod entity;
7mod link;
9mod manual;
11mod protocol;
13
14use switchback_traits::{ReferenceManual, Result, SwitchbackError};
15
16use crate::pb;
17
18pub const WIRE_VERSION: &str = "v1alpha1";
20
21pub fn to_proto(manual: &ReferenceManual) -> Result<pb::ReferenceManual> {
25 validate_resolved_links(manual)?;
26 manual::reference_manual_to_proto(manual)
27}
28
29pub fn from_proto(manual: pb::ReferenceManual) -> Result<ReferenceManual> {
33 validate_wire_version(&manual.switchback_version)?;
34 manual::reference_manual_from_proto(manual)
35}
36
37fn validate_wire_version(version: &str) -> Result<()> {
38 if version.starts_with(WIRE_VERSION) {
39 Ok(())
40 } else {
41 Err(SwitchbackError::codec(format!(
42 "unsupported switchback_version {version:?}; expected prefix {WIRE_VERSION:?}"
43 )))
44 }
45}
46
47fn validate_resolved_links(manual: &ReferenceManual) -> Result<()> {
48 for module in &manual.modules {
49 for contract in &module.contracts {
50 for group in &contract.groups {
51 for entity in &group.entities {
52 for link in &entity.intra_links {
53 if matches!(link.target, switchback_traits::LinkTarget::Unresolved) {
54 return Err(SwitchbackError::codec(
55 "cannot serialize manual with unresolved intra-link",
56 ));
57 }
58 }
59 }
60 }
61 }
62 }
63 Ok(())
64}
65
66pub(crate) fn opt_string(value: &Option<String>) -> String {
67 value.clone().unwrap_or_default()
68}
69
70pub(crate) fn string_opt(value: String) -> Option<String> {
71 if value.is_empty() { None } else { Some(value) }
72}
73
74pub(crate) fn codec_err(message: impl Into<String>) -> SwitchbackError {
75 SwitchbackError::codec(message)
76}
77
78pub(crate) fn missing_link_target() -> SwitchbackError {
79 codec_err("link target missing on wire")
80}
81
82pub(crate) fn missing_entity_body() -> SwitchbackError {
83 codec_err("entity body missing on wire")
84}