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            // The empty reference is written as a bare delimiter pair; writing it
352            // as nothing would drop it from the document.
353            LiNo::Ref(value) => {
354                let value = value.to_string();
355                if value.is_empty() {
356                    write!(f, "\"\"")
357                } else {
358                    write!(f, "{}", value)
359                }
360            }
361            LiNo::Link { id, values } => {
362                let id_str = id
363                    .as_ref()
364                    .map(|id| {
365                        let id = id.to_string();
366                        if id.is_empty() {
367                            "\"\": ".to_string()
368                        } else {
369                            format!("{}: ", id)
370                        }
371                    })
372                    .unwrap_or_default();
373
374                if f.alternate() {
375                    // Format top-level as lines
376                    let lines = values
377                        .iter()
378                        .map(|value| {
379                            // For alternate formatting, ensure standalone references are wrapped in parentheses
380                            // so that flattened structures like indented blocks render as "(ref)" lines
381                            match value {
382                                LiNo::Ref(_) => format!("{}({})", id_str, value),
383                                _ => format!("{}{}", id_str, value),
384                            }
385                        })
386                        .collect::<Vec<_>>()
387                        .join("\n");
388                    write!(f, "{}", lines)
389                } else {
390                    let values_str = values
391                        .iter()
392                        .map(|value| value.to_string())
393                        .collect::<Vec<_>>()
394                        .join(" ");
395                    write!(f, "({}{})", id_str, values_str)
396                }
397            }
398        }
399    }
400}
401
402// Convert from parser::Link to LiNo (without flattening)
403impl From<parser::Link> for LiNo<String> {
404    fn from(link: parser::Link) -> Self {
405        if let Some(body) = &link.nested {
406            return transform_nested(body);
407        }
408        if link.values.is_empty() && link.children.is_empty() {
409            if let Some(id) = link.id {
410                LiNo::Ref(id)
411            } else {
412                LiNo::Link {
413                    id: None,
414                    values: vec![],
415                }
416            }
417        } else {
418            let values: Vec<LiNo<String>> = link.values.into_iter().map(|v| v.into()).collect();
419            LiNo::Link {
420                id: link.id,
421                values,
422            }
423        }
424    }
425}
426
427// A parenthesized group is a nested document: its body follows the same rules as
428// the root, so it is flattened the same way. A body that produces a single link
429// collapses to that link, unless the body is a single parenthesized group, which
430// keeps `((a b))` different from `(a b)`.
431fn transform_nested(body: &[parser::Link]) -> LiNo<String> {
432    let links = flatten_links(body.to_vec());
433    let wraps_single_group =
434        body.len() == 1 && body[0].nested.is_some() && body[0].children.is_empty();
435    if links.len() == 1 && !wraps_single_group {
436        return links.into_iter().next().unwrap();
437    }
438    LiNo::Link {
439        id: None,
440        values: links,
441    }
442}
443
444// Helper function to flatten indented structures according to Lino spec
445fn flatten_links(links: Vec<parser::Link>) -> Vec<LiNo<String>> {
446    let mut result = vec![];
447
448    for link in links {
449        flatten_link_recursive(&link, None, &mut result);
450    }
451
452    result
453}
454
455fn flatten_link_recursive(
456    link: &parser::Link,
457    parent: Option<&LiNo<String>>,
458    result: &mut Vec<LiNo<String>>,
459) {
460    // Special case: If this is an indented ID (with colon) with children,
461    // the children should become the values of the link (indented ID syntax)
462    if link.is_indented_id
463        && link.id.is_some()
464        && link.values.is_empty()
465        && !link.children.is_empty()
466    {
467        let child_values: Vec<LiNo<String>> = link
468            .children
469            .iter()
470            .map(|child| {
471                // For indented children, if they have single values, extract them
472                if child.values.len() == 1
473                    && child.values[0].values.is_empty()
474                    && child.values[0].children.is_empty()
475                {
476                    // Use if let to safely extract the ID instead of unwrap()
477                    if let Some(ref id) = child.values[0].id {
478                        LiNo::Ref(id.clone())
479                    } else {
480                        // If no ID, create an empty link
481                        parser::Link {
482                            id: child.id.clone(),
483                            values: child.values.clone(),
484                            children: vec![],
485                            is_indented_id: false,
486                            nested: child.nested.clone(),
487                        }
488                        .into()
489                    }
490                } else {
491                    parser::Link {
492                        id: child.id.clone(),
493                        values: child.values.clone(),
494                        children: vec![],
495                        is_indented_id: false,
496                        nested: child.nested.clone(),
497                    }
498                    .into()
499                }
500            })
501            .collect();
502
503        let current = LiNo::Link {
504            id: link.id.clone(),
505            values: child_values,
506        };
507
508        let combined = if let Some(parent) = parent {
509            // Wrap parent in parentheses if it's a reference
510            let wrapped_parent = match parent {
511                LiNo::Ref(ref_id) => LiNo::Link {
512                    id: None,
513                    values: vec![LiNo::Ref(ref_id.clone())],
514                },
515                link => link.clone(),
516            };
517
518            LiNo::Link {
519                id: None,
520                values: vec![wrapped_parent, current],
521            }
522        } else {
523            current
524        };
525
526        result.push(combined);
527        return; // Don't process children again
528    }
529
530    // Create the current link without children
531    let current = if let Some(body) = &link.nested {
532        transform_nested(body)
533    } else if link.values.is_empty() {
534        if let Some(id) = &link.id {
535            LiNo::Ref(id.clone())
536        } else {
537            LiNo::Link {
538                id: None,
539                values: vec![],
540            }
541        }
542    } else {
543        let values: Vec<LiNo<String>> = link
544            .values
545            .iter()
546            .map(|v| {
547                parser::Link {
548                    id: v.id.clone(),
549                    values: v.values.clone(),
550                    children: vec![],
551                    is_indented_id: false,
552                    nested: v.nested.clone(),
553                }
554                .into()
555            })
556            .collect();
557        LiNo::Link {
558            id: link.id.clone(),
559            values,
560        }
561    };
562
563    // Create the combined link (parent + current) with proper wrapping
564    let combined = if let Some(parent) = parent {
565        // Wrap parent in parentheses if it's a reference
566        let wrapped_parent = match parent {
567            LiNo::Ref(ref_id) => LiNo::Link {
568                id: None,
569                values: vec![LiNo::Ref(ref_id.clone())],
570            },
571            link => link.clone(),
572        };
573
574        // Wrap current in parentheses if it's a reference
575        let wrapped_current = match &current {
576            LiNo::Ref(ref_id) => LiNo::Link {
577                id: None,
578                values: vec![LiNo::Ref(ref_id.clone())],
579            },
580            link => link.clone(),
581        };
582
583        LiNo::Link {
584            id: None,
585            values: vec![wrapped_parent, wrapped_current],
586        }
587    } else {
588        current.clone()
589    };
590
591    result.push(combined.clone());
592
593    // Process children
594    for child in &link.children {
595        flatten_link_recursive(child, Some(&combined), result);
596    }
597}
598
599pub fn parse_lino(document: &str) -> Result<LiNo<String>, ParseError> {
600    // Handle empty or whitespace-only input by returning empty result
601    if document.trim().is_empty() {
602        return Ok(LiNo::Link {
603            id: None,
604            values: vec![],
605        });
606    }
607
608    match parser::parse_document(document) {
609        Ok((_, links)) => {
610            if links.is_empty() {
611                Ok(LiNo::Link {
612                    id: None,
613                    values: vec![],
614                })
615            } else {
616                // Flatten the indented structure according to Lino spec
617                let flattened = flatten_links(links);
618                Ok(LiNo::Link {
619                    id: None,
620                    values: flattened,
621                })
622            }
623        }
624        Err(e) => Err(ParseError::SyntaxError(format!("{:?}", e))),
625    }
626}
627
628// New function that matches C# and JS API - returns collection of links
629pub fn parse_lino_to_links(document: &str) -> Result<Vec<LiNo<String>>, ParseError> {
630    // Handle empty or whitespace-only input by returning empty collection
631    if document.trim().is_empty() {
632        return Ok(vec![]);
633    }
634
635    match parser::parse_document(document) {
636        Ok((_, links)) => {
637            if links.is_empty() {
638                Ok(vec![])
639            } else {
640                // Flatten the indented structure according to Lino spec
641                let flattened = flatten_links(links);
642                Ok(flattened)
643            }
644        }
645        Err(e) => Err(ParseError::SyntaxError(format!("{:?}", e))),
646    }
647}
648
649/// Formats a collection of LiNo links as a multi-line string.
650/// Each link is formatted on a separate line.
651pub fn format_links(links: &[LiNo<String>]) -> String {
652    links
653        .iter()
654        .map(|link| format!("{}", link))
655        .collect::<Vec<_>>()
656        .join("\n")
657}
658
659/// Formats a collection of LiNo links as a multi-line string using FormatConfig.
660/// Supports all formatting options including consecutive link grouping.
661///
662/// # Arguments
663/// * `links` - The collection of links to format
664/// * `config` - The FormatConfig to use for formatting
665///
666/// # Returns
667/// Formatted string in Lino notation
668pub fn format_links_with_config(links: &[LiNo<String>], config: &FormatConfig) -> String {
669    if links.is_empty() {
670        return String::new();
671    }
672
673    // Apply consecutive link grouping if enabled
674    let links_to_format = if config.group_consecutive {
675        group_consecutive_links(links)
676    } else {
677        links.to_vec()
678    };
679
680    links_to_format
681        .iter()
682        .map(|link| link.format_with_config(config))
683        .collect::<Vec<_>>()
684        .join("\n")
685}
686
687/// Groups consecutive links with the same ID.
688///
689/// For example:
690/// ```text
691/// SetA a
692/// SetA b
693/// SetA c
694/// ```
695/// Becomes:
696/// ```text
697/// SetA
698///   a
699///   b
700///   c
701/// ```
702fn group_consecutive_links(links: &[LiNo<String>]) -> Vec<LiNo<String>> {
703    if links.is_empty() {
704        return vec![];
705    }
706
707    let mut grouped = vec![];
708    let mut i = 0;
709
710    while i < links.len() {
711        let current = &links[i];
712
713        // Look ahead for consecutive links with same ID
714        if let LiNo::Link {
715            id: Some(ref current_id),
716            values: ref current_values,
717        } = current
718        {
719            if !current_values.is_empty() {
720                // Collect all values with same ID
721                let mut same_id_values = current_values.clone();
722                let mut j = i + 1;
723
724                while j < links.len() {
725                    if let LiNo::Link {
726                        id: Some(ref next_id),
727                        values: ref next_values,
728                    } = &links[j]
729                    {
730                        if next_id == current_id && !next_values.is_empty() {
731                            same_id_values.extend(next_values.clone());
732                            j += 1;
733                        } else {
734                            break;
735                        }
736                    } else {
737                        break;
738                    }
739                }
740
741                // If we found consecutive links, create grouped link
742                if j > i + 1 {
743                    grouped.push(LiNo::Link {
744                        id: Some(current_id.clone()),
745                        values: same_id_values,
746                    });
747                    i = j;
748                    continue;
749                }
750            }
751        }
752
753        grouped.push(current.clone());
754        i += 1;
755    }
756
757    grouped
758}
759
760/// Escape a reference string by adding quotes if necessary.
761fn escape_reference(reference: &str) -> String {
762    // The empty reference is written as a bare delimiter pair, so that it reads
763    // back as itself instead of disappearing from the document.
764    if reference.is_empty() {
765        return "\"\"".to_string();
766    }
767
768    let has_single_quote = reference.contains('\'');
769    let has_double_quote = reference.contains('"');
770
771    let needs_quoting = reference.contains(':')
772        || reference.contains('(')
773        || reference.contains(')')
774        || reference.contains(' ')
775        || reference.contains('\t')
776        || reference.contains('\n')
777        || reference.contains('\r')
778        || has_double_quote
779        || has_single_quote;
780
781    // Handle edge case: reference contains both single and double quotes
782    if has_single_quote && has_double_quote {
783        // Escape single quotes and wrap in single quotes
784        return format!("'{}'", reference.replace('\'', "\\'"));
785    }
786
787    // Prefer single quotes if double quotes are present
788    if has_double_quote {
789        return format!("'{}'", reference);
790    }
791
792    // Use double quotes if single quotes are present
793    if has_single_quote {
794        return format!("\"{}\"", reference);
795    }
796
797    // Use single quotes for special characters
798    if needs_quoting {
799        return format!("'{}'", reference);
800    }
801
802    // No quoting needed
803    reference.to_string()
804}
805
806/// Check if a string needs to be wrapped in parentheses.
807fn needs_parentheses(s: &str) -> bool {
808    s.contains(' ') || s.contains(':') || s.contains('(') || s.contains(')')
809}
810
811/// Format a value within a link.
812fn format_value<T: ToString>(value: &LiNo<T>) -> String {
813    match value {
814        LiNo::Ref(r) => escape_reference(&r.to_string()),
815        LiNo::Link { id, values } => {
816            // Simple link with just an ID - don't wrap in extra parentheses
817            if values.is_empty() {
818                if let Some(ref id_val) = id {
819                    return escape_reference(&id_val.to_string());
820                }
821                return String::new();
822            }
823            // Complex value - format with parentheses
824            format!("{}", value)
825        }
826    }
827}
828
829// Tuple conversion implementations for ergonomic link creation
830// These implementations allow creating links using Rust tuple syntax
831//
832// The macro generates From implementations for tuples of sizes 2-12.
833// For each size, it generates 4 types of conversions:
834// 1. All &str - first element becomes ID, rest become values
835// 2. All String - first element becomes ID, rest become values
836// 3. &str ID with LiNo values - first element becomes ID, LiNo elements become values
837// 4. All LiNo - creates anonymous link (no ID) with all elements as values
838
839/// Macro to implement From trait for tuples converting to LiNo<String>.
840///
841/// This macro generates four From implementations for each tuple size:
842/// - `(&str, &str, ...)` - First element becomes ID, rest become string values
843/// - `(String, String, ...)` - First element becomes ID, rest become string values
844/// - `(&str, LiNo<String>, ...)` - First element becomes ID, LiNo elements become values
845/// - `(LiNo<String>, LiNo<String>, ...)` - Creates anonymous link with all elements as values
846///
847/// # Examples
848/// ```
849/// use links_notation::LiNo;
850///
851/// // 2-tuple: ("id", "value") -> (id: value)
852/// let link: LiNo<String> = ("papa", "mama").into();
853/// assert_eq!(format!("{}", link), "(papa: mama)");
854///
855/// // 3-tuple: ("id", "v1", "v2") -> (id: v1 v2)
856/// let link: LiNo<String> = ("parent", "child1", "child2").into();
857/// assert_eq!(format!("{}", link), "(parent: child1 child2)");
858///
859/// // Anonymous link from all LiNo elements
860/// let a = LiNo::Ref("a".to_string());
861/// let b = LiNo::Ref("b".to_string());
862/// let link: LiNo<String> = (a, b).into();
863/// assert_eq!(format!("{}", link), "(a b)");
864/// ```
865macro_rules! impl_tuple_from {
866    // Implementation for 2-tuples
867    (@str_tuple 2, $t0:tt, $t1:tt) => {
868        impl From<(&str, &str)> for LiNo<String> {
869            fn from(tuple: (&str, &str)) -> Self {
870                LiNo::Link {
871                    id: Some(tuple.$t0.to_string()),
872                    values: vec![LiNo::Ref(tuple.$t1.to_string())],
873                }
874            }
875        }
876    };
877    (@string_tuple 2, $t0:tt, $t1:tt) => {
878        impl From<(String, String)> for LiNo<String> {
879            fn from(tuple: (String, String)) -> Self {
880                LiNo::Link {
881                    id: Some(tuple.$t0),
882                    values: vec![LiNo::Ref(tuple.$t1)],
883                }
884            }
885        }
886    };
887    (@str_lino_tuple 2, $t0:tt, $t1:tt) => {
888        impl From<(&str, LiNo<String>)> for LiNo<String> {
889            fn from(tuple: (&str, LiNo<String>)) -> Self {
890                LiNo::Link {
891                    id: Some(tuple.$t0.to_string()),
892                    values: vec![tuple.$t1],
893                }
894            }
895        }
896    };
897    (@lino_tuple 2, $t0:tt, $t1:tt) => {
898        impl From<(LiNo<String>, LiNo<String>)> for LiNo<String> {
899            fn from(tuple: (LiNo<String>, LiNo<String>)) -> Self {
900                LiNo::Link {
901                    id: None,
902                    values: vec![tuple.$t0, tuple.$t1],
903                }
904            }
905        }
906    };
907
908    // Implementation for 3-tuples
909    (@str_tuple 3, $t0:tt, $t1:tt, $t2:tt) => {
910        impl From<(&str, &str, &str)> for LiNo<String> {
911            fn from(tuple: (&str, &str, &str)) -> Self {
912                LiNo::Link {
913                    id: Some(tuple.$t0.to_string()),
914                    values: vec![LiNo::Ref(tuple.$t1.to_string()), LiNo::Ref(tuple.$t2.to_string())],
915                }
916            }
917        }
918    };
919    (@string_tuple 3, $t0:tt, $t1:tt, $t2:tt) => {
920        impl From<(String, String, String)> for LiNo<String> {
921            fn from(tuple: (String, String, String)) -> Self {
922                LiNo::Link {
923                    id: Some(tuple.$t0),
924                    values: vec![LiNo::Ref(tuple.$t1), LiNo::Ref(tuple.$t2)],
925                }
926            }
927        }
928    };
929    (@str_lino_tuple 3, $t0:tt, $t1:tt, $t2:tt) => {
930        impl From<(&str, LiNo<String>, LiNo<String>)> for LiNo<String> {
931            fn from(tuple: (&str, LiNo<String>, LiNo<String>)) -> Self {
932                LiNo::Link {
933                    id: Some(tuple.$t0.to_string()),
934                    values: vec![tuple.$t1, tuple.$t2],
935                }
936            }
937        }
938    };
939    (@lino_tuple 3, $t0:tt, $t1:tt, $t2:tt) => {
940        impl From<(LiNo<String>, LiNo<String>, LiNo<String>)> for LiNo<String> {
941            fn from(tuple: (LiNo<String>, LiNo<String>, LiNo<String>)) -> Self {
942                LiNo::Link {
943                    id: None,
944                    values: vec![tuple.$t0, tuple.$t1, tuple.$t2],
945                }
946            }
947        }
948    };
949
950    // Implementation for 4-tuples
951    (@str_tuple 4, $t0:tt, $t1:tt, $t2:tt, $t3:tt) => {
952        impl From<(&str, &str, &str, &str)> for LiNo<String> {
953            fn from(tuple: (&str, &str, &str, &str)) -> Self {
954                LiNo::Link {
955                    id: Some(tuple.$t0.to_string()),
956                    values: vec![
957                        LiNo::Ref(tuple.$t1.to_string()),
958                        LiNo::Ref(tuple.$t2.to_string()),
959                        LiNo::Ref(tuple.$t3.to_string()),
960                    ],
961                }
962            }
963        }
964    };
965    (@string_tuple 4, $t0:tt, $t1:tt, $t2:tt, $t3:tt) => {
966        impl From<(String, String, String, String)> for LiNo<String> {
967            fn from(tuple: (String, String, String, String)) -> Self {
968                LiNo::Link {
969                    id: Some(tuple.$t0),
970                    values: vec![LiNo::Ref(tuple.$t1), LiNo::Ref(tuple.$t2), LiNo::Ref(tuple.$t3)],
971                }
972            }
973        }
974    };
975    (@str_lino_tuple 4, $t0:tt, $t1:tt, $t2:tt, $t3:tt) => {
976        impl From<(&str, LiNo<String>, LiNo<String>, LiNo<String>)> for LiNo<String> {
977            fn from(tuple: (&str, LiNo<String>, LiNo<String>, LiNo<String>)) -> Self {
978                LiNo::Link {
979                    id: Some(tuple.$t0.to_string()),
980                    values: vec![tuple.$t1, tuple.$t2, tuple.$t3],
981                }
982            }
983        }
984    };
985    (@lino_tuple 4, $t0:tt, $t1:tt, $t2:tt, $t3:tt) => {
986        impl From<(LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)> for LiNo<String> {
987            fn from(tuple: (LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)) -> Self {
988                LiNo::Link {
989                    id: None,
990                    values: vec![tuple.$t0, tuple.$t1, tuple.$t2, tuple.$t3],
991                }
992            }
993        }
994    };
995
996    // Implementation for 5-tuples
997    (@str_tuple 5, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt) => {
998        impl From<(&str, &str, &str, &str, &str)> for LiNo<String> {
999            fn from(tuple: (&str, &str, &str, &str, &str)) -> Self {
1000                LiNo::Link {
1001                    id: Some(tuple.$t0.to_string()),
1002                    values: vec![
1003                        LiNo::Ref(tuple.$t1.to_string()),
1004                        LiNo::Ref(tuple.$t2.to_string()),
1005                        LiNo::Ref(tuple.$t3.to_string()),
1006                        LiNo::Ref(tuple.$t4.to_string()),
1007                    ],
1008                }
1009            }
1010        }
1011    };
1012    (@string_tuple 5, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt) => {
1013        impl From<(String, String, String, String, String)> for LiNo<String> {
1014            fn from(tuple: (String, String, String, String, String)) -> Self {
1015                LiNo::Link {
1016                    id: Some(tuple.$t0),
1017                    values: vec![
1018                        LiNo::Ref(tuple.$t1),
1019                        LiNo::Ref(tuple.$t2),
1020                        LiNo::Ref(tuple.$t3),
1021                        LiNo::Ref(tuple.$t4),
1022                    ],
1023                }
1024            }
1025        }
1026    };
1027    (@str_lino_tuple 5, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt) => {
1028        impl From<(&str, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)> for LiNo<String> {
1029            fn from(tuple: (&str, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)) -> Self {
1030                LiNo::Link {
1031                    id: Some(tuple.$t0.to_string()),
1032                    values: vec![tuple.$t1, tuple.$t2, tuple.$t3, tuple.$t4],
1033                }
1034            }
1035        }
1036    };
1037    (@lino_tuple 5, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt) => {
1038        impl From<(LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)> for LiNo<String> {
1039            fn from(tuple: (LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)) -> Self {
1040                LiNo::Link {
1041                    id: None,
1042                    values: vec![tuple.$t0, tuple.$t1, tuple.$t2, tuple.$t3, tuple.$t4],
1043                }
1044            }
1045        }
1046    };
1047
1048    // Implementation for 6-tuples
1049    (@str_tuple 6, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt, $t5:tt) => {
1050        impl From<(&str, &str, &str, &str, &str, &str)> for LiNo<String> {
1051            fn from(tuple: (&str, &str, &str, &str, &str, &str)) -> Self {
1052                LiNo::Link {
1053                    id: Some(tuple.$t0.to_string()),
1054                    values: vec![
1055                        LiNo::Ref(tuple.$t1.to_string()),
1056                        LiNo::Ref(tuple.$t2.to_string()),
1057                        LiNo::Ref(tuple.$t3.to_string()),
1058                        LiNo::Ref(tuple.$t4.to_string()),
1059                        LiNo::Ref(tuple.$t5.to_string()),
1060                    ],
1061                }
1062            }
1063        }
1064    };
1065    (@string_tuple 6, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt, $t5:tt) => {
1066        impl From<(String, String, String, String, String, String)> for LiNo<String> {
1067            fn from(tuple: (String, String, String, String, String, String)) -> Self {
1068                LiNo::Link {
1069                    id: Some(tuple.$t0),
1070                    values: vec![
1071                        LiNo::Ref(tuple.$t1),
1072                        LiNo::Ref(tuple.$t2),
1073                        LiNo::Ref(tuple.$t3),
1074                        LiNo::Ref(tuple.$t4),
1075                        LiNo::Ref(tuple.$t5),
1076                    ],
1077                }
1078            }
1079        }
1080    };
1081    (@str_lino_tuple 6, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt, $t5:tt) => {
1082        impl From<(&str, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)> for LiNo<String> {
1083            fn from(tuple: (&str, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)) -> Self {
1084                LiNo::Link {
1085                    id: Some(tuple.$t0.to_string()),
1086                    values: vec![tuple.$t1, tuple.$t2, tuple.$t3, tuple.$t4, tuple.$t5],
1087                }
1088            }
1089        }
1090    };
1091    (@lino_tuple 6, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt, $t5:tt) => {
1092        impl From<(LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)> for LiNo<String> {
1093            fn from(tuple: (LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)) -> Self {
1094                LiNo::Link {
1095                    id: None,
1096                    values: vec![tuple.$t0, tuple.$t1, tuple.$t2, tuple.$t3, tuple.$t4, tuple.$t5],
1097                }
1098            }
1099        }
1100    };
1101
1102    // Implementation for 7-tuples
1103    (@str_tuple 7, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt, $t5:tt, $t6:tt) => {
1104        impl From<(&str, &str, &str, &str, &str, &str, &str)> for LiNo<String> {
1105            fn from(tuple: (&str, &str, &str, &str, &str, &str, &str)) -> Self {
1106                LiNo::Link {
1107                    id: Some(tuple.$t0.to_string()),
1108                    values: vec![
1109                        LiNo::Ref(tuple.$t1.to_string()),
1110                        LiNo::Ref(tuple.$t2.to_string()),
1111                        LiNo::Ref(tuple.$t3.to_string()),
1112                        LiNo::Ref(tuple.$t4.to_string()),
1113                        LiNo::Ref(tuple.$t5.to_string()),
1114                        LiNo::Ref(tuple.$t6.to_string()),
1115                    ],
1116                }
1117            }
1118        }
1119    };
1120    (@string_tuple 7, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt, $t5:tt, $t6:tt) => {
1121        impl From<(String, String, String, String, String, String, String)> for LiNo<String> {
1122            fn from(tuple: (String, String, String, String, String, String, String)) -> Self {
1123                LiNo::Link {
1124                    id: Some(tuple.$t0),
1125                    values: vec![
1126                        LiNo::Ref(tuple.$t1),
1127                        LiNo::Ref(tuple.$t2),
1128                        LiNo::Ref(tuple.$t3),
1129                        LiNo::Ref(tuple.$t4),
1130                        LiNo::Ref(tuple.$t5),
1131                        LiNo::Ref(tuple.$t6),
1132                    ],
1133                }
1134            }
1135        }
1136    };
1137    (@str_lino_tuple 7, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt, $t5:tt, $t6:tt) => {
1138        impl From<(&str, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)> for LiNo<String> {
1139            fn from(tuple: (&str, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)) -> Self {
1140                LiNo::Link {
1141                    id: Some(tuple.$t0.to_string()),
1142                    values: vec![tuple.$t1, tuple.$t2, tuple.$t3, tuple.$t4, tuple.$t5, tuple.$t6],
1143                }
1144            }
1145        }
1146    };
1147    (@lino_tuple 7, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt, $t5:tt, $t6:tt) => {
1148        impl From<(LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)> for LiNo<String> {
1149            fn from(tuple: (LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)) -> Self {
1150                LiNo::Link {
1151                    id: None,
1152                    values: vec![tuple.$t0, tuple.$t1, tuple.$t2, tuple.$t3, tuple.$t4, tuple.$t5, tuple.$t6],
1153                }
1154            }
1155        }
1156    };
1157
1158    // Implementation for 8-tuples
1159    (@str_tuple 8, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt, $t5:tt, $t6:tt, $t7:tt) => {
1160        impl From<(&str, &str, &str, &str, &str, &str, &str, &str)> for LiNo<String> {
1161            fn from(tuple: (&str, &str, &str, &str, &str, &str, &str, &str)) -> Self {
1162                LiNo::Link {
1163                    id: Some(tuple.$t0.to_string()),
1164                    values: vec![
1165                        LiNo::Ref(tuple.$t1.to_string()),
1166                        LiNo::Ref(tuple.$t2.to_string()),
1167                        LiNo::Ref(tuple.$t3.to_string()),
1168                        LiNo::Ref(tuple.$t4.to_string()),
1169                        LiNo::Ref(tuple.$t5.to_string()),
1170                        LiNo::Ref(tuple.$t6.to_string()),
1171                        LiNo::Ref(tuple.$t7.to_string()),
1172                    ],
1173                }
1174            }
1175        }
1176    };
1177    (@string_tuple 8, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt, $t5:tt, $t6:tt, $t7:tt) => {
1178        impl From<(String, String, String, String, String, String, String, String)> for LiNo<String> {
1179            fn from(tuple: (String, String, String, String, String, String, String, String)) -> Self {
1180                LiNo::Link {
1181                    id: Some(tuple.$t0),
1182                    values: vec![
1183                        LiNo::Ref(tuple.$t1),
1184                        LiNo::Ref(tuple.$t2),
1185                        LiNo::Ref(tuple.$t3),
1186                        LiNo::Ref(tuple.$t4),
1187                        LiNo::Ref(tuple.$t5),
1188                        LiNo::Ref(tuple.$t6),
1189                        LiNo::Ref(tuple.$t7),
1190                    ],
1191                }
1192            }
1193        }
1194    };
1195    (@str_lino_tuple 8, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt, $t5:tt, $t6:tt, $t7:tt) => {
1196        impl From<(&str, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)> for LiNo<String> {
1197            fn from(tuple: (&str, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)) -> Self {
1198                LiNo::Link {
1199                    id: Some(tuple.$t0.to_string()),
1200                    values: vec![tuple.$t1, tuple.$t2, tuple.$t3, tuple.$t4, tuple.$t5, tuple.$t6, tuple.$t7],
1201                }
1202            }
1203        }
1204    };
1205    (@lino_tuple 8, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt, $t5:tt, $t6:tt, $t7:tt) => {
1206        impl From<(LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)> for LiNo<String> {
1207            fn from(tuple: (LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)) -> Self {
1208                LiNo::Link {
1209                    id: None,
1210                    values: vec![tuple.$t0, tuple.$t1, tuple.$t2, tuple.$t3, tuple.$t4, tuple.$t5, tuple.$t6, tuple.$t7],
1211                }
1212            }
1213        }
1214    };
1215
1216    // Implementation for 9-tuples
1217    (@str_tuple 9, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt, $t5:tt, $t6:tt, $t7:tt, $t8:tt) => {
1218        impl From<(&str, &str, &str, &str, &str, &str, &str, &str, &str)> for LiNo<String> {
1219            fn from(tuple: (&str, &str, &str, &str, &str, &str, &str, &str, &str)) -> Self {
1220                LiNo::Link {
1221                    id: Some(tuple.$t0.to_string()),
1222                    values: vec![
1223                        LiNo::Ref(tuple.$t1.to_string()),
1224                        LiNo::Ref(tuple.$t2.to_string()),
1225                        LiNo::Ref(tuple.$t3.to_string()),
1226                        LiNo::Ref(tuple.$t4.to_string()),
1227                        LiNo::Ref(tuple.$t5.to_string()),
1228                        LiNo::Ref(tuple.$t6.to_string()),
1229                        LiNo::Ref(tuple.$t7.to_string()),
1230                        LiNo::Ref(tuple.$t8.to_string()),
1231                    ],
1232                }
1233            }
1234        }
1235    };
1236    (@string_tuple 9, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt, $t5:tt, $t6:tt, $t7:tt, $t8:tt) => {
1237        impl From<(String, String, String, String, String, String, String, String, String)> for LiNo<String> {
1238            fn from(tuple: (String, String, String, String, String, String, String, String, String)) -> Self {
1239                LiNo::Link {
1240                    id: Some(tuple.$t0),
1241                    values: vec![
1242                        LiNo::Ref(tuple.$t1),
1243                        LiNo::Ref(tuple.$t2),
1244                        LiNo::Ref(tuple.$t3),
1245                        LiNo::Ref(tuple.$t4),
1246                        LiNo::Ref(tuple.$t5),
1247                        LiNo::Ref(tuple.$t6),
1248                        LiNo::Ref(tuple.$t7),
1249                        LiNo::Ref(tuple.$t8),
1250                    ],
1251                }
1252            }
1253        }
1254    };
1255    (@str_lino_tuple 9, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt, $t5:tt, $t6:tt, $t7:tt, $t8:tt) => {
1256        impl From<(&str, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)> for LiNo<String> {
1257            fn from(tuple: (&str, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)) -> Self {
1258                LiNo::Link {
1259                    id: Some(tuple.$t0.to_string()),
1260                    values: vec![tuple.$t1, tuple.$t2, tuple.$t3, tuple.$t4, tuple.$t5, tuple.$t6, tuple.$t7, tuple.$t8],
1261                }
1262            }
1263        }
1264    };
1265    (@lino_tuple 9, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt, $t5:tt, $t6:tt, $t7:tt, $t8:tt) => {
1266        impl From<(LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)> for LiNo<String> {
1267            fn from(tuple: (LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)) -> Self {
1268                LiNo::Link {
1269                    id: None,
1270                    values: vec![tuple.$t0, tuple.$t1, tuple.$t2, tuple.$t3, tuple.$t4, tuple.$t5, tuple.$t6, tuple.$t7, tuple.$t8],
1271                }
1272            }
1273        }
1274    };
1275
1276    // Implementation for 10-tuples
1277    (@str_tuple 10, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt, $t5:tt, $t6:tt, $t7:tt, $t8:tt, $t9:tt) => {
1278        impl From<(&str, &str, &str, &str, &str, &str, &str, &str, &str, &str)> for LiNo<String> {
1279            fn from(tuple: (&str, &str, &str, &str, &str, &str, &str, &str, &str, &str)) -> Self {
1280                LiNo::Link {
1281                    id: Some(tuple.$t0.to_string()),
1282                    values: vec![
1283                        LiNo::Ref(tuple.$t1.to_string()),
1284                        LiNo::Ref(tuple.$t2.to_string()),
1285                        LiNo::Ref(tuple.$t3.to_string()),
1286                        LiNo::Ref(tuple.$t4.to_string()),
1287                        LiNo::Ref(tuple.$t5.to_string()),
1288                        LiNo::Ref(tuple.$t6.to_string()),
1289                        LiNo::Ref(tuple.$t7.to_string()),
1290                        LiNo::Ref(tuple.$t8.to_string()),
1291                        LiNo::Ref(tuple.$t9.to_string()),
1292                    ],
1293                }
1294            }
1295        }
1296    };
1297    (@string_tuple 10, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt, $t5:tt, $t6:tt, $t7:tt, $t8:tt, $t9:tt) => {
1298        impl From<(String, String, String, String, String, String, String, String, String, String)> for LiNo<String> {
1299            fn from(tuple: (String, String, String, String, String, String, String, String, String, String)) -> Self {
1300                LiNo::Link {
1301                    id: Some(tuple.$t0),
1302                    values: vec![
1303                        LiNo::Ref(tuple.$t1),
1304                        LiNo::Ref(tuple.$t2),
1305                        LiNo::Ref(tuple.$t3),
1306                        LiNo::Ref(tuple.$t4),
1307                        LiNo::Ref(tuple.$t5),
1308                        LiNo::Ref(tuple.$t6),
1309                        LiNo::Ref(tuple.$t7),
1310                        LiNo::Ref(tuple.$t8),
1311                        LiNo::Ref(tuple.$t9),
1312                    ],
1313                }
1314            }
1315        }
1316    };
1317    (@str_lino_tuple 10, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt, $t5:tt, $t6:tt, $t7:tt, $t8:tt, $t9:tt) => {
1318        impl From<(&str, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)> for LiNo<String> {
1319            fn from(tuple: (&str, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)) -> Self {
1320                LiNo::Link {
1321                    id: Some(tuple.$t0.to_string()),
1322                    values: vec![tuple.$t1, tuple.$t2, tuple.$t3, tuple.$t4, tuple.$t5, tuple.$t6, tuple.$t7, tuple.$t8, tuple.$t9],
1323                }
1324            }
1325        }
1326    };
1327    (@lino_tuple 10, $t0:tt, $t1:tt, $t2:tt, $t3:tt, $t4:tt, $t5:tt, $t6:tt, $t7:tt, $t8:tt, $t9:tt) => {
1328        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> {
1329            fn from(tuple: (LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>, LiNo<String>)) -> Self {
1330                LiNo::Link {
1331                    id: None,
1332                    values: vec![tuple.$t0, tuple.$t1, tuple.$t2, tuple.$t3, tuple.$t4, tuple.$t5, tuple.$t6, tuple.$t7, tuple.$t8, tuple.$t9],
1333                }
1334            }
1335        }
1336    };
1337
1338    // Implementation for 11-tuples
1339    (@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) => {
1340        impl From<(&str, &str, &str, &str, &str, &str, &str, &str, &str, &str, &str)> for LiNo<String> {
1341            fn from(tuple: (&str, &str, &str, &str, &str, &str, &str, &str, &str, &str, &str)) -> Self {
1342                LiNo::Link {
1343                    id: Some(tuple.$t0.to_string()),
1344                    values: vec![
1345                        LiNo::Ref(tuple.$t1.to_string()),
1346                        LiNo::Ref(tuple.$t2.to_string()),
1347                        LiNo::Ref(tuple.$t3.to_string()),
1348                        LiNo::Ref(tuple.$t4.to_string()),
1349                        LiNo::Ref(tuple.$t5.to_string()),
1350                        LiNo::Ref(tuple.$t6.to_string()),
1351                        LiNo::Ref(tuple.$t7.to_string()),
1352                        LiNo::Ref(tuple.$t8.to_string()),
1353                        LiNo::Ref(tuple.$t9.to_string()),
1354                        LiNo::Ref(tuple.$t10.to_string()),
1355                    ],
1356                }
1357            }
1358        }
1359    };
1360    (@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) => {
1361        impl From<(String, String, String, String, String, String, String, String, String, String, String)> for LiNo<String> {
1362            fn from(tuple: (String, String, String, String, String, String, String, String, String, String, String)) -> Self {
1363                LiNo::Link {
1364                    id: Some(tuple.$t0),
1365                    values: vec![
1366                        LiNo::Ref(tuple.$t1),
1367                        LiNo::Ref(tuple.$t2),
1368                        LiNo::Ref(tuple.$t3),
1369                        LiNo::Ref(tuple.$t4),
1370                        LiNo::Ref(tuple.$t5),
1371                        LiNo::Ref(tuple.$t6),
1372                        LiNo::Ref(tuple.$t7),
1373                        LiNo::Ref(tuple.$t8),
1374                        LiNo::Ref(tuple.$t9),
1375                        LiNo::Ref(tuple.$t10),
1376                    ],
1377                }
1378            }
1379        }
1380    };
1381    (@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) => {
1382        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> {
1383            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 {
1384                LiNo::Link {
1385                    id: Some(tuple.$t0.to_string()),
1386                    values: vec![tuple.$t1, tuple.$t2, tuple.$t3, tuple.$t4, tuple.$t5, tuple.$t6, tuple.$t7, tuple.$t8, tuple.$t9, tuple.$t10],
1387                }
1388            }
1389        }
1390    };
1391    (@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) => {
1392        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> {
1393            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 {
1394                LiNo::Link {
1395                    id: None,
1396                    values: vec![tuple.$t0, tuple.$t1, tuple.$t2, tuple.$t3, tuple.$t4, tuple.$t5, tuple.$t6, tuple.$t7, tuple.$t8, tuple.$t9, tuple.$t10],
1397                }
1398            }
1399        }
1400    };
1401
1402    // Implementation for 12-tuples
1403    (@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) => {
1404        impl From<(&str, &str, &str, &str, &str, &str, &str, &str, &str, &str, &str, &str)> for LiNo<String> {
1405            fn from(tuple: (&str, &str, &str, &str, &str, &str, &str, &str, &str, &str, &str, &str)) -> Self {
1406                LiNo::Link {
1407                    id: Some(tuple.$t0.to_string()),
1408                    values: vec![
1409                        LiNo::Ref(tuple.$t1.to_string()),
1410                        LiNo::Ref(tuple.$t2.to_string()),
1411                        LiNo::Ref(tuple.$t3.to_string()),
1412                        LiNo::Ref(tuple.$t4.to_string()),
1413                        LiNo::Ref(tuple.$t5.to_string()),
1414                        LiNo::Ref(tuple.$t6.to_string()),
1415                        LiNo::Ref(tuple.$t7.to_string()),
1416                        LiNo::Ref(tuple.$t8.to_string()),
1417                        LiNo::Ref(tuple.$t9.to_string()),
1418                        LiNo::Ref(tuple.$t10.to_string()),
1419                        LiNo::Ref(tuple.$t11.to_string()),
1420                    ],
1421                }
1422            }
1423        }
1424    };
1425    (@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) => {
1426        impl From<(String, String, String, String, String, String, String, String, String, String, String, String)> for LiNo<String> {
1427            fn from(tuple: (String, String, String, String, String, String, String, String, String, String, String, String)) -> Self {
1428                LiNo::Link {
1429                    id: Some(tuple.$t0),
1430                    values: vec![
1431                        LiNo::Ref(tuple.$t1),
1432                        LiNo::Ref(tuple.$t2),
1433                        LiNo::Ref(tuple.$t3),
1434                        LiNo::Ref(tuple.$t4),
1435                        LiNo::Ref(tuple.$t5),
1436                        LiNo::Ref(tuple.$t6),
1437                        LiNo::Ref(tuple.$t7),
1438                        LiNo::Ref(tuple.$t8),
1439                        LiNo::Ref(tuple.$t9),
1440                        LiNo::Ref(tuple.$t10),
1441                        LiNo::Ref(tuple.$t11),
1442                    ],
1443                }
1444            }
1445        }
1446    };
1447    (@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) => {
1448        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> {
1449            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 {
1450                LiNo::Link {
1451                    id: Some(tuple.$t0.to_string()),
1452                    values: vec![tuple.$t1, tuple.$t2, tuple.$t3, tuple.$t4, tuple.$t5, tuple.$t6, tuple.$t7, tuple.$t8, tuple.$t9, tuple.$t10, tuple.$t11],
1453                }
1454            }
1455        }
1456    };
1457    (@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) => {
1458        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> {
1459            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 {
1460                LiNo::Link {
1461                    id: None,
1462                    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],
1463                }
1464            }
1465        }
1466    };
1467
1468    // Entry point - generates all four types for a given tuple size
1469    (2) => {
1470        impl_tuple_from!(@str_tuple 2, 0, 1);
1471        impl_tuple_from!(@string_tuple 2, 0, 1);
1472        impl_tuple_from!(@str_lino_tuple 2, 0, 1);
1473        impl_tuple_from!(@lino_tuple 2, 0, 1);
1474    };
1475    (3) => {
1476        impl_tuple_from!(@str_tuple 3, 0, 1, 2);
1477        impl_tuple_from!(@string_tuple 3, 0, 1, 2);
1478        impl_tuple_from!(@str_lino_tuple 3, 0, 1, 2);
1479        impl_tuple_from!(@lino_tuple 3, 0, 1, 2);
1480    };
1481    (4) => {
1482        impl_tuple_from!(@str_tuple 4, 0, 1, 2, 3);
1483        impl_tuple_from!(@string_tuple 4, 0, 1, 2, 3);
1484        impl_tuple_from!(@str_lino_tuple 4, 0, 1, 2, 3);
1485        impl_tuple_from!(@lino_tuple 4, 0, 1, 2, 3);
1486    };
1487    (5) => {
1488        impl_tuple_from!(@str_tuple 5, 0, 1, 2, 3, 4);
1489        impl_tuple_from!(@string_tuple 5, 0, 1, 2, 3, 4);
1490        impl_tuple_from!(@str_lino_tuple 5, 0, 1, 2, 3, 4);
1491        impl_tuple_from!(@lino_tuple 5, 0, 1, 2, 3, 4);
1492    };
1493    (6) => {
1494        impl_tuple_from!(@str_tuple 6, 0, 1, 2, 3, 4, 5);
1495        impl_tuple_from!(@string_tuple 6, 0, 1, 2, 3, 4, 5);
1496        impl_tuple_from!(@str_lino_tuple 6, 0, 1, 2, 3, 4, 5);
1497        impl_tuple_from!(@lino_tuple 6, 0, 1, 2, 3, 4, 5);
1498    };
1499    (7) => {
1500        impl_tuple_from!(@str_tuple 7, 0, 1, 2, 3, 4, 5, 6);
1501        impl_tuple_from!(@string_tuple 7, 0, 1, 2, 3, 4, 5, 6);
1502        impl_tuple_from!(@str_lino_tuple 7, 0, 1, 2, 3, 4, 5, 6);
1503        impl_tuple_from!(@lino_tuple 7, 0, 1, 2, 3, 4, 5, 6);
1504    };
1505    (8) => {
1506        impl_tuple_from!(@str_tuple 8, 0, 1, 2, 3, 4, 5, 6, 7);
1507        impl_tuple_from!(@string_tuple 8, 0, 1, 2, 3, 4, 5, 6, 7);
1508        impl_tuple_from!(@str_lino_tuple 8, 0, 1, 2, 3, 4, 5, 6, 7);
1509        impl_tuple_from!(@lino_tuple 8, 0, 1, 2, 3, 4, 5, 6, 7);
1510    };
1511    (9) => {
1512        impl_tuple_from!(@str_tuple 9, 0, 1, 2, 3, 4, 5, 6, 7, 8);
1513        impl_tuple_from!(@string_tuple 9, 0, 1, 2, 3, 4, 5, 6, 7, 8);
1514        impl_tuple_from!(@str_lino_tuple 9, 0, 1, 2, 3, 4, 5, 6, 7, 8);
1515        impl_tuple_from!(@lino_tuple 9, 0, 1, 2, 3, 4, 5, 6, 7, 8);
1516    };
1517    (10) => {
1518        impl_tuple_from!(@str_tuple 10, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
1519        impl_tuple_from!(@string_tuple 10, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
1520        impl_tuple_from!(@str_lino_tuple 10, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
1521        impl_tuple_from!(@lino_tuple 10, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
1522    };
1523    (11) => {
1524        impl_tuple_from!(@str_tuple 11, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
1525        impl_tuple_from!(@string_tuple 11, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
1526        impl_tuple_from!(@str_lino_tuple 11, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
1527        impl_tuple_from!(@lino_tuple 11, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
1528    };
1529    (12) => {
1530        impl_tuple_from!(@str_tuple 12, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);
1531        impl_tuple_from!(@string_tuple 12, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);
1532        impl_tuple_from!(@str_lino_tuple 12, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);
1533        impl_tuple_from!(@lino_tuple 12, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);
1534    };
1535}
1536
1537// Generate implementations for tuples of sizes 2 through 12
1538// This follows the Rust standard library convention of supporting up to 12-tuples
1539impl_tuple_from!(2);
1540impl_tuple_from!(3);
1541impl_tuple_from!(4);
1542impl_tuple_from!(5);
1543impl_tuple_from!(6);
1544impl_tuple_from!(7);
1545impl_tuple_from!(8);
1546impl_tuple_from!(9);
1547impl_tuple_from!(10);
1548impl_tuple_from!(11);
1549impl_tuple_from!(12);
1550
1551// Vec-based conversions for arbitrary-length link creation
1552//
1553// These implementations provide an escape hatch for creating links with more
1554// than 12 values, or when the number of values is determined at runtime.
1555//
1556// Note: Rust does not support variadic generics (as of Rust 1.92), which means
1557// we cannot implement `From` for tuples of arbitrary length. This is a fundamental
1558// limitation of Rust's type system. The Rust standard library faces the same
1559// limitation, which is why traits like `Debug`, `Default`, `Hash`, etc. are only
1560// implemented for tuples up to 12 elements.
1561//
1562// For more information, see:
1563// - https://github.com/rust-lang/rfcs/issues/376 (Draft RFC: variadic generics)
1564// - https://github.com/rust-lang/rust/issues/10124 (RFC: variadic generics)
1565//
1566// Alternative approaches for arbitrary-length links:
1567// 1. Use the `LiNoBuilder` API for fluent construction
1568// 2. Use `LiNo::new()` or `LiNo::anonymous()` with a `Vec`
1569// 3. Use the `From<Vec<_>>` implementations below
1570
1571/// Convert a Vec of strings into an anonymous link.
1572///
1573/// # Examples
1574/// ```
1575/// use links_notation::LiNo;
1576///
1577/// // Create anonymous link from vector of any size
1578/// let values: Vec<&str> = (1..=20).map(|_| "val").collect();
1579/// let link: LiNo<String> = values.into();
1580/// ```
1581impl From<Vec<&str>> for LiNo<String> {
1582    fn from(values: Vec<&str>) -> Self {
1583        LiNo::Link {
1584            id: None,
1585            values: values
1586                .into_iter()
1587                .map(|s| LiNo::Ref(s.to_string()))
1588                .collect(),
1589        }
1590    }
1591}
1592
1593/// Convert a Vec of Strings into an anonymous link.
1594impl From<Vec<String>> for LiNo<String> {
1595    fn from(values: Vec<String>) -> Self {
1596        LiNo::Link {
1597            id: None,
1598            values: values.into_iter().map(LiNo::Ref).collect(),
1599        }
1600    }
1601}
1602
1603/// Convert a Vec of LiNo into an anonymous link.
1604impl From<Vec<LiNo<String>>> for LiNo<String> {
1605    fn from(values: Vec<LiNo<String>>) -> Self {
1606        LiNo::Link { id: None, values }
1607    }
1608}
1609
1610/// Convert a tuple of (id, Vec<values>) into a named link.
1611///
1612/// # Examples
1613/// ```
1614/// use links_notation::LiNo;
1615///
1616/// // Create named link with arbitrary number of values
1617/// let values: Vec<&str> = vec!["v1", "v2", "v3", "v4", "v5"];
1618/// let link: LiNo<String> = ("myLink", values).into();
1619/// assert_eq!(format!("{}", link), "(myLink: v1 v2 v3 v4 v5)");
1620/// ```
1621impl From<(&str, Vec<&str>)> for LiNo<String> {
1622    fn from((id, values): (&str, Vec<&str>)) -> Self {
1623        LiNo::Link {
1624            id: Some(id.to_string()),
1625            values: values
1626                .into_iter()
1627                .map(|s| LiNo::Ref(s.to_string()))
1628                .collect(),
1629        }
1630    }
1631}
1632
1633/// Convert a tuple of (id, Vec<String>) into a named link.
1634impl From<(String, Vec<String>)> for LiNo<String> {
1635    fn from((id, values): (String, Vec<String>)) -> Self {
1636        LiNo::Link {
1637            id: Some(id),
1638            values: values.into_iter().map(LiNo::Ref).collect(),
1639        }
1640    }
1641}
1642
1643/// Convert a tuple of (id, Vec<LiNo>) into a named link.
1644impl From<(&str, Vec<LiNo<String>>)> for LiNo<String> {
1645    fn from((id, values): (&str, Vec<LiNo<String>>)) -> Self {
1646        LiNo::Link {
1647            id: Some(id.to_string()),
1648            values,
1649        }
1650    }
1651}
1652
1653/// Convert a tuple of (String id, Vec<LiNo>) into a named link.
1654impl From<(String, Vec<LiNo<String>>)> for LiNo<String> {
1655    fn from((id, values): (String, Vec<LiNo<String>>)) -> Self {
1656        LiNo::Link {
1657            id: Some(id),
1658            values,
1659        }
1660    }
1661}