2022-07-01 18:19:57 +00:00
|
|
|
# Nim-LibP2P
|
2023-01-20 14:47:40 +00:00
|
|
|
# Copyright (c) 2023 Status Research & Development GmbH
|
2022-07-01 18:19:57 +00:00
|
|
|
# Licensed under either of
|
|
|
|
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
|
|
|
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
|
|
|
# at your option.
|
|
|
|
# This file may not be copied, modified, or distributed except according to
|
|
|
|
# those terms.
|
2020-03-23 06:03:36 +00:00
|
|
|
|
2023-06-07 11:12:49 +00:00
|
|
|
{.push raises: [].}
|
2021-03-09 12:22:52 +00:00
|
|
|
|
2024-06-12 13:46:47 +00:00
|
|
|
import std/[sets, options, macros]
|
2023-06-28 14:44:58 +00:00
|
|
|
import stew/[byteutils, results]
|
|
|
|
|
|
|
|
export results
|
2020-03-23 06:03:36 +00:00
|
|
|
|
2022-07-01 18:19:57 +00:00
|
|
|
template public*() {.pragma.}
|
|
|
|
|
2020-03-23 06:03:36 +00:00
|
|
|
const ShortDumpMax = 12
|
|
|
|
|
2023-02-14 09:35:44 +00:00
|
|
|
template compilesOr*(a, b: untyped): untyped =
|
|
|
|
when compiles(a): a else: b
|
|
|
|
|
2021-12-16 10:05:20 +00:00
|
|
|
func shortLog*(item: openArray[byte]): string =
|
2020-03-23 06:03:36 +00:00
|
|
|
if item.len <= ShortDumpMax:
|
|
|
|
result = item.toHex()
|
|
|
|
else:
|
|
|
|
const
|
|
|
|
split = ShortDumpMax div 2
|
|
|
|
dumpLen = (ShortDumpMax * 2) + 3
|
|
|
|
result = newStringOfCap(dumpLen)
|
|
|
|
result &= item.toOpenArray(0, split - 1).toHex()
|
|
|
|
result &= "..."
|
|
|
|
result &= item.toOpenArray(item.len - split, item.high).toHex()
|
|
|
|
|
|
|
|
func shortLog*(item: string): string =
|
|
|
|
if item.len <= ShortDumpMax:
|
|
|
|
result = item
|
|
|
|
else:
|
|
|
|
const
|
|
|
|
split = ShortDumpMax div 2
|
|
|
|
dumpLen = ShortDumpMax + 3
|
|
|
|
result = newStringOfCap(dumpLen)
|
|
|
|
result &= item[0 ..< split]
|
|
|
|
result &= "..."
|
|
|
|
result &= item[(item.len - split) .. item.high]
|
2021-01-08 05:21:24 +00:00
|
|
|
|
|
|
|
when defined(libp2p_agents_metrics):
|
2021-03-15 01:42:47 +00:00
|
|
|
import strutils
|
|
|
|
export split
|
|
|
|
|
|
|
|
proc safeToLowerAscii*(s: string): Result[string, cstring] =
|
|
|
|
try:
|
|
|
|
ok(s.toLowerAscii())
|
2021-03-15 07:48:11 +00:00
|
|
|
except CatchableError:
|
2021-03-15 01:42:47 +00:00
|
|
|
err("toLowerAscii failed")
|
|
|
|
|
2021-01-08 05:21:24 +00:00
|
|
|
const
|
2023-04-03 09:05:01 +00:00
|
|
|
KnownLibP2PAgents* {.strdefine.} = "nim-libp2p"
|
2021-03-15 01:42:47 +00:00
|
|
|
KnownLibP2PAgentsSeq* = KnownLibP2PAgents.safeToLowerAscii().tryGet().split(",")
|
2023-05-18 08:24:17 +00:00
|
|
|
|
2024-09-19 11:35:50 +00:00
|
|
|
proc safeConvert*[T: SomeInteger](value: SomeOrdinal): T =
|
|
|
|
type S = typeof(value)
|
2023-05-18 08:24:17 +00:00
|
|
|
## Converts `value` from S to `T` iff `value` is guaranteed to be preserved.
|
|
|
|
when int64(T.low) <= int64(S.low()) and uint64(T.high) >= uint64(S.high):
|
|
|
|
T(value)
|
|
|
|
else:
|
|
|
|
{.error: "Source and target types have an incompatible range low..high".}
|
|
|
|
|
2023-07-31 09:13:51 +00:00
|
|
|
proc capLen*[T](s: var seq[T], length: Natural) =
|
|
|
|
if s.len > length:
|
|
|
|
s.setLen(length)
|
|
|
|
|
2023-05-18 08:24:17 +00:00
|
|
|
template exceptionToAssert*(body: untyped): untyped =
|
|
|
|
block:
|
|
|
|
var res: type(body)
|
|
|
|
when defined(nimHasWarnBareExcept):
|
|
|
|
{.push warning[BareExcept]: off.}
|
|
|
|
try:
|
|
|
|
res = body
|
|
|
|
except CatchableError as exc:
|
|
|
|
raise exc
|
|
|
|
except Defect as exc:
|
|
|
|
raise exc
|
|
|
|
except Exception as exc:
|
|
|
|
raiseAssert exc.msg
|
|
|
|
when defined(nimHasWarnBareExcept):
|
|
|
|
{.pop.}
|
|
|
|
res
|
2023-06-28 14:44:58 +00:00
|
|
|
|
|
|
|
template withValue*[T](self: Opt[T] | Option[T], value, body: untyped): untyped =
|
2024-01-18 15:25:56 +00:00
|
|
|
## This template provides a convenient way to work with `Option` types in Nim.
|
|
|
|
## It allows you to execute a block of code (`body`) only when the `Option` is not empty.
|
|
|
|
##
|
|
|
|
## `self` is the `Option` instance being checked.
|
|
|
|
## `value` is the variable name to be used within the `body` for the unwrapped value.
|
|
|
|
## `body` is a block of code that is executed only if `self` contains a value.
|
|
|
|
##
|
|
|
|
## The `value` within `body` is automatically unwrapped from the `Option`, making it
|
|
|
|
## simpler to work with without needing explicit checks or unwrapping.
|
|
|
|
##
|
|
|
|
## Example:
|
|
|
|
## ```nim
|
|
|
|
## let myOpt = Opt.some(5)
|
|
|
|
## myOpt.withValue(value):
|
|
|
|
## echo value # Will print 5
|
|
|
|
## ```
|
|
|
|
##
|
|
|
|
## Note: This is a template, and it will be inlined at the call site, offering good performance.
|
|
|
|
let temp = (self)
|
|
|
|
if temp.isSome:
|
|
|
|
let value {.inject.} = temp.get()
|
2023-06-28 14:44:58 +00:00
|
|
|
body
|
|
|
|
|
2024-06-06 11:05:45 +00:00
|
|
|
template withValue*[T, E](self: Result[T, E], value, body: untyped): untyped =
|
|
|
|
self.toOpt().withValue(value, body)
|
|
|
|
|
2024-04-04 15:15:50 +00:00
|
|
|
macro withValue*[T](self: Opt[T] | Option[T], value, body, elseStmt: untyped): untyped =
|
|
|
|
let elseBody = elseStmt[0]
|
2023-06-28 14:44:58 +00:00
|
|
|
quote:
|
2024-04-04 15:15:50 +00:00
|
|
|
let temp = (`self`)
|
|
|
|
if temp.isSome:
|
|
|
|
let `value` {.inject.} = temp.get()
|
2023-06-28 14:44:58 +00:00
|
|
|
`body`
|
|
|
|
else:
|
|
|
|
`elseBody`
|
|
|
|
|
|
|
|
template valueOr*[T](self: Option[T], body: untyped): untyped =
|
2024-04-04 15:15:50 +00:00
|
|
|
let temp = (self)
|
|
|
|
if temp.isSome:
|
|
|
|
temp.get()
|
2023-06-28 14:44:58 +00:00
|
|
|
else:
|
|
|
|
body
|
|
|
|
|
|
|
|
template toOpt*[T, E](self: Result[T, E]): Opt[T] =
|
2024-04-04 15:15:50 +00:00
|
|
|
let temp = (self)
|
|
|
|
if temp.isOk:
|
2023-06-28 14:44:58 +00:00
|
|
|
when T is void:
|
|
|
|
Result[void, void].ok()
|
2024-04-04 15:15:50 +00:00
|
|
|
else:
|
|
|
|
Opt.some(temp.unsafeGet())
|
2023-06-28 14:44:58 +00:00
|
|
|
else:
|
|
|
|
Opt.none(type(T))
|
2024-06-12 13:46:47 +00:00
|
|
|
|
|
|
|
template exclIfIt*[T](set: var HashSet[T], condition: untyped) =
|
|
|
|
if set.len != 0:
|
|
|
|
var toExcl = HashSet[T]()
|
|
|
|
for it {.inject.} in set:
|
|
|
|
if condition:
|
|
|
|
toExcl.incl(it)
|
|
|
|
set.excl(toExcl)
|