-
Notifications
You must be signed in to change notification settings - Fork 54
/
utility.nim
150 lines (130 loc) · 4.24 KB
/
utility.nim
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# Nim-LibP2P
# Copyright (c) 2023 Status Research & Development GmbH
# 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.
{.push raises: [].}
import std/[sets, options, macros]
import stew/[byteutils, results]
export results
template public*() {.pragma.}
const ShortDumpMax = 12
template compilesOr*(a, b: untyped): untyped =
when compiles(a): a else: b
func shortLog*(item: openArray[byte]): string =
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]
when defined(libp2p_agents_metrics):
import strutils
export split
proc safeToLowerAscii*(s: string): Result[string, cstring] =
try:
ok(s.toLowerAscii())
except CatchableError:
err("toLowerAscii failed")
const
KnownLibP2PAgents* {.strdefine.} = "nim-libp2p"
KnownLibP2PAgentsSeq* = KnownLibP2PAgents.safeToLowerAscii().tryGet().split(",")
template safeConvert*[T: SomeInteger, S: Ordinal](value: S): T =
## 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".}
proc capLen*[T](s: var seq[T], length: Natural) =
if s.len > length:
s.setLen(length)
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
template withValue*[T](self: Opt[T] | Option[T], value, body: untyped): untyped =
## 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()
body
template withValue*[T, E](self: Result[T, E], value, body: untyped): untyped =
self.toOpt().withValue(value, body)
macro withValue*[T](self: Opt[T] | Option[T], value, body, elseStmt: untyped): untyped =
let elseBody = elseStmt[0]
quote:
let temp = (`self`)
if temp.isSome:
let `value` {.inject.} = temp.get()
`body`
else:
`elseBody`
template valueOr*[T](self: Option[T], body: untyped): untyped =
let temp = (self)
if temp.isSome:
temp.get()
else:
body
template toOpt*[T, E](self: Result[T, E]): Opt[T] =
let temp = (self)
if temp.isOk:
when T is void:
Result[void, void].ok()
else:
Opt.some(temp.unsafeGet())
else:
Opt.none(type(T))
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)