msggen: Use the inferred optional field

Changelog-Changed: msggen: The generated interfaces `cln-rpc` anc `cln-grpc` can now work with a range of versions rather than having to match the CLN version
This commit is contained in:
Christian Decker 2023-03-28 13:59:35 +02:00 committed by Rusty Russell
parent 392cacac81
commit 60b12ec096
7 changed files with 352 additions and 344 deletions

View file

@ -131,7 +131,7 @@ message ListpeersResponse {
message ListpeersPeers {
bytes id = 1;
bool connected = 2;
uint32 num_channels = 8;
optional uint32 num_channels = 8;
repeated ListpeersPeersLog log = 3;
repeated ListpeersPeersChannels channels = 4;
repeated string netaddr = 5;
@ -303,7 +303,7 @@ message ListfundsChannels {
uint32 funding_output = 5;
bool connected = 6;
ChannelState state = 7;
bytes channel_id = 9;
optional bytes channel_id = 9;
optional string short_channel_id = 8;
}

View file

@ -212,7 +212,7 @@ impl From<responses::ListpeersPeers> for pb::ListpeersPeers {
Self {
id: c.id.serialize().to_vec(), // Rule #2 for type pubkey
connected: c.connected, // Rule #2 for type boolean
num_channels: c.num_channels, // Rule #2 for type u32
num_channels: c.num_channels, // Rule #2 for type u32?
log: c.log.map(|arr| arr.into_iter().map(|i| i.into()).collect()).unwrap_or(vec![]), // Rule #3
channels: c.channels.map(|arr| arr.into_iter().map(|i| i.into()).collect()).unwrap_or(vec![]), // Rule #3
netaddr: c.netaddr.map(|arr| arr.into_iter().map(|i| i.into()).collect()).unwrap_or(vec![]), // Rule #3
@ -259,7 +259,7 @@ impl From<responses::ListfundsChannels> for pb::ListfundsChannels {
funding_output: c.funding_output, // Rule #2 for type u32
connected: c.connected, // Rule #2 for type boolean
state: c.state as i32,
channel_id: c.channel_id.to_vec(), // Rule #2 for type hash
channel_id: c.channel_id.map(|v| v.to_vec()), // Rule #2 for type hash?
short_channel_id: c.short_channel_id.map(|v| v.to_string()), // Rule #2 for type short_channel_id?
}
}
@ -2550,7 +2550,7 @@ impl From<pb::ListpeersPeers> for responses::ListpeersPeers {
Self {
id: PublicKey::from_slice(&c.id).unwrap(), // Rule #1 for type pubkey
connected: c.connected, // Rule #1 for type boolean
num_channels: c.num_channels, // Rule #1 for type u32
num_channels: c.num_channels, // Rule #1 for type u32?
log: Some(c.log.into_iter().map(|s| s.into()).collect()), // Rule #4
channels: Some(c.channels.into_iter().map(|s| s.into()).collect()), // Rule #4
netaddr: Some(c.netaddr.into_iter().map(|s| s.into()).collect()), // Rule #4
@ -2597,7 +2597,7 @@ impl From<pb::ListfundsChannels> for responses::ListfundsChannels {
funding_output: c.funding_output, // Rule #1 for type u32
connected: c.connected, // Rule #1 for type boolean
state: c.state.try_into().unwrap(),
channel_id: Sha256::from_slice(&c.channel_id).unwrap(), // Rule #1 for type hash
channel_id: c.channel_id.map(|v| Sha256::from_slice(&v).unwrap()), // Rule #1 for type hash?
short_channel_id: c.short_channel_id.map(|v| cln_rpc::primitives::ShortChannelId::from_str(&v).unwrap()), // Rule #1 for type short_channel_id?
}
}

6
cln-rpc/src/model.rs generated
View file

@ -1728,7 +1728,8 @@ pub mod responses {
pub struct ListpeersPeers {
pub id: PublicKey,
pub connected: bool,
pub num_channels: u32,
#[serde(skip_serializing_if = "Option::is_none")]
pub num_channels: Option<u32>,
#[serde(skip_serializing_if = "crate::is_none_or_empty")]
pub log: Option<Vec<ListpeersPeersLog>>,
#[deprecated]
@ -1809,7 +1810,8 @@ pub mod responses {
pub connected: bool,
// Path `ListFunds.channels[].state`
pub state: ChannelState,
pub channel_id: Sha256,
#[serde(skip_serializing_if = "Option::is_none")]
pub channel_id: Option<Sha256>,
#[serde(skip_serializing_if = "Option::is_none")]
pub short_channel_id: Option<ShortChannelId>,
}

View file

@ -194,7 +194,7 @@ class GrpcGenerator(IGenerator):
if overrides.get(f.path, "") is None:
continue
opt = "optional " if not f.required else ""
opt = "optional " if f.optional else ""
if isinstance(f, ArrayField):
typename = typemap.get(f.itemtype.typename, f.itemtype.typename)
if f.path in overrides:
@ -288,18 +288,18 @@ class GrpcConverterGenerator(IGenerator):
'secret': f'i.to_vec()',
}.get(typ, f'i.into()')
if f.required:
if not f.optional:
self.write(f"{name}: c.{name}.into_iter().map(|i| {mapping}).collect(), // Rule #3 for type {typ}\n", numindent=3)
else:
self.write(f"{name}: c.{name}.map(|arr| arr.into_iter().map(|i| {mapping}).collect()).unwrap_or(vec![]), // Rule #3\n", numindent=3)
elif isinstance(f, EnumField):
if f.required:
if not f.optional:
self.write(f"{name}: c.{name} as i32,\n", numindent=3)
else:
self.write(f"{name}: c.{name}.map(|v| v as i32),\n", numindent=3)
elif isinstance(f, PrimitiveField):
typ = f.typename + ("?" if not f.required else "")
typ = f.typename + ("?" if f.optional else "")
# We may need to reduce or increase the size of some
# types, or have some conversion such as
# hex-decoding. Also includes the `Some()` that grpc
@ -344,7 +344,7 @@ class GrpcConverterGenerator(IGenerator):
elif isinstance(f, CompositeField):
rhs = ""
if f.required:
if not f.optional:
rhs = f'Some(c.{name}.into())'
else:
rhs = f'c.{name}.map(|v| v.into())'
@ -446,7 +446,7 @@ class GrpcUnconverterGenerator(GrpcConverterGenerator):
self.write(f" state_changes: None,")
continue
if f.required:
if not f.optional:
self.write(f"{name}: c.{name}.into_iter().map(|s| {mapping}).collect(), // Rule #4\n", numindent=3)
else:
self.write(f"{name}: Some(c.{name}.into_iter().map(|s| {mapping}).collect()), // Rule #4\n", numindent=3)
@ -454,13 +454,13 @@ class GrpcUnconverterGenerator(GrpcConverterGenerator):
elif isinstance(f, EnumField):
if f.path == 'ListPeers.peers[].channels[].htlcs[].state':
continue
if f.required:
if not f.optional:
self.write(f"{name}: c.{name}.try_into().unwrap(),\n", numindent=3)
else:
self.write(f"{name}: c.{name}.map(|v| v.try_into().unwrap()),\n", numindent=3)
pass
elif isinstance(f, PrimitiveField):
typ = f.typename + ("?" if not f.required else "")
typ = f.typename + ("?" if f.optional else "")
# We may need to reduce or increase the size of some
# types, or have some conversion such as
# hex-decoding. Also includes the `Some()` that grpc
@ -503,7 +503,7 @@ class GrpcUnconverterGenerator(GrpcConverterGenerator):
self.write(f"{name}: {rhs}, // Rule #1 for type {typ}\n", numindent=3)
elif isinstance(f, CompositeField):
rhs = ""
if f.required:
if not f.optional:
rhs = f'c.{name}.unwrap().into()'
else:
rhs = f'c.{name}.map(|v| v.into())'

View file

@ -132,7 +132,7 @@ def gen_enum(e):
decl = "" # No declaration if we have an override
typename = overrides[e.path]
if e.required:
if not e.optional:
defi = f" // Path `{e.path}`\n"
defi += rename_if_necessary(str(e.name), e.name.normalized())
defi += f" pub {e.name.normalized()}: {typename},\n"
@ -152,7 +152,7 @@ def gen_primitive(p):
if p.deprecated:
defi += " #[deprecated]\n"
defi += rename_if_necessary(org, p.name.name)
if p.required:
if not p.optional:
defi += f" pub {p.name}: {typename},\n"
else:
defi += f" #[serde(skip_serializing_if = \"Option::is_none\")]\n pub {p.name}: Option<{typename}>,\n"
@ -191,7 +191,7 @@ def gen_array(a):
if a.deprecated:
defi += " #[deprecated]\n"
defi += rename_if_necessary(alias, name)
if a.required:
if not a.optional:
defi += f" pub {name}: {'Vec<'*a.dims}{itemtype}{'>'*a.dims},\n"
else:
defi += f" #[serde(skip_serializing_if = \"crate::is_none_or_empty\")]\n pub {name}: Option<{'Vec<'*a.dims}{itemtype}{'>'*a.dims}>,\n"
@ -216,7 +216,7 @@ def gen_composite(c) -> Tuple[str, str]:
defi = ""
if c.deprecated:
defi += " #[deprecated]\n"
if c.required:
if not c.optional:
defi += f" pub {c.name}: {c.typename},\n"
else:
defi += f" #[serde(skip_serializing_if = \"Option::is_none\")]\n pub {c.name}: Option<{c.typename}>,\n"

View file

@ -64,17 +64,23 @@ class VersionAnnotationPatch(Patch):
# if f.added is None and 'added' not in m:
# m['added'] = 'pre-v0.10.1'
assert m.get('added', None) is not None or f.added is not None, f"Field {f.path} does not have an `added` annotation"
added = m.get('added', None)
deprecated = m.get('deprecated', None)
assert added or not f.added, f"Field {f.path} does not have an `added` annotation"
# We do not allow the added and deprecated flags to be
# modified after the fact.
assert f.added is None or f.added == m['added']
assert f.deprecated is None or f.deprecated == m.get('deprecated', None)
if f.added and added and f.added != m['added']:
raise ValueError(f"Field {f.path} changed `added` annotation: {f.added} != {m['added']}")
if f.deprecated and deprecated and f.deprecated != deprecated:
raise ValueError(f"Field {f.path} changed `deprecated` annotation: {f.deprecated} != {m['deprecated']}")
if f.added is None:
f.added = m['added']
f.added = added
if f.deprecated is None:
f.deprecated = m.get('deprecated', None)
f.deprecated = deprecated
# Backfill the metadata using the annotation
self.meta['model-field-versions'][f.path] = {

File diff suppressed because one or more lines are too long