1// Copyright (C) MongoDB, Inc. 2014-present.
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may
4// not use this file except in compliance with the License. You may obtain
5// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
6
7package json
8
9import (
10	"fmt"
11	"gopkg.in/mgo.v2/bson"
12	"reflect"
13)
14
15// Transition functions for recognizing DBPointer.
16// Adapted from encoding/json/scanner.go.
17
18// stateDB is the state after reading `DB`.
19func stateDBP(s *scanner, c int) int {
20	if c == 'o' {
21		s.step = generateState("DBPointer", []byte("inter"), stateConstructor)
22		return scanContinue
23	}
24	return s.error(c, "in literal DBPointer (expecting 'o')")
25}
26
27// Decodes a DBRef literal stored in the underlying byte data into v.
28func (d *decodeState) storeDBPointer(v reflect.Value) {
29	op := d.scanWhile(scanSkipSpace)
30	if op != scanBeginCtor {
31		d.error(fmt.Errorf("expected beginning of constructor"))
32	}
33
34	args := d.ctorInterface()
35	if len(args) != 2 {
36		d.error(fmt.Errorf("expected 2 arguments to DBPointer constructor, but %v received", len(args)))
37	}
38	switch kind := v.Kind(); kind {
39	case reflect.Interface:
40		arg0, ok := args[0].(string)
41		if !ok {
42			d.error(fmt.Errorf("expected first argument to DBPointer to be of type string"))
43		}
44		arg1, ok := args[1].(ObjectId)
45		if !ok {
46			d.error(fmt.Errorf("expected second argument to DBPointer to be of type ObjectId, but ended up being %t", args[1]))
47		}
48		id := bson.ObjectIdHex(string(arg1))
49		v.Set(reflect.ValueOf(DBPointer{arg0, id}))
50	default:
51		d.error(fmt.Errorf("cannot store %v value into %v type", dbPointerType, kind))
52	}
53}
54
55// Returns a DBRef literal from the underlying byte data.
56func (d *decodeState) getDBPointer() interface{} {
57	op := d.scanWhile(scanSkipSpace)
58	if op != scanBeginCtor {
59		d.error(fmt.Errorf("expected beginning of constructor"))
60	}
61
62	args := d.ctorInterface()
63	if err := ctorNumArgsMismatch("DBPointer", 2, len(args)); err != nil {
64		d.error(err)
65	}
66	arg0, ok := args[0].(string)
67	if !ok {
68		d.error(fmt.Errorf("expected string for first argument of DBPointer constructor"))
69	}
70	arg1, ok := args[1].(ObjectId)
71	if !ok {
72		d.error(fmt.Errorf("expected ObjectId for second argument of DBPointer constructor"))
73	}
74	id := bson.ObjectIdHex(string(arg1))
75
76	return DBPointer{arg0, id}
77}
78