///|
/// AS_SET 无序,连续 AS_SEQUENCE 的分段边界不影响路径含义。
fn canonical_path(path : Array[AsSegment]) -> Array[AsSegment] {
  let result : Array[AsSegment] = []
  for segment in path {
    if segment.kind == 1 || segment.kind == 4 {
      let sorted = segment.asns.copy()
      sorted.sort()
      let unique = []
      for asn in sorted {
        if unique.last() != Some(asn) {
          unique.push(asn)
        }
      }
      result.push({ kind: segment.kind, asns: unique, })
    } else {
      match result.last() {
        Some(previous) if previous.kind == segment.kind =>
          result[result.length() - 1] = {
            kind: segment.kind,
            asns: previous.asns + segment.asns,
          }
        _ => result.push(segment)
      }
    }
  }
  result
}

///|
fn same_path(a : Array[AsSegment], b : Array[AsSegment]) -> Bool {
  canonical_path(a) == canonical_path(b)
}

///|
fn semantic_attributes(a : Attributes) -> Attributes {
  // 同一 UPDATE 携带的其他前缀及 ASN 兼容编码不构成该路由的变化。
  let ao = a.other
    .filter(fn(attr) {
      attr.code != 6 &&
      attr.code != 7 &&
      attr.code != 18 &&
      attr.code != 14 &&
      attr.code != 15 &&
      attr.code != 32
    })
    .map(fn(attr) { { ..attr, flags: attr.flags & 224, } })
  ao.sort_by_key(fn(attr) { attr.code })
  {
    ..a,
    path: canonical_path(a.path),
    wire_path: [],
    as4_path: [],
    wire_aggregator: None,
    as4_aggregator: None,
    raw_attributes: [],
    communities: unique_communities(a.communities),
    large_communities: unique_large_communities(a.large_communities),
    other: ao,
  }
}

///|
fn route_attributes_equal(a : Attributes, b : Attributes) -> Bool {
  semantic_attributes(a) == semantic_attributes(b)
}