Comments (1)
If I do source[idx..source.len-1]
in every clause of the case
, it compiles and to get it working for numbers higher than 10 I changed the decoding ints to:
proc decodeString(this: Decoder, s: string): (BencodeType, int) =
let
colonPos = s.find(':')
strLen = s[0..<colonPos].parseInt
str = s[colonPos+1..colonPos+strLen]
result = (BencodeType(kind: btString, s: str),
colonPos+strLen)
But now I can't decode lists anymore :(. Getting the following error:
Got it working here is the full working code, compiles all the examples:
# A simple Bencode parser following Nim Days by xmonader
import strformat, tables, json, strutils, hashes
type
BencodeKind* = enum
btString, btInt, btList, btDict
BencodeType* = ref object
case kind*: BencodeKind
of BencodeKind.btString: s* : string
of BencodeKind.btInt: i* : int
of BencodeKind.btList: l* : seq[BencodeType]
of BencodeKind.btDict: d* : OrderedTable[BencodeType, BencodeType]
Encoder* = ref object
Decoder* = ref object
# Forward declaration because of recursion
proc encode(this: Encoder, obj: BencodeType): string
proc decode(this: Decoder, source: string): (BencodeType, int)
# Constructors
proc newEncoder*(): Encoder = new Encoder
proc newDecoder*(): Decoder = new Decoder
# Dispatch API for BencodeType
proc encodeObject*(this: Encoder, obj: BencodeType): string = this.encode(obj)
proc decodeObject*(this: Decoder, source: string): BencodeType =
result = this.decode(source)[0]
# For object variants like BencodeType we need to define custom `==` and `hash` procs
proc hash*(obj: BencodeType): Hash =
case obj.kind
of btString: !$(hash(obj.s))
of btInt: !$(hash(obj.i))
of btList: !$(hash(obj.l))
of btDict:
var h = 0
for key, value in obj.d.pairs:
h = h !& hash(key) !& hash(value)
!$(h)
proc `==`*(a, b: BencodeType): bool =
if a.isNil:
if b.isNil: return true
return false
elif b.isNil or a.kind != b.kind:
return false
else:
case a.kind
of btString:
result = a.s == b.s
of btInt:
result = a.i == b.i
of btList:
result = a.l == b.l
of btDict:
if a.d.len != b.d.len: return false
for key, value in a.d:
if not b.d.hasKey(key): return false
if b.d[key] != value: return false
result = true
# Define a simple string representation for BencodeType
proc `$`*(a: BencodeType): string =
case a.kind
of btString: fmt("<Bencode {a.s}>")
of btInt: fmt("<Bencode {a.i}>")
of btList: fmt("<Bencode {a.l}>")
of btDict: fmt("<Bencode {a.d}>")
# Encoding procs
proc encodeString(this: Encoder, s: string): string =
if s.len == 0: return ""
return $s.len & ":" & s
proc encodeInt(this: Encoder, i: int): string =
return fmt("i{i}e")
proc encodeList(this: Encoder, l: seq[BencodeType]): string =
result = "l"
for el in l:
result &= this.encode(el)
result &= "e"
proc encodeDict(this: Encoder, d: OrderedTable[BencodeType, BencodeType]): string =
result = "d"
for key, value in d.pairs():
# Bencode dicts must have String keys
assert key.kind == BencodeKind.btString
result &= this.encode(key) & this.encode(value)
result &= "e"
proc encode(this: Encoder, obj: BencodeType): string =
case obj.kind
of BencodeKind.btString: result = this.encodeString(obj.s)
of BencodeKind.btInt: result = this.encodeInt(obj.i)
of BencodeKind.btList: result = this.encodeList(obj.l)
of BencodeKind.btDict: result = this.encodeDict(obj.d)
# Procs for decoding
proc decodeString(this: Decoder, s: string): (BencodeType, int) =
let
colonPos = s.find(':')
strLen = s[0..<colonPos].parseInt
str = s[colonPos+1..colonPos+strLen]
result = (BencodeType(kind: btString, s: str),
colonPos+strLen+1)
proc decodeInt(this: Decoder, s: string): (BencodeType, int) =
let epos = s.find('e')
let i = parseInt(s[1..<epos])
result = (BencodeType(kind: btInt, i:i), epos+1)
proc decodeList(this: Decoder, s: string): (BencodeType, int) =
var
resultList = newSeq[BencodeType]()
currentChar = s[1]
idx = 1
while idx < s.len:
currentChar = s[idx]
if currentChar == 'e':
idx += 1
break
let (obj, nextObjPos) = this.decode(s[idx..<s.len])
echo obj
resultList.add(obj)
idx += nextObjPos
result = (BencodeType(kind: btList, l: resultList), idx)
proc decodeDict(this: Decoder, s: string): (BencodeType, int) =
var
resultDict = initOrderedTable[BencodeType, BencodeType]()
currentChar = s[1]
idx = 1
readingKey = true
currentKey: BencodeType
while idx < s.len:
currentChar = s[idx]
if currentChar == 'e': break
let (obj, nextObjPos) = this.decode(s[idx..<s.len])
if readingKey:
currentKey = obj
readingKey = false
else:
resultDict[currentKey] = obj
readingKey = true
idx += nextObjPos
result = (BencodeType(kind: btDict, d: resultDict), idx)
proc decode(this: Decoder, source: string): (BencodeType, int) =
var
currentChar = source[0]
idx = 0
while idx < source.len:
currentChar = source[idx]
case currentChar
of 'i':
let (obj, nextObjPos) = this.decodeInt(source[idx..source.len-1])
idx += nextObjPos
return (obj, idx)
of 'l':
let (obj, nextObjPos) = this.decodeList(source[idx..source.len-1])
idx += nextObjPos
return (obj, idx)
of 'd':
let (obj, nextObjPos) = this.decodeDict(source[idx..source.len-1])
idx += nextObjPos
return (obj, idx)
else:
let (obj, nextObjPos) = this.decodeString(source[idx..source.len-1])
idx += nextObjPos
return (obj, idx)
from nimdays.
Related Issues (13)
- Suggestion: Keep chapters' format in linear order HOT 1
- Tests HOT 2
- Make codeblocks wider HOT 1
- Very new person, can't get first code to compile HOT 3
- Update the book with source code links
- tcp router question HOT 3
- use tcp router with http port forwarding HOT 4
- Incomplete shell commands in Day 1 HOT 3
- Document mdbook dependency HOT 3
- Switch to nimibook instead of mdbook
- broken `nim-parsec` link on day 21 HOT 1
- parseopt2 dependency doesn't exist anymore for Nim days 9:TicTacToe
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from nimdays.