Skip to main content

links_notation/
lib.rs

1pub mod format_config;
2pub mod parser;
3
4use format_config::FormatConfig;
5
6// Re-export the lino! macro when the macro feature is enabled
7#[cfg(feature = "macro")]
8pub use links_notation_macro::lino;
9use std::error::Error as StdError;
10use std::fmt;
11
12/// Error type for Lino parsing
13#[derive(Debug)]
14pub enum ParseError {
15    /// Input string is empty or contains only whitespace
16    EmptyInput,
17    /// Syntax error during parsing
18    SyntaxError(String),
19    /// Internal parser error
20    InternalError(String),
21}
22
23impl fmt::Display for ParseError {
24    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25        match self {
26            ParseError::EmptyInput => write!(f, "Empty input"),
27            ParseError::SyntaxError(msg) => write!(f, "Syntax error: {}", msg),
28            ParseError::InternalError(msg) => write!(f, "Internal error: {}", msg),
29        }
30    }
31}
32
33impl StdError for ParseError {}
34
35#[derive(Debug, Clone, PartialEq)]
36pub enum LiNo<T> {
37    Link { id: Option<T>, values: Vec<Self> },
38    Ref(T),
39}
40
41impl<T> LiNo<T> {
42    pub fn is_ref(&self) -> bool {
43        matches!(self, LiNo::Ref(_))
44    }
45
46    pub fn is_link(&self) -> bool {
47        matches!(self, LiNo::Link { .. })
48    }
49
50    /// Creates a new link with the given ID and values.
51    ///
52    /// This method allows creating links with any number of values,
53    /// providing an alternative to tuple conversion for cases where
54    /// more than 12 values are needed.
55    ///
56    /// # Examples
57    /// ```
58    /// use links_notation::LiNo;
59    ///
60    /// // Create a link with many values
61    /// let values: Vec<LiNo<String>> = (1..=20)
62    ///     .map(|i| LiNo::Ref(format!("v{}", i)))
63    ///     .collect();
64    /// let link = LiNo::new(Some("id".to_string()), values);
65    /// ```
66    pub fn new(id: Option<T>, values: Vec<Self>) -> Self {
67        LiNo::Link { id, values }
68    }
69
70    /// Creates a new anonymous link (no ID) with the given values.
71    ///
72    /// # Examples
73    /// ```
74    /// use links_notation::LiNo;
75    ///
76    /// let values = vec![LiNo::Ref("a".to_string()), LiNo::Ref("b".to_string())];
77    /// let link = LiNo::anonymous(values);
78    /// assert_eq!(format!("{}", link), "(a b)");
79    /// ```
80    pub fn anonymous(values: Vec<Self>) -> Self {
81        LiNo::Link { id: None, values }
82    }
83
84    /// Creates a new reference.
85    ///
86    /// # Examples
87    /// ```
88    /// use links_notation::LiNo;
89    ///
90    /// let r: LiNo<String> = LiNo::reference("hello".to_string());
91    /// assert_eq!(format!("{}", r), "hello");
92    /// ```
93    pub fn reference(value: T) -> Self {
94        LiNo::Ref(value)
95    }
96}
97
98/// Builder for creating LiNo links with arbitrary number of values.
99///
100/// This builder provides a fluent API for constructing links when the tuple
101/// conversion (limited to 12 elements) is insufficient.
102///
103/// # Examples
104/// ```
105/// use links_notation::{LiNo, LiNoBuilder};
106///
107/// // Build a link with many string values
108/// let link: LiNo<String> = LiNoBuilder::new()
109///     .id("myLink")
110///     .value("v1")
111///     .value("v2")
112///     .value("v3")
113///     .build();
114/// assert_eq!(format!("{}", link), "(myLink: v1 v2 v3)");
115///
116/// // Build a link with LiNo values
117/// let nested: LiNo<String> = ("inner", "a", "b").into();
118/// let link: LiNo<String> = LiNoBuilder::new()
119///     .id("outer")
120///     .lino(nested)
121///     .value("c")
122///     .build();
123/// assert_eq!(format!("{}", link), "(outer: (inner: a b) c)");
124///
125/// // Build anonymous link
126/// let link: LiNo<String> = LiNoBuilder::new()
127///     .value("a")
128///     .value("b")
129///     .build();
130/// assert_eq!(format!("{}", link), "(a b)");
131/// ```
132#[derive(Debug, Clone, Default)]
133pub struct LiNoBuilder {
134    id: Option<String>,
135    values: Vec<LiNo<String>>,
136}
137
138impl LiNoBuilder {
139    /// Creates a new empty LiNoBuilder.
140    pub fn new() -> Self {
141        Self::default()
142    }
143
144    /// Sets the ID of the link.
145    ///
146    /// If called multiple times, the last value wins.
147    pub fn id(mut self, id: &str) -> Self {
148        self.id = Some(id.to_string());
149        self
150    }
151
152    /// Adds a string value to the link (converted to a Ref).
153    pub fn value(mut self, value: &str) -> Self {
154        self.values.push(LiNo::Ref(value.to_string()));
155        self
156    }
157
158    /// Adds a LiNo value to the link.
159    pub fn lino(mut self, value: LiNo<String>) -> Self {
160        self.values.push(value);
161        self
162    }
163
164    /// Adds multiple string values to the link.
165    pub fn values<I, S>(mut self, values: I) -> Self
166    where
167        I: IntoIterator<Item = S>,
168        S: AsRef<str>,
169    {
170        for v in values {
171            self.values.push(LiNo::Ref(v.as_ref().to_string()));
172        }
173        self
174    }
175
176    /// Adds multiple LiNo values to the link.
177    pub fn linos<I>(mut self, values: I) -> Self
178    where
179        I: IntoIterator<Item = LiNo<String>>,
180    {
181        self.values.extend(values);
182        self
183    }
184
185    /// Builds the final LiNo link.
186    pub fn build(self) -> LiNo<String> {
187        LiNo::Link {
188            id: self.id,
189            values: self.values,
190        }
191    }
192}
193
194/// Type alias for backward compatibility (deprecated).
195#[deprecated(since = "0.3.0", note = "Use LiNoBuilder instead")]
196pub type LinkBuilder = LiNoBuilder;
197
198impl<T: ToString + Clone> LiNo<T> {
199    /// Format the link using FormatConfig configuration.
200    ///
201    /// # Arguments
202    /// * `config` - The FormatConfig to use for formatting
203    ///
204    /// # Returns
205    /// Formatted string representation
206    pub fn format_with_config(&self, config: &FormatConfig) -> String {
207        match self {
208            LiNo::Ref(value) => {
209                let escaped = escape_reference(&value.to_string());
210                if config.less_parentheses {
211                    escaped
212                } else {
213                    format!("({})", escaped)
214                }
215            }
216            LiNo::Link { id, values } => {
217                // Empty link
218                if id.is_none() && values.is_empty() {
219                    return if config.less_parentheses {
220                        String::new()
221                    } else {
222                        "()".to_string()
223                    };
224                }
225
226                // Link with only ID, no values
227                if values.is_empty() {
228                    if let Some(ref id_val) = id {
229                        let escaped_id = escape_reference(&id_val.to_string());
230                        return if config.less_parentheses && !needs_parentheses(&id_val.to_string())
231                        {
232                            escaped_id
233                        } else {
234                            format!("({})", escaped_id)
235                        };
236                    }
237                    return if config.less_parentheses {
238                        String::new()
239                    } else {
240                        "()".to_string()
241                    };
242                }
243
244                // Check if we should use indented format
245                let mut should_indent = false;
246                if config.should_indent_by_ref_count(values.len()) {
247                    should_indent = true;
248                } else {
249                    // Try inline format first to check line length
250                    let values_str = values
251                        .iter()
252                        .map(|v| format_value(v))
253                        .collect::<Vec<_>>()
254                        .join(" ");
255
256                    let test_line = if let Some(ref id_val) = id {
257                        let id_str = escape_reference(&id_val.to_string());
258                        if config.less_parentheses {
259                            format!("{}: {}", id_str, values_str)
260                        } else {
261                            format!("({}: {})", id_str, values_str)
262                        }
263                    } else if config.less_parentheses {
264                        values_str.clone()
265                    } else {
266                        format!("({})", values_str)
267                    };
268
269                    if config.should_indent_by_length(&test_line) {
270                        should_indent = true;
271                    }
272                }
273
274                // Format with indentation if needed
275                if should_indent && !config.prefer_inline {
276                    return self.format_indented(config);
277                }
278
279                // Standard inline formatting
280                let values_str = values
281                    .iter()
282                    .map(|v| format_value(v))
283                    .collect::<Vec<_>>()
284                    .join(" ");
285
286                // Link with values only (null id)
287                if id.is_none() {
288                    if config.less_parentheses {
289                        // Check if all values are simple (no nested values)
290                        let all_simple = values.iter().all(|v| matches!(v, LiNo::Ref(_)));
291                        if all_simple {
292                            return values
293                                .iter()
294                                .map(|v| match v {
295                                    LiNo::Ref(r) => escape_reference(&r.to_string()),
296                                    _ => format_value(v),
297                                })
298                                .collect::<Vec<_>>()
299                                .join(" ");
300                        }
301                        return values_str;
302                    }
303                    return format!("({})", values_str);
304                }
305
306                // Link with ID and values
307                let id_str = escape_reference(&id.as_ref().unwrap().to_string());
308                let with_colon = format!("{}: {}", id_str, values_str);
309                if config.less_parentheses && !needs_parentheses(&id.as_ref().unwrap().to_string())
310                {
311                    with_colon
312                } else {
313                    format!("({})", with_colon)
314                }
315            }
316        }
317    }
318
319    /// Format the link with indentation.
320    fn format_indented(&self, config: &FormatConfig) -> String {
321        match self {
322            LiNo::Ref(value) => {
323                let escaped = escape_reference(&value.to_string());
324                format!("({})", escaped)
325            }
326            LiNo::Link { id, values } => {
327                if id.is_none() {
328                    // Values only - format each on separate line
329                    values
330                        .iter()
331                        .map(|v| format!("{}{}", config.indent_string, format_value(v)))
332                        .collect::<Vec<_>>()
333                        .join("\n")
334                } else {
335                    // Link with ID - format as id:\n  value1\n  value2
336                    let id_str = escape_reference(&id.as_ref().unwrap().to_string());
337                    let mut lines = vec![format!("{}:", id_str)];
338                    for v in values {
339                        lines.push(format!("{}{}", config.indent_string, format_value(v)));
340                    }
341                    lines.join("\n")
342                }
343            }
344        }
345    }
346}
347
348impl<T: ToString> fmt::Display for LiNo<T> {
349    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
350        match self {
351            LiNo::Ref(value) => write!(f, "{}", value.to_string()),
352            LiNo::Link { id, values } => {
353                let id_str = id
354                    .as_ref()
355                    .map(|id| format!("{}: ", id.to_string()))
356                    .unwrap_or_default();
357
358                if f.alternate() {
359                    // Format top-level as lines
360                    let lines = values
361                        .iter()
362                        .map(|value| {
363                            // For alternate formatting, ensure standalone references are wrapped in parentheses
364                            // so that flattened structures like indented blocks render as "(ref)" lines
365                            match value {
366                                LiNo::Ref(_) => format!("{}({})", id_str, value),
367                                _ => format!("{}{}", id_str, value),
368                            }
369                        })
370                        .collect::<Vec<_>>()
371                        .join("\n");
372                    write!(f, "{}", lines)
373                } else {
374                    let values_str = values
375                        .iter()
376                        .map(|value| value.to_string())
377                        .collect::<Vec<_>>()
378                        .join(" ");
379                    write!(f, "({}{})", id_str, values_str)
380                }
381            }
382        }
383    }
384}
385
386// Convert from parser::Link to LiNo (without flattening)
387impl From<parser::Link> for LiNo<String> {
388    fn from(link: parser::Link) -> Self {
389        if let Some(body) = &link.nested {
390            return transform_nested(body);
391        }
392        if link.values.is_empty() && link.children.is_empty() {
393            if let Some(id) = link.id {
394                LiNo::Ref(id)
395            } else {
396                LiNo::Link {
397                    id: None,
398                    values: vec![],
399                }
400            }
401        } else {
402            let values: Vec<LiNo<String>> = link.values.into_iter().map(|v| v.into()).collect();
403            LiNo::Link {
404                id: link.id,
405                values,
406            }
407        }
408    }
409}
410
411// A parenthesized group is a nested document: its body follows the same rules as
412// the root, so it is flattened the same way. A body that produces a single link
413// collapses to that link, unless the body is a single parenthesized group, which
414// keeps `((a b))` different from `(a b)`.
415fn transform_nested(body: &[parser::Link]) -> LiNo<String> {
416    let links = flatten_links(body.to_vec());
417    let wraps_single_group =
418        body.len() == 1 && body[0].nested.is_some() && body[0].children.is_empty();
419    if links.len() == 1 && !wraps_single_group {
420        return links.into_iter().next().unwrap();
421    }
422    LiNo::Link {
423        id: None,
424        values: links,
425    }
426}
427
428// Helper function to flatten indented structures according to Lino spec
429fn flatten_links(links: Vec<parser::Link>) -> Vec<LiNo<String>> {
430    let mut result = vec![];
431
432    for link in links {
433        flatten_link_recursive(&link, None, &mut result);
434    }
435
436    result
437}
438
439fn flatten_link_recursive(
440    link: &parser::Link,
441    parent: Option<&LiNo<String>>,
442    result: &mut Vec<LiNo<String>>,
443) {
444    // Special case: If this is an indented ID (with colon) with children,
445    // the children should become the values of the link (indented ID syntax)
446    if link.is_indented_id
447        && link.id.is_some()
448        && link.values.is_empty()
449        && !link.children.is_empty()
450    {
451        let child_values: Vec<LiNo<String>> = link
452            .children
453            .iter()
454            .map(|child| {
455                // For indented children, if they have single values, extract them
456                if child.values.len() == 1
457                    && child.values[0].values.is_empty()
458                    && child.values[0].children.is_empty()
459                {
460                    // Use if let to safely extract the ID instead of unwrap()
461                    if let Some(ref id) = child.values[0].id {
462                        LiNo::Ref(id.clone())
463                    } else {
464                        // If no ID, create an empty link
465                        parser::Link {
466                            id: child.id.clone(),
467                            values: child.values.clone(),
468                            children: vec![],
469                            is_indented_id: false,
470                            nested: child.nested.clone(),
471                        }
472                        .into()
473                    }
474                } else {
475                    parser::Link {
476                        id: child.id.clone(),
477                        values: child.values.clone(),
478                        children: vec![],
479                        is_indented_id: false,
480                        nested: child.nested.clone(),
481                    }
482                    .into()
483                }
484            })
485            .collect();
486
487        let current = LiNo::Link {
488            id: link.id.clone(),
489            values: child_values,
490        };
491
492        let combined = if let Some(parent) = parent {
493            // Wrap parent in parentheses if it's a reference
494            let wrapped_parent = match parent {
495                LiNo::Ref(ref_id) => LiNo::Link {
496                    id: None,
497                    values: vec![LiNo::Ref(ref_id.clone())],
498                },
499                link => link.clone(),
500            };
501
502            LiNo::Link {
503                id: None,
504                values: vec![wrapped_parent, current],
505            }
506        } else {
507            current
508        };
509
510        result.push(combined);
511        return; // Don't process children again
512    }
513
514    // Create the current link without children
515    let current = if let Some(body) = &link.nested {
516        transform_nested(body)
517    } else if link.values.is_empty() {
518        if let Some(id) = &link.id {
519            LiNo::Ref(id.clone())
520        } else {
521            LiNo::Link {
522                id: None,
523                values: vec![],
524            }
525        }
526    } else {
527        let values: Vec<LiNo<String>> = link
528            .values
529            .iter()
530            .map(|v| {
531                parser::Link {
532                    id: v.id.clone(),
533                    values: v.values.clone(),
534                    children: vec![],
535                    is_indented_id: false,
536                    nested: v.nested.clone(),
537                }
538                .into()
539            })
540            .collect();
541        LiNo::Link {
542            id: link.id.clone(),
543            values,
544        }
545    };
546
547    // Create the combined link (parent + current) with proper wrapping
548    let combined = if let Some(parent) = parent {
549        // Wrap parent in parentheses if it's a reference
550        let wrapped_parent = match parent {
551            LiNo::Ref(ref_id) => LiNo::Link {
552                id: None,
553                values: vec![LiNo::Ref(ref_id.clone())],
554            },
555            link => link.clone(),
556        };
557
558        // Wrap current in parentheses if it's a reference
559        let wrapped_current = match &current {
560            LiNo::Ref(ref_id) => LiNo::Link {
561                id: None,
562                values: vec![LiNo::Ref(ref_id.clone())],
563            },
564            link => link.clone(),
565        };
566
567        LiNo::Link {
568            id: None,
569            values: vec![wrapped_parent, wrapped_current],
570        }
571    } else {
572        current.clone()
573    };
574
575    result.push(combined.clone());
576
577    // Process children
578    for child in &link.children {
579        flatten_link_recursive(child, Some(&combined), result);
580    }
581}
582
583pub fn parse_lino(document: &str) -> Result<LiNo<String>, ParseError> {
584    // Handle empty or whitespace-only input by returning empty result
585    if document.trim().is_empty() {
586        return Ok(LiNo::Link {
587            id: None,
588            values: vec![],
589        });
590    }
591
592    match parser::parse_document(document) {
593        Ok((_, links)) => {
594            if links.is_empty() {
595                Ok(LiNo::Link {
596                    id: None,
597                    values: vec![],
598                })
599            } else {
600                // Flatten the indented structure according to Lino spec
601                let flattened = flatten_links(links);
602                Ok(LiNo::Link {
603                    id: None,
604                    values: flattened,
605                })
606            }
607        }
608        Err(e) => Err(ParseError::SyntaxError(format!("{:?}", e))),
609    }
610}
611
612// New function that matches C# and JS API - returns collection of links
613pub fn parse_lino_to_links(document: &str) -> Result<Vec<LiNo<String>>, ParseError> {
614    // Handle empty or whitespace-only input by returning empty collection
615    if document.trim().is_empty() {
616        return Ok(vec![]);
617    }
618
619    match parser::parse_document(document) {
620        Ok((_, links)) => {
621            if links.is_empty() {
622                Ok(vec![])
623            } else {
624                // Flatten the indented structure according to Lino spec
625                let flattened = flatten_links(links);
626                Ok(flattened)
627            }
628        }
629        Err(e) => Err(ParseError::SyntaxError(format!("{:?}", e))),
630    }
631}
632
633/// Formats a collection of LiNo links as a multi-line string.
634/// Each link is formatted on a separate line.
635pub fn format_links(links: &[LiNo<String>]) -> String {
636    links
637        .iter()
638        .map(|link| format!("{}", link))
639        .collect::<Vec<_>>()
640        .join("\n")
641}
642
643/// Formats a collection of LiNo links as a multi-line string using FormatConfig.
644/// Supports all formatting options including consecutive link grouping.
645///
646/// # Arguments
647/// * `links` - The collection of links to format
648/// * `config` - The FormatConfig to use for formatting
649///
650/// # Returns
651/// Formatted string in Lino notation
652pub fn format_links_with_config(links: &[LiNo<String>], config: &FormatConfig) -> String {
653    if links.is_empty() {
654        return String::new();
655    }
656
657    // Apply consecutive link grouping if enabled
658    let links_to_format = if config.group_consecutive {
659        group_consecutive_links(links)
660    } else {
661        links.to_vec()
662    };
663
664    links_to_format
665        .iter()
666        .map(|link| link.format_with_config(config))
667        .collect::<Vec<_>>()
668        .join("\n")
669}
670
671/// Groups consecutive links with the same ID.
672///
673/// For example:
674/// ```text
675/// SetA a
676/// SetA b
677/// SetA c
678/// ```
679/// Becomes:
680/// ```text
681/// SetA
682///   a
683///   b
684///   c
685/// ```
686fn group_consecutive_links(links: &[LiNo<String>]) -> Vec<LiNo<String>> {
687    if links.is_empty() {
688        return vec![];
689    }
690
691    let mut grouped = vec![];
692    let mut i = 0;
693
694    while i < links.len() {
695        let current = &links[i];
696
697        // Look ahead for consecutive links with same ID
698        if let LiNo::Link {
699            id: Some(ref current_id),
700            values: ref current_values,
701        } = current
702        {
703            if !current_values.is_empty() {
704                // Collect all values with same ID
705                let mut same_id_values = current_values.clone();
706                let mut j = i + 1;
707
708                while j < links.len() {
709                    if let LiNo::Link {
710                        id: Some(ref next_id),
711                        values: ref next_values,
712                    } = &links[j]
713                    {
714                        if next_id == current_id && !next_values.is_empty() {
715                            same_id_values.extend(next_values.clone());
716                            j += 1;
717                        } else {
718                            break;
719                        }
720                    } else {
721                        break;
722                    }
723                }
724
725                // If we found consecutive links, create grouped link
726                if j > i + 1 {
727                    grouped.push(LiNo::Link {
728                        id: Some(current_id.clone()),
729                        values: same_id_values,
730                    });
731                    i = j;
732                    continue;
733                }
734            }
735        }
736
737        grouped.push(current.clone());
738        i += 1;
739    }
740
741    grouped
742}
743
744/// Escape a reference string by adding quotes if necessary.
745fn escape_reference(reference: &str) -> String {
746    if reference.is_empty() || reference.trim().is_empty() {
747        return String::new();
748    }
749
750    let has_single_quote = reference.contains('\'');
751    let has_double_quote = reference.contains('"');
752
753    let needs_quoting = reference.contains(':')
754        || reference.contains('(')
755        || reference.contains(')')
756        || reference.contains(' ')
757        || reference.contains('\t')
758        || reference.contains('\n')
759        || reference.contains('\r')
760        || has_double_quote
761        || has_single_quote;
762
763    // Handle edge case: reference contains both single and double quotes
764    if has_single_quote && has_double_quote {
765        // Escape single quotes and wrap in single quotes
766        return format!("'{}'", reference.replace('\'', "\\'"));
767    }
768
769    // Prefer single quotes if double quotes are present
770    if has_double_quote {
771        return format!("'{}'", reference);
772    }
773
774    // Use double quotes if single quotes are present
775    if has_single_quote {
776        return format!("\"{}\"", reference);
777    }
778
779    // Use single quotes for special characters
780    if needs_quoting {
781        return format!("'{}'", reference);
782    }
783
784    // No quoting needed
785    reference.to_string()
786}
787
788/// Check if a string needs to be wrapped in parentheses.
789fn needs_parentheses(s: &str) -> bool {
790    s.contains(' ') || s.contains(':') || s.contains('(') || s.contains(')')
791}
792
793/// Format a value within a link.
794fn format_value<T: ToString>(value: &LiNo<T>) -> String {
795    match value {
796        LiNo::Ref(r) => escape_reference(&r.to_string()),
797        LiNo::Link { id, values } => {
798            // Simple link with just an ID - don't wrap in extra parentheses
799            if values.is_empty() {
800                if let Some(ref id_val) = id {
801                    return escape_reference(&id_val.to_string());
802                }
803                return String::new();
804            }
805            // Complex value - format with parentheses
806            format!("{}", value)
807        }
808    }
809}
810
811// Tuple conversion implementations for ergonomic link creation
812// These implementations allow creating links using Rust tuple syntax
813//
814// The macro generates From implementations for tuples of sizes 2-12.
815// For each size, it generates 4 types of conversions:
816// 1. All &str - first element becomes ID, rest become values
817// 2. All String - first element becomes ID, rest become values
818// 3. &str ID with LiNo values - first element becomes ID, LiNo elements become values
819// 4. All LiNo - creates anonymous link (no ID) with all elements as values
820
821/// Macro to implement From trait for tuples converting to LiNo<String>.
822///
823/// This macro generates four From implementations for each tuple size:
824/// - `(&str, &str, ...)` - First element becomes ID, rest become string values
825/// - `(String, String, ...)` - First element becomes ID, rest become string values
826/// - `(&str, LiNo<String>, ...)` - First element becomes ID, LiNo elements become values
827/// - `(LiNo<String>, LiNo<String>, ...)` - Creates anonymous link with all elements as values
828///
829/// # Examples
830/// ```
831/// use links_notation::LiNo;
832///
833/// // 2-tuple: ("id", "value") -> (id: value)
834/// let link: LiNo<String> = ("papa", "mama").into();
835/// assert_eq!(format!("{}", link), "(papa: mama)");
836///
837/// // 3-tuple: ("id", "v1", "v2") -> (id: v1 v2)
838/// let link: LiNo<String> = ("parent", "child1", "child2").into();
839/// assert_eq!(format!("{}", link), "(parent: child1 child2)");
840///
841/// // Anonymous link from all LiNo elements
842/// let a = LiNo::Ref("a".to_string());
843/// let b = LiNo::Ref("b".to_string());
844/// let link: LiNo<String> = (a, b).into();
845/// assert_eq!(format!("{}", link), "(a b)");
846/// ```
847macro_rules! impl_tuple_from {
848    // Implementation for 2-tuples
849    (@str_tuple 2, $t0:tt, $t1:tt) => {
850        impl From<(&str, &str)> for LiNo<String> {
851            fn from(tuple: (&str, &str)) -> Self {
852                LiNo::Link {
853                    id: Some(tuple.$t0.to_string()),
854                    values: vec![LiNo::Ref(tuple.$t1.to_string())],
855                }
856            }
857        }
858    };
859    (@string_tuple 2, $t0:tt, $t1:tt) => {
860        impl From<(String, String)> for LiNo<String> {
861            fn from(tuple: (String, String)) -> Self {
862                LiNo::Link {
863                    id: Some(tuple.$t0),
864                    values: vec![LiNo::Ref(tuple.$t1)],
865                }
866            }
867        }
868    };
869    (@str_lino_tuple 2, $t0:tt, $t1:tt) => {
870        impl From<(&str, LiNo<String>)> for LiNo<String> {
871            fn from(tuple: (&str, LiNo<String>)) -> Self {
872                LiNo::Link {
873                    id: Some(tuple.$t0.to_string()),
874                    values: vec![tuple.$t1],
875                }
876            }
877        }
878    };
879    (@lino_tuple 2, $t0:tt, $t1:tt) => {
880        impl From<(LiNo<String>, LiNo<String>)> for LiNo<String> {
881            fn from(tuple: (LiNo<String>, LiNo<String>)) -> Self {
882                LiNo::Link {
883                    id: None,
884                    values: vec![tuple.$t0, tuple.$t1],
885                }
886            }
887        }
888    };
889
890    // Implementation for 3-tuples
891    (@str_tuple 3, $t0:tt, $t1:tt, $t2:tt) => {
892        impl From<(&str, &str, &str)> for LiNo<String> {
893            fn from(tuple: (&str, &str, &str)) -> Self {
894                LiNo::Link {
895                    id: Some(tuple.$t0.to_string()),
896                    values: vec![LiNo::Ref(tuple.$t1.to_string()), LiNo::Ref(tuple.$t2.to_string())],
897                }
898            }
899        }
900    };
901    (@string_tuple 3, $t0:tt, $t1:tt, $t2:tt) => {
902        impl From<(String, String, String)> for LiNo<String> {
903            fn from(tuple: (String, String, String)) -> Self {
904                LiNo::Link {
905                    id: Some(tuple.$t0),
906                    values: vec![LiNo::Ref(tuple.$t1), LiNo::Ref(tuple.$t2)],
907                }
908            }
909        }
910    };
911    (@str_lino_tuple 3, $t0:tt, $t1:tt, $t2:tt) => {
912        impl From<(&str, LiNo<String>, LiNo<String>)> for LiNo<String> {
913            fn from(tuple: (&str, LiNo<String>, LiNo<String>)) -> Self {
914                LiNo::Link {
915                    id: Some(tuple.$t0.to_string()),
916                    values: vec![tuple.$t1, tuple.$t2],
917                }
918            }
919        }
920    };
921    (@lino_tuple 3, $t0:tt, $t1:tt, $t2:tt) => {
922        impl From<(LiNo<String>, LiNo<String>, LiNo<String>)> for LiNo<String> {
923            fn from(tuple: (LiNo<String>, LiNo<String>, LiNo<String>)) -> Self {
924                LiNo::Link {
925                    id: None,
926                    values: vec![tuple.$t0, tuple.$t1, tuple.$t2],
927                }
928            }
929        }
930    };
931
932    // Implementation for 4-tuples
933    (@str_tuple 4, $t0:tt, $t1:tt, $t2:tt, $t3:tt) => {
934        impl From<(&str, &str, &str, &str)> for LiNo<String> {
935            fn from(tuple: (&str, &str, &str, &str)) -> Self {
936                LiNo::Link {
937                    id: Some(tuple.$t0.to_string()),
938                    values: vec![
939                        LiNo::Ref(tuple.$t1.to_string()),
940                        LiNo::Ref(tuple.$t2.to_string()),
941                        LiNo::Ref(tuple.$t3.to_string()),
942                    ],
943                }
944            }
945        }
946    };
947    (@string_tuple 4, $t0:tt, $t1:tt, $t2:tt, $t3:tt) => {
948        impl From<(String, String, String, String)> for LiNo<String> {
949            fn from(tuple: (String, String, String, String)) -> Self {
950                LiNo::Link {
951                    id: Some(tuple.$t0),
952                    values: vec![LiNo::Ref(tuple.$t1), LiNo::Ref(tuple.$t2), LiNo::Ref(tuple.$t3)],
953                }
954            }
955        }
956    };
957    (@str_lino_tuple 4, $t0:tt, $t1:tt, $t2:tt, $t3:tt) => {
958        impl From<(&str, LiNo<String>, LiNo<String>, LiNo<String>)> for LiNo<String> {
959            fn from(tuple: (&str, LiNo<String>, LiNo<String>, LiNo<String>)) -> Self {
960                LiNo::Link {
961                    id: Some(tuple.$t0.to_string()),
962                    values: vec![tuple.$t1, tuple.$t2, tuple.$t3],
963                }
964            }
965        }
966    };
967    (@lino_tuple 4, $t0:tt, $t1:tt, $t2:tt, $t3:tt) => {
968        impl From<(LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)> for LiNo<String> {
969            fn from(tuple: (LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)) -> Self {
970                LiNo::Link {
971                    id: None,
972                    values: vec![tuple.$t0, tuple.$t1, tuple.$t2, tuple.$t3],
973                }
974            }
975        }
976    };
977
978    // Implementation for 5-tuples
979    (@str_tuple 5, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt) => {
980        impl From<(&str, &str, &str, &str, &str)> for LiNo<String> {
981            fn from(tuple: (&str, &str, &str, &str, &str)) -> Self {
982                LiNo::Link {
983                    id: Some(tuple.$t0.to_string()),
984                    values: vec![
985                        LiNo::Ref(tuple.$t1.to_string()),
986                        LiNo::Ref(tuple.$t2.to_string()),
987                        LiNo::Ref(tuple.$t3.to_string()),
988                        LiNo::Ref(tuple.$t4.to_string()),
989                    ],
990                }
991            }
992        }
993    };
994    (@string_tuple 5, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt) => {
995        impl From<(String, String, String, String, String)> for LiNo<String> {
996            fn from(tuple: (String, String, String, String, String)) -> Self {
997                LiNo::Link {
998                    id: Some(tuple.$t0),
999                    values: vec![
1000                        LiNo::Ref(tuple.$t1),
1001                        LiNo::Ref(tuple.$t2),
1002                        LiNo::Ref(tuple.$t3),
1003                        LiNo::Ref(tuple.$t4),
1004                    ],
1005                }
1006            }
1007        }
1008    };
1009    (@str_lino_tuple 5, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt) => {
1010        impl From<(&str, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)> for LiNo<String> {
1011            fn from(tuple: (&str, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)) -> Self {
1012                LiNo::Link {
1013                    id: Some(tuple.$t0.to_string()),
1014                    values: vec![tuple.$t1, tuple.$t2, tuple.$t3, tuple.$t4],
1015                }
1016            }
1017        }
1018    };
1019    (@lino_tuple 5, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt) => {
1020        impl From<(LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)> for LiNo<String> {
1021            fn from(tuple: (LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)) -> Self {
1022                LiNo::Link {
1023                    id: None,
1024                    values: vec![tuple.$t0, tuple.$t1, tuple.$t2, tuple.$t3, tuple.$t4],
1025                }
1026            }
1027        }
1028    };
1029
1030    // Implementation for 6-tuples
1031    (@str_tuple 6, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt, $t5:tt) => {
1032        impl From<(&str, &str, &str, &str, &str, &str)> for LiNo<String> {
1033            fn from(tuple: (&str, &str, &str, &str, &str, &str)) -> Self {
1034                LiNo::Link {
1035                    id: Some(tuple.$t0.to_string()),
1036                    values: vec![
1037                        LiNo::Ref(tuple.$t1.to_string()),
1038                        LiNo::Ref(tuple.$t2.to_string()),
1039                        LiNo::Ref(tuple.$t3.to_string()),
1040                        LiNo::Ref(tuple.$t4.to_string()),
1041                        LiNo::Ref(tuple.$t5.to_string()),
1042                    ],
1043                }
1044            }
1045        }
1046    };
1047    (@string_tuple 6, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt, $t5:tt) => {
1048        impl From<(String, String, String, String, String, String)> for LiNo<String> {
1049            fn from(tuple: (String, String, String, String, String, String)) -> Self {
1050                LiNo::Link {
1051                    id: Some(tuple.$t0),
1052                    values: vec![
1053                        LiNo::Ref(tuple.$t1),
1054                        LiNo::Ref(tuple.$t2),
1055                        LiNo::Ref(tuple.$t3),
1056                        LiNo::Ref(tuple.$t4),
1057                        LiNo::Ref(tuple.$t5),
1058                    ],
1059                }
1060            }
1061        }
1062    };
1063    (@str_lino_tuple 6, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt, $t5:tt) => {
1064        impl From<(&str, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)> for LiNo<String> {
1065            fn from(tuple: (&str, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)) -> Self {
1066                LiNo::Link {
1067                    id: Some(tuple.$t0.to_string()),
1068                    values: vec![tuple.$t1, tuple.$t2, tuple.$t3, tuple.$t4, tuple.$t5],
1069                }
1070            }
1071        }
1072    };
1073    (@lino_tuple 6, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt, $t5:tt) => {
1074        impl From<(LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)> for LiNo<String> {
1075            fn from(tuple: (LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)) -> Self {
1076                LiNo::Link {
1077                    id: None,
1078                    values: vec![tuple.$t0, tuple.$t1, tuple.$t2, tuple.$t3, tuple.$t4, tuple.$t5],
1079                }
1080            }
1081        }
1082    };
1083
1084    // Implementation for 7-tuples
1085    (@str_tuple 7, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt, $t5:tt, $t6:tt) => {
1086        impl From<(&str, &str, &str, &str, &str, &str, &str)> for LiNo<String> {
1087            fn from(tuple: (&str, &str, &str, &str, &str, &str, &str)) -> Self {
1088                LiNo::Link {
1089                    id: Some(tuple.$t0.to_string()),
1090                    values: vec![
1091                        LiNo::Ref(tuple.$t1.to_string()),
1092                        LiNo::Ref(tuple.$t2.to_string()),
1093                        LiNo::Ref(tuple.$t3.to_string()),
1094                        LiNo::Ref(tuple.$t4.to_string()),
1095                        LiNo::Ref(tuple.$t5.to_string()),
1096                        LiNo::Ref(tuple.$t6.to_string()),
1097                    ],
1098                }
1099            }
1100        }
1101    };
1102    (@string_tuple 7, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt, $t5:tt, $t6:tt) => {
1103        impl From<(String, String, String, String, String, String, String)> for LiNo<String> {
1104            fn from(tuple: (String, String, String, String, String, String, String)) -> Self {
1105                LiNo::Link {
1106                    id: Some(tuple.$t0),
1107                    values: vec![
1108                        LiNo::Ref(tuple.$t1),
1109                        LiNo::Ref(tuple.$t2),
1110                        LiNo::Ref(tuple.$t3),
1111                        LiNo::Ref(tuple.$t4),
1112                        LiNo::Ref(tuple.$t5),
1113                        LiNo::Ref(tuple.$t6),
1114                    ],
1115                }
1116            }
1117        }
1118    };
1119    (@str_lino_tuple 7, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt, $t5:tt, $t6:tt) => {
1120        impl From<(&str, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)> for LiNo<String> {
1121            fn from(tuple: (&str, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)) -> Self {
1122                LiNo::Link {
1123                    id: Some(tuple.$t0.to_string()),
1124                    values: vec![tuple.$t1, tuple.$t2, tuple.$t3, tuple.$t4, tuple.$t5, tuple.$t6],
1125                }
1126            }
1127        }
1128    };
1129    (@lino_tuple 7, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt, $t5:tt, $t6:tt) => {
1130        impl From<(LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)> for LiNo<String> {
1131            fn from(tuple: (LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)) -> Self {
1132                LiNo::Link {
1133                    id: None,
1134                    values: vec![tuple.$t0, tuple.$t1, tuple.$t2, tuple.$t3, tuple.$t4, tuple.$t5, tuple.$t6],
1135                }
1136            }
1137        }
1138    };
1139
1140    // Implementation for 8-tuples
1141    (@str_tuple 8, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt, $t5:tt, $t6:tt, $t7:tt) => {
1142        impl From<(&str, &str, &str, &str, &str, &str, &str, &str)> for LiNo<String> {
1143            fn from(tuple: (&str, &str, &str, &str, &str, &str, &str, &str)) -> Self {
1144                LiNo::Link {
1145                    id: Some(tuple.$t0.to_string()),
1146                    values: vec![
1147                        LiNo::Ref(tuple.$t1.to_string()),
1148                        LiNo::Ref(tuple.$t2.to_string()),
1149                        LiNo::Ref(tuple.$t3.to_string()),
1150                        LiNo::Ref(tuple.$t4.to_string()),
1151                        LiNo::Ref(tuple.$t5.to_string()),
1152                        LiNo::Ref(tuple.$t6.to_string()),
1153                        LiNo::Ref(tuple.$t7.to_string()),
1154                    ],
1155                }
1156            }
1157        }
1158    };
1159    (@string_tuple 8, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt, $t5:tt, $t6:tt, $t7:tt) => {
1160        impl From<(String, String, String, String, String, String, String, String)> for LiNo<String> {
1161            fn from(tuple: (String, String, String, String, String, String, String, String)) -> Self {
1162                LiNo::Link {
1163                    id: Some(tuple.$t0),
1164                    values: vec![
1165                        LiNo::Ref(tuple.$t1),
1166                        LiNo::Ref(tuple.$t2),
1167                        LiNo::Ref(tuple.$t3),
1168                        LiNo::Ref(tuple.$t4),
1169                        LiNo::Ref(tuple.$t5),
1170                        LiNo::Ref(tuple.$t6),
1171                        LiNo::Ref(tuple.$t7),
1172                    ],
1173                }
1174            }
1175        }
1176    };
1177    (@str_lino_tuple 8, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt, $t5:tt, $t6:tt, $t7:tt) => {
1178        impl From<(&str, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)> for LiNo<String> {
1179            fn from(tuple: (&str, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)) -> Self {
1180                LiNo::Link {
1181                    id: Some(tuple.$t0.to_string()),
1182                    values: vec![tuple.$t1, tuple.$t2, tuple.$t3, tuple.$t4, tuple.$t5, tuple.$t6, tuple.$t7],
1183                }
1184            }
1185        }
1186    };
1187    (@lino_tuple 8, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt, $t5:tt, $t6:tt, $t7:tt) => {
1188        impl From<(LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)> for LiNo<String> {
1189            fn from(tuple: (LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)) -> Self {
1190                LiNo::Link {
1191                    id: None,
1192                    values: vec![tuple.$t0, tuple.$t1, tuple.$t2, tuple.$t3, tuple.$t4, tuple.$t5, tuple.$t6, tuple.$t7],
1193                }
1194            }
1195        }
1196    };
1197
1198    // Implementation for 9-tuples
1199    (@str_tuple 9, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt, $t5:tt, $t6:tt, $t7:tt, $t8:tt) => {
1200        impl From<(&str, &str, &str, &str, &str, &str, &str, &str, &str)> for LiNo<String> {
1201            fn from(tuple: (&str, &str, &str, &str, &str, &str, &str, &str, &str)) -> Self {
1202                LiNo::Link {
1203                    id: Some(tuple.$t0.to_string()),
1204                    values: vec![
1205                        LiNo::Ref(tuple.$t1.to_string()),
1206                        LiNo::Ref(tuple.$t2.to_string()),
1207                        LiNo::Ref(tuple.$t3.to_string()),
1208                        LiNo::Ref(tuple.$t4.to_string()),
1209                        LiNo::Ref(tuple.$t5.to_string()),
1210                        LiNo::Ref(tuple.$t6.to_string()),
1211                        LiNo::Ref(tuple.$t7.to_string()),
1212                        LiNo::Ref(tuple.$t8.to_string()),
1213                    ],
1214                }
1215            }
1216        }
1217    };
1218    (@string_tuple 9, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt, $t5:tt, $t6:tt, $t7:tt, $t8:tt) => {
1219        impl From<(String, String, String, String, String, String, String, String, String)> for LiNo<String> {
1220            fn from(tuple: (String, String, String, String, String, String, String, String, String)) -> Self {
1221                LiNo::Link {
1222                    id: Some(tuple.$t0),
1223                    values: vec![
1224                        LiNo::Ref(tuple.$t1),
1225                        LiNo::Ref(tuple.$t2),
1226                        LiNo::Ref(tuple.$t3),
1227                        LiNo::Ref(tuple.$t4),
1228                        LiNo::Ref(tuple.$t5),
1229                        LiNo::Ref(tuple.$t6),
1230                        LiNo::Ref(tuple.$t7),
1231                        LiNo::Ref(tuple.$t8),
1232                    ],
1233                }
1234            }
1235        }
1236    };
1237    (@str_lino_tuple 9, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt, $t5:tt, $t6:tt, $t7:tt, $t8:tt) => {
1238        impl From<(&str, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)> for LiNo<String> {
1239            fn from(tuple: (&str, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)) -> Self {
1240                LiNo::Link {
1241                    id: Some(tuple.$t0.to_string()),
1242                    values: vec![tuple.$t1, tuple.$t2, tuple.$t3, tuple.$t4, tuple.$t5, tuple.$t6, tuple.$t7, tuple.$t8],
1243                }
1244            }
1245        }
1246    };
1247    (@lino_tuple 9, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt, $t5:tt, $t6:tt, $t7:tt, $t8:tt) => {
1248        impl From<(LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)> for LiNo<String> {
1249            fn from(tuple: (LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)) -> Self {
1250                LiNo::Link {
1251                    id: None,
1252                    values: vec![tuple.$t0, tuple.$t1, tuple.$t2, tuple.$t3, tuple.$t4, tuple.$t5, tuple.$t6, tuple.$t7, tuple.$t8],
1253                }
1254            }
1255        }
1256    };
1257
1258    // Implementation for 10-tuples
1259    (@str_tuple 10, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt, $t5:tt, $t6:tt, $t7:tt, $t8:tt, $t9:tt) => {
1260        impl From<(&str, &str, &str, &str, &str, &str, &str, &str, &str, &str)> for LiNo<String> {
1261            fn from(tuple: (&str, &str, &str, &str, &str, &str, &str, &str, &str, &str)) -> Self {
1262                LiNo::Link {
1263                    id: Some(tuple.$t0.to_string()),
1264                    values: vec![
1265                        LiNo::Ref(tuple.$t1.to_string()),
1266                        LiNo::Ref(tuple.$t2.to_string()),
1267                        LiNo::Ref(tuple.$t3.to_string()),
1268                        LiNo::Ref(tuple.$t4.to_string()),
1269                        LiNo::Ref(tuple.$t5.to_string()),
1270                        LiNo::Ref(tuple.$t6.to_string()),
1271                        LiNo::Ref(tuple.$t7.to_string()),
1272                        LiNo::Ref(tuple.$t8.to_string()),
1273                        LiNo::Ref(tuple.$t9.to_string()),
1274                    ],
1275                }
1276            }
1277        }
1278    };
1279    (@string_tuple 10, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt, $t5:tt, $t6:tt, $t7:tt, $t8:tt, $t9:tt) => {
1280        impl From<(String, String, String, String, String, String, String, String, String, String)> for LiNo<String> {
1281            fn from(tuple: (String, String, String, String, String, String, String, String, String, String)) -> Self {
1282                LiNo::Link {
1283                    id: Some(tuple.$t0),
1284                    values: vec![
1285                        LiNo::Ref(tuple.$t1),
1286                        LiNo::Ref(tuple.$t2),
1287                        LiNo::Ref(tuple.$t3),
1288                        LiNo::Ref(tuple.$t4),
1289                        LiNo::Ref(tuple.$t5),
1290                        LiNo::Ref(tuple.$t6),
1291                        LiNo::Ref(tuple.$t7),
1292                        LiNo::Ref(tuple.$t8),
1293                        LiNo::Ref(tuple.$t9),
1294                    ],
1295                }
1296            }
1297        }
1298    };
1299    (@str_lino_tuple 10, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt, $t5:tt, $t6:tt, $t7:tt, $t8:tt, $t9:tt) => {
1300        impl From<(&str, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)> for LiNo<String> {
1301            fn from(tuple: (&str, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)) -> Self {
1302                LiNo::Link {
1303                    id: Some(tuple.$t0.to_string()),
1304                    values: vec![tuple.$t1, tuple.$t2, tuple.$t3, tuple.$t4, tuple.$t5, tuple.$t6, tuple.$t7, tuple.$t8, tuple.$t9],
1305                }
1306            }
1307        }
1308    };
1309    (@lino_tuple 10, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt, $t5:tt, $t6:tt, $t7:tt, $t8:tt, $t9:tt) => {
1310        impl From<(LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)> for LiNo<String> {
1311            fn from(tuple: (LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)) -> Self {
1312                LiNo::Link {
1313                    id: None,
1314                    values: vec![tuple.$t0, tuple.$t1, tuple.$t2, tuple.$t3, tuple.$t4, tuple.$t5, tuple.$t6, tuple.$t7, tuple.$t8, tuple.$t9],
1315                }
1316            }
1317        }
1318    };
1319
1320    // Implementation for 11-tuples
1321    (@str_tuple 11, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt, $t5:tt, $t6:tt, $t7:tt, $t8:tt, $t9:tt, $t10:tt) => {
1322        impl From<(&str, &str, &str, &str, &str, &str, &str, &str, &str, &str, &str)> for LiNo<String> {
1323            fn from(tuple: (&str, &str, &str, &str, &str, &str, &str, &str, &str, &str, &str)) -> Self {
1324                LiNo::Link {
1325                    id: Some(tuple.$t0.to_string()),
1326                    values: vec![
1327                        LiNo::Ref(tuple.$t1.to_string()),
1328                        LiNo::Ref(tuple.$t2.to_string()),
1329                        LiNo::Ref(tuple.$t3.to_string()),
1330                        LiNo::Ref(tuple.$t4.to_string()),
1331                        LiNo::Ref(tuple.$t5.to_string()),
1332                        LiNo::Ref(tuple.$t6.to_string()),
1333                        LiNo::Ref(tuple.$t7.to_string()),
1334                        LiNo::Ref(tuple.$t8.to_string()),
1335                        LiNo::Ref(tuple.$t9.to_string()),
1336                        LiNo::Ref(tuple.$t10.to_string()),
1337                    ],
1338                }
1339            }
1340        }
1341    };
1342    (@string_tuple 11, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt, $t5:tt, $t6:tt, $t7:tt, $t8:tt, $t9:tt, $t10:tt) => {
1343        impl From<(String, String, String, String, String, String, String, String, String, String, String)> for LiNo<String> {
1344            fn from(tuple: (String, String, String, String, String, String, String, String, String, String, String)) -> Self {
1345                LiNo::Link {
1346                    id: Some(tuple.$t0),
1347                    values: vec![
1348                        LiNo::Ref(tuple.$t1),
1349                        LiNo::Ref(tuple.$t2),
1350                        LiNo::Ref(tuple.$t3),
1351                        LiNo::Ref(tuple.$t4),
1352                        LiNo::Ref(tuple.$t5),
1353                        LiNo::Ref(tuple.$t6),
1354                        LiNo::Ref(tuple.$t7),
1355                        LiNo::Ref(tuple.$t8),
1356                        LiNo::Ref(tuple.$t9),
1357                        LiNo::Ref(tuple.$t10),
1358                    ],
1359                }
1360            }
1361        }
1362    };
1363    (@str_lino_tuple 11, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt, $t5:tt, $t6:tt, $t7:tt, $t8:tt, $t9:tt, $t10:tt) => {
1364        impl From<(&str, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)> for LiNo<String> {
1365            fn from(tuple: (&str, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)) -> Self {
1366                LiNo::Link {
1367                    id: Some(tuple.$t0.to_string()),
1368                    values: vec![tuple.$t1, tuple.$t2, tuple.$t3, tuple.$t4, tuple.$t5, tuple.$t6, tuple.$t7, tuple.$t8, tuple.$t9, tuple.$t10],
1369                }
1370            }
1371        }
1372    };
1373    (@lino_tuple 11, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt, $t5:tt, $t6:tt, $t7:tt, $t8:tt, $t9:tt, $t10:tt) => {
1374        impl From<(LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)> for LiNo<String> {
1375            fn from(tuple: (LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)) -> Self {
1376                LiNo::Link {
1377                    id: None,
1378                    values: vec![tuple.$t0, tuple.$t1, tuple.$t2, tuple.$t3, tuple.$t4, tuple.$t5, tuple.$t6, tuple.$t7, tuple.$t8, tuple.$t9, tuple.$t10],
1379                }
1380            }
1381        }
1382    };
1383
1384    // Implementation for 12-tuples
1385    (@str_tuple 12, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt, $t5:tt, $t6:tt, $t7:tt, $t8:tt, $t9:tt, $t10:tt, $t11:tt) => {
1386        impl From<(&str, &str, &str, &str, &str, &str, &str, &str, &str, &str, &str, &str)> for LiNo<String> {
1387            fn from(tuple: (&str, &str, &str, &str, &str, &str, &str, &str, &str, &str, &str, &str)) -> Self {
1388                LiNo::Link {
1389                    id: Some(tuple.$t0.to_string()),
1390                    values: vec![
1391                        LiNo::Ref(tuple.$t1.to_string()),
1392                        LiNo::Ref(tuple.$t2.to_string()),
1393                        LiNo::Ref(tuple.$t3.to_string()),
1394                        LiNo::Ref(tuple.$t4.to_string()),
1395                        LiNo::Ref(tuple.$t5.to_string()),
1396                        LiNo::Ref(tuple.$t6.to_string()),
1397                        LiNo::Ref(tuple.$t7.to_string()),
1398                        LiNo::Ref(tuple.$t8.to_string()),
1399                        LiNo::Ref(tuple.$t9.to_string()),
1400                        LiNo::Ref(tuple.$t10.to_string()),
1401                        LiNo::Ref(tuple.$t11.to_string()),
1402                    ],
1403                }
1404            }
1405        }
1406    };
1407    (@string_tuple 12, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt, $t5:tt, $t6:tt, $t7:tt, $t8:tt, $t9:tt, $t10:tt, $t11:tt) => {
1408        impl From<(String, String, String, String, String, String, String, String, String, String, String, String)> for LiNo<String> {
1409            fn from(tuple: (String, String, String, String, String, String, String, String, String, String, String, String)) -> Self {
1410                LiNo::Link {
1411                    id: Some(tuple.$t0),
1412                    values: vec![
1413                        LiNo::Ref(tuple.$t1),
1414                        LiNo::Ref(tuple.$t2),
1415                        LiNo::Ref(tuple.$t3),
1416                        LiNo::Ref(tuple.$t4),
1417                        LiNo::Ref(tuple.$t5),
1418                        LiNo::Ref(tuple.$t6),
1419                        LiNo::Ref(tuple.$t7),
1420                        LiNo::Ref(tuple.$t8),
1421                        LiNo::Ref(tuple.$t9),
1422                        LiNo::Ref(tuple.$t10),
1423                        LiNo::Ref(tuple.$t11),
1424                    ],
1425                }
1426            }
1427        }
1428    };
1429    (@str_lino_tuple 12, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt, $t5:tt, $t6:tt, $t7:tt, $t8:tt, $t9:tt, $t10:tt, $t11:tt) => {
1430        impl From<(&str, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)> for LiNo<String> {
1431            fn from(tuple: (&str, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)) -> Self {
1432                LiNo::Link {
1433                    id: Some(tuple.$t0.to_string()),
1434                    values: vec![tuple.$t1, tuple.$t2, tuple.$t3, tuple.$t4, tuple.$t5, tuple.$t6, tuple.$t7, tuple.$t8, tuple.$t9, tuple.$t10, tuple.$t11],
1435                }
1436            }
1437        }
1438    };
1439    (@lino_tuple 12, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt, $t5:tt, $t6:tt, $t7:tt, $t8:tt, $t9:tt, $t10:tt, $t11:tt) => {
1440        impl From<(LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)> for LiNo<String> {
1441            fn from(tuple: (LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)) -> Self {
1442                LiNo::Link {
1443                    id: None,
1444                    values: vec![tuple.$t0, tuple.$t1, tuple.$t2, tuple.$t3, tuple.$t4, tuple.$t5, tuple.$t6, tuple.$t7, tuple.$t8, tuple.$t9, tuple.$t10, tuple.$t11],
1445                }
1446            }
1447        }
1448    };
1449
1450    // Entry point - generates all four types for a given tuple size
1451    (2) => {
1452        impl_tuple_from!(@str_tuple 2, 0, 1);
1453        impl_tuple_from!(@string_tuple 2, 0, 1);
1454        impl_tuple_from!(@str_lino_tuple 2, 0, 1);
1455        impl_tuple_from!(@lino_tuple 2, 0, 1);
1456    };
1457    (3) => {
1458        impl_tuple_from!(@str_tuple 3, 0, 1, 2);
1459        impl_tuple_from!(@string_tuple 3, 0, 1, 2);
1460        impl_tuple_from!(@str_lino_tuple 3, 0, 1, 2);
1461        impl_tuple_from!(@lino_tuple 3, 0, 1, 2);
1462    };
1463    (4) => {
1464        impl_tuple_from!(@str_tuple 4, 0, 1, 2, 3);
1465        impl_tuple_from!(@string_tuple 4, 0, 1, 2, 3);
1466        impl_tuple_from!(@str_lino_tuple 4, 0, 1, 2, 3);
1467        impl_tuple_from!(@lino_tuple 4, 0, 1, 2, 3);
1468    };
1469    (5) => {
1470        impl_tuple_from!(@str_tuple 5, 0, 1, 2, 3, 4);
1471        impl_tuple_from!(@string_tuple 5, 0, 1, 2, 3, 4);
1472        impl_tuple_from!(@str_lino_tuple 5, 0, 1, 2, 3, 4);
1473        impl_tuple_from!(@lino_tuple 5, 0, 1, 2, 3, 4);
1474    };
1475    (6) => {
1476        impl_tuple_from!(@str_tuple 6, 0, 1, 2, 3, 4, 5);
1477        impl_tuple_from!(@string_tuple 6, 0, 1, 2, 3, 4, 5);
1478        impl_tuple_from!(@str_lino_tuple 6, 0, 1, 2, 3, 4, 5);
1479        impl_tuple_from!(@lino_tuple 6, 0, 1, 2, 3, 4, 5);
1480    };
1481    (7) => {
1482        impl_tuple_from!(@str_tuple 7, 0, 1, 2, 3, 4, 5, 6);
1483        impl_tuple_from!(@string_tuple 7, 0, 1, 2, 3, 4, 5, 6);
1484        impl_tuple_from!(@str_lino_tuple 7, 0, 1, 2, 3, 4, 5, 6);
1485        impl_tuple_from!(@lino_tuple 7, 0, 1, 2, 3, 4, 5, 6);
1486    };
1487    (8) => {
1488        impl_tuple_from!(@str_tuple 8, 0, 1, 2, 3, 4, 5, 6, 7);
1489        impl_tuple_from!(@string_tuple 8, 0, 1, 2, 3, 4, 5, 6, 7);
1490        impl_tuple_from!(@str_lino_tuple 8, 0, 1, 2, 3, 4, 5, 6, 7);
1491        impl_tuple_from!(@lino_tuple 8, 0, 1, 2, 3, 4, 5, 6, 7);
1492    };
1493    (9) => {
1494        impl_tuple_from!(@str_tuple 9, 0, 1, 2, 3, 4, 5, 6, 7, 8);
1495        impl_tuple_from!(@string_tuple 9, 0, 1, 2, 3, 4, 5, 6, 7, 8);
1496        impl_tuple_from!(@str_lino_tuple 9, 0, 1, 2, 3, 4, 5, 6, 7, 8);
1497        impl_tuple_from!(@lino_tuple 9, 0, 1, 2, 3, 4, 5, 6, 7, 8);
1498    };
1499    (10) => {
1500        impl_tuple_from!(@str_tuple 10, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
1501        impl_tuple_from!(@string_tuple 10, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
1502        impl_tuple_from!(@str_lino_tuple 10, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
1503        impl_tuple_from!(@lino_tuple 10, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
1504    };
1505    (11) => {
1506        impl_tuple_from!(@str_tuple 11, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
1507        impl_tuple_from!(@string_tuple 11, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
1508        impl_tuple_from!(@str_lino_tuple 11, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
1509        impl_tuple_from!(@lino_tuple 11, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
1510    };
1511    (12) => {
1512        impl_tuple_from!(@str_tuple 12, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);
1513        impl_tuple_from!(@string_tuple 12, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);
1514        impl_tuple_from!(@str_lino_tuple 12, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);
1515        impl_tuple_from!(@lino_tuple 12, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);
1516    };
1517}
1518
1519// Generate implementations for tuples of sizes 2 through 12
1520// This follows the Rust standard library convention of supporting up to 12-tuples
1521impl_tuple_from!(2);
1522impl_tuple_from!(3);
1523impl_tuple_from!(4);
1524impl_tuple_from!(5);
1525impl_tuple_from!(6);
1526impl_tuple_from!(7);
1527impl_tuple_from!(8);
1528impl_tuple_from!(9);
1529impl_tuple_from!(10);
1530impl_tuple_from!(11);
1531impl_tuple_from!(12);
1532
1533// Vec-based conversions for arbitrary-length link creation
1534//
1535// These implementations provide an escape hatch for creating links with more
1536// than 12 values, or when the number of values is determined at runtime.
1537//
1538// Note: Rust does not support variadic generics (as of Rust 1.92), which means
1539// we cannot implement `From` for tuples of arbitrary length. This is a fundamental
1540// limitation of Rust's type system. The Rust standard library faces the same
1541// limitation, which is why traits like `Debug`, `Default`, `Hash`, etc. are only
1542// implemented for tuples up to 12 elements.
1543//
1544// For more information, see:
1545// - https://github.com/rust-lang/rfcs/issues/376 (Draft RFC: variadic generics)
1546// - https://github.com/rust-lang/rust/issues/10124 (RFC: variadic generics)
1547//
1548// Alternative approaches for arbitrary-length links:
1549// 1. Use the `LiNoBuilder` API for fluent construction
1550// 2. Use `LiNo::new()` or `LiNo::anonymous()` with a `Vec`
1551// 3. Use the `From<Vec<_>>` implementations below
1552
1553/// Convert a Vec of strings into an anonymous link.
1554///
1555/// # Examples
1556/// ```
1557/// use links_notation::LiNo;
1558///
1559/// // Create anonymous link from vector of any size
1560/// let values: Vec<&str> = (1..=20).map(|_| "val").collect();
1561/// let link: LiNo<String> = values.into();
1562/// ```
1563impl From<Vec<&str>> for LiNo<String> {
1564    fn from(values: Vec<&str>) -> Self {
1565        LiNo::Link {
1566            id: None,
1567            values: values
1568                .into_iter()
1569                .map(|s| LiNo::Ref(s.to_string()))
1570                .collect(),
1571        }
1572    }
1573}
1574
1575/// Convert a Vec of Strings into an anonymous link.
1576impl From<Vec<String>> for LiNo<String> {
1577    fn from(values: Vec<String>) -> Self {
1578        LiNo::Link {
1579            id: None,
1580            values: values.into_iter().map(LiNo::Ref).collect(),
1581        }
1582    }
1583}
1584
1585/// Convert a Vec of LiNo into an anonymous link.
1586impl From<Vec<LiNo<String>>> for LiNo<String> {
1587    fn from(values: Vec<LiNo<String>>) -> Self {
1588        LiNo::Link { id: None, values }
1589    }
1590}
1591
1592/// Convert a tuple of (id, Vec<values>) into a named link.
1593///
1594/// # Examples
1595/// ```
1596/// use links_notation::LiNo;
1597///
1598/// // Create named link with arbitrary number of values
1599/// let values: Vec<&str> = vec!["v1", "v2", "v3", "v4", "v5"];
1600/// let link: LiNo<String> = ("myLink", values).into();
1601/// assert_eq!(format!("{}", link), "(myLink: v1 v2 v3 v4 v5)");
1602/// ```
1603impl From<(&str, Vec<&str>)> for LiNo<String> {
1604    fn from((id, values): (&str, Vec<&str>)) -> Self {
1605        LiNo::Link {
1606            id: Some(id.to_string()),
1607            values: values
1608                .into_iter()
1609                .map(|s| LiNo::Ref(s.to_string()))
1610                .collect(),
1611        }
1612    }
1613}
1614
1615/// Convert a tuple of (id, Vec<String>) into a named link.
1616impl From<(String, Vec<String>)> for LiNo<String> {
1617    fn from((id, values): (String, Vec<String>)) -> Self {
1618        LiNo::Link {
1619            id: Some(id),
1620            values: values.into_iter().map(LiNo::Ref).collect(),
1621        }
1622    }
1623}
1624
1625/// Convert a tuple of (id, Vec<LiNo>) into a named link.
1626impl From<(&str, Vec<LiNo<String>>)> for LiNo<String> {
1627    fn from((id, values): (&str, Vec<LiNo<String>>)) -> Self {
1628        LiNo::Link {
1629            id: Some(id.to_string()),
1630            values,
1631        }
1632    }
1633}
1634
1635/// Convert a tuple of (String id, Vec<LiNo>) into a named link.
1636impl From<(String, Vec<LiNo<String>>)> for LiNo<String> {
1637    fn from((id, values): (String, Vec<LiNo<String>>)) -> Self {
1638        LiNo::Link {
1639            id: Some(id),
1640            values,
1641        }
1642    }
1643}