Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

127 changes: 69 additions & 58 deletions codama-attributes/src/codama_directives/account_directive.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
use crate::{
utils::{FromMeta, SetOnce},
Attribute, AttributeContext, CodamaAttribute, CodamaDirective,
Attribute, AttributeContext, CodamaAttribute, CodamaDirective, Resolvable,
};
use codama_errors::CodamaError;
use codama_errors::{CodamaError, CodamaResult};
use codama_nodes::{
CamelCaseString, Docs, InstructionAccountNode, InstructionInputValueNode, IsAccountSigner,
};
use codama_syn_helpers::{extensions::*, Meta};

#[derive(Debug, PartialEq)]
pub struct AccountDirective {
pub account: InstructionAccountNode,
pub name: CamelCaseString,
pub is_writable: bool,
pub is_signer: IsAccountSigner,
pub is_optional: bool,
pub docs: Docs,
pub default_value: Option<Resolvable<InstructionInputValueNode>>,
}

impl AccountDirective {
Expand All @@ -26,7 +31,8 @@ impl AccountDirective {
let mut is_writable = SetOnce::<bool>::new("writable").initial_value(false);
let mut is_signer = SetOnce::<IsAccountSigner>::new("signer").initial_value(false.into());
let mut is_optional = SetOnce::<bool>::new("optional").initial_value(false);
let mut default_value = SetOnce::<InstructionInputValueNode>::new("default_value");
let mut default_value =
SetOnce::<Resolvable<InstructionInputValueNode>>::new("default_value");
let mut docs = SetOnce::<Docs>::new("docs");
match meta.is_path_or_empty_list() {
true => (),
Expand All @@ -38,22 +44,37 @@ impl AccountDirective {
"signer" => is_signer.set(IsAccountSigner::from_meta(meta)?, meta),
"optional" => is_optional.set(bool::from_meta(meta)?, meta),
"default_value" => default_value.set(
InstructionInputValueNode::from_meta(meta.as_value()?)?,
Resolvable::<InstructionInputValueNode>::from_meta(meta.as_value()?)?,
meta,
),
"docs" => docs.set(Docs::from_meta(meta)?, meta),
_ => Err(meta.error("unrecognized attribute")),
})?,
}
Ok(AccountDirective {
account: InstructionAccountNode {
name: name.take(meta)?,
is_writable: is_writable.take(meta)?,
is_signer: is_signer.take(meta)?,
is_optional: is_optional.take(meta)?,
docs: docs.option().unwrap_or_default(),
default_value: default_value.option(),
},
name: name.take(meta)?,
is_writable: is_writable.take(meta)?,
is_signer: is_signer.take(meta)?,
is_optional: is_optional.take(meta)?,
docs: docs.option().unwrap_or_default(),
default_value: default_value.option(),
})
}

/// Construct an `InstructionAccountNode` from this directive.
/// Returns an error if any unresolved directives remain.
pub fn to_instruction_account_node(&self) -> CodamaResult<InstructionAccountNode> {
Ok(InstructionAccountNode {
name: self.name.clone(),
is_writable: self.is_writable,
is_signer: self.is_signer,
is_optional: self.is_optional,
docs: self.docs.clone(),
default_value: self
.default_value
.as_ref()
.map(|r| r.try_resolved().cloned())
.transpose()?,
})
}
}
Expand Down Expand Up @@ -94,14 +115,12 @@ mod tests {
assert_eq!(
directive,
AccountDirective {
account: InstructionAccountNode {
name: "payer".into(),
is_writable: true,
is_signer: IsAccountSigner::True,
is_optional: true,
default_value: Some(PayerValueNode::new().into()),
docs: Docs::default(),
},
name: "payer".into(),
is_writable: true,
is_signer: IsAccountSigner::True,
is_optional: true,
default_value: Some(Resolvable::Resolved(PayerValueNode::new().into())),
docs: Docs::default(),
}
);
}
Expand All @@ -121,14 +140,12 @@ mod tests {
assert_eq!(
directive,
AccountDirective {
account: InstructionAccountNode {
name: "payer".into(),
is_writable: true,
is_signer: IsAccountSigner::Either,
is_optional: false,
default_value: Some(PayerValueNode::new().into()),
docs: Docs::default(),
},
name: "payer".into(),
is_writable: true,
is_signer: IsAccountSigner::Either,
is_optional: false,
default_value: Some(Resolvable::Resolved(PayerValueNode::new().into())),
docs: Docs::default(),
}
);
}
Expand All @@ -142,14 +159,12 @@ mod tests {
assert_eq!(
directive,
AccountDirective {
account: InstructionAccountNode {
name: "authority".into(),
is_writable: false,
is_signer: IsAccountSigner::False,
is_optional: false,
default_value: None,
docs: Docs::default(),
},
name: "authority".into(),
is_writable: false,
is_signer: IsAccountSigner::False,
is_optional: false,
default_value: None,
docs: Docs::default(),
}
);
}
Expand All @@ -172,14 +187,12 @@ mod tests {
assert_eq!(
directive,
AccountDirective {
account: InstructionAccountNode {
name: "stake".into(),
is_writable: true,
is_signer: IsAccountSigner::False,
is_optional: false,
default_value: None,
docs: vec!["what this account is for".to_string()].into(),
},
name: "stake".into(),
is_writable: true,
is_signer: IsAccountSigner::False,
is_optional: false,
default_value: None,
docs: vec!["what this account is for".to_string()].into(),
}
);
}
Expand All @@ -193,19 +206,17 @@ mod tests {
assert_eq!(
directive,
AccountDirective {
account: InstructionAccountNode {
name: "authority".into(),
is_writable: false,
is_signer: IsAccountSigner::True,
is_optional: false,
default_value: None,
docs: vec![
"Line 1".to_string(),
"Line 2".to_string(),
"Line 3".to_string()
]
.into(),
},
name: "authority".into(),
is_writable: false,
is_signer: IsAccountSigner::True,
is_optional: false,
default_value: None,
docs: vec![
"Line 1".to_string(),
"Line 2".to_string(),
"Line 3".to_string()
]
.into(),
}
);
}
Expand Down
68 changes: 49 additions & 19 deletions codama-attributes/src/codama_directives/argument_directive.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
use crate::{
codama_directives::type_nodes::StructFieldMetaConsumer,
utils::{FromMeta, MetaConsumer},
Attribute, CodamaAttribute, CodamaDirective,
Attribute, CodamaAttribute, CodamaDirective, Resolvable,
};
use codama_errors::{CodamaError, CodamaResult};
use codama_nodes::{
CamelCaseString, DefaultValueStrategy, Docs, InstructionArgumentNode,
InstructionInputValueNode, TypeNode,
};
use codama_errors::CodamaError;
use codama_nodes::InstructionArgumentNode;
use codama_syn_helpers::Meta;

#[derive(Debug, PartialEq)]
pub struct ArgumentDirective {
pub after: bool,
pub argument: InstructionArgumentNode,
pub name: CamelCaseString,
pub r#type: Resolvable<TypeNode>,
pub docs: Docs,
pub default_value: Option<Resolvable<InstructionInputValueNode>>,
pub default_value_strategy: Option<DefaultValueStrategy>,
}

impl ArgumentDirective {
Expand All @@ -27,13 +34,27 @@ impl ArgumentDirective {

Ok(ArgumentDirective {
after: consumer.after.option().unwrap_or(false),
argument: InstructionArgumentNode {
name: consumer.name.take(meta)?,
r#type: consumer.r#type.take(meta)?,
docs: consumer.docs.option().unwrap_or_default(),
default_value,
default_value_strategy,
},
name: consumer.name.take(meta)?,
r#type: consumer.r#type.take(meta)?,
docs: consumer.docs.option().unwrap_or_default(),
default_value,
default_value_strategy,
})
}

/// Construct an `InstructionArgumentNode` from this directive.
/// Returns an error if any unresolved directives remain.
pub fn to_instruction_argument_node(&self) -> CodamaResult<InstructionArgumentNode> {
Ok(InstructionArgumentNode {
name: self.name.clone(),
r#type: self.r#type.try_resolved()?.clone(),
docs: self.docs.clone(),
default_value: self
.default_value
.as_ref()
.map(|r| r.try_resolved().cloned())
.transpose()?,
default_value_strategy: self.default_value_strategy,
})
}
}
Expand Down Expand Up @@ -73,7 +94,11 @@ mod tests {
directive,
ArgumentDirective {
after: false,
argument: InstructionArgumentNode::new("age", NumberTypeNode::le(U8)),
name: "age".into(),
r#type: Resolvable::Resolved(NumberTypeNode::le(U8).into()),
docs: Docs::default(),
default_value: None,
default_value_strategy: None,
}
);
}
Expand All @@ -86,7 +111,11 @@ mod tests {
directive,
ArgumentDirective {
after: true,
argument: InstructionArgumentNode::new("age", NumberTypeNode::le(U8)),
name: "age".into(),
r#type: Resolvable::Resolved(NumberTypeNode::le(U8).into()),
docs: Docs::default(),
default_value: None,
default_value_strategy: None,
}
);
}
Expand All @@ -99,10 +128,11 @@ mod tests {
directive,
ArgumentDirective {
after: false,
argument: InstructionArgumentNode {
default_value: Some(PayerValueNode::new().into()),
..InstructionArgumentNode::new("age", NumberTypeNode::le(U8))
},
name: "age".into(),
r#type: Resolvable::Resolved(NumberTypeNode::le(U8).into()),
docs: Docs::default(),
default_value: Some(Resolvable::Resolved(PayerValueNode::new().into())),
default_value_strategy: None,
}
);
}
Expand All @@ -111,15 +141,15 @@ mod tests {
fn with_docs_string() {
let meta: Meta = syn::parse_quote! { argument("cake", number(u8), docs = "The cake") };
let directive = ArgumentDirective::parse(&meta).unwrap();
assert_eq!(directive.argument.docs, vec!["The cake".to_string()].into());
assert_eq!(directive.docs, vec!["The cake".to_string()].into());
}

#[test]
fn with_docs_array() {
let meta: Meta = syn::parse_quote! { argument("cake", number(u8), docs = ["The cake", "must be a lie"]) };
let directive = ArgumentDirective::parse(&meta).unwrap();
assert_eq!(
directive.argument.docs,
directive.docs,
vec!["The cake".to_string(), "must be a lie".to_string()].into()
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use crate::{utils::FromMeta, Attribute, CodamaAttribute, CodamaDirective};
use crate::{Attribute, CodamaAttribute, CodamaDirective, Resolvable};
use codama_errors::CodamaError;
use codama_nodes::{DefaultValueStrategy, InstructionInputValueNode, ValueNode};
use codama_syn_helpers::{extensions::*, Meta};

#[derive(Debug, PartialEq)]
pub struct DefaultValueDirective {
pub node: InstructionInputValueNode,
pub node: Resolvable<InstructionInputValueNode>,
pub default_value_strategy: Option<DefaultValueStrategy>,
}

Expand All @@ -29,8 +29,10 @@ impl DefaultValueDirective {
};

let node = match value_nodes_only {
true => ValueNode::from_meta(&pv.value)?.into(),
false => InstructionInputValueNode::from_meta(&pv.value)?,
true => {
Resolvable::<ValueNode>::from_meta(&pv.value)?.map(InstructionInputValueNode::from)
}
false => Resolvable::<InstructionInputValueNode>::from_meta(&pv.value)?,
};

let default_value_strategy = match is_value {
Expand Down Expand Up @@ -81,7 +83,7 @@ mod tests {
assert_eq!(
directive,
DefaultValueDirective {
node: PayerValueNode::new().into(),
node: Resolvable::Resolved(PayerValueNode::new().into()),
default_value_strategy: None,
}
);
Expand All @@ -95,7 +97,7 @@ mod tests {
assert_eq!(
directive,
DefaultValueDirective {
node: PayerValueNode::new().into(),
node: Resolvable::Resolved(PayerValueNode::new().into()),
default_value_strategy: Some(DefaultValueStrategy::Omitted),
}
);
Expand All @@ -109,7 +111,7 @@ mod tests {
assert_eq!(
directive,
DefaultValueDirective {
node: BooleanValueNode::new(true).into(),
node: Resolvable::Resolved(BooleanValueNode::new(true).into()),
default_value_strategy: Some(DefaultValueStrategy::Omitted),
}
);
Expand Down
Loading
Loading