1use crate::{
2 load::ModuleLoader,
3 model::{
4 annotations::{
5 Annotation, AnnotationBuilder, AnnotationOnlyBody, AnnotationProperty, HasAnnotations,
6 },
7 check::{find_definition, validate_multiple_method_duplicates, MaybeIncomplete, Validate},
8 identifiers::{Identifier, IdentifierReference},
9 members::Member,
10 modules::Module,
11 values::Value,
12 HasName, HasOptionalBody, HasSourceSpan, References, Span,
13 },
14 stdlib::is_builtin_type_name,
15 store::ModuleStore,
16};
17use std::{
18 collections::{BTreeMap, BTreeSet},
19 fmt::Debug,
20};
21
22use sdml_errors::diagnostics::functions::{
23 dimension_parent_not_entity, source_entity_missing_member, source_entity_not_entity,
24 type_definition_not_found, IdentifierCaseConvention,
25};
26#[cfg(feature = "serde")]
27use serde::{Deserialize, Serialize};
28
29use super::HasMultiMembers;
30
31#[derive(Clone, Debug)]
37#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
38pub struct DimensionDef {
39 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
40 span: Option<Span>,
41 name: Identifier,
42 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
43 body: Option<DimensionBody>,
44}
45
46#[derive(Clone, Debug)]
48#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
49pub struct DimensionBody {
50 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
51 span: Option<Span>,
52 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
53 annotations: Vec<Annotation>,
54 identity: DimensionIdentity,
55 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "BTreeMap::is_empty"))]
56 parents: BTreeMap<Identifier, DimensionParent>,
57 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "BTreeMap::is_empty"))]
58 members: BTreeMap<Identifier, Member>,
59}
60
61#[derive(Clone, Debug)]
63#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
64pub enum DimensionIdentity {
65 Source(SourceEntity),
66 Identity(Member),
67}
68
69#[derive(Clone, Debug)]
71#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
72pub struct DimensionParent {
73 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
74 span: Option<Span>,
75 name: Identifier,
76 target_entity: IdentifierReference,
77 body: Option<AnnotationOnlyBody>,
78}
79
80#[derive(Clone, Debug)]
82#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
83pub struct SourceEntity {
84 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
85 span: Option<Span>,
86 target_entity: IdentifierReference,
87 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
88 with_members: Vec<Identifier>,
89}
90
91impl HasName for DimensionDef {
96 fn name(&self) -> &Identifier {
97 &self.name
98 }
99
100 fn set_name(&mut self, name: Identifier) {
101 self.name = name;
102 }
103}
104
105impl HasOptionalBody for DimensionDef {
106 type Body = DimensionBody;
107
108 fn body(&self) -> Option<&Self::Body> {
109 self.body.as_ref()
110 }
111
112 fn body_mut(&mut self) -> Option<&mut Self::Body> {
113 self.body.as_mut()
114 }
115
116 fn set_body(&mut self, body: Self::Body) {
117 self.body = Some(body);
118 }
119
120 fn unset_body(&mut self) {
121 self.body = None;
122 }
123}
124
125impl HasSourceSpan for DimensionDef {
126 fn with_source_span(self, span: Span) -> Self {
127 let mut self_mut = self;
128 self_mut.span = Some(span);
129 self_mut
130 }
131
132 fn source_span(&self) -> Option<&Span> {
133 self.span.as_ref()
134 }
135
136 fn set_source_span(&mut self, span: Span) {
137 self.span = Some(span);
138 }
139
140 fn unset_source_span(&mut self) {
141 self.span = None;
142 }
143}
144
145impl References for DimensionDef {
146 fn referenced_annotations<'a>(
147 &'a self,
148 names: &mut ::std::collections::BTreeSet<&'a IdentifierReference>,
149 ) {
150 if let Some(inner) = &self.body {
151 inner.referenced_annotations(names);
152 }
153 }
154
155 fn referenced_types<'a>(
156 &'a self,
157 names: &mut ::std::collections::BTreeSet<&'a IdentifierReference>,
158 ) {
159 if let Some(inner) = &self.body {
160 inner.referenced_types(names);
161 }
162 }
163}
164
165impl AnnotationBuilder for DimensionDef {
166 fn with_predicate<I, V>(self, predicate: I, value: V) -> Self
167 where
168 Self: Sized,
169 I: Into<IdentifierReference>,
170 V: Into<Value>,
171 {
172 let mut self_mut = self;
173 if let Some(ref mut inner) = self_mut.body {
174 inner.add_to_annotations(AnnotationProperty::new(predicate.into(), value.into()));
175 }
176 self_mut
177 }
178}
179
180impl MaybeIncomplete for DimensionDef {
181 fn is_incomplete(&self, top: &Module, cache: &impl ModuleStore) -> bool {
182 if let Some(body) = &self.body {
183 body.is_incomplete(top, cache)
184 } else {
185 true
186 }
187 }
188}
189
190impl Validate for DimensionDef {
191 fn validate(
192 &self,
193 top: &Module,
194 cache: &impl ModuleStore,
195 loader: &impl ModuleLoader,
196 check_constraints: bool,
197 ) {
198 self.name
199 .validate(top, loader, Some(IdentifierCaseConvention::TypeDefinition));
200 if let Some(body) = &self.body {
201 body.validate(top, cache, loader, check_constraints);
202 }
203 }
204}
205
206impl DimensionDef {
207 pub fn new(name: Identifier) -> Self {
212 Self {
213 span: None,
214 name,
215 body: None,
216 }
217 }
218
219 pub fn with_body(self, body: DimensionBody) -> Self {
220 let mut self_mut = self;
221 self_mut.body = Some(body);
222 self_mut
223 }
224}
225
226impl HasAnnotations for DimensionBody {
231 fn has_annotations(&self) -> bool {
232 !self.annotations.is_empty()
233 }
234
235 fn annotation_count(&self) -> usize {
236 self.annotations.len()
237 }
238
239 fn annotations(&self) -> impl Iterator<Item = &Annotation> {
240 self.annotations.iter()
241 }
242
243 fn annotations_mut(&mut self) -> impl Iterator<Item = &mut Annotation> {
244 self.annotations.iter_mut()
245 }
246
247 fn add_to_annotations<I>(&mut self, value: I)
248 where
249 I: Into<Annotation>,
250 {
251 self.annotations.push(value.into())
252 }
253
254 fn extend_annotations<I>(&mut self, extension: I)
255 where
256 I: IntoIterator<Item = Annotation>,
257 {
258 self.annotations.extend(extension)
259 }
260}
261
262impl HasSourceSpan for DimensionBody {
263 fn with_source_span(self, span: Span) -> Self {
264 let mut self_mut = self;
265 self_mut.span = Some(span);
266 self_mut
267 }
268
269 fn source_span(&self) -> Option<&Span> {
270 self.span.as_ref()
271 }
272
273 fn set_source_span(&mut self, span: Span) {
274 self.span = Some(span);
275 }
276
277 fn unset_source_span(&mut self) {
278 self.span = None;
279 }
280}
281
282impl MaybeIncomplete for DimensionBody {
283 fn is_incomplete(&self, top: &Module, cache: &impl ModuleStore) -> bool {
284 self.identity().is_incomplete(top, cache)
285 || self.members().any(|elem| elem.is_incomplete(top, cache))
286 }
287}
288
289impl Validate for DimensionBody {
290 fn validate(
291 &self,
292 top: &Module,
293 cache: &impl ModuleStore,
294 loader: &impl ModuleLoader,
295 check_constraints: bool,
296 ) {
297 validate_multiple_method_duplicates(self, top, cache, loader);
298
299 self.identity()
300 .validate(top, cache, loader, check_constraints);
301 self.annotations()
302 .for_each(|m| m.validate(top, cache, loader, check_constraints));
303 self.parents()
304 .for_each(|m| m.validate(top, cache, loader, check_constraints));
305 self.members()
306 .for_each(|m| m.validate(top, cache, loader, check_constraints));
307 }
308}
309
310impl References for DimensionBody {
311 fn referenced_types<'a>(&'a self, names: &mut BTreeSet<&'a IdentifierReference>) {
312 self.identity().referenced_types(names);
313 self.parents().for_each(|m| m.referenced_types(names));
314 self.members().for_each(|m| m.referenced_types(names));
315 }
316
317 fn referenced_annotations<'a>(&'a self, names: &mut BTreeSet<&'a IdentifierReference>) {
318 self.members().for_each(|m| m.referenced_annotations(names));
319 }
320}
321
322impl HasMultiMembers for DimensionBody {
323 fn has_any_members(&self) -> bool {
324 !(self.has_identity() || self.has_parents() || self.has_members())
325 }
326
327 fn contains_any_member(&self, name: &Identifier) -> bool {
328 self.contains_identity(name) || self.contains_parent(name) || self.contains_member(name)
329 }
330
331 fn all_member_count(&self) -> usize {
332 self.identity_count() + self.parent_count() + self.members.len()
333 }
334
335 fn all_member_names(&self) -> impl Iterator<Item = &Identifier> {
336 self.identity_names()
337 .chain(self.parent_names().chain(self.member_names()))
338 }
339}
340
341impl DimensionBody {
342 pub fn new<E>(entity: E) -> Self
347 where
348 E: Into<DimensionIdentity>,
349 {
350 Self {
351 span: Default::default(),
352 annotations: Default::default(),
353 identity: entity.into(),
354 parents: Default::default(),
355 members: Default::default(),
356 }
357 }
358
359 pub fn with_members<I>(self, members: I) -> Self
360 where
361 I: IntoIterator<Item = Member>,
362 {
363 let mut self_mut = self;
364 self_mut.members = members
365 .into_iter()
366 .map(|mem| (mem.name().clone(), mem))
367 .collect();
368 self_mut
369 }
370
371 pub fn with_parents<I>(self, parents: I) -> Self
372 where
373 I: IntoIterator<Item = DimensionParent>,
374 {
375 let mut self_mut = self;
376 self_mut.parents = parents
377 .into_iter()
378 .map(|mem| (mem.name().clone(), mem))
379 .collect();
380 self_mut
381 }
382
383 pub const fn identity(&self) -> &DimensionIdentity {
388 &self.identity
389 }
390
391 pub fn set_identity<T>(&mut self, identity: T)
392 where
393 T: Into<DimensionIdentity>,
394 {
395 self.identity = identity.into();
396 }
397
398 fn has_identity(&self) -> bool {
399 matches!(self.identity, DimensionIdentity::Identity(_))
400 }
401
402 fn identity_count(&self) -> usize {
403 match self.identity() {
404 DimensionIdentity::Source(src) => src.member_count(),
405 DimensionIdentity::Identity(_) => 1,
406 }
407 }
408
409 fn identity_names<'a>(&'a self) -> Box<dyn Iterator<Item = &'a Identifier> + 'a> {
410 match self.identity() {
411 DimensionIdentity::Source(src) => Box::new(src.members()),
412 DimensionIdentity::Identity(id) => Box::new(std::iter::once(id.name())),
413 }
414 }
415
416 fn contains_identity(&self, name: &Identifier) -> bool {
417 match self.identity() {
418 DimensionIdentity::Source(src) => src.contains_member(name),
419 DimensionIdentity::Identity(id) => name == id.name(),
420 }
421 }
422
423 pub fn has_members(&self) -> bool {
428 !self.members.is_empty()
429 }
430
431 pub fn member_count(&self) -> usize {
432 self.members.len()
433 }
434
435 pub fn contains_member(&self, name: &Identifier) -> bool {
436 self.members.contains_key(name)
437 }
438
439 pub fn member(&self, name: &Identifier) -> Option<&Member> {
440 self.members.get(name)
441 }
442
443 pub fn member_mut(&mut self, name: &Identifier) -> Option<&mut Member> {
444 self.members.get_mut(name)
445 }
446
447 pub fn members(&self) -> impl Iterator<Item = &Member> {
448 self.members.values()
449 }
450
451 pub fn members_mut(&mut self) -> impl Iterator<Item = &mut Member> {
452 self.members.values_mut()
453 }
454
455 pub fn member_names(&self) -> impl Iterator<Item = &Identifier> {
456 self.members.keys()
457 }
458
459 pub fn add_to_members(&mut self, value: Member) -> Option<Member> {
460 self.members.insert(value.name().clone(), value)
461 }
462
463 pub fn extend_member<I>(&mut self, extension: I)
464 where
465 I: IntoIterator<Item = Member>,
466 {
467 self.members.extend(
468 extension
469 .into_iter()
470 .map(|elem| (elem.name().clone(), elem)),
471 )
472 }
473
474 pub fn has_parents(&self) -> bool {
479 !self.parents.is_empty()
480 }
481
482 pub fn parent_count(&self) -> usize {
483 self.parents.len()
484 }
485
486 pub fn contains_parent(&self, name: &Identifier) -> bool {
487 self.parents.contains_key(name)
488 }
489
490 pub fn parent(&self, name: &Identifier) -> Option<&DimensionParent> {
491 self.parents.get(name)
492 }
493
494 pub fn parent_mut(&mut self, name: &Identifier) -> Option<&mut DimensionParent> {
495 self.parents.get_mut(name)
496 }
497
498 pub fn parents(&self) -> impl Iterator<Item = &DimensionParent> {
499 self.parents.values()
500 }
501
502 pub fn parents_mut(&mut self) -> impl Iterator<Item = &mut DimensionParent> {
503 self.parents.values_mut()
504 }
505
506 pub fn parent_names(&self) -> impl Iterator<Item = &Identifier> {
507 self.parents.keys()
508 }
509
510 pub fn add_to_parents(&mut self, value: DimensionParent) -> Option<DimensionParent> {
511 self.parents.insert(value.name().clone(), value)
512 }
513
514 pub fn extend_parents<I>(&mut self, extension: I)
515 where
516 I: IntoIterator<Item = DimensionParent>,
517 {
518 self.parents.extend(
519 extension
520 .into_iter()
521 .map(|elem| (elem.name().clone(), elem)),
522 )
523 }
524}
525
526impl From<SourceEntity> for DimensionIdentity {
531 fn from(value: SourceEntity) -> Self {
532 Self::Source(value)
533 }
534}
535
536impl From<&SourceEntity> for DimensionIdentity {
537 fn from(value: &SourceEntity) -> Self {
538 Self::Source(value.clone())
539 }
540}
541
542impl From<Member> for DimensionIdentity {
543 fn from(value: Member) -> Self {
544 Self::Identity(value)
545 }
546}
547
548impl From<&Member> for DimensionIdentity {
549 fn from(value: &Member) -> Self {
550 Self::Identity(value.clone())
551 }
552}
553
554impl References for DimensionIdentity {
555 fn referenced_types<'a>(&'a self, names: &mut BTreeSet<&'a IdentifierReference>) {
556 match self {
557 DimensionIdentity::Source(v) => v.referenced_types(names),
558 DimensionIdentity::Identity(v) => v.referenced_types(names),
559 }
560 }
561}
562
563impl MaybeIncomplete for DimensionIdentity {
564 fn is_incomplete(&self, top: &Module, cache: &impl ModuleStore) -> bool {
565 match self {
566 Self::Source(_) => false,
567 Self::Identity(member) => member.is_incomplete(top, cache),
568 }
569 }
570}
571
572impl Validate for DimensionIdentity {
573 fn validate(
574 &self,
575 top: &Module,
576 cache: &impl ModuleStore,
577 loader: &impl ModuleLoader,
578 check_constraints: bool,
579 ) {
580 match self {
581 Self::Source(src) => src.validate(top, cache, loader, check_constraints),
582 Self::Identity(member) => member.validate(top, cache, loader, check_constraints),
583 }
584 }
585}
586
587impl DimensionIdentity {
588 pub const fn is_source_entity(&self) -> bool {
593 matches!(self, Self::Source(_))
594 }
595
596 pub const fn as_source_entity(&self) -> Option<&SourceEntity> {
597 match self {
598 Self::Source(v) => Some(v),
599 _ => None,
600 }
601 }
602
603 pub const fn is_identity_member(&self) -> bool {
604 matches!(self, Self::Identity(_))
605 }
606
607 pub const fn as_identity_member(&self) -> Option<&Member> {
608 match self {
609 Self::Identity(v) => Some(v),
610 _ => None,
611 }
612 }
613}
614
615impl HasName for DimensionParent {
620 fn name(&self) -> &Identifier {
621 &self.name
622 }
623
624 fn set_name(&mut self, name: Identifier) {
625 self.name = name;
626 }
627}
628
629impl HasSourceSpan for DimensionParent {
630 fn with_source_span(self, span: Span) -> Self {
631 let mut self_mut = self;
632 self_mut.span = Some(span);
633 self_mut
634 }
635
636 fn source_span(&self) -> Option<&Span> {
637 self.span.as_ref()
638 }
639
640 fn set_source_span(&mut self, span: Span) {
641 self.span = Some(span);
642 }
643
644 fn unset_source_span(&mut self) {
645 self.span = None;
646 }
647}
648
649impl HasOptionalBody for DimensionParent {
650 type Body = AnnotationOnlyBody;
651
652 fn body(&self) -> Option<&Self::Body> {
653 self.body.as_ref()
654 }
655
656 fn body_mut(&mut self) -> Option<&mut Self::Body> {
657 self.body.as_mut()
658 }
659
660 fn set_body(&mut self, body: Self::Body) {
661 self.body = Some(body);
662 }
663
664 fn unset_body(&mut self) {
665 self.body = None;
666 }
667}
668
669impl References for DimensionParent {
670 fn referenced_types<'a>(&'a self, names: &mut BTreeSet<&'a IdentifierReference>) {
671 names.insert(self.target_entity());
672 }
673}
674
675impl Validate for DimensionParent {
676 fn validate(
677 &self,
678 top: &Module,
679 cache: &impl ModuleStore,
680 loader: &impl ModuleLoader,
681 _: bool,
682 ) {
683 let name = self.target_entity();
684 if let Some(defn) = find_definition(name, top, cache) {
685 if !defn.is_entity() {
686 loader
687 .report(&dimension_parent_not_entity(
688 top.file_id().copied().unwrap_or_default(),
689 name.source_span().as_ref().map(|span| (*span).into()),
690 name,
691 ))
692 .unwrap();
693 }
694 } else {
695 if !name
696 .as_identifier()
697 .map(is_builtin_type_name)
698 .unwrap_or_default()
699 {
700 loader
701 .report(&type_definition_not_found(
702 top.file_id().copied().unwrap_or_default(),
703 name.source_span().as_ref().map(|span| (*span).into()),
704 name,
705 ))
706 .unwrap();
707 } else {
708 loader
709 .report(&dimension_parent_not_entity(
710 top.file_id().copied().unwrap_or_default(),
711 name.source_span().as_ref().map(|span| (*span).into()),
712 name,
713 ))
714 .unwrap();
715 }
716 }
717 }
718}
719
720impl DimensionParent {
721 pub fn new<I>(name: Identifier, target_entity: I) -> Self
726 where
727 I: Into<IdentifierReference>,
728 {
729 Self {
730 span: Default::default(),
731 name,
732 target_entity: target_entity.into(),
733 body: Default::default(),
734 }
735 }
736
737 pub fn with_body(self, body: AnnotationOnlyBody) -> Self {
738 let mut self_mut = self;
739 self_mut.body = Some(body);
740 self_mut
741 }
742
743 pub const fn target_entity(&self) -> &IdentifierReference {
748 &self.target_entity
749 }
750
751 pub fn set_target_entity<T>(&mut self, target_entity: T)
752 where
753 T: Into<IdentifierReference>,
754 {
755 self.target_entity = target_entity.into();
756 }
757}
758
759impl From<IdentifierReference> for SourceEntity {
764 fn from(value: IdentifierReference) -> Self {
765 Self::new(value)
766 }
767}
768
769impl From<&IdentifierReference> for SourceEntity {
770 fn from(value: &IdentifierReference) -> Self {
771 Self::new(value.clone())
772 }
773}
774
775impl HasSourceSpan for SourceEntity {
776 fn with_source_span(self, span: Span) -> Self {
777 let mut self_mut = self;
778 self_mut.span = Some(span);
779 self_mut
780 }
781
782 fn source_span(&self) -> Option<&Span> {
783 self.span.as_ref()
784 }
785
786 fn set_source_span(&mut self, span: Span) {
787 self.span = Some(span);
788 }
789
790 fn unset_source_span(&mut self) {
791 self.span = None;
792 }
793}
794
795impl Validate for SourceEntity {
796 fn validate(
797 &self,
798 top: &Module,
799 cache: &impl ModuleStore,
800 loader: &impl ModuleLoader,
801 _check_constraints: bool,
802 ) {
803 let name = self.target_entity();
804 if let Some(defn) = find_definition(name, top, cache) {
805 if let Some(entity) = defn.as_entity() {
806 match (self.has_members(), entity.body()) {
807 (true, Some(body)) => {
808 for member in self.members() {
809 if !body.contains_member(member) {
810 loader
811 .report(&source_entity_missing_member(
812 top.file_id().copied().unwrap_or_default(),
813 name.source_span().as_ref().map(|span| (*span).into()),
814 name,
815 ))
816 .unwrap();
817 }
818 }
819 }
820 (true, None) => {
821 for name in self.members() {
822 loader
823 .report(&source_entity_missing_member(
824 top.file_id().copied().unwrap_or_default(),
825 name.source_span().as_ref().map(|span| (*span).into()),
826 name,
827 ))
828 .unwrap();
829 }
830 }
831 (false, _) => (),
832 }
833 } else {
834 loader
835 .report(&source_entity_not_entity(
836 top.file_id().copied().unwrap_or_default(),
837 name.source_span().as_ref().map(|span| (*span).into()),
838 name,
839 ))
840 .unwrap();
841 }
842 } else {
843 if !name
844 .as_identifier()
845 .map(is_builtin_type_name)
846 .unwrap_or_default()
847 {
848 loader
849 .report(&type_definition_not_found(
850 top.file_id().copied().unwrap_or_default(),
851 name.source_span().as_ref().map(|span| (*span).into()),
852 name,
853 ))
854 .unwrap();
855 } else {
856 loader
857 .report(&source_entity_not_entity(
858 top.file_id().copied().unwrap_or_default(),
859 name.source_span().as_ref().map(|span| (*span).into()),
860 name,
861 ))
862 .unwrap();
863 }
864 }
865 }
866}
867
868impl References for SourceEntity {
869 fn referenced_types<'a>(&'a self, names: &mut BTreeSet<&'a IdentifierReference>) {
870 names.insert(self.target_entity());
871 }
872}
873
874impl SourceEntity {
875 pub fn new<T>(target_entity: T) -> Self
880 where
881 T: Into<IdentifierReference>,
882 {
883 Self {
884 span: Default::default(),
885 target_entity: target_entity.into(),
886 with_members: Default::default(),
887 }
888 }
889
890 pub fn with_members<I>(self, members: I) -> Self
891 where
892 I: IntoIterator<Item = Identifier>,
893 {
894 let mut self_mut = self;
895 self_mut.with_members = members.into_iter().collect();
896 self_mut
897 }
898
899 pub const fn target_entity(&self) -> &IdentifierReference {
904 &self.target_entity
905 }
906
907 pub fn set_target_entity<T>(&mut self, target_entity: T)
908 where
909 T: Into<IdentifierReference>,
910 {
911 self.target_entity = target_entity.into();
912 }
913
914 pub fn has_members(&self) -> bool {
917 !self.with_members.is_empty()
918 }
919
920 pub fn member_count(&self) -> usize {
921 self.with_members.len()
922 }
923
924 pub fn contains_member(&self, name: &Identifier) -> bool {
925 self.members().any(|n| n == name)
926 }
927
928 pub fn members(&self) -> impl Iterator<Item = &Identifier> {
929 self.with_members.iter()
930 }
931
932 pub fn members_mut(&mut self) -> impl Iterator<Item = &mut Identifier> {
933 self.with_members.iter_mut()
934 }
935
936 pub fn add_to_members<I>(&mut self, value: I)
937 where
938 I: Into<Identifier>,
939 {
940 self.with_members.push(value.into())
941 }
942
943 pub fn extend_members<I>(&mut self, extension: I)
944 where
945 I: IntoIterator<Item = Identifier>,
946 {
947 self.with_members.extend(extension)
948 }
949}