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