So I'm having trouble adding support for case objects in my deserialization 
library. I'm sorry for the long post but the question is really simple.

Let's consider this example:
    
    
    type
      Fruit = enum
        Apple
        Banana
      
      Foo = object
        name: string
        case kind: Fruit
        of Banana: banana: int
        of Apple: apple: string
    
    let
      original = Foo(name: "hello", kind: Apple, apple: "world")
    let s = 
newStringStream("""{"name":"hello","apple":"world","kind":"Apple"}""")
    echo s.to(Foo)
    
    
    Run

Warning pseudocode ahead:

1\. In this approach it requires the kind field to be ahead of the rest. 
However JSON does not pose requirements for field ordering.
    
    
    proc packImpl(p: var JsonParser): Foo =
      while readfields:
        case key
        of "name":
          tmp_name = readAny(value)
        of "kind":
          tmp_kind = readAny(value)
        else:
          error("object field")
      result = Obj(name: tmp_name, kind: tmp_kind)
      while readfields:
        case kind
        of Banana:
          case key
          of "banana":
            result.banana = readAny(value)
          of "name":
            result.name = readAny(value)
          else:
            error("object field")
        of Apple:
          case key
          of "apple":
            result.apple = readAny(value)
          of "name"
            result.name = readAny(value)
          else:
            error("object field")
    
    
    Run

2\. This approach creates tmps for every field in the object (is that 
unwanted?), but is more flexible:
    
    
    proc packImpl(p: var JsonParser): Foo =
      while readfields:
        case key
        of "name":
          tmp_name = readAny(value)
        of "kind":
          tmp_kind = readAny(value)
        of "banana":
          isBanana = true
          tmp_banana = readAny(value)
        of "apple":
          isApple = true
          tmp_apple = readAny(value)
        else:
          error("object field")
      result = Obj(kind: tmp_kind)
      if not(isBanana xor isApple):
        raise newException(FieldDefect, "field is not accessible using 
discriminant " & $tmp_kind)
      result.name = tmp_name
      case kind
      of Banana:
        result.banana = tmp_banana
      of Apple:
        result.apple = tmp_apple
    
    
    Run

3\. And of couse we can assign to field kind directly ignoring the compiler 
warnings. This is what `json.to` and `status-im/nim-json-serialization` do.
    
    
    proc packImpl(p: var JsonParser): Foo =
      while readfields:
        case key
        of "name":
          result.name = readAny(value)
        of "kind":
          resulr.kind = readAny(value)
        of "banana":
          isBanana = true
          result.banana = readAny(value)
        of "apple":
          isApple = true
          result.apple = readAny(value)
        else:
          error("object field")
      if not(isBanana xor isApple):
        raise newException(FieldDefect, "field is not accessible using 
discriminant " & $tmp_kind)
    
    
    Run

So which approach should I follow?

Reply via email to