[chore]: Bump github.com/gin-contrib/sessions from 0.0.5 to 1.0.0 (#2782)

This commit is contained in:
dependabot[bot] 2024-03-25 11:00:36 +00:00 committed by GitHub
parent a24936040c
commit 29031d1e27
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
93 changed files with 2888 additions and 969 deletions

12
go.mod
View file

@ -29,7 +29,7 @@ require (
github.com/disintegration/imaging v1.6.2 github.com/disintegration/imaging v1.6.2
github.com/gin-contrib/cors v1.7.1 github.com/gin-contrib/cors v1.7.1
github.com/gin-contrib/gzip v1.0.0 github.com/gin-contrib/gzip v1.0.0
github.com/gin-contrib/sessions v0.0.5 github.com/gin-contrib/sessions v1.0.0
github.com/gin-gonic/gin v1.9.1 github.com/gin-gonic/gin v1.9.1
github.com/go-playground/form/v4 v4.2.1 github.com/go-playground/form/v4 v4.2.1
github.com/go-swagger/go-swagger v0.30.5 github.com/go-swagger/go-swagger v0.30.5
@ -137,11 +137,11 @@ require (
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
github.com/golang/geo v0.0.0-20210211234256-740aa86cb551 // indirect github.com/golang/geo v0.0.0-20210211234256-740aa86cb551 // indirect
github.com/golang/protobuf v1.5.3 // indirect github.com/golang/protobuf v1.5.3 // indirect
github.com/gorilla/context v1.1.1 // indirect github.com/gorilla/context v1.1.2 // indirect
github.com/gorilla/css v1.0.0 // indirect github.com/gorilla/css v1.0.0 // indirect
github.com/gorilla/handlers v1.5.1 // indirect github.com/gorilla/handlers v1.5.1 // indirect
github.com/gorilla/securecookie v1.1.1 // indirect github.com/gorilla/securecookie v1.1.2 // indirect
github.com/gorilla/sessions v1.2.1 // indirect github.com/gorilla/sessions v1.2.2 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect
@ -155,7 +155,7 @@ require (
github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect
github.com/josharian/intern v1.0.0 // indirect github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.17.6 // indirect github.com/klauspost/compress v1.17.7 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/kr/pretty v0.3.1 // indirect github.com/kr/pretty v0.3.1 // indirect
github.com/kr/text v0.2.0 // indirect github.com/kr/text v0.2.0 // indirect
@ -203,7 +203,7 @@ require (
github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
github.com/zeebo/xxh3 v1.0.2 // indirect github.com/zeebo/xxh3 v1.0.2 // indirect
go.mongodb.org/mongo-driver v1.11.3 // indirect go.mongodb.org/mongo-driver v1.14.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 // indirect
go.opentelemetry.io/proto/otlp v1.1.0 // indirect go.opentelemetry.io/proto/otlp v1.1.0 // indirect
go.uber.org/multierr v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect

30
go.sum
View file

@ -187,8 +187,8 @@ github.com/gin-contrib/cors v1.7.1 h1:s9SIppU/rk8enVvkzwiC2VK3UZ/0NNGsWfUKvV55rq
github.com/gin-contrib/cors v1.7.1/go.mod h1:n/Zj7B4xyrgk/cX1WCX2dkzFfaNm/xJb6oIUk7WTtps= github.com/gin-contrib/cors v1.7.1/go.mod h1:n/Zj7B4xyrgk/cX1WCX2dkzFfaNm/xJb6oIUk7WTtps=
github.com/gin-contrib/gzip v1.0.0 h1:UKN586Po/92IDX6ie5CWLgMI81obiIp5nSP85T3wlTk= github.com/gin-contrib/gzip v1.0.0 h1:UKN586Po/92IDX6ie5CWLgMI81obiIp5nSP85T3wlTk=
github.com/gin-contrib/gzip v1.0.0/go.mod h1:CtG7tQrPB3vIBo6Gat9FVUsis+1emjvQqd66ME5TdnE= github.com/gin-contrib/gzip v1.0.0/go.mod h1:CtG7tQrPB3vIBo6Gat9FVUsis+1emjvQqd66ME5TdnE=
github.com/gin-contrib/sessions v0.0.5 h1:CATtfHmLMQrMNpJRgzjWXD7worTh7g7ritsQfmF+0jE= github.com/gin-contrib/sessions v1.0.0 h1:r5GLta4Oy5xo9rAwMHx8B4wLpeRGHMdz9NafzJAdP8Y=
github.com/gin-contrib/sessions v0.0.5/go.mod h1:vYAuaUPqie3WUSsft6HUlCjlwwoJQs97miaG2+7neKY= github.com/gin-contrib/sessions v1.0.0/go.mod h1:DN0f4bvpqMQElDdi+gNGScrP2QEI04IErRyMFyorUOI=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
@ -355,6 +355,8 @@ github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
@ -375,18 +377,18 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8= github.com/gorilla/context v1.1.2 h1:WRkNAv2uoa03QNIc1A6u4O7DAGMUVoopZhkiXWA2V1o=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/context v1.1.2/go.mod h1:KDPwT9i/MeWHiLl90fuTgrt4/wPcv75vFAZLaOOcbxM=
github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=
github.com/gorilla/feeds v1.1.2 h1:pxzZ5PD3RJdhFH2FsJJ4x6PqMqbgFk1+Vez4XWBW8Iw= github.com/gorilla/feeds v1.1.2 h1:pxzZ5PD3RJdhFH2FsJJ4x6PqMqbgFk1+Vez4XWBW8Iw=
github.com/gorilla/feeds v1.1.2/go.mod h1:WMib8uJP3BbY+X8Szd1rA5Pzhdfh+HCCAYT2z7Fza6Y= github.com/gorilla/feeds v1.1.2/go.mod h1:WMib8uJP3BbY+X8Szd1rA5Pzhdfh+HCCAYT2z7Fza6Y=
github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4=
github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q=
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA=
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo=
github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI= github.com/gorilla/sessions v1.2.2 h1:lqzMYz6bOfvn2WriPUjNByzeXIlVzURcPmgMczkmTjY=
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/gorilla/sessions v1.2.2/go.mod h1:ePLdVu+jbEgHH+KWw8I1z2wqd0BAdAQh/8LRvBeoNcQ=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
@ -441,8 +443,8 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o
github.com/klauspost/compress v1.10.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.10.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.10.10/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.10.10/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/compress v1.17.6 h1:60eq2E/jlfwQXtvZEeBUYADs+BwKBWURIY+Gj2eRGjI= github.com/klauspost/compress v1.17.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLAKQQg=
github.com/klauspost/compress v1.17.6/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
@ -474,8 +476,8 @@ github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U= github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg=
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k=
github.com/microcosm-cc/bluemonday v1.0.26 h1:xbqSvqzQMeEHCqMi64VAs4d8uy6Mequs3rQ0k/Khz58= github.com/microcosm-cc/bluemonday v1.0.26 h1:xbqSvqzQMeEHCqMi64VAs4d8uy6Mequs3rQ0k/Khz58=
@ -714,8 +716,8 @@ github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaD
go.mongodb.org/mongo-driver v1.7.3/go.mod h1:NqaYOwnXWr5Pm7AOpO5QFxKJ503nbMse/R79oO62zWg= go.mongodb.org/mongo-driver v1.7.3/go.mod h1:NqaYOwnXWr5Pm7AOpO5QFxKJ503nbMse/R79oO62zWg=
go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng= go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng=
go.mongodb.org/mongo-driver v1.10.0/go.mod h1:wsihk0Kdgv8Kqu1Anit4sfK+22vSFbUrAVEYRhCXrA8= go.mongodb.org/mongo-driver v1.10.0/go.mod h1:wsihk0Kdgv8Kqu1Anit4sfK+22vSFbUrAVEYRhCXrA8=
go.mongodb.org/mongo-driver v1.11.3 h1:Ql6K6qYHEzB6xvu4+AU0BoRoqf9vFPcc4o7MUIdPW8Y= go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd80=
go.mongodb.org/mongo-driver v1.11.3/go.mod h1:PTSz5yu21bkT/wXpkS7WR5f0ddqw5quethTUn9WM+2g= go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=

View file

@ -1,8 +1,7 @@
project_name: queue project_name: queue
builds: builds:
- - # If true, skip the build.
# If true, skip the build.
# Useful for library projects. # Useful for library projects.
# Default is false # Default is false
skip: true skip: true
@ -38,10 +37,10 @@ changelog:
- title: Features - title: Features
regexp: "^.*feat[(\\w)]*:+.*$" regexp: "^.*feat[(\\w)]*:+.*$"
order: 0 order: 0
- title: 'Bug fixes' - title: "Bug fixes"
regexp: "^.*fix[(\\w)]*:+.*$" regexp: "^.*fix[(\\w)]*:+.*$"
order: 1 order: 1
- title: 'Enhancements' - title: "Enhancements"
regexp: "^.*chore[(\\w)]*:+.*$" regexp: "^.*chore[(\\w)]*:+.*$"
order: 2 order: 2
- title: Others - title: Others
@ -52,6 +51,6 @@ changelog:
# the changelog # the changelog
# Default is empty # Default is empty
exclude: exclude:
- '^docs' - "^docs"
- 'CICD' - "CICD"
- typo - typo

View file

@ -1,11 +1,10 @@
# sessions # sessions
[![Run CI Lint](https://github.com/gin-contrib/sessions/actions/workflows/lint.yml/badge.svg)](https://github.com/gin-contrib/sessions/actions/workflows/lint.yml) [![Run CI Lint](https://github.com/gin-contrib/sessions/actions/workflows/lint.yml/badge.svg?branch=master)](https://github.com/gin-contrib/sessions/actions/workflows/lint.yml)
[![Run Testing](https://github.com/gin-contrib/sessions/actions/workflows/testing.yml/badge.svg)](https://github.com/gin-contrib/sessions/actions/workflows/testing.yml) [![Run Testing](https://github.com/gin-contrib/sessions/actions/workflows/testing.yml/badge.svg?branch=master)](https://github.com/gin-contrib/sessions/actions/workflows/testing.yml)
[![codecov](https://codecov.io/gh/gin-contrib/sessions/branch/master/graph/badge.svg)](https://codecov.io/gh/gin-contrib/sessions) [![codecov](https://codecov.io/gh/gin-contrib/sessions/branch/master/graph/badge.svg)](https://codecov.io/gh/gin-contrib/sessions)
[![Go Report Card](https://goreportcard.com/badge/github.com/gin-contrib/sessions)](https://goreportcard.com/report/github.com/gin-contrib/sessions) [![Go Report Card](https://goreportcard.com/badge/github.com/gin-contrib/sessions)](https://goreportcard.com/report/github.com/gin-contrib/sessions)
[![GoDoc](https://godoc.org/github.com/gin-contrib/sessions?status.svg)](https://godoc.org/github.com/gin-contrib/sessions) [![GoDoc](https://godoc.org/github.com/gin-contrib/sessions?status.svg)](https://godoc.org/github.com/gin-contrib/sessions)
[![Join the chat at https://gitter.im/gin-gonic/gin](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/gin-gonic/gin)
Gin middleware for session management with multi-backend support: Gin middleware for session management with multi-backend support:
@ -13,7 +12,7 @@ Gin middleware for session management with multi-backend support:
- [Redis](#redis) - [Redis](#redis)
- [memcached](#memcached) - [memcached](#memcached)
- [MongoDB](#mongodb) - [MongoDB](#mongodb)
- [GoRM](#gorm) - [GORM](#gorm)
- [memstore](#memstore) - [memstore](#memstore)
- [PostgreSQL](#postgresql) - [PostgreSQL](#postgresql)
@ -251,6 +250,7 @@ func main() {
### MongoDB ### MongoDB
#### mgo #### mgo
```go ```go
package main package main
@ -291,7 +291,8 @@ func main() {
``` ```
#### mongo-driver #### mongo-driver
```
```go
package main package main
import ( import (
@ -371,9 +372,8 @@ func main() {
} }
``` ```
### GoRM ### GORM
[embedmd]:# (_example/gorm/main.go go)
```go ```go
package main package main

View file

@ -1,3 +1,4 @@
//go:build !go1.11
// +build !go1.11 // +build !go1.11
package sessions package sessions

View file

@ -1,10 +1,12 @@
//go:build go1.11
// +build go1.11 // +build go1.11
package sessions package sessions
import ( import (
gsessions "github.com/gorilla/sessions"
"net/http" "net/http"
gsessions "github.com/gorilla/sessions"
) )
// Options stores configuration for a session or session store. // Options stores configuration for a session or session store.

20
vendor/github.com/gorilla/context/.editorconfig generated vendored Normal file
View file

@ -0,0 +1,20 @@
; https://editorconfig.org/
root = true
[*]
insert_final_newline = true
charset = utf-8
trim_trailing_whitespace = true
indent_style = space
indent_size = 2
[{Makefile,go.mod,go.sum,*.go,.gitmodules}]
indent_style = tab
indent_size = 4
[*.md]
indent_size = 4
trim_trailing_whitespace = false
eclint_indent_style = unset

1
vendor/github.com/gorilla/context/.gitignore generated vendored Normal file
View file

@ -0,0 +1 @@
coverage.coverprofile

12
vendor/github.com/gorilla/context/.golangci.yml generated vendored Normal file
View file

@ -0,0 +1,12 @@
linters:
enable:
- errcheck
- gosimple
- govet
- ineffassign
- staticcheck
- unused
- contextcheck
- goconst
- gofmt
- misspell

View file

@ -1,19 +0,0 @@
language: go
sudo: false
matrix:
include:
- go: 1.3
- go: 1.4
- go: 1.5
- go: 1.6
- go: 1.7
- go: tip
allow_failures:
- go: tip
script:
- go get -t -v ./...
- diff -u <(echo -n) <(gofmt -d .)
- go vet $(go list ./... | grep -v /vendor/)
- go test -v -race ./...

View file

@ -1,4 +1,4 @@
Copyright (c) 2012 Rodrigo Moraes. All rights reserved. Copyright (c) 2012-2023 The Gorilla web toolkit authors. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are modification, are permitted provided that the following conditions are

52
vendor/github.com/gorilla/context/Makefile generated vendored Normal file
View file

@ -0,0 +1,52 @@
GO_LINT=$(shell which golangci-lint 2> /dev/null || echo '')
GO_LINT_URI=github.com/golangci/golangci-lint/cmd/golangci-lint@latest
GO_SEC=$(shell which gosec 2> /dev/null || echo '')
GO_SEC_URI=github.com/securego/gosec/v2/cmd/gosec@latest
GO_VULNCHECK=$(shell which govulncheck 2> /dev/null || echo '')
GO_VULNCHECK_URI=golang.org/x/vuln/cmd/govulncheck@latest
.PHONY: golangci-lint
golangci-lint: ## Run golangci-lint. Example: make golangci-lint
$(if $(GO_LINT), ,go install $(GO_LINT_URI))
@echo "##### Running golangci-lint #####"
golangci-lint run -v
.PHONY: verify
verify: ## Run all verifications [golangci-lint]. Example: make verify
@echo "##### Running verifications #####"
$(MAKE) golangci-lint
.PHONY: gosec
gosec: ## Run gosec. Example: make gosec
$(if $(GO_SEC), ,go install $(GO_SEC_URI))
@echo "##### Running gosec #####"
gosec ./...
.PHONY: govulncheck
govulncheck: ## Run govulncheck. Example: make govulncheck
$(if $(GO_VULNCHECK), ,go install $(GO_VULNCHECK_URI))
@echo "##### Running govulncheck #####"
govulncheck ./...
.PHONY: security
security: ## Run all security checks [gosec, govulncheck]. Example: make security
@echo "##### Running security checks #####"
$(MAKE) gosec
$(MAKE) govulncheck
.PHONY: test-unit
test-unit: ## Run unit tests. Example: make test-unit
@echo "##### Running unit tests #####"
go test -race -cover -coverprofile=coverage.coverprofile -covermode=atomic -v ./...
.PHONY: test
test: ## Run all tests [test-unit]. Example: make test
@echo "##### Running tests #####"
$(MAKE) test-unit
.PHONY: help
help: ## Print this help. Example: make help
@echo "##### Printing help #####"
@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST)

View file

@ -1,10 +1,26 @@
context # gorilla/context
=======
[![Build Status](https://travis-ci.org/gorilla/context.png?branch=master)](https://travis-ci.org/gorilla/context) [![License](https://img.shields.io/github/license/gorilla/.github)](https://img.shields.io/github/license/gorilla/.github)
![testing](https://github.com/gorilla/context/actions/workflows/test.yml/badge.svg)
[![codecov](https://codecov.io/github/gorilla/context/branch/main/graph/badge.svg)](https://codecov.io/github/gorilla/context)
[![godoc](https://godoc.org/github.com/gorilla/context?status.svg)](https://godoc.org/github.com/gorilla/context)
[![sourcegraph](https://sourcegraph.com/github.com/gorilla/context/-/badge.svg)](https://sourcegraph.com/github.com/gorilla/context?badge)
[![OpenSSF Best Practices](https://bestpractices.coreinfrastructure.org/projects/7656/badge)](https://bestpractices.coreinfrastructure.org/projects/7656)
![Gorilla Logo](https://github.com/gorilla/.github/assets/53367916/d92caabf-98e0-473e-bfbf-ab554ba435e5)
> ⚠⚠⚠ **Note** ⚠⚠⚠ gorilla/context, having been born well before `context.Context` existed, does not play well
> with the shallow copying of the request that [`http.Request.WithContext`](https://golang.org/pkg/net/http/#Request.WithContext) (added to net/http Go 1.7 onwards) performs.
>
> Using gorilla/context may lead to memory leaks under those conditions, as the pointers to each `http.Request` become "islanded" and will not be cleaned up when the response is sent.
>
> You should use the `http.Request.Context()` feature in Go 1.7.
gorilla/context is a general purpose registry for global request variables. gorilla/context is a general purpose registry for global request variables.
> Note: gorilla/context, having been born well before `context.Context` existed, does not play well * It stores a `map[*http.Request]map[interface{}]interface{}` as a global singleton, and thus tracks variables by their HTTP request.
> with the shallow copying of the request that [`http.Request.WithContext`](https://golang.org/pkg/net/http/#Request.WithContext) (added to net/http Go 1.7 onwards) performs. You should either use *just* gorilla/context, or moving forward, the new `http.Request.Context()`.
Read the full documentation here: http://www.gorillatoolkit.org/pkg/context
### License
See the LICENSE file for details.

View file

@ -1,7 +1,3 @@
// Copyright 2012 The Gorilla Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package context package context
import ( import (

20
vendor/github.com/gorilla/securecookie/.editorconfig generated vendored Normal file
View file

@ -0,0 +1,20 @@
; https://editorconfig.org/
root = true
[*]
insert_final_newline = true
charset = utf-8
trim_trailing_whitespace = true
indent_style = space
indent_size = 2
[{Makefile,go.mod,go.sum,*.go,.gitmodules}]
indent_style = tab
indent_size = 4
[*.md]
indent_size = 4
trim_trailing_whitespace = false
eclint_indent_style = unset

1
vendor/github.com/gorilla/securecookie/.gitignore generated vendored Normal file
View file

@ -0,0 +1 @@
coverage.coverprofile

View file

@ -1,19 +0,0 @@
language: go
sudo: false
matrix:
include:
- go: 1.3
- go: 1.4
- go: 1.5
- go: 1.6
- go: 1.7
- go: tip
allow_failures:
- go: tip
script:
- go get -t -v ./...
- diff -u <(echo -n) <(gofmt -d .)
- go vet $(go list ./... | grep -v /vendor/)
- go test -v -race ./...

View file

@ -1,4 +1,4 @@
Copyright (c) 2012 Rodrigo Moraes. All rights reserved. Copyright (c) 2023 The Gorilla Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are modification, are permitted provided that the following conditions are

39
vendor/github.com/gorilla/securecookie/Makefile generated vendored Normal file
View file

@ -0,0 +1,39 @@
GO_LINT=$(shell which golangci-lint 2> /dev/null || echo '')
GO_LINT_URI=github.com/golangci/golangci-lint/cmd/golangci-lint@latest
GO_SEC=$(shell which gosec 2> /dev/null || echo '')
GO_SEC_URI=github.com/securego/gosec/v2/cmd/gosec@latest
GO_VULNCHECK=$(shell which govulncheck 2> /dev/null || echo '')
GO_VULNCHECK_URI=golang.org/x/vuln/cmd/govulncheck@latest
.PHONY: golangci-lint
golangci-lint:
$(if $(GO_LINT), ,go install $(GO_LINT_URI))
@echo "##### Running golangci-lint"
golangci-lint run -v
.PHONY: gosec
gosec:
$(if $(GO_SEC), ,go install $(GO_SEC_URI))
@echo "##### Running gosec"
gosec ./...
.PHONY: govulncheck
govulncheck:
$(if $(GO_VULNCHECK), ,go install $(GO_VULNCHECK_URI))
@echo "##### Running govulncheck"
govulncheck ./...
.PHONY: verify
verify: golangci-lint gosec govulncheck
.PHONY: test
test:
@echo "##### Running tests"
go test -race -cover -coverprofile=coverage.coverprofile -covermode=atomic -v ./...
.PHONY: fuzz
fuzz:
@echo "##### Running fuzz tests"
go test -v -fuzz FuzzEncodeDecode -fuzztime 60s

View file

@ -1,10 +1,13 @@
securecookie # gorilla/securecookie
============
[![GoDoc](https://godoc.org/github.com/gorilla/securecookie?status.svg)](https://godoc.org/github.com/gorilla/securecookie) [![Build Status](https://travis-ci.org/gorilla/securecookie.png?branch=master)](https://travis-ci.org/gorilla/securecookie)
[![Sourcegraph](https://sourcegraph.com/github.com/gorilla/securecookie/-/badge.svg)](https://sourcegraph.com/github.com/gorilla/securecookie?badge)
![testing](https://github.com/gorilla/securecookie/actions/workflows/test.yml/badge.svg)
[![codecov](https://codecov.io/github/gorilla/securecookie/branch/main/graph/badge.svg)](https://codecov.io/github/gorilla/securecookie)
[![godoc](https://godoc.org/github.com/gorilla/securecookie?status.svg)](https://godoc.org/github.com/gorilla/securecookie)
[![sourcegraph](https://sourcegraph.com/github.com/gorilla/securecookie/-/badge.svg)](https://sourcegraph.com/github.com/gorilla/securecookie?badge)
securecookie encodes and decodes authenticated and optionally encrypted ![Gorilla Logo](https://github.com/gorilla/.github/assets/53367916/d92caabf-98e0-473e-bfbf-ab554ba435e5)
securecookie encodes and decodes authenticated and optionally encrypted
cookie values. cookie values.
Secure cookies can't be forged, because their values are validated using HMAC. Secure cookies can't be forged, because their values are validated using HMAC.
@ -33,7 +36,10 @@ to not use encryption. If set, the length must correspond to the block size
of the encryption algorithm. For AES, used by default, valid lengths are of the encryption algorithm. For AES, used by default, valid lengths are
16, 24, or 32 bytes to select AES-128, AES-192, or AES-256. 16, 24, or 32 bytes to select AES-128, AES-192, or AES-256.
Strong keys can be created using the convenience function GenerateRandomKey(). Strong keys can be created using the convenience function
`GenerateRandomKey()`. Note that keys created using `GenerateRandomKey()` are not
automatically persisted. New keys will be created when the application is
restarted, and previously issued cookies will not be able to be decoded.
Once a SecureCookie instance is set, use it to encode a cookie value: Once a SecureCookie instance is set, use it to encode a cookie value:
@ -75,6 +81,64 @@ registered first using gob.Register(). For basic types this is not needed;
it works out of the box. An optional JSON encoder that uses `encoding/json` is it works out of the box. An optional JSON encoder that uses `encoding/json` is
available for types compatible with JSON. available for types compatible with JSON.
### Key Rotation
Rotating keys is an important part of any security strategy. The `EncodeMulti` and
`DecodeMulti` functions allow for multiple keys to be rotated in and out.
For example, let's take a system that stores keys in a map:
```go
// keys stored in a map will not be persisted between restarts
// a more persistent storage should be considered for production applications.
var cookies = map[string]*securecookie.SecureCookie{
"previous": securecookie.New(
securecookie.GenerateRandomKey(64),
securecookie.GenerateRandomKey(32),
),
"current": securecookie.New(
securecookie.GenerateRandomKey(64),
securecookie.GenerateRandomKey(32),
),
}
```
Using the current key to encode new cookies:
```go
func SetCookieHandler(w http.ResponseWriter, r *http.Request) {
value := map[string]string{
"foo": "bar",
}
if encoded, err := securecookie.EncodeMulti("cookie-name", value, cookies["current"]); err == nil {
cookie := &http.Cookie{
Name: "cookie-name",
Value: encoded,
Path: "/",
}
http.SetCookie(w, cookie)
}
}
```
Later, decode cookies. Check against all valid keys:
```go
func ReadCookieHandler(w http.ResponseWriter, r *http.Request) {
if cookie, err := r.Cookie("cookie-name"); err == nil {
value := make(map[string]string)
err = securecookie.DecodeMulti("cookie-name", cookie.Value, &value, cookies["current"], cookies["previous"])
if err == nil {
fmt.Fprintf(w, "The value of foo is %q", value["foo"])
}
}
}
```
Rotate the keys. This strategy allows previously issued cookies to be valid until the next rotation:
```go
func Rotate(newCookie *securecookie.SecureCookie) {
cookies["previous"] = cookies["current"]
cookies["current"] = newCookie
}
```
## License ## License
BSD licensed. See the LICENSE file for details. BSD licensed. See the LICENSE file for details.

View file

@ -1,25 +0,0 @@
// +build gofuzz
package securecookie
var hashKey = []byte("very-secret12345")
var blockKey = []byte("a-lot-secret1234")
var s = New(hashKey, blockKey)
type Cookie struct {
B bool
I int
S string
}
func Fuzz(data []byte) int {
datas := string(data)
var c Cookie
if err := s.Decode("fuzz", datas, &c); err != nil {
return 0
}
if _, err := s.Encode("fuzz", c); err != nil {
panic(err)
}
return 1
}

View file

@ -124,7 +124,7 @@ type Codec interface {
// GenerateRandomKey(). It is recommended to use a key with 32 or 64 bytes. // GenerateRandomKey(). It is recommended to use a key with 32 or 64 bytes.
// //
// blockKey is optional, used to encrypt values. Create it using // blockKey is optional, used to encrypt values. Create it using
// GenerateRandomKey(). The key length must correspond to the block size // GenerateRandomKey(). The key length must correspond to the key size
// of the encryption algorithm. For AES, used by default, valid lengths are // of the encryption algorithm. For AES, used by default, valid lengths are
// 16, 24, or 32 bytes to select AES-128, AES-192, or AES-256. // 16, 24, or 32 bytes to select AES-128, AES-192, or AES-256.
// The default encoder used for cookie serialization is encoding/gob. // The default encoder used for cookie serialization is encoding/gob.
@ -141,7 +141,7 @@ func New(hashKey, blockKey []byte) *SecureCookie {
maxLength: 4096, maxLength: 4096,
sz: GobEncoder{}, sz: GobEncoder{},
} }
if hashKey == nil { if len(hashKey) == 0 {
s.err = errHashKeyNotSet s.err = errHashKeyNotSet
} }
if blockKey != nil { if blockKey != nil {
@ -286,7 +286,7 @@ func (s *SecureCookie) Encode(name string, value interface{}) (string, error) {
b = encode(b) b = encode(b)
// 5. Check length. // 5. Check length.
if s.maxLength != 0 && len(b) > s.maxLength { if s.maxLength != 0 && len(b) > s.maxLength {
return "", errEncodedValueTooLong return "", fmt.Errorf("%s: %d", errEncodedValueTooLong, len(b))
} }
// Done. // Done.
return string(b), nil return string(b), nil
@ -310,7 +310,7 @@ func (s *SecureCookie) Decode(name, value string, dst interface{}) error {
} }
// 1. Check length. // 1. Check length.
if s.maxLength != 0 && len(value) > s.maxLength { if s.maxLength != 0 && len(value) > s.maxLength {
return errValueToDecodeTooLong return fmt.Errorf("%s: %d", errValueToDecodeTooLong, len(value))
} }
// 2. Decode from base64. // 2. Decode from base64.
b, err := decode([]byte(value)) b, err := decode([]byte(value))
@ -391,7 +391,7 @@ func verifyMac(h hash.Hash, value []byte, mac []byte) error {
// encrypt encrypts a value using the given block in counter mode. // encrypt encrypts a value using the given block in counter mode.
// //
// A random initialization vector (http://goo.gl/zF67k) with the length of the // A random initialization vector ( https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Initialization_vector_(IV) ) with the length of the
// block size is prepended to the resulting ciphertext. // block size is prepended to the resulting ciphertext.
func encrypt(block cipher.Block, value []byte) ([]byte, error) { func encrypt(block cipher.Block, value []byte) ([]byte, error) {
iv := GenerateRandomKey(block.BlockSize()) iv := GenerateRandomKey(block.BlockSize())
@ -408,7 +408,7 @@ func encrypt(block cipher.Block, value []byte) ([]byte, error) {
// decrypt decrypts a value using the given block in counter mode. // decrypt decrypts a value using the given block in counter mode.
// //
// The value to be decrypted must be prepended by a initialization vector // The value to be decrypted must be prepended by a initialization vector
// (http://goo.gl/zF67k) with the length of the block size. // ( https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Initialization_vector_(IV) ) with the length of the block size.
func decrypt(block cipher.Block, value []byte) ([]byte, error) { func decrypt(block cipher.Block, value []byte) ([]byte, error) {
size := block.BlockSize() size := block.BlockSize()
if len(value) > size { if len(value) > size {
@ -506,6 +506,10 @@ func decode(value []byte) ([]byte, error) {
// GenerateRandomKey creates a random key with the given length in bytes. // GenerateRandomKey creates a random key with the given length in bytes.
// On failure, returns nil. // On failure, returns nil.
// //
// Note that keys created using `GenerateRandomKey()` are not automatically
// persisted. New keys will be created when the application is restarted, and
// previously issued cookies will not be able to be decoded.
//
// Callers should explicitly check for the possibility of a nil return, treat // Callers should explicitly check for the possibility of a nil return, treat
// it as a failure of the system random number generator, and not continue. // it as a failure of the system random number generator, and not continue.
func GenerateRandomKey(length int) []byte { func GenerateRandomKey(length int) []byte {
@ -525,22 +529,21 @@ func GenerateRandomKey(length int) []byte {
// //
// Example: // Example:
// //
// codecs := securecookie.CodecsFromPairs( // codecs := securecookie.CodecsFromPairs(
// []byte("new-hash-key"), // []byte("new-hash-key"),
// []byte("new-block-key"), // []byte("new-block-key"),
// []byte("old-hash-key"), // []byte("old-hash-key"),
// []byte("old-block-key"), // []byte("old-block-key"),
// ) // )
//
// // Modify each instance.
// for _, s := range codecs {
// if cookie, ok := s.(*securecookie.SecureCookie); ok {
// cookie.MaxAge(86400 * 7)
// cookie.SetSerializer(securecookie.JSONEncoder{})
// cookie.HashFunc(sha512.New512_256)
// }
// }
// //
// // Modify each instance.
// for _, s := range codecs {
// if cookie, ok := s.(*securecookie.SecureCookie); ok {
// cookie.MaxAge(86400 * 7)
// cookie.SetSerializer(securecookie.JSONEncoder{})
// cookie.HashFunc(sha512.New512_256)
// }
// }
func CodecsFromPairs(keyPairs ...[]byte) []Codec { func CodecsFromPairs(keyPairs ...[]byte) []Codec {
codecs := make([]Codec, len(keyPairs)/2+len(keyPairs)%2) codecs := make([]Codec, len(keyPairs)/2+len(keyPairs)%2)
for i := 0; i < len(keyPairs); i += 2 { for i := 0; i < len(keyPairs); i += 2 {

20
vendor/github.com/gorilla/sessions/.editorconfig generated vendored Normal file
View file

@ -0,0 +1,20 @@
; https://editorconfig.org/
root = true
[*]
insert_final_newline = true
charset = utf-8
trim_trailing_whitespace = true
indent_style = space
indent_size = 2
[{Makefile,go.mod,go.sum,*.go,.gitmodules}]
indent_style = tab
indent_size = 4
[*.md]
indent_size = 4
trim_trailing_whitespace = false
eclint_indent_style = unset

1
vendor/github.com/gorilla/sessions/.gitignore generated vendored Normal file
View file

@ -0,0 +1 @@
coverage.coverprofile

View file

@ -1,43 +0,0 @@
# This is the official list of gorilla/sessions authors for copyright purposes.
#
# Please keep the list sorted.
Ahmadreza Zibaei <ahmadrezazibaei@hotmail.com>
Anton Lindström <lindztr@gmail.com>
Brian Jones <mojobojo@gmail.com>
Collin Stedman <kronion@users.noreply.github.com>
Deniz Eren <dee.116@gmail.com>
Dmitry Chestnykh <dmitry@codingrobots.com>
Dustin Oprea <myselfasunder@gmail.com>
Egon Elbre <egonelbre@gmail.com>
enumappstore <appstore@enumapps.com>
Geofrey Ernest <geofreyernest@live.com>
Google LLC (https://opensource.google.com/)
Jerry Saravia <SaraviaJ@gmail.com>
Jonathan Gillham <jonathan.gillham@gamil.com>
Justin Clift <justin@postgresql.org>
Justin Hellings <justin.hellings@gmail.com>
Kamil Kisiel <kamil@kamilkisiel.net>
Keiji Yoshida <yoshida.keiji.84@gmail.com>
kliron <kliron@gmail.com>
Kshitij Saraogi <KshitijSaraogi@gmail.com>
Lauris BH <lauris@nix.lv>
Lukas Rist <glaslos@gmail.com>
Mark Dain <ancarda@users.noreply.github.com>
Matt Ho <matt.ho@gmail.com>
Matt Silverlock <matt@eatsleeprepeat.net>
Mattias Wadman <mattias.wadman@gmail.com>
Michael Schuett <michaeljs1990@gmail.com>
Michael Stapelberg <stapelberg@users.noreply.github.com>
Mirco Zeiss <mirco.zeiss@gmail.com>
moraes <rodrigo.moraes@gmail.com>
nvcnvn <nguyen@open-vn.org>
pappz <zoltan.pmail@gmail.com>
Pontus Leitzler <leitzler@users.noreply.github.com>
QuaSoft <info@quasoft.net>
rcadena <robert.cadena@gmail.com>
rodrigo moraes <rodrigo.moraes@gmail.com>
Shawn Smith <shawnpsmith@gmail.com>
Taylor Hurt <taylor.a.hurt@gmail.com>
Tortuoise <sanyasinp@gmail.com>
Vitor De Mario <vitordemario@gmail.com>

View file

@ -1,4 +1,4 @@
Copyright (c) 2012-2018 The Gorilla Authors. All rights reserved. Copyright (c) 2023 The Gorilla Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are modification, are permitted provided that the following conditions are

34
vendor/github.com/gorilla/sessions/Makefile generated vendored Normal file
View file

@ -0,0 +1,34 @@
GO_LINT=$(shell which golangci-lint 2> /dev/null || echo '')
GO_LINT_URI=github.com/golangci/golangci-lint/cmd/golangci-lint@latest
GO_SEC=$(shell which gosec 2> /dev/null || echo '')
GO_SEC_URI=github.com/securego/gosec/v2/cmd/gosec@latest
GO_VULNCHECK=$(shell which govulncheck 2> /dev/null || echo '')
GO_VULNCHECK_URI=golang.org/x/vuln/cmd/govulncheck@latest
.PHONY: golangci-lint
golangci-lint:
$(if $(GO_LINT), ,go install $(GO_LINT_URI))
@echo "##### Running golangci-lint"
golangci-lint run -v
.PHONY: gosec
gosec:
$(if $(GO_SEC), ,go install $(GO_SEC_URI))
@echo "##### Running gosec"
gosec ./...
.PHONY: govulncheck
govulncheck:
$(if $(GO_VULNCHECK), ,go install $(GO_VULNCHECK_URI))
@echo "##### Running govulncheck"
govulncheck ./...
.PHONY: verify
verify: golangci-lint gosec govulncheck
.PHONY: test
test:
@echo "##### Running tests"
go test -race -cover -coverprofile=coverage.coverprofile -covermode=atomic -v ./...

View file

@ -1,7 +1,11 @@
# sessions # sessions
[![GoDoc](https://godoc.org/github.com/gorilla/sessions?status.svg)](https://godoc.org/github.com/gorilla/sessions) [![Build Status](https://travis-ci.org/gorilla/sessions.svg?branch=master)](https://travis-ci.org/gorilla/sessions) ![testing](https://github.com/gorilla/sessions/actions/workflows/test.yml/badge.svg)
[![Sourcegraph](https://sourcegraph.com/github.com/gorilla/sessions/-/badge.svg)](https://sourcegraph.com/github.com/gorilla/sessions?badge) [![codecov](https://codecov.io/github/gorilla/sessions/branch/main/graph/badge.svg)](https://codecov.io/github/gorilla/sessions)
[![godoc](https://godoc.org/github.com/gorilla/sessions?status.svg)](https://godoc.org/github.com/gorilla/sessions)
[![sourcegraph](https://sourcegraph.com/github.com/gorilla/sessions/-/badge.svg)](https://sourcegraph.com/github.com/gorilla/sessions?badge)
![Gorilla Logo](https://github.com/gorilla/.github/assets/53367916/d92caabf-98e0-473e-bfbf-ab554ba435e5)
gorilla/sessions provides cookie and filesystem sessions and infrastructure for gorilla/sessions provides cookie and filesystem sessions and infrastructure for
custom session backends. custom session backends.
@ -84,6 +88,7 @@ Other implementations of the `sessions.Store` interface:
- [github.com/lafriks/xormstore](https://github.com/lafriks/xormstore) - XORM (MySQL, PostgreSQL, SQLite, Microsoft SQL Server, TiDB) - [github.com/lafriks/xormstore](https://github.com/lafriks/xormstore) - XORM (MySQL, PostgreSQL, SQLite, Microsoft SQL Server, TiDB)
- [github.com/GoogleCloudPlatform/firestore-gorilla-sessions](https://github.com/GoogleCloudPlatform/firestore-gorilla-sessions) - Cloud Firestore - [github.com/GoogleCloudPlatform/firestore-gorilla-sessions](https://github.com/GoogleCloudPlatform/firestore-gorilla-sessions) - Cloud Firestore
- [github.com/stephenafamo/crdbstore](https://github.com/stephenafamo/crdbstore) - CockroachDB - [github.com/stephenafamo/crdbstore](https://github.com/stephenafamo/crdbstore) - CockroachDB
- [github.com/ryicoh/tikvstore](github.com/ryicoh/tikvstore) - TiKV
## License ## License

View file

@ -1,3 +1,4 @@
//go:build !go1.11
// +build !go1.11 // +build !go1.11
package sessions package sessions

View file

@ -1,3 +1,4 @@
//go:build go1.11
// +build go1.11 // +build go1.11
package sessions package sessions

View file

@ -1,3 +1,4 @@
//go:build !go1.11
// +build !go1.11 // +build !go1.11
package sessions package sessions

View file

@ -1,3 +1,4 @@
//go:build go1.11
// +build go1.11 // +build go1.11
package sessions package sessions

View file

@ -6,11 +6,9 @@
import ( import (
"encoding/base32" "encoding/base32"
"io/ioutil"
"net/http" "net/http"
"os" "os"
"path/filepath" "path/filepath"
"strings"
"sync" "sync"
"github.com/gorilla/securecookie" "github.com/gorilla/securecookie"
@ -201,6 +199,8 @@ func (s *FilesystemStore) New(r *http.Request, name string) (*Session, error) {
return session, err return session, err
} }
var base32RawStdEncoding = base32.StdEncoding.WithPadding(base32.NoPadding)
// Save adds a single session to the response. // Save adds a single session to the response.
// //
// If the Options.MaxAge of the session is <= 0 then the session file will be // If the Options.MaxAge of the session is <= 0 then the session file will be
@ -211,7 +211,7 @@ func (s *FilesystemStore) Save(r *http.Request, w http.ResponseWriter,
session *Session) error { session *Session) error {
// Delete if max-age is <= 0 // Delete if max-age is <= 0
if session.Options.MaxAge <= 0 { if session.Options.MaxAge <= 0 {
if err := s.erase(session); err != nil { if err := s.erase(session); err != nil && !os.IsNotExist(err) {
return err return err
} }
http.SetCookie(w, NewCookie(session.Name(), "", session.Options)) http.SetCookie(w, NewCookie(session.Name(), "", session.Options))
@ -221,9 +221,8 @@ func (s *FilesystemStore) Save(r *http.Request, w http.ResponseWriter,
if session.ID == "" { if session.ID == "" {
// Because the ID is used in the filename, encode it to // Because the ID is used in the filename, encode it to
// use alphanumeric characters only. // use alphanumeric characters only.
session.ID = strings.TrimRight( session.ID = base32RawStdEncoding.EncodeToString(
base32.StdEncoding.EncodeToString( securecookie.GenerateRandomKey(32))
securecookie.GenerateRandomKey(32)), "=")
} }
if err := s.save(session); err != nil { if err := s.save(session); err != nil {
return err return err
@ -261,7 +260,7 @@ func (s *FilesystemStore) save(session *Session) error {
filename := filepath.Join(s.path, "session_"+session.ID) filename := filepath.Join(s.path, "session_"+session.ID)
fileMutex.Lock() fileMutex.Lock()
defer fileMutex.Unlock() defer fileMutex.Unlock()
return ioutil.WriteFile(filename, []byte(encoded), 0600) return os.WriteFile(filename, []byte(encoded), 0600)
} }
// load reads a file and decodes its content into session.Values. // load reads a file and decodes its content into session.Values.
@ -269,7 +268,7 @@ func (s *FilesystemStore) load(session *Session) error {
filename := filepath.Join(s.path, "session_"+session.ID) filename := filepath.Join(s.path, "session_"+session.ID)
fileMutex.RLock() fileMutex.RLock()
defer fileMutex.RUnlock() defer fileMutex.RUnlock()
fdata, err := ioutil.ReadFile(filename) fdata, err := os.ReadFile(filepath.Clean(filename))
if err != nil { if err != nil {
return err return err
} }

View file

@ -117,6 +117,12 @@ func encodeBlockGo(dst, src []byte) (d int) {
i-- i--
base-- base--
} }
// Bail if we exceed the maximum size.
if d+(base-nextEmit) > dstLimit {
return 0
}
d += emitLiteral(dst[d:], src[nextEmit:base]) d += emitLiteral(dst[d:], src[nextEmit:base])
// Extend forward // Extend forward
@ -152,7 +158,6 @@ func encodeBlockGo(dst, src []byte) (d int) {
if s >= sLimit { if s >= sLimit {
goto emitRemainder goto emitRemainder
} }
cv = load64(src, s) cv = load64(src, s)
continue continue
} }
@ -325,6 +330,11 @@ func encodeBlockSnappyGo(dst, src []byte) (d int) {
i-- i--
base-- base--
} }
// Bail if we exceed the maximum size.
if d+(base-nextEmit) > dstLimit {
return 0
}
d += emitLiteral(dst[d:], src[nextEmit:base]) d += emitLiteral(dst[d:], src[nextEmit:base])
// Extend forward // Extend forward
@ -532,6 +542,11 @@ func encodeBlockDictGo(dst, src []byte, dict *Dict) (d int) {
i-- i--
base-- base--
} }
// Bail if we exceed the maximum size.
if d+(base-nextEmit) > dstLimit {
return 0
}
d += emitLiteral(dst[d:], src[nextEmit:base]) d += emitLiteral(dst[d:], src[nextEmit:base])
if debug && nextEmit != base { if debug && nextEmit != base {
fmt.Println("emitted ", base-nextEmit, "literals") fmt.Println("emitted ", base-nextEmit, "literals")
@ -880,6 +895,11 @@ func encodeBlockDictGo(dst, src []byte, dict *Dict) (d int) {
i-- i--
base-- base--
} }
// Bail if we exceed the maximum size.
if d+(base-nextEmit) > dstLimit {
return 0
}
d += emitLiteral(dst[d:], src[nextEmit:base]) d += emitLiteral(dst[d:], src[nextEmit:base])
if debug && nextEmit != base { if debug && nextEmit != base {
fmt.Println("emitted ", base-nextEmit, "literals") fmt.Println("emitted ", base-nextEmit, "literals")

View file

@ -100,6 +100,15 @@ repeat_extend_back_loop_encodeBlockAsm:
JNZ repeat_extend_back_loop_encodeBlockAsm JNZ repeat_extend_back_loop_encodeBlockAsm
repeat_extend_back_end_encodeBlockAsm: repeat_extend_back_end_encodeBlockAsm:
MOVL SI, BX
SUBL 12(SP), BX
LEAQ 5(AX)(BX*1), BX
CMPQ BX, (SP)
JB repeat_dst_size_check_encodeBlockAsm
MOVQ $0x00000000, ret+48(FP)
RET
repeat_dst_size_check_encodeBlockAsm:
MOVL 12(SP), BX MOVL 12(SP), BX
CMPL BX, SI CMPL BX, SI
JEQ emit_literal_done_repeat_emit_encodeBlockAsm JEQ emit_literal_done_repeat_emit_encodeBlockAsm
@ -1513,6 +1522,15 @@ repeat_extend_back_loop_encodeBlockAsm4MB:
JNZ repeat_extend_back_loop_encodeBlockAsm4MB JNZ repeat_extend_back_loop_encodeBlockAsm4MB
repeat_extend_back_end_encodeBlockAsm4MB: repeat_extend_back_end_encodeBlockAsm4MB:
MOVL SI, BX
SUBL 12(SP), BX
LEAQ 4(AX)(BX*1), BX
CMPQ BX, (SP)
JB repeat_dst_size_check_encodeBlockAsm4MB
MOVQ $0x00000000, ret+48(FP)
RET
repeat_dst_size_check_encodeBlockAsm4MB:
MOVL 12(SP), BX MOVL 12(SP), BX
CMPL BX, SI CMPL BX, SI
JEQ emit_literal_done_repeat_emit_encodeBlockAsm4MB JEQ emit_literal_done_repeat_emit_encodeBlockAsm4MB
@ -2828,6 +2846,15 @@ repeat_extend_back_loop_encodeBlockAsm12B:
JNZ repeat_extend_back_loop_encodeBlockAsm12B JNZ repeat_extend_back_loop_encodeBlockAsm12B
repeat_extend_back_end_encodeBlockAsm12B: repeat_extend_back_end_encodeBlockAsm12B:
MOVL SI, BX
SUBL 12(SP), BX
LEAQ 3(AX)(BX*1), BX
CMPQ BX, (SP)
JB repeat_dst_size_check_encodeBlockAsm12B
MOVQ $0x00000000, ret+48(FP)
RET
repeat_dst_size_check_encodeBlockAsm12B:
MOVL 12(SP), BX MOVL 12(SP), BX
CMPL BX, SI CMPL BX, SI
JEQ emit_literal_done_repeat_emit_encodeBlockAsm12B JEQ emit_literal_done_repeat_emit_encodeBlockAsm12B
@ -3903,6 +3930,15 @@ repeat_extend_back_loop_encodeBlockAsm10B:
JNZ repeat_extend_back_loop_encodeBlockAsm10B JNZ repeat_extend_back_loop_encodeBlockAsm10B
repeat_extend_back_end_encodeBlockAsm10B: repeat_extend_back_end_encodeBlockAsm10B:
MOVL SI, BX
SUBL 12(SP), BX
LEAQ 3(AX)(BX*1), BX
CMPQ BX, (SP)
JB repeat_dst_size_check_encodeBlockAsm10B
MOVQ $0x00000000, ret+48(FP)
RET
repeat_dst_size_check_encodeBlockAsm10B:
MOVL 12(SP), BX MOVL 12(SP), BX
CMPL BX, SI CMPL BX, SI
JEQ emit_literal_done_repeat_emit_encodeBlockAsm10B JEQ emit_literal_done_repeat_emit_encodeBlockAsm10B
@ -4978,6 +5014,15 @@ repeat_extend_back_loop_encodeBlockAsm8B:
JNZ repeat_extend_back_loop_encodeBlockAsm8B JNZ repeat_extend_back_loop_encodeBlockAsm8B
repeat_extend_back_end_encodeBlockAsm8B: repeat_extend_back_end_encodeBlockAsm8B:
MOVL SI, BX
SUBL 12(SP), BX
LEAQ 3(AX)(BX*1), BX
CMPQ BX, (SP)
JB repeat_dst_size_check_encodeBlockAsm8B
MOVQ $0x00000000, ret+48(FP)
RET
repeat_dst_size_check_encodeBlockAsm8B:
MOVL 12(SP), BX MOVL 12(SP), BX
CMPL BX, SI CMPL BX, SI
JEQ emit_literal_done_repeat_emit_encodeBlockAsm8B JEQ emit_literal_done_repeat_emit_encodeBlockAsm8B
@ -10756,6 +10801,15 @@ repeat_extend_back_loop_encodeSnappyBlockAsm:
JNZ repeat_extend_back_loop_encodeSnappyBlockAsm JNZ repeat_extend_back_loop_encodeSnappyBlockAsm
repeat_extend_back_end_encodeSnappyBlockAsm: repeat_extend_back_end_encodeSnappyBlockAsm:
MOVL SI, BX
SUBL 12(SP), BX
LEAQ 5(AX)(BX*1), BX
CMPQ BX, (SP)
JB repeat_dst_size_check_encodeSnappyBlockAsm
MOVQ $0x00000000, ret+48(FP)
RET
repeat_dst_size_check_encodeSnappyBlockAsm:
MOVL 12(SP), BX MOVL 12(SP), BX
CMPL BX, SI CMPL BX, SI
JEQ emit_literal_done_repeat_emit_encodeSnappyBlockAsm JEQ emit_literal_done_repeat_emit_encodeSnappyBlockAsm
@ -11678,6 +11732,15 @@ repeat_extend_back_loop_encodeSnappyBlockAsm64K:
JNZ repeat_extend_back_loop_encodeSnappyBlockAsm64K JNZ repeat_extend_back_loop_encodeSnappyBlockAsm64K
repeat_extend_back_end_encodeSnappyBlockAsm64K: repeat_extend_back_end_encodeSnappyBlockAsm64K:
MOVL SI, BX
SUBL 12(SP), BX
LEAQ 3(AX)(BX*1), BX
CMPQ BX, (SP)
JB repeat_dst_size_check_encodeSnappyBlockAsm64K
MOVQ $0x00000000, ret+48(FP)
RET
repeat_dst_size_check_encodeSnappyBlockAsm64K:
MOVL 12(SP), BX MOVL 12(SP), BX
CMPL BX, SI CMPL BX, SI
JEQ emit_literal_done_repeat_emit_encodeSnappyBlockAsm64K JEQ emit_literal_done_repeat_emit_encodeSnappyBlockAsm64K
@ -12504,6 +12567,15 @@ repeat_extend_back_loop_encodeSnappyBlockAsm12B:
JNZ repeat_extend_back_loop_encodeSnappyBlockAsm12B JNZ repeat_extend_back_loop_encodeSnappyBlockAsm12B
repeat_extend_back_end_encodeSnappyBlockAsm12B: repeat_extend_back_end_encodeSnappyBlockAsm12B:
MOVL SI, BX
SUBL 12(SP), BX
LEAQ 3(AX)(BX*1), BX
CMPQ BX, (SP)
JB repeat_dst_size_check_encodeSnappyBlockAsm12B
MOVQ $0x00000000, ret+48(FP)
RET
repeat_dst_size_check_encodeSnappyBlockAsm12B:
MOVL 12(SP), BX MOVL 12(SP), BX
CMPL BX, SI CMPL BX, SI
JEQ emit_literal_done_repeat_emit_encodeSnappyBlockAsm12B JEQ emit_literal_done_repeat_emit_encodeSnappyBlockAsm12B
@ -13330,6 +13402,15 @@ repeat_extend_back_loop_encodeSnappyBlockAsm10B:
JNZ repeat_extend_back_loop_encodeSnappyBlockAsm10B JNZ repeat_extend_back_loop_encodeSnappyBlockAsm10B
repeat_extend_back_end_encodeSnappyBlockAsm10B: repeat_extend_back_end_encodeSnappyBlockAsm10B:
MOVL SI, BX
SUBL 12(SP), BX
LEAQ 3(AX)(BX*1), BX
CMPQ BX, (SP)
JB repeat_dst_size_check_encodeSnappyBlockAsm10B
MOVQ $0x00000000, ret+48(FP)
RET
repeat_dst_size_check_encodeSnappyBlockAsm10B:
MOVL 12(SP), BX MOVL 12(SP), BX
CMPL BX, SI CMPL BX, SI
JEQ emit_literal_done_repeat_emit_encodeSnappyBlockAsm10B JEQ emit_literal_done_repeat_emit_encodeSnappyBlockAsm10B
@ -14156,6 +14237,15 @@ repeat_extend_back_loop_encodeSnappyBlockAsm8B:
JNZ repeat_extend_back_loop_encodeSnappyBlockAsm8B JNZ repeat_extend_back_loop_encodeSnappyBlockAsm8B
repeat_extend_back_end_encodeSnappyBlockAsm8B: repeat_extend_back_end_encodeSnappyBlockAsm8B:
MOVL SI, BX
SUBL 12(SP), BX
LEAQ 3(AX)(BX*1), BX
CMPQ BX, (SP)
JB repeat_dst_size_check_encodeSnappyBlockAsm8B
MOVQ $0x00000000, ret+48(FP)
RET
repeat_dst_size_check_encodeSnappyBlockAsm8B:
MOVL 12(SP), BX MOVL 12(SP), BX
CMPL BX, SI CMPL BX, SI
JEQ emit_literal_done_repeat_emit_encodeSnappyBlockAsm8B JEQ emit_literal_done_repeat_emit_encodeSnappyBlockAsm8B
@ -17949,6 +18039,15 @@ repeat_extend_back_loop_calcBlockSize:
JNZ repeat_extend_back_loop_calcBlockSize JNZ repeat_extend_back_loop_calcBlockSize
repeat_extend_back_end_calcBlockSize: repeat_extend_back_end_calcBlockSize:
MOVL SI, BX
SUBL 12(SP), BX
LEAQ 5(AX)(BX*1), BX
CMPQ BX, (SP)
JB repeat_dst_size_check_calcBlockSize
MOVQ $0x00000000, ret+24(FP)
RET
repeat_dst_size_check_calcBlockSize:
MOVL 12(SP), BX MOVL 12(SP), BX
CMPL BX, SI CMPL BX, SI
JEQ emit_literal_done_repeat_emit_calcBlockSize JEQ emit_literal_done_repeat_emit_calcBlockSize
@ -18531,6 +18630,15 @@ repeat_extend_back_loop_calcBlockSizeSmall:
JNZ repeat_extend_back_loop_calcBlockSizeSmall JNZ repeat_extend_back_loop_calcBlockSizeSmall
repeat_extend_back_end_calcBlockSizeSmall: repeat_extend_back_end_calcBlockSizeSmall:
MOVL SI, BX
SUBL 12(SP), BX
LEAQ 3(AX)(BX*1), BX
CMPQ BX, (SP)
JB repeat_dst_size_check_calcBlockSizeSmall
MOVQ $0x00000000, ret+24(FP)
RET
repeat_dst_size_check_calcBlockSizeSmall:
MOVL 12(SP), BX MOVL 12(SP), BX
CMPL BX, SI CMPL BX, SI
JEQ emit_literal_done_repeat_emit_calcBlockSizeSmall JEQ emit_literal_done_repeat_emit_calcBlockSizeSmall

View file

@ -215,7 +215,7 @@ func (w *Writer) ReadFrom(r io.Reader) (n int64, err error) {
return 0, err return 0, err
} }
if len(w.ibuf) > 0 { if len(w.ibuf) > 0 {
err := w.Flush() err := w.AsyncFlush()
if err != nil { if err != nil {
return 0, err return 0, err
} }
@ -225,7 +225,7 @@ func (w *Writer) ReadFrom(r io.Reader) (n int64, err error) {
if err := w.EncodeBuffer(buf); err != nil { if err := w.EncodeBuffer(buf); err != nil {
return 0, err return 0, err
} }
return int64(len(buf)), w.Flush() return int64(len(buf)), w.AsyncFlush()
} }
for { for {
inbuf := w.buffers.Get().([]byte)[:w.blockSize+obufHeaderLen] inbuf := w.buffers.Get().([]byte)[:w.blockSize+obufHeaderLen]
@ -354,7 +354,7 @@ func (w *Writer) EncodeBuffer(buf []byte) (err error) {
} }
// Flush queued data first. // Flush queued data first.
if len(w.ibuf) > 0 { if len(w.ibuf) > 0 {
err := w.Flush() err := w.AsyncFlush()
if err != nil { if err != nil {
return err return err
} }
@ -716,9 +716,9 @@ func (w *Writer) writeSync(p []byte) (nRet int, errRet error) {
return nRet, nil return nRet, nil
} }
// Flush flushes the Writer to its underlying io.Writer. // AsyncFlush writes any buffered bytes to a block and starts compressing it.
// This does not apply padding. // It does not wait for the output has been written as Flush() does.
func (w *Writer) Flush() error { func (w *Writer) AsyncFlush() error {
if err := w.err(nil); err != nil { if err := w.err(nil); err != nil {
return err return err
} }
@ -738,6 +738,15 @@ func (w *Writer) Flush() error {
} }
} }
} }
return w.err(nil)
}
// Flush flushes the Writer to its underlying io.Writer.
// This does not apply padding.
func (w *Writer) Flush() error {
if err := w.AsyncFlush(); err != nil {
return err
}
if w.output == nil { if w.output == nil {
return w.err(nil) return w.err(nil)
} }

View file

@ -14,17 +14,22 @@
) )
// ArrayCodec is the Codec used for bsoncore.Array values. // ArrayCodec is the Codec used for bsoncore.Array values.
//
// Deprecated: ArrayCodec will not be directly accessible in Go Driver 2.0.
type ArrayCodec struct{} type ArrayCodec struct{}
var defaultArrayCodec = NewArrayCodec() var defaultArrayCodec = NewArrayCodec()
// NewArrayCodec returns an ArrayCodec. // NewArrayCodec returns an ArrayCodec.
//
// Deprecated: NewArrayCodec will not be available in Go Driver 2.0. See
// [ArrayCodec] for more details.
func NewArrayCodec() *ArrayCodec { func NewArrayCodec() *ArrayCodec {
return &ArrayCodec{} return &ArrayCodec{}
} }
// EncodeValue is the ValueEncoder for bsoncore.Array values. // EncodeValue is the ValueEncoder for bsoncore.Array values.
func (ac *ArrayCodec) EncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { func (ac *ArrayCodec) EncodeValue(_ EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {
if !val.IsValid() || val.Type() != tCoreArray { if !val.IsValid() || val.Type() != tCoreArray {
return ValueEncoderError{Name: "CoreArrayEncodeValue", Types: []reflect.Type{tCoreArray}, Received: val} return ValueEncoderError{Name: "CoreArrayEncodeValue", Types: []reflect.Type{tCoreArray}, Received: val}
} }
@ -34,7 +39,7 @@ func (ac *ArrayCodec) EncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val r
} }
// DecodeValue is the ValueDecoder for bsoncore.Array values. // DecodeValue is the ValueDecoder for bsoncore.Array values.
func (ac *ArrayCodec) DecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { func (ac *ArrayCodec) DecodeValue(_ DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
if !val.CanSet() || val.Type() != tCoreArray { if !val.CanSet() || val.Type() != tCoreArray {
return ValueDecoderError{Name: "CoreArrayDecodeValue", Types: []reflect.Type{tCoreArray}, Received: val} return ValueDecoderError{Name: "CoreArrayDecodeValue", Types: []reflect.Type{tCoreArray}, Received: val}
} }

View file

@ -23,6 +23,8 @@
// Marshaler is an interface implemented by types that can marshal themselves // Marshaler is an interface implemented by types that can marshal themselves
// into a BSON document represented as bytes. The bytes returned must be a valid // into a BSON document represented as bytes. The bytes returned must be a valid
// BSON document if the error is nil. // BSON document if the error is nil.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.Marshaler] instead.
type Marshaler interface { type Marshaler interface {
MarshalBSON() ([]byte, error) MarshalBSON() ([]byte, error)
} }
@ -31,6 +33,8 @@ type Marshaler interface {
// themselves into a BSON value as bytes. The type must be the valid type for // themselves into a BSON value as bytes. The type must be the valid type for
// the bytes returned. The bytes and byte type together must be valid if the // the bytes returned. The bytes and byte type together must be valid if the
// error is nil. // error is nil.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.ValueMarshaler] instead.
type ValueMarshaler interface { type ValueMarshaler interface {
MarshalBSONValue() (bsontype.Type, []byte, error) MarshalBSONValue() (bsontype.Type, []byte, error)
} }
@ -39,6 +43,8 @@ type ValueMarshaler interface {
// document representation of themselves. The BSON bytes can be assumed to be // document representation of themselves. The BSON bytes can be assumed to be
// valid. UnmarshalBSON must copy the BSON bytes if it wishes to retain the data // valid. UnmarshalBSON must copy the BSON bytes if it wishes to retain the data
// after returning. // after returning.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.Unmarshaler] instead.
type Unmarshaler interface { type Unmarshaler interface {
UnmarshalBSON([]byte) error UnmarshalBSON([]byte) error
} }
@ -47,6 +53,8 @@ type Unmarshaler interface {
// BSON value representation of themselves. The BSON bytes and type can be // BSON value representation of themselves. The BSON bytes and type can be
// assumed to be valid. UnmarshalBSONValue must copy the BSON value bytes if it // assumed to be valid. UnmarshalBSONValue must copy the BSON value bytes if it
// wishes to retain the data after returning. // wishes to retain the data after returning.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.ValueUnmarshaler] instead.
type ValueUnmarshaler interface { type ValueUnmarshaler interface {
UnmarshalBSONValue(bsontype.Type, []byte) error UnmarshalBSONValue(bsontype.Type, []byte) error
} }
@ -111,13 +119,93 @@ func (vde ValueDecoderError) Error() string {
// value. // value.
type EncodeContext struct { type EncodeContext struct {
*Registry *Registry
// MinSize causes the Encoder to marshal Go integer values (int, int8, int16, int32, int64,
// uint, uint8, uint16, uint32, or uint64) as the minimum BSON int size (either 32 or 64 bits)
// that can represent the integer value.
//
// Deprecated: Use bson.Encoder.IntMinSize instead.
MinSize bool MinSize bool
errorOnInlineDuplicates bool
stringifyMapKeysWithFmt bool
nilMapAsEmpty bool
nilSliceAsEmpty bool
nilByteSliceAsEmpty bool
omitZeroStruct bool
useJSONStructTags bool
}
// ErrorOnInlineDuplicates causes the Encoder to return an error if there is a duplicate field in
// the marshaled BSON when the "inline" struct tag option is set.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.Encoder.ErrorOnInlineDuplicates] instead.
func (ec *EncodeContext) ErrorOnInlineDuplicates() {
ec.errorOnInlineDuplicates = true
}
// StringifyMapKeysWithFmt causes the Encoder to convert Go map keys to BSON document field name
// strings using fmt.Sprintf() instead of the default string conversion logic.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.Encoder.StringifyMapKeysWithFmt] instead.
func (ec *EncodeContext) StringifyMapKeysWithFmt() {
ec.stringifyMapKeysWithFmt = true
}
// NilMapAsEmpty causes the Encoder to marshal nil Go maps as empty BSON documents instead of BSON
// null.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.Encoder.NilMapAsEmpty] instead.
func (ec *EncodeContext) NilMapAsEmpty() {
ec.nilMapAsEmpty = true
}
// NilSliceAsEmpty causes the Encoder to marshal nil Go slices as empty BSON arrays instead of BSON
// null.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.Encoder.NilSliceAsEmpty] instead.
func (ec *EncodeContext) NilSliceAsEmpty() {
ec.nilSliceAsEmpty = true
}
// NilByteSliceAsEmpty causes the Encoder to marshal nil Go byte slices as empty BSON binary values
// instead of BSON null.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.Encoder.NilByteSliceAsEmpty] instead.
func (ec *EncodeContext) NilByteSliceAsEmpty() {
ec.nilByteSliceAsEmpty = true
}
// OmitZeroStruct causes the Encoder to consider the zero value for a struct (e.g. MyStruct{})
// as empty and omit it from the marshaled BSON when the "omitempty" struct tag option is set.
//
// Note that the Encoder only examines exported struct fields when determining if a struct is the
// zero value. It considers pointers to a zero struct value (e.g. &MyStruct{}) not empty.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.Encoder.OmitZeroStruct] instead.
func (ec *EncodeContext) OmitZeroStruct() {
ec.omitZeroStruct = true
}
// UseJSONStructTags causes the Encoder to fall back to using the "json" struct tag if a "bson"
// struct tag is not specified.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.Encoder.UseJSONStructTags] instead.
func (ec *EncodeContext) UseJSONStructTags() {
ec.useJSONStructTags = true
} }
// DecodeContext is the contextual information required for a Codec to decode a // DecodeContext is the contextual information required for a Codec to decode a
// value. // value.
type DecodeContext struct { type DecodeContext struct {
*Registry *Registry
// Truncate, if true, instructs decoders to to truncate the fractional part of BSON "double"
// values when attempting to unmarshal them into a Go integer (int, int8, int16, int32, int64,
// uint, uint8, uint16, uint32, or uint64) struct field. The truncation logic does not apply to
// BSON "decimal128" values.
//
// Deprecated: Use bson.Decoder.AllowTruncatingDoubles instead.
Truncate bool Truncate bool
// Ancestor is the type of a containing document. This is mainly used to determine what type // Ancestor is the type of a containing document. This is mainly used to determine what type
@ -125,7 +213,7 @@ type DecodeContext struct {
// Ancestor is a bson.M, BSON embedded document values being decoded into an empty interface // Ancestor is a bson.M, BSON embedded document values being decoded into an empty interface
// will be decoded into a bson.M. // will be decoded into a bson.M.
// //
// Deprecated: Use DefaultDocumentM or DefaultDocumentD instead. // Deprecated: Use bson.Decoder.DefaultDocumentM or bson.Decoder.DefaultDocumentD instead.
Ancestor reflect.Type Ancestor reflect.Type
// defaultDocumentType specifies the Go type to decode top-level and nested BSON documents into. In particular, the // defaultDocumentType specifies the Go type to decode top-level and nested BSON documents into. In particular, the
@ -133,22 +221,74 @@ type DecodeContext struct {
// set to a type that a BSON document cannot be unmarshaled into (e.g. "string"), unmarshalling will result in an // set to a type that a BSON document cannot be unmarshaled into (e.g. "string"), unmarshalling will result in an
// error. DocumentType overrides the Ancestor field. // error. DocumentType overrides the Ancestor field.
defaultDocumentType reflect.Type defaultDocumentType reflect.Type
binaryAsSlice bool
useJSONStructTags bool
useLocalTimeZone bool
zeroMaps bool
zeroStructs bool
} }
// DefaultDocumentM will decode empty documents using the primitive.M type. This behavior is restricted to data typed as // BinaryAsSlice causes the Decoder to unmarshal BSON binary field values that are the "Generic" or
// "interface{}" or "map[string]interface{}". // "Old" BSON binary subtype as a Go byte slice instead of a primitive.Binary.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.Decoder.BinaryAsSlice] instead.
func (dc *DecodeContext) BinaryAsSlice() {
dc.binaryAsSlice = true
}
// UseJSONStructTags causes the Decoder to fall back to using the "json" struct tag if a "bson"
// struct tag is not specified.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.Decoder.UseJSONStructTags] instead.
func (dc *DecodeContext) UseJSONStructTags() {
dc.useJSONStructTags = true
}
// UseLocalTimeZone causes the Decoder to unmarshal time.Time values in the local timezone instead
// of the UTC timezone.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.Decoder.UseLocalTimeZone] instead.
func (dc *DecodeContext) UseLocalTimeZone() {
dc.useLocalTimeZone = true
}
// ZeroMaps causes the Decoder to delete any existing values from Go maps in the destination value
// passed to Decode before unmarshaling BSON documents into them.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.Decoder.ZeroMaps] instead.
func (dc *DecodeContext) ZeroMaps() {
dc.zeroMaps = true
}
// ZeroStructs causes the Decoder to delete any existing values from Go structs in the destination
// value passed to Decode before unmarshaling BSON documents into them.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.Decoder.ZeroStructs] instead.
func (dc *DecodeContext) ZeroStructs() {
dc.zeroStructs = true
}
// DefaultDocumentM causes the Decoder to always unmarshal documents into the primitive.M type. This
// behavior is restricted to data typed as "interface{}" or "map[string]interface{}".
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.Decoder.DefaultDocumentM] instead.
func (dc *DecodeContext) DefaultDocumentM() { func (dc *DecodeContext) DefaultDocumentM() {
dc.defaultDocumentType = reflect.TypeOf(primitive.M{}) dc.defaultDocumentType = reflect.TypeOf(primitive.M{})
} }
// DefaultDocumentD will decode empty documents using the primitive.D type. This behavior is restricted to data typed as // DefaultDocumentD causes the Decoder to always unmarshal documents into the primitive.D type. This
// "interface{}" or "map[string]interface{}". // behavior is restricted to data typed as "interface{}" or "map[string]interface{}".
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.Decoder.DefaultDocumentD] instead.
func (dc *DecodeContext) DefaultDocumentD() { func (dc *DecodeContext) DefaultDocumentD() {
dc.defaultDocumentType = reflect.TypeOf(primitive.D{}) dc.defaultDocumentType = reflect.TypeOf(primitive.D{})
} }
// ValueCodec is the interface that groups the methods to encode and decode // ValueCodec is an interface for encoding and decoding a reflect.Value.
// values. // values.
//
// Deprecated: Use [ValueEncoder] and [ValueDecoder] instead.
type ValueCodec interface { type ValueCodec interface {
ValueEncoder ValueEncoder
ValueDecoder ValueDecoder
@ -233,6 +373,10 @@ func decodeTypeOrValueWithInfo(vd ValueDecoder, td typeDecoder, dc DecodeContext
// CodecZeroer is the interface implemented by Codecs that can also determine if // CodecZeroer is the interface implemented by Codecs that can also determine if
// a value of the type that would be encoded is zero. // a value of the type that would be encoded is zero.
//
// Deprecated: Defining custom rules for the zero/empty value will not be supported in Go Driver
// 2.0. Users who want to omit empty complex values should use a pointer field and set the value to
// nil instead.
type CodecZeroer interface { type CodecZeroer interface {
IsTypeZero(interface{}) bool IsTypeZero(interface{}) bool
} }

View file

@ -16,18 +16,45 @@
) )
// ByteSliceCodec is the Codec used for []byte values. // ByteSliceCodec is the Codec used for []byte values.
//
// Deprecated: ByteSliceCodec will not be directly configurable in Go Driver
// 2.0. To configure the byte slice encode and decode behavior, use the
// configuration methods on a [go.mongodb.org/mongo-driver/bson.Encoder] or
// [go.mongodb.org/mongo-driver/bson.Decoder]. To configure the byte slice
// encode and decode behavior for a mongo.Client, use
// [go.mongodb.org/mongo-driver/mongo/options.ClientOptions.SetBSONOptions].
//
// For example, to configure a mongo.Client to encode nil byte slices as empty
// BSON binary values, use:
//
// opt := options.Client().SetBSONOptions(&options.BSONOptions{
// NilByteSliceAsEmpty: true,
// })
//
// See the deprecation notice for each field in ByteSliceCodec for the
// corresponding settings.
type ByteSliceCodec struct { type ByteSliceCodec struct {
// EncodeNilAsEmpty causes EncodeValue to marshal nil Go byte slices as empty BSON binary values
// instead of BSON null.
//
// Deprecated: Use bson.Encoder.NilByteSliceAsEmpty or options.BSONOptions.NilByteSliceAsEmpty
// instead.
EncodeNilAsEmpty bool EncodeNilAsEmpty bool
} }
var ( var (
defaultByteSliceCodec = NewByteSliceCodec() defaultByteSliceCodec = NewByteSliceCodec()
_ ValueCodec = defaultByteSliceCodec // Assert that defaultByteSliceCodec satisfies the typeDecoder interface, which allows it to be
// used by collection type decoders (e.g. map, slice, etc) to set individual values in a
// collection.
_ typeDecoder = defaultByteSliceCodec _ typeDecoder = defaultByteSliceCodec
) )
// NewByteSliceCodec returns a StringCodec with options opts. // NewByteSliceCodec returns a ByteSliceCodec with options opts.
//
// Deprecated: NewByteSliceCodec will not be available in Go Driver 2.0. See
// [ByteSliceCodec] for more details.
func NewByteSliceCodec(opts ...*bsonoptions.ByteSliceCodecOptions) *ByteSliceCodec { func NewByteSliceCodec(opts ...*bsonoptions.ByteSliceCodecOptions) *ByteSliceCodec {
byteSliceOpt := bsonoptions.MergeByteSliceCodecOptions(opts...) byteSliceOpt := bsonoptions.MergeByteSliceCodecOptions(opts...)
codec := ByteSliceCodec{} codec := ByteSliceCodec{}
@ -42,13 +69,13 @@ func (bsc *ByteSliceCodec) EncodeValue(ec EncodeContext, vw bsonrw.ValueWriter,
if !val.IsValid() || val.Type() != tByteSlice { if !val.IsValid() || val.Type() != tByteSlice {
return ValueEncoderError{Name: "ByteSliceEncodeValue", Types: []reflect.Type{tByteSlice}, Received: val} return ValueEncoderError{Name: "ByteSliceEncodeValue", Types: []reflect.Type{tByteSlice}, Received: val}
} }
if val.IsNil() && !bsc.EncodeNilAsEmpty { if val.IsNil() && !bsc.EncodeNilAsEmpty && !ec.nilByteSliceAsEmpty {
return vw.WriteNull() return vw.WriteNull()
} }
return vw.WriteBinary(val.Interface().([]byte)) return vw.WriteBinary(val.Interface().([]byte))
} }
func (bsc *ByteSliceCodec) decodeType(dc DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) { func (bsc *ByteSliceCodec) decodeType(_ DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) {
if t != tByteSlice { if t != tByteSlice {
return emptyValue, ValueDecoderError{ return emptyValue, ValueDecoderError{
Name: "ByteSliceDecodeValue", Name: "ByteSliceDecodeValue",

View file

@ -0,0 +1,166 @@
// Copyright (C) MongoDB, Inc. 2017-present.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
package bsoncodec
import (
"reflect"
"sync"
"sync/atomic"
)
// Runtime check that the kind encoder and decoder caches can store any valid
// reflect.Kind constant.
func init() {
if s := reflect.Kind(len(kindEncoderCache{}.entries)).String(); s != "kind27" {
panic("The capacity of kindEncoderCache is too small.\n" +
"This is due to a new type being added to reflect.Kind.")
}
}
// statically assert array size
var _ = (kindEncoderCache{}).entries[reflect.UnsafePointer]
var _ = (kindDecoderCache{}).entries[reflect.UnsafePointer]
type typeEncoderCache struct {
cache sync.Map // map[reflect.Type]ValueEncoder
}
func (c *typeEncoderCache) Store(rt reflect.Type, enc ValueEncoder) {
c.cache.Store(rt, enc)
}
func (c *typeEncoderCache) Load(rt reflect.Type) (ValueEncoder, bool) {
if v, _ := c.cache.Load(rt); v != nil {
return v.(ValueEncoder), true
}
return nil, false
}
func (c *typeEncoderCache) LoadOrStore(rt reflect.Type, enc ValueEncoder) ValueEncoder {
if v, loaded := c.cache.LoadOrStore(rt, enc); loaded {
enc = v.(ValueEncoder)
}
return enc
}
func (c *typeEncoderCache) Clone() *typeEncoderCache {
cc := new(typeEncoderCache)
c.cache.Range(func(k, v interface{}) bool {
if k != nil && v != nil {
cc.cache.Store(k, v)
}
return true
})
return cc
}
type typeDecoderCache struct {
cache sync.Map // map[reflect.Type]ValueDecoder
}
func (c *typeDecoderCache) Store(rt reflect.Type, dec ValueDecoder) {
c.cache.Store(rt, dec)
}
func (c *typeDecoderCache) Load(rt reflect.Type) (ValueDecoder, bool) {
if v, _ := c.cache.Load(rt); v != nil {
return v.(ValueDecoder), true
}
return nil, false
}
func (c *typeDecoderCache) LoadOrStore(rt reflect.Type, dec ValueDecoder) ValueDecoder {
if v, loaded := c.cache.LoadOrStore(rt, dec); loaded {
dec = v.(ValueDecoder)
}
return dec
}
func (c *typeDecoderCache) Clone() *typeDecoderCache {
cc := new(typeDecoderCache)
c.cache.Range(func(k, v interface{}) bool {
if k != nil && v != nil {
cc.cache.Store(k, v)
}
return true
})
return cc
}
// atomic.Value requires that all calls to Store() have the same concrete type
// so we wrap the ValueEncoder with a kindEncoderCacheEntry to ensure the type
// is always the same (since different concrete types may implement the
// ValueEncoder interface).
type kindEncoderCacheEntry struct {
enc ValueEncoder
}
type kindEncoderCache struct {
entries [reflect.UnsafePointer + 1]atomic.Value // *kindEncoderCacheEntry
}
func (c *kindEncoderCache) Store(rt reflect.Kind, enc ValueEncoder) {
if enc != nil && rt < reflect.Kind(len(c.entries)) {
c.entries[rt].Store(&kindEncoderCacheEntry{enc: enc})
}
}
func (c *kindEncoderCache) Load(rt reflect.Kind) (ValueEncoder, bool) {
if rt < reflect.Kind(len(c.entries)) {
if ent, ok := c.entries[rt].Load().(*kindEncoderCacheEntry); ok {
return ent.enc, ent.enc != nil
}
}
return nil, false
}
func (c *kindEncoderCache) Clone() *kindEncoderCache {
cc := new(kindEncoderCache)
for i, v := range c.entries {
if val := v.Load(); val != nil {
cc.entries[i].Store(val)
}
}
return cc
}
// atomic.Value requires that all calls to Store() have the same concrete type
// so we wrap the ValueDecoder with a kindDecoderCacheEntry to ensure the type
// is always the same (since different concrete types may implement the
// ValueDecoder interface).
type kindDecoderCacheEntry struct {
dec ValueDecoder
}
type kindDecoderCache struct {
entries [reflect.UnsafePointer + 1]atomic.Value // *kindDecoderCacheEntry
}
func (c *kindDecoderCache) Store(rt reflect.Kind, dec ValueDecoder) {
if rt < reflect.Kind(len(c.entries)) {
c.entries[rt].Store(&kindDecoderCacheEntry{dec: dec})
}
}
func (c *kindDecoderCache) Load(rt reflect.Kind) (ValueDecoder, bool) {
if rt < reflect.Kind(len(c.entries)) {
if ent, ok := c.entries[rt].Load().(*kindDecoderCacheEntry); ok {
return ent.dec, ent.dec != nil
}
}
return nil, false
}
func (c *kindDecoderCache) Clone() *kindDecoderCache {
cc := new(kindDecoderCache)
for i, v := range c.entries {
if val := v.Load(); val != nil {
cc.entries[i].Store(val)
}
}
return cc
}

View file

@ -24,7 +24,7 @@
var ( var (
defaultValueDecoders DefaultValueDecoders defaultValueDecoders DefaultValueDecoders
errCannotTruncate = errors.New("float64 can only be truncated to an integer type when truncation is enabled") errCannotTruncate = errors.New("float64 can only be truncated to a lower precision type when truncation is enabled")
) )
type decodeBinaryError struct { type decodeBinaryError struct {
@ -41,13 +41,16 @@ func newDefaultStructCodec() *StructCodec {
if err != nil { if err != nil {
// This function is called from the codec registration path, so errors can't be propagated. If there's an error // This function is called from the codec registration path, so errors can't be propagated. If there's an error
// constructing the StructCodec, we panic to avoid losing it. // constructing the StructCodec, we panic to avoid losing it.
panic(fmt.Errorf("error creating default StructCodec: %v", err)) panic(fmt.Errorf("error creating default StructCodec: %w", err))
} }
return codec return codec
} }
// DefaultValueDecoders is a namespace type for the default ValueDecoders used // DefaultValueDecoders is a namespace type for the default ValueDecoders used
// when creating a registry. // when creating a registry.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with all default
// value decoders registered.
type DefaultValueDecoders struct{} type DefaultValueDecoders struct{}
// RegisterDefaultDecoders will register the decoder methods attached to DefaultValueDecoders with // RegisterDefaultDecoders will register the decoder methods attached to DefaultValueDecoders with
@ -56,6 +59,9 @@ type DefaultValueDecoders struct{
// There is no support for decoding map[string]interface{} because there is no decoder for // There is no support for decoding map[string]interface{} because there is no decoder for
// interface{}, so users must either register this decoder themselves or use the // interface{}, so users must either register this decoder themselves or use the
// EmptyInterfaceDecoder available in the bson package. // EmptyInterfaceDecoder available in the bson package.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with all default
// value decoders registered.
func (dvd DefaultValueDecoders) RegisterDefaultDecoders(rb *RegistryBuilder) { func (dvd DefaultValueDecoders) RegisterDefaultDecoders(rb *RegistryBuilder) {
if rb == nil { if rb == nil {
panic(errors.New("argument to RegisterDefaultDecoders must not be nil")) panic(errors.New("argument to RegisterDefaultDecoders must not be nil"))
@ -132,6 +138,9 @@ func (dvd DefaultValueDecoders) RegisterDefaultDecoders(rb *RegistryBuilder) {
} }
// DDecodeValue is the ValueDecoderFunc for primitive.D instances. // DDecodeValue is the ValueDecoderFunc for primitive.D instances.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with all default
// value decoders registered.
func (dvd DefaultValueDecoders) DDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { func (dvd DefaultValueDecoders) DDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
if !val.IsValid() || !val.CanSet() || val.Type() != tD { if !val.IsValid() || !val.CanSet() || val.Type() != tD {
return ValueDecoderError{Name: "DDecodeValue", Kinds: []reflect.Kind{reflect.Slice}, Received: val} return ValueDecoderError{Name: "DDecodeValue", Kinds: []reflect.Kind{reflect.Slice}, Received: val}
@ -169,7 +178,7 @@ func (dvd DefaultValueDecoders) DDecodeValue(dc DecodeContext, vr bsonrw.ValueRe
for { for {
key, elemVr, err := dr.ReadElement() key, elemVr, err := dr.ReadElement()
if err == bsonrw.ErrEOD { if errors.Is(err, bsonrw.ErrEOD) {
break break
} else if err != nil { } else if err != nil {
return err return err
@ -188,7 +197,7 @@ func (dvd DefaultValueDecoders) DDecodeValue(dc DecodeContext, vr bsonrw.ValueRe
return nil return nil
} }
func (dvd DefaultValueDecoders) booleanDecodeType(dctx DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) { func (dvd DefaultValueDecoders) booleanDecodeType(_ DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) {
if t.Kind() != reflect.Bool { if t.Kind() != reflect.Bool {
return emptyValue, ValueDecoderError{ return emptyValue, ValueDecoderError{
Name: "BooleanDecodeValue", Name: "BooleanDecodeValue",
@ -235,6 +244,9 @@ func (dvd DefaultValueDecoders) booleanDecodeType(dctx DecodeContext, vr bsonrw.
} }
// BooleanDecodeValue is the ValueDecoderFunc for bool types. // BooleanDecodeValue is the ValueDecoderFunc for bool types.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with all default
// value decoders registered.
func (dvd DefaultValueDecoders) BooleanDecodeValue(dctx DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { func (dvd DefaultValueDecoders) BooleanDecodeValue(dctx DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
if !val.IsValid() || !val.CanSet() || val.Kind() != reflect.Bool { if !val.IsValid() || !val.CanSet() || val.Kind() != reflect.Bool {
return ValueDecoderError{Name: "BooleanDecodeValue", Kinds: []reflect.Kind{reflect.Bool}, Received: val} return ValueDecoderError{Name: "BooleanDecodeValue", Kinds: []reflect.Kind{reflect.Bool}, Received: val}
@ -333,6 +345,9 @@ func (DefaultValueDecoders) intDecodeType(dc DecodeContext, vr bsonrw.ValueReade
} }
// IntDecodeValue is the ValueDecoderFunc for int types. // IntDecodeValue is the ValueDecoderFunc for int types.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with all default
// value decoders registered.
func (dvd DefaultValueDecoders) IntDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { func (dvd DefaultValueDecoders) IntDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
if !val.CanSet() { if !val.CanSet() {
return ValueDecoderError{ return ValueDecoderError{
@ -434,7 +449,7 @@ func (dvd DefaultValueDecoders) UintDecodeValue(dc DecodeContext, vr bsonrw.Valu
return nil return nil
} }
func (dvd DefaultValueDecoders) floatDecodeType(ec DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) { func (dvd DefaultValueDecoders) floatDecodeType(dc DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) {
var f float64 var f float64
var err error var err error
switch vrType := vr.Type(); vrType { switch vrType := vr.Type(); vrType {
@ -477,7 +492,7 @@ func (dvd DefaultValueDecoders) floatDecodeType(ec DecodeContext, vr bsonrw.Valu
switch t.Kind() { switch t.Kind() {
case reflect.Float32: case reflect.Float32:
if !ec.Truncate && float64(float32(f)) != f { if !dc.Truncate && float64(float32(f)) != f {
return emptyValue, errCannotTruncate return emptyValue, errCannotTruncate
} }
@ -494,6 +509,9 @@ func (dvd DefaultValueDecoders) floatDecodeType(ec DecodeContext, vr bsonrw.Valu
} }
// FloatDecodeValue is the ValueDecoderFunc for float types. // FloatDecodeValue is the ValueDecoderFunc for float types.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with all default
// value decoders registered.
func (dvd DefaultValueDecoders) FloatDecodeValue(ec DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { func (dvd DefaultValueDecoders) FloatDecodeValue(ec DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
if !val.CanSet() { if !val.CanSet() {
return ValueDecoderError{ return ValueDecoderError{
@ -515,7 +533,7 @@ func (dvd DefaultValueDecoders) FloatDecodeValue(ec DecodeContext, vr bsonrw.Val
// StringDecodeValue is the ValueDecoderFunc for string types. // StringDecodeValue is the ValueDecoderFunc for string types.
// //
// Deprecated: StringDecodeValue is not registered by default. Use StringCodec.DecodeValue instead. // Deprecated: StringDecodeValue is not registered by default. Use StringCodec.DecodeValue instead.
func (dvd DefaultValueDecoders) StringDecodeValue(dctx DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { func (dvd DefaultValueDecoders) StringDecodeValue(_ DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
var str string var str string
var err error var err error
switch vr.Type() { switch vr.Type() {
@ -536,7 +554,7 @@ func (dvd DefaultValueDecoders) StringDecodeValue(dctx DecodeContext, vr bsonrw.
return nil return nil
} }
func (DefaultValueDecoders) javaScriptDecodeType(dctx DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) { func (DefaultValueDecoders) javaScriptDecodeType(_ DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) {
if t != tJavaScript { if t != tJavaScript {
return emptyValue, ValueDecoderError{ return emptyValue, ValueDecoderError{
Name: "JavaScriptDecodeValue", Name: "JavaScriptDecodeValue",
@ -565,6 +583,9 @@ func (DefaultValueDecoders) javaScriptDecodeType(dctx DecodeContext, vr bsonrw.V
} }
// JavaScriptDecodeValue is the ValueDecoderFunc for the primitive.JavaScript type. // JavaScriptDecodeValue is the ValueDecoderFunc for the primitive.JavaScript type.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with all default
// value decoders registered.
func (dvd DefaultValueDecoders) JavaScriptDecodeValue(dctx DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { func (dvd DefaultValueDecoders) JavaScriptDecodeValue(dctx DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
if !val.CanSet() || val.Type() != tJavaScript { if !val.CanSet() || val.Type() != tJavaScript {
return ValueDecoderError{Name: "JavaScriptDecodeValue", Types: []reflect.Type{tJavaScript}, Received: val} return ValueDecoderError{Name: "JavaScriptDecodeValue", Types: []reflect.Type{tJavaScript}, Received: val}
@ -579,7 +600,7 @@ func (dvd DefaultValueDecoders) JavaScriptDecodeValue(dctx DecodeContext, vr bso
return nil return nil
} }
func (DefaultValueDecoders) symbolDecodeType(dctx DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) { func (DefaultValueDecoders) symbolDecodeType(_ DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) {
if t != tSymbol { if t != tSymbol {
return emptyValue, ValueDecoderError{ return emptyValue, ValueDecoderError{
Name: "SymbolDecodeValue", Name: "SymbolDecodeValue",
@ -620,6 +641,9 @@ func (DefaultValueDecoders) symbolDecodeType(dctx DecodeContext, vr bsonrw.Value
} }
// SymbolDecodeValue is the ValueDecoderFunc for the primitive.Symbol type. // SymbolDecodeValue is the ValueDecoderFunc for the primitive.Symbol type.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with all default
// value decoders registered.
func (dvd DefaultValueDecoders) SymbolDecodeValue(dctx DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { func (dvd DefaultValueDecoders) SymbolDecodeValue(dctx DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
if !val.CanSet() || val.Type() != tSymbol { if !val.CanSet() || val.Type() != tSymbol {
return ValueDecoderError{Name: "SymbolDecodeValue", Types: []reflect.Type{tSymbol}, Received: val} return ValueDecoderError{Name: "SymbolDecodeValue", Types: []reflect.Type{tSymbol}, Received: val}
@ -634,7 +658,7 @@ func (dvd DefaultValueDecoders) SymbolDecodeValue(dctx DecodeContext, vr bsonrw.
return nil return nil
} }
func (DefaultValueDecoders) binaryDecodeType(dc DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) { func (DefaultValueDecoders) binaryDecodeType(_ DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) {
if t != tBinary { if t != tBinary {
return emptyValue, ValueDecoderError{ return emptyValue, ValueDecoderError{
Name: "BinaryDecodeValue", Name: "BinaryDecodeValue",
@ -664,6 +688,9 @@ func (DefaultValueDecoders) binaryDecodeType(dc DecodeContext, vr bsonrw.ValueRe
} }
// BinaryDecodeValue is the ValueDecoderFunc for Binary. // BinaryDecodeValue is the ValueDecoderFunc for Binary.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with all default
// value decoders registered.
func (dvd DefaultValueDecoders) BinaryDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { func (dvd DefaultValueDecoders) BinaryDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
if !val.CanSet() || val.Type() != tBinary { if !val.CanSet() || val.Type() != tBinary {
return ValueDecoderError{Name: "BinaryDecodeValue", Types: []reflect.Type{tBinary}, Received: val} return ValueDecoderError{Name: "BinaryDecodeValue", Types: []reflect.Type{tBinary}, Received: val}
@ -678,7 +705,7 @@ func (dvd DefaultValueDecoders) BinaryDecodeValue(dc DecodeContext, vr bsonrw.Va
return nil return nil
} }
func (DefaultValueDecoders) undefinedDecodeType(dc DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) { func (DefaultValueDecoders) undefinedDecodeType(_ DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) {
if t != tUndefined { if t != tUndefined {
return emptyValue, ValueDecoderError{ return emptyValue, ValueDecoderError{
Name: "UndefinedDecodeValue", Name: "UndefinedDecodeValue",
@ -704,6 +731,9 @@ func (DefaultValueDecoders) undefinedDecodeType(dc DecodeContext, vr bsonrw.Valu
} }
// UndefinedDecodeValue is the ValueDecoderFunc for Undefined. // UndefinedDecodeValue is the ValueDecoderFunc for Undefined.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with all default
// value decoders registered.
func (dvd DefaultValueDecoders) UndefinedDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { func (dvd DefaultValueDecoders) UndefinedDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
if !val.CanSet() || val.Type() != tUndefined { if !val.CanSet() || val.Type() != tUndefined {
return ValueDecoderError{Name: "UndefinedDecodeValue", Types: []reflect.Type{tUndefined}, Received: val} return ValueDecoderError{Name: "UndefinedDecodeValue", Types: []reflect.Type{tUndefined}, Received: val}
@ -719,7 +749,7 @@ func (dvd DefaultValueDecoders) UndefinedDecodeValue(dc DecodeContext, vr bsonrw
} }
// Accept both 12-byte string and pretty-printed 24-byte hex string formats. // Accept both 12-byte string and pretty-printed 24-byte hex string formats.
func (dvd DefaultValueDecoders) objectIDDecodeType(dc DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) { func (dvd DefaultValueDecoders) objectIDDecodeType(_ DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) {
if t != tOID { if t != tOID {
return emptyValue, ValueDecoderError{ return emptyValue, ValueDecoderError{
Name: "ObjectIDDecodeValue", Name: "ObjectIDDecodeValue",
@ -765,6 +795,9 @@ func (dvd DefaultValueDecoders) objectIDDecodeType(dc DecodeContext, vr bsonrw.V
} }
// ObjectIDDecodeValue is the ValueDecoderFunc for primitive.ObjectID. // ObjectIDDecodeValue is the ValueDecoderFunc for primitive.ObjectID.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with all default
// value decoders registered.
func (dvd DefaultValueDecoders) ObjectIDDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { func (dvd DefaultValueDecoders) ObjectIDDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
if !val.CanSet() || val.Type() != tOID { if !val.CanSet() || val.Type() != tOID {
return ValueDecoderError{Name: "ObjectIDDecodeValue", Types: []reflect.Type{tOID}, Received: val} return ValueDecoderError{Name: "ObjectIDDecodeValue", Types: []reflect.Type{tOID}, Received: val}
@ -779,7 +812,7 @@ func (dvd DefaultValueDecoders) ObjectIDDecodeValue(dc DecodeContext, vr bsonrw.
return nil return nil
} }
func (DefaultValueDecoders) dateTimeDecodeType(dc DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) { func (DefaultValueDecoders) dateTimeDecodeType(_ DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) {
if t != tDateTime { if t != tDateTime {
return emptyValue, ValueDecoderError{ return emptyValue, ValueDecoderError{
Name: "DateTimeDecodeValue", Name: "DateTimeDecodeValue",
@ -808,6 +841,9 @@ func (DefaultValueDecoders) dateTimeDecodeType(dc DecodeContext, vr bsonrw.Value
} }
// DateTimeDecodeValue is the ValueDecoderFunc for DateTime. // DateTimeDecodeValue is the ValueDecoderFunc for DateTime.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with all default
// value decoders registered.
func (dvd DefaultValueDecoders) DateTimeDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { func (dvd DefaultValueDecoders) DateTimeDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
if !val.CanSet() || val.Type() != tDateTime { if !val.CanSet() || val.Type() != tDateTime {
return ValueDecoderError{Name: "DateTimeDecodeValue", Types: []reflect.Type{tDateTime}, Received: val} return ValueDecoderError{Name: "DateTimeDecodeValue", Types: []reflect.Type{tDateTime}, Received: val}
@ -822,7 +858,7 @@ func (dvd DefaultValueDecoders) DateTimeDecodeValue(dc DecodeContext, vr bsonrw.
return nil return nil
} }
func (DefaultValueDecoders) nullDecodeType(dc DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) { func (DefaultValueDecoders) nullDecodeType(_ DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) {
if t != tNull { if t != tNull {
return emptyValue, ValueDecoderError{ return emptyValue, ValueDecoderError{
Name: "NullDecodeValue", Name: "NullDecodeValue",
@ -848,6 +884,9 @@ func (DefaultValueDecoders) nullDecodeType(dc DecodeContext, vr bsonrw.ValueRead
} }
// NullDecodeValue is the ValueDecoderFunc for Null. // NullDecodeValue is the ValueDecoderFunc for Null.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with all default
// value decoders registered.
func (dvd DefaultValueDecoders) NullDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { func (dvd DefaultValueDecoders) NullDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
if !val.CanSet() || val.Type() != tNull { if !val.CanSet() || val.Type() != tNull {
return ValueDecoderError{Name: "NullDecodeValue", Types: []reflect.Type{tNull}, Received: val} return ValueDecoderError{Name: "NullDecodeValue", Types: []reflect.Type{tNull}, Received: val}
@ -862,7 +901,7 @@ func (dvd DefaultValueDecoders) NullDecodeValue(dc DecodeContext, vr bsonrw.Valu
return nil return nil
} }
func (DefaultValueDecoders) regexDecodeType(dc DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) { func (DefaultValueDecoders) regexDecodeType(_ DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) {
if t != tRegex { if t != tRegex {
return emptyValue, ValueDecoderError{ return emptyValue, ValueDecoderError{
Name: "RegexDecodeValue", Name: "RegexDecodeValue",
@ -891,6 +930,9 @@ func (DefaultValueDecoders) regexDecodeType(dc DecodeContext, vr bsonrw.ValueRea
} }
// RegexDecodeValue is the ValueDecoderFunc for Regex. // RegexDecodeValue is the ValueDecoderFunc for Regex.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with all default
// value decoders registered.
func (dvd DefaultValueDecoders) RegexDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { func (dvd DefaultValueDecoders) RegexDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
if !val.CanSet() || val.Type() != tRegex { if !val.CanSet() || val.Type() != tRegex {
return ValueDecoderError{Name: "RegexDecodeValue", Types: []reflect.Type{tRegex}, Received: val} return ValueDecoderError{Name: "RegexDecodeValue", Types: []reflect.Type{tRegex}, Received: val}
@ -905,7 +947,7 @@ func (dvd DefaultValueDecoders) RegexDecodeValue(dc DecodeContext, vr bsonrw.Val
return nil return nil
} }
func (DefaultValueDecoders) dBPointerDecodeType(dc DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) { func (DefaultValueDecoders) dBPointerDecodeType(_ DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) {
if t != tDBPointer { if t != tDBPointer {
return emptyValue, ValueDecoderError{ return emptyValue, ValueDecoderError{
Name: "DBPointerDecodeValue", Name: "DBPointerDecodeValue",
@ -935,6 +977,9 @@ func (DefaultValueDecoders) dBPointerDecodeType(dc DecodeContext, vr bsonrw.Valu
} }
// DBPointerDecodeValue is the ValueDecoderFunc for DBPointer. // DBPointerDecodeValue is the ValueDecoderFunc for DBPointer.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with all default
// value decoders registered.
func (dvd DefaultValueDecoders) DBPointerDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { func (dvd DefaultValueDecoders) DBPointerDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
if !val.CanSet() || val.Type() != tDBPointer { if !val.CanSet() || val.Type() != tDBPointer {
return ValueDecoderError{Name: "DBPointerDecodeValue", Types: []reflect.Type{tDBPointer}, Received: val} return ValueDecoderError{Name: "DBPointerDecodeValue", Types: []reflect.Type{tDBPointer}, Received: val}
@ -949,7 +994,7 @@ func (dvd DefaultValueDecoders) DBPointerDecodeValue(dc DecodeContext, vr bsonrw
return nil return nil
} }
func (DefaultValueDecoders) timestampDecodeType(dc DecodeContext, vr bsonrw.ValueReader, reflectType reflect.Type) (reflect.Value, error) { func (DefaultValueDecoders) timestampDecodeType(_ DecodeContext, vr bsonrw.ValueReader, reflectType reflect.Type) (reflect.Value, error) {
if reflectType != tTimestamp { if reflectType != tTimestamp {
return emptyValue, ValueDecoderError{ return emptyValue, ValueDecoderError{
Name: "TimestampDecodeValue", Name: "TimestampDecodeValue",
@ -978,6 +1023,9 @@ func (DefaultValueDecoders) timestampDecodeType(dc DecodeContext, vr bsonrw.Valu
} }
// TimestampDecodeValue is the ValueDecoderFunc for Timestamp. // TimestampDecodeValue is the ValueDecoderFunc for Timestamp.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with all default
// value decoders registered.
func (dvd DefaultValueDecoders) TimestampDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { func (dvd DefaultValueDecoders) TimestampDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
if !val.CanSet() || val.Type() != tTimestamp { if !val.CanSet() || val.Type() != tTimestamp {
return ValueDecoderError{Name: "TimestampDecodeValue", Types: []reflect.Type{tTimestamp}, Received: val} return ValueDecoderError{Name: "TimestampDecodeValue", Types: []reflect.Type{tTimestamp}, Received: val}
@ -992,7 +1040,7 @@ func (dvd DefaultValueDecoders) TimestampDecodeValue(dc DecodeContext, vr bsonrw
return nil return nil
} }
func (DefaultValueDecoders) minKeyDecodeType(dc DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) { func (DefaultValueDecoders) minKeyDecodeType(_ DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) {
if t != tMinKey { if t != tMinKey {
return emptyValue, ValueDecoderError{ return emptyValue, ValueDecoderError{
Name: "MinKeyDecodeValue", Name: "MinKeyDecodeValue",
@ -1020,6 +1068,9 @@ func (DefaultValueDecoders) minKeyDecodeType(dc DecodeContext, vr bsonrw.ValueRe
} }
// MinKeyDecodeValue is the ValueDecoderFunc for MinKey. // MinKeyDecodeValue is the ValueDecoderFunc for MinKey.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with all default
// value decoders registered.
func (dvd DefaultValueDecoders) MinKeyDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { func (dvd DefaultValueDecoders) MinKeyDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
if !val.CanSet() || val.Type() != tMinKey { if !val.CanSet() || val.Type() != tMinKey {
return ValueDecoderError{Name: "MinKeyDecodeValue", Types: []reflect.Type{tMinKey}, Received: val} return ValueDecoderError{Name: "MinKeyDecodeValue", Types: []reflect.Type{tMinKey}, Received: val}
@ -1034,7 +1085,7 @@ func (dvd DefaultValueDecoders) MinKeyDecodeValue(dc DecodeContext, vr bsonrw.Va
return nil return nil
} }
func (DefaultValueDecoders) maxKeyDecodeType(dc DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) { func (DefaultValueDecoders) maxKeyDecodeType(_ DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) {
if t != tMaxKey { if t != tMaxKey {
return emptyValue, ValueDecoderError{ return emptyValue, ValueDecoderError{
Name: "MaxKeyDecodeValue", Name: "MaxKeyDecodeValue",
@ -1062,6 +1113,9 @@ func (DefaultValueDecoders) maxKeyDecodeType(dc DecodeContext, vr bsonrw.ValueRe
} }
// MaxKeyDecodeValue is the ValueDecoderFunc for MaxKey. // MaxKeyDecodeValue is the ValueDecoderFunc for MaxKey.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with all default
// value decoders registered.
func (dvd DefaultValueDecoders) MaxKeyDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { func (dvd DefaultValueDecoders) MaxKeyDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
if !val.CanSet() || val.Type() != tMaxKey { if !val.CanSet() || val.Type() != tMaxKey {
return ValueDecoderError{Name: "MaxKeyDecodeValue", Types: []reflect.Type{tMaxKey}, Received: val} return ValueDecoderError{Name: "MaxKeyDecodeValue", Types: []reflect.Type{tMaxKey}, Received: val}
@ -1076,7 +1130,7 @@ func (dvd DefaultValueDecoders) MaxKeyDecodeValue(dc DecodeContext, vr bsonrw.Va
return nil return nil
} }
func (dvd DefaultValueDecoders) decimal128DecodeType(dctx DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) { func (dvd DefaultValueDecoders) decimal128DecodeType(_ DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) {
if t != tDecimal { if t != tDecimal {
return emptyValue, ValueDecoderError{ return emptyValue, ValueDecoderError{
Name: "Decimal128DecodeValue", Name: "Decimal128DecodeValue",
@ -1105,6 +1159,9 @@ func (dvd DefaultValueDecoders) decimal128DecodeType(dctx DecodeContext, vr bson
} }
// Decimal128DecodeValue is the ValueDecoderFunc for primitive.Decimal128. // Decimal128DecodeValue is the ValueDecoderFunc for primitive.Decimal128.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with all default
// value decoders registered.
func (dvd DefaultValueDecoders) Decimal128DecodeValue(dctx DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { func (dvd DefaultValueDecoders) Decimal128DecodeValue(dctx DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
if !val.CanSet() || val.Type() != tDecimal { if !val.CanSet() || val.Type() != tDecimal {
return ValueDecoderError{Name: "Decimal128DecodeValue", Types: []reflect.Type{tDecimal}, Received: val} return ValueDecoderError{Name: "Decimal128DecodeValue", Types: []reflect.Type{tDecimal}, Received: val}
@ -1119,7 +1176,7 @@ func (dvd DefaultValueDecoders) Decimal128DecodeValue(dctx DecodeContext, vr bso
return nil return nil
} }
func (dvd DefaultValueDecoders) jsonNumberDecodeType(dc DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) { func (dvd DefaultValueDecoders) jsonNumberDecodeType(_ DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) {
if t != tJSONNumber { if t != tJSONNumber {
return emptyValue, ValueDecoderError{ return emptyValue, ValueDecoderError{
Name: "JSONNumberDecodeValue", Name: "JSONNumberDecodeValue",
@ -1164,6 +1221,9 @@ func (dvd DefaultValueDecoders) jsonNumberDecodeType(dc DecodeContext, vr bsonrw
} }
// JSONNumberDecodeValue is the ValueDecoderFunc for json.Number. // JSONNumberDecodeValue is the ValueDecoderFunc for json.Number.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with all default
// value decoders registered.
func (dvd DefaultValueDecoders) JSONNumberDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { func (dvd DefaultValueDecoders) JSONNumberDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
if !val.CanSet() || val.Type() != tJSONNumber { if !val.CanSet() || val.Type() != tJSONNumber {
return ValueDecoderError{Name: "JSONNumberDecodeValue", Types: []reflect.Type{tJSONNumber}, Received: val} return ValueDecoderError{Name: "JSONNumberDecodeValue", Types: []reflect.Type{tJSONNumber}, Received: val}
@ -1178,7 +1238,7 @@ func (dvd DefaultValueDecoders) JSONNumberDecodeValue(dc DecodeContext, vr bsonr
return nil return nil
} }
func (dvd DefaultValueDecoders) urlDecodeType(dc DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) { func (dvd DefaultValueDecoders) urlDecodeType(_ DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) {
if t != tURL { if t != tURL {
return emptyValue, ValueDecoderError{ return emptyValue, ValueDecoderError{
Name: "URLDecodeValue", Name: "URLDecodeValue",
@ -1213,6 +1273,9 @@ func (dvd DefaultValueDecoders) urlDecodeType(dc DecodeContext, vr bsonrw.ValueR
} }
// URLDecodeValue is the ValueDecoderFunc for url.URL. // URLDecodeValue is the ValueDecoderFunc for url.URL.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with all default
// value decoders registered.
func (dvd DefaultValueDecoders) URLDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { func (dvd DefaultValueDecoders) URLDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
if !val.CanSet() || val.Type() != tURL { if !val.CanSet() || val.Type() != tURL {
return ValueDecoderError{Name: "URLDecodeValue", Types: []reflect.Type{tURL}, Received: val} return ValueDecoderError{Name: "URLDecodeValue", Types: []reflect.Type{tURL}, Received: val}
@ -1230,7 +1293,7 @@ func (dvd DefaultValueDecoders) URLDecodeValue(dc DecodeContext, vr bsonrw.Value
// TimeDecodeValue is the ValueDecoderFunc for time.Time. // TimeDecodeValue is the ValueDecoderFunc for time.Time.
// //
// Deprecated: TimeDecodeValue is not registered by default. Use TimeCodec.DecodeValue instead. // Deprecated: TimeDecodeValue is not registered by default. Use TimeCodec.DecodeValue instead.
func (dvd DefaultValueDecoders) TimeDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { func (dvd DefaultValueDecoders) TimeDecodeValue(_ DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
if vr.Type() != bsontype.DateTime { if vr.Type() != bsontype.DateTime {
return fmt.Errorf("cannot decode %v into a time.Time", vr.Type()) return fmt.Errorf("cannot decode %v into a time.Time", vr.Type())
} }
@ -1251,7 +1314,7 @@ func (dvd DefaultValueDecoders) TimeDecodeValue(dc DecodeContext, vr bsonrw.Valu
// ByteSliceDecodeValue is the ValueDecoderFunc for []byte. // ByteSliceDecodeValue is the ValueDecoderFunc for []byte.
// //
// Deprecated: ByteSliceDecodeValue is not registered by default. Use ByteSliceCodec.DecodeValue instead. // Deprecated: ByteSliceDecodeValue is not registered by default. Use ByteSliceCodec.DecodeValue instead.
func (dvd DefaultValueDecoders) ByteSliceDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { func (dvd DefaultValueDecoders) ByteSliceDecodeValue(_ DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
if vr.Type() != bsontype.Binary && vr.Type() != bsontype.Null { if vr.Type() != bsontype.Binary && vr.Type() != bsontype.Null {
return fmt.Errorf("cannot decode %v into a []byte", vr.Type()) return fmt.Errorf("cannot decode %v into a []byte", vr.Type())
} }
@ -1316,7 +1379,7 @@ func (dvd DefaultValueDecoders) MapDecodeValue(dc DecodeContext, vr bsonrw.Value
keyType := val.Type().Key() keyType := val.Type().Key()
for { for {
key, vr, err := dr.ReadElement() key, vr, err := dr.ReadElement()
if err == bsonrw.ErrEOD { if errors.Is(err, bsonrw.ErrEOD) {
break break
} }
if err != nil { if err != nil {
@ -1336,6 +1399,9 @@ func (dvd DefaultValueDecoders) MapDecodeValue(dc DecodeContext, vr bsonrw.Value
} }
// ArrayDecodeValue is the ValueDecoderFunc for array types. // ArrayDecodeValue is the ValueDecoderFunc for array types.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with all default
// value decoders registered.
func (dvd DefaultValueDecoders) ArrayDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { func (dvd DefaultValueDecoders) ArrayDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
if !val.IsValid() || val.Kind() != reflect.Array { if !val.IsValid() || val.Kind() != reflect.Array {
return ValueDecoderError{Name: "ArrayDecodeValue", Kinds: []reflect.Kind{reflect.Array}, Received: val} return ValueDecoderError{Name: "ArrayDecodeValue", Kinds: []reflect.Kind{reflect.Array}, Received: val}
@ -1447,7 +1513,10 @@ func (dvd DefaultValueDecoders) SliceDecodeValue(dc DecodeContext, vr bsonrw.Val
} }
// ValueUnmarshalerDecodeValue is the ValueDecoderFunc for ValueUnmarshaler implementations. // ValueUnmarshalerDecodeValue is the ValueDecoderFunc for ValueUnmarshaler implementations.
func (dvd DefaultValueDecoders) ValueUnmarshalerDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { //
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with all default
// value decoders registered.
func (dvd DefaultValueDecoders) ValueUnmarshalerDecodeValue(_ DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
if !val.IsValid() || (!val.Type().Implements(tValueUnmarshaler) && !reflect.PtrTo(val.Type()).Implements(tValueUnmarshaler)) { if !val.IsValid() || (!val.Type().Implements(tValueUnmarshaler) && !reflect.PtrTo(val.Type()).Implements(tValueUnmarshaler)) {
return ValueDecoderError{Name: "ValueUnmarshalerDecodeValue", Types: []reflect.Type{tValueUnmarshaler}, Received: val} return ValueDecoderError{Name: "ValueUnmarshalerDecodeValue", Types: []reflect.Type{tValueUnmarshaler}, Received: val}
} }
@ -1471,16 +1540,19 @@ func (dvd DefaultValueDecoders) ValueUnmarshalerDecodeValue(dc DecodeContext, vr
return err return err
} }
fn := val.Convert(tValueUnmarshaler).MethodByName("UnmarshalBSONValue") m, ok := val.Interface().(ValueUnmarshaler)
errVal := fn.Call([]reflect.Value{reflect.ValueOf(t), reflect.ValueOf(src)})[0] if !ok {
if !errVal.IsNil() { // NB: this error should be unreachable due to the above checks
return errVal.Interface().(error) return ValueDecoderError{Name: "ValueUnmarshalerDecodeValue", Types: []reflect.Type{tValueUnmarshaler}, Received: val}
} }
return nil return m.UnmarshalBSONValue(t, src)
} }
// UnmarshalerDecodeValue is the ValueDecoderFunc for Unmarshaler implementations. // UnmarshalerDecodeValue is the ValueDecoderFunc for Unmarshaler implementations.
func (dvd DefaultValueDecoders) UnmarshalerDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { //
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with all default
// value decoders registered.
func (dvd DefaultValueDecoders) UnmarshalerDecodeValue(_ DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
if !val.IsValid() || (!val.Type().Implements(tUnmarshaler) && !reflect.PtrTo(val.Type()).Implements(tUnmarshaler)) { if !val.IsValid() || (!val.Type().Implements(tUnmarshaler) && !reflect.PtrTo(val.Type()).Implements(tUnmarshaler)) {
return ValueDecoderError{Name: "UnmarshalerDecodeValue", Types: []reflect.Type{tUnmarshaler}, Received: val} return ValueDecoderError{Name: "UnmarshalerDecodeValue", Types: []reflect.Type{tUnmarshaler}, Received: val}
} }
@ -1516,12 +1588,12 @@ func (dvd DefaultValueDecoders) UnmarshalerDecodeValue(dc DecodeContext, vr bson
val = val.Addr() // If the type doesn't implement the interface, a pointer to it must. val = val.Addr() // If the type doesn't implement the interface, a pointer to it must.
} }
fn := val.Convert(tUnmarshaler).MethodByName("UnmarshalBSON") m, ok := val.Interface().(Unmarshaler)
errVal := fn.Call([]reflect.Value{reflect.ValueOf(src)})[0] if !ok {
if !errVal.IsNil() { // NB: this error should be unreachable due to the above checks
return errVal.Interface().(error) return ValueDecoderError{Name: "UnmarshalerDecodeValue", Types: []reflect.Type{tUnmarshaler}, Received: val}
} }
return nil return m.UnmarshalBSON(src)
} }
// EmptyInterfaceDecodeValue is the ValueDecoderFunc for interface{}. // EmptyInterfaceDecodeValue is the ValueDecoderFunc for interface{}.
@ -1565,7 +1637,10 @@ func (dvd DefaultValueDecoders) EmptyInterfaceDecodeValue(dc DecodeContext, vr b
} }
// CoreDocumentDecodeValue is the ValueDecoderFunc for bsoncore.Document. // CoreDocumentDecodeValue is the ValueDecoderFunc for bsoncore.Document.
func (DefaultValueDecoders) CoreDocumentDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { //
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with all default
// value decoders registered.
func (DefaultValueDecoders) CoreDocumentDecodeValue(_ DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
if !val.CanSet() || val.Type() != tCoreDocument { if !val.CanSet() || val.Type() != tCoreDocument {
return ValueDecoderError{Name: "CoreDocumentDecodeValue", Types: []reflect.Type{tCoreDocument}, Received: val} return ValueDecoderError{Name: "CoreDocumentDecodeValue", Types: []reflect.Type{tCoreDocument}, Received: val}
} }
@ -1600,7 +1675,7 @@ func (dvd DefaultValueDecoders) decodeDefault(dc DecodeContext, vr bsonrw.ValueR
idx := 0 idx := 0
for { for {
vr, err := ar.ReadValue() vr, err := ar.ReadValue()
if err == bsonrw.ErrEOA { if errors.Is(err, bsonrw.ErrEOA) {
break break
} }
if err != nil { if err != nil {
@ -1671,6 +1746,9 @@ func (dvd DefaultValueDecoders) codeWithScopeDecodeType(dc DecodeContext, vr bso
} }
// CodeWithScopeDecodeValue is the ValueDecoderFunc for CodeWithScope. // CodeWithScopeDecodeValue is the ValueDecoderFunc for CodeWithScope.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with all default
// value decoders registered.
func (dvd DefaultValueDecoders) CodeWithScopeDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { func (dvd DefaultValueDecoders) CodeWithScopeDecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
if !val.CanSet() || val.Type() != tCodeWithScope { if !val.CanSet() || val.Type() != tCodeWithScope {
return ValueDecoderError{Name: "CodeWithScopeDecodeValue", Types: []reflect.Type{tCodeWithScope}, Received: val} return ValueDecoderError{Name: "CodeWithScopeDecodeValue", Types: []reflect.Type{tCodeWithScope}, Received: val}
@ -1709,7 +1787,7 @@ func (DefaultValueDecoders) decodeElemsFromDocumentReader(dc DecodeContext, dr b
elems := make([]reflect.Value, 0) elems := make([]reflect.Value, 0)
for { for {
key, vr, err := dr.ReadElement() key, vr, err := dr.ReadElement()
if err == bsonrw.ErrEOD { if errors.Is(err, bsonrw.ErrEOD) {
break break
} }
if err != nil { if err != nil {

View file

@ -58,10 +58,16 @@ func encodeElement(ec EncodeContext, dw bsonrw.DocumentWriter, e primitive.E) er
// DefaultValueEncoders is a namespace type for the default ValueEncoders used // DefaultValueEncoders is a namespace type for the default ValueEncoders used
// when creating a registry. // when creating a registry.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with all default
// value encoders registered.
type DefaultValueEncoders struct{} type DefaultValueEncoders struct{}
// RegisterDefaultEncoders will register the encoder methods attached to DefaultValueEncoders with // RegisterDefaultEncoders will register the encoder methods attached to DefaultValueEncoders with
// the provided RegistryBuilder. // the provided RegistryBuilder.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with all default
// value encoders registered.
func (dve DefaultValueEncoders) RegisterDefaultEncoders(rb *RegistryBuilder) { func (dve DefaultValueEncoders) RegisterDefaultEncoders(rb *RegistryBuilder) {
if rb == nil { if rb == nil {
panic(errors.New("argument to RegisterDefaultEncoders must not be nil")) panic(errors.New("argument to RegisterDefaultEncoders must not be nil"))
@ -113,7 +119,10 @@ func (dve DefaultValueEncoders) RegisterDefaultEncoders(rb *RegistryBuilder) {
} }
// BooleanEncodeValue is the ValueEncoderFunc for bool types. // BooleanEncodeValue is the ValueEncoderFunc for bool types.
func (dve DefaultValueEncoders) BooleanEncodeValue(ectx EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { //
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with all default
// value encoders registered.
func (dve DefaultValueEncoders) BooleanEncodeValue(_ EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {
if !val.IsValid() || val.Kind() != reflect.Bool { if !val.IsValid() || val.Kind() != reflect.Bool {
return ValueEncoderError{Name: "BooleanEncodeValue", Kinds: []reflect.Kind{reflect.Bool}, Received: val} return ValueEncoderError{Name: "BooleanEncodeValue", Kinds: []reflect.Kind{reflect.Bool}, Received: val}
} }
@ -125,6 +134,9 @@ func fitsIn32Bits(i int64) bool {
} }
// IntEncodeValue is the ValueEncoderFunc for int types. // IntEncodeValue is the ValueEncoderFunc for int types.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with all default
// value encoders registered.
func (dve DefaultValueEncoders) IntEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { func (dve DefaultValueEncoders) IntEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {
switch val.Kind() { switch val.Kind() {
case reflect.Int8, reflect.Int16, reflect.Int32: case reflect.Int8, reflect.Int16, reflect.Int32:
@ -176,7 +188,10 @@ func (dve DefaultValueEncoders) UintEncodeValue(ec EncodeContext, vw bsonrw.Valu
} }
// FloatEncodeValue is the ValueEncoderFunc for float types. // FloatEncodeValue is the ValueEncoderFunc for float types.
func (dve DefaultValueEncoders) FloatEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { //
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with all default
// value encoders registered.
func (dve DefaultValueEncoders) FloatEncodeValue(_ EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {
switch val.Kind() { switch val.Kind() {
case reflect.Float32, reflect.Float64: case reflect.Float32, reflect.Float64:
return vw.WriteDouble(val.Float()) return vw.WriteDouble(val.Float())
@ -188,7 +203,7 @@ func (dve DefaultValueEncoders) FloatEncodeValue(ec EncodeContext, vw bsonrw.Val
// StringEncodeValue is the ValueEncoderFunc for string types. // StringEncodeValue is the ValueEncoderFunc for string types.
// //
// Deprecated: StringEncodeValue is not registered by default. Use StringCodec.EncodeValue instead. // Deprecated: StringEncodeValue is not registered by default. Use StringCodec.EncodeValue instead.
func (dve DefaultValueEncoders) StringEncodeValue(ectx EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { func (dve DefaultValueEncoders) StringEncodeValue(_ EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {
if val.Kind() != reflect.String { if val.Kind() != reflect.String {
return ValueEncoderError{ return ValueEncoderError{
Name: "StringEncodeValue", Name: "StringEncodeValue",
@ -201,7 +216,10 @@ func (dve DefaultValueEncoders) StringEncodeValue(ectx EncodeContext, vw bsonrw.
} }
// ObjectIDEncodeValue is the ValueEncoderFunc for primitive.ObjectID. // ObjectIDEncodeValue is the ValueEncoderFunc for primitive.ObjectID.
func (dve DefaultValueEncoders) ObjectIDEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { //
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with all default
// value encoders registered.
func (dve DefaultValueEncoders) ObjectIDEncodeValue(_ EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {
if !val.IsValid() || val.Type() != tOID { if !val.IsValid() || val.Type() != tOID {
return ValueEncoderError{Name: "ObjectIDEncodeValue", Types: []reflect.Type{tOID}, Received: val} return ValueEncoderError{Name: "ObjectIDEncodeValue", Types: []reflect.Type{tOID}, Received: val}
} }
@ -209,7 +227,10 @@ func (dve DefaultValueEncoders) ObjectIDEncodeValue(ec EncodeContext, vw bsonrw.
} }
// Decimal128EncodeValue is the ValueEncoderFunc for primitive.Decimal128. // Decimal128EncodeValue is the ValueEncoderFunc for primitive.Decimal128.
func (dve DefaultValueEncoders) Decimal128EncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { //
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with all default
// value encoders registered.
func (dve DefaultValueEncoders) Decimal128EncodeValue(_ EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {
if !val.IsValid() || val.Type() != tDecimal { if !val.IsValid() || val.Type() != tDecimal {
return ValueEncoderError{Name: "Decimal128EncodeValue", Types: []reflect.Type{tDecimal}, Received: val} return ValueEncoderError{Name: "Decimal128EncodeValue", Types: []reflect.Type{tDecimal}, Received: val}
} }
@ -217,6 +238,9 @@ func (dve DefaultValueEncoders) Decimal128EncodeValue(ec EncodeContext, vw bsonr
} }
// JSONNumberEncodeValue is the ValueEncoderFunc for json.Number. // JSONNumberEncodeValue is the ValueEncoderFunc for json.Number.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with all default
// value encoders registered.
func (dve DefaultValueEncoders) JSONNumberEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { func (dve DefaultValueEncoders) JSONNumberEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {
if !val.IsValid() || val.Type() != tJSONNumber { if !val.IsValid() || val.Type() != tJSONNumber {
return ValueEncoderError{Name: "JSONNumberEncodeValue", Types: []reflect.Type{tJSONNumber}, Received: val} return ValueEncoderError{Name: "JSONNumberEncodeValue", Types: []reflect.Type{tJSONNumber}, Received: val}
@ -237,7 +261,10 @@ func (dve DefaultValueEncoders) JSONNumberEncodeValue(ec EncodeContext, vw bsonr
} }
// URLEncodeValue is the ValueEncoderFunc for url.URL. // URLEncodeValue is the ValueEncoderFunc for url.URL.
func (dve DefaultValueEncoders) URLEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { //
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with all default
// value encoders registered.
func (dve DefaultValueEncoders) URLEncodeValue(_ EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {
if !val.IsValid() || val.Type() != tURL { if !val.IsValid() || val.Type() != tURL {
return ValueEncoderError{Name: "URLEncodeValue", Types: []reflect.Type{tURL}, Received: val} return ValueEncoderError{Name: "URLEncodeValue", Types: []reflect.Type{tURL}, Received: val}
} }
@ -248,7 +275,7 @@ func (dve DefaultValueEncoders) URLEncodeValue(ec EncodeContext, vw bsonrw.Value
// TimeEncodeValue is the ValueEncoderFunc for time.TIme. // TimeEncodeValue is the ValueEncoderFunc for time.TIme.
// //
// Deprecated: TimeEncodeValue is not registered by default. Use TimeCodec.EncodeValue instead. // Deprecated: TimeEncodeValue is not registered by default. Use TimeCodec.EncodeValue instead.
func (dve DefaultValueEncoders) TimeEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { func (dve DefaultValueEncoders) TimeEncodeValue(_ EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {
if !val.IsValid() || val.Type() != tTime { if !val.IsValid() || val.Type() != tTime {
return ValueEncoderError{Name: "TimeEncodeValue", Types: []reflect.Type{tTime}, Received: val} return ValueEncoderError{Name: "TimeEncodeValue", Types: []reflect.Type{tTime}, Received: val}
} }
@ -260,7 +287,7 @@ func (dve DefaultValueEncoders) TimeEncodeValue(ec EncodeContext, vw bsonrw.Valu
// ByteSliceEncodeValue is the ValueEncoderFunc for []byte. // ByteSliceEncodeValue is the ValueEncoderFunc for []byte.
// //
// Deprecated: ByteSliceEncodeValue is not registered by default. Use ByteSliceCodec.EncodeValue instead. // Deprecated: ByteSliceEncodeValue is not registered by default. Use ByteSliceCodec.EncodeValue instead.
func (dve DefaultValueEncoders) ByteSliceEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { func (dve DefaultValueEncoders) ByteSliceEncodeValue(_ EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {
if !val.IsValid() || val.Type() != tByteSlice { if !val.IsValid() || val.Type() != tByteSlice {
return ValueEncoderError{Name: "ByteSliceEncodeValue", Types: []reflect.Type{tByteSlice}, Received: val} return ValueEncoderError{Name: "ByteSliceEncodeValue", Types: []reflect.Type{tByteSlice}, Received: val}
} }
@ -316,7 +343,7 @@ func (dve DefaultValueEncoders) mapEncodeValue(ec EncodeContext, dw bsonrw.Docum
} }
currEncoder, currVal, lookupErr := dve.lookupElementEncoder(ec, encoder, val.MapIndex(key)) currEncoder, currVal, lookupErr := dve.lookupElementEncoder(ec, encoder, val.MapIndex(key))
if lookupErr != nil && lookupErr != errInvalidValue { if lookupErr != nil && !errors.Is(lookupErr, errInvalidValue) {
return lookupErr return lookupErr
} }
@ -325,7 +352,7 @@ func (dve DefaultValueEncoders) mapEncodeValue(ec EncodeContext, dw bsonrw.Docum
return err return err
} }
if lookupErr == errInvalidValue { if errors.Is(lookupErr, errInvalidValue) {
err = vw.WriteNull() err = vw.WriteNull()
if err != nil { if err != nil {
return err return err
@ -343,6 +370,9 @@ func (dve DefaultValueEncoders) mapEncodeValue(ec EncodeContext, dw bsonrw.Docum
} }
// ArrayEncodeValue is the ValueEncoderFunc for array types. // ArrayEncodeValue is the ValueEncoderFunc for array types.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with all default
// value encoders registered.
func (dve DefaultValueEncoders) ArrayEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { func (dve DefaultValueEncoders) ArrayEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {
if !val.IsValid() || val.Kind() != reflect.Array { if !val.IsValid() || val.Kind() != reflect.Array {
return ValueEncoderError{Name: "ArrayEncodeValue", Kinds: []reflect.Kind{reflect.Array}, Received: val} return ValueEncoderError{Name: "ArrayEncodeValue", Kinds: []reflect.Kind{reflect.Array}, Received: val}
@ -388,7 +418,7 @@ func (dve DefaultValueEncoders) ArrayEncodeValue(ec EncodeContext, vw bsonrw.Val
for idx := 0; idx < val.Len(); idx++ { for idx := 0; idx < val.Len(); idx++ {
currEncoder, currVal, lookupErr := dve.lookupElementEncoder(ec, encoder, val.Index(idx)) currEncoder, currVal, lookupErr := dve.lookupElementEncoder(ec, encoder, val.Index(idx))
if lookupErr != nil && lookupErr != errInvalidValue { if lookupErr != nil && !errors.Is(lookupErr, errInvalidValue) {
return lookupErr return lookupErr
} }
@ -397,7 +427,7 @@ func (dve DefaultValueEncoders) ArrayEncodeValue(ec EncodeContext, vw bsonrw.Val
return err return err
} }
if lookupErr == errInvalidValue { if errors.Is(lookupErr, errInvalidValue) {
err = vw.WriteNull() err = vw.WriteNull()
if err != nil { if err != nil {
return err return err
@ -457,7 +487,7 @@ func (dve DefaultValueEncoders) SliceEncodeValue(ec EncodeContext, vw bsonrw.Val
for idx := 0; idx < val.Len(); idx++ { for idx := 0; idx < val.Len(); idx++ {
currEncoder, currVal, lookupErr := dve.lookupElementEncoder(ec, encoder, val.Index(idx)) currEncoder, currVal, lookupErr := dve.lookupElementEncoder(ec, encoder, val.Index(idx))
if lookupErr != nil && lookupErr != errInvalidValue { if lookupErr != nil && !errors.Is(lookupErr, errInvalidValue) {
return lookupErr return lookupErr
} }
@ -466,7 +496,7 @@ func (dve DefaultValueEncoders) SliceEncodeValue(ec EncodeContext, vw bsonrw.Val
return err return err
} }
if lookupErr == errInvalidValue { if errors.Is(lookupErr, errInvalidValue) {
err = vw.WriteNull() err = vw.WriteNull()
if err != nil { if err != nil {
return err return err
@ -515,7 +545,10 @@ func (dve DefaultValueEncoders) EmptyInterfaceEncodeValue(ec EncodeContext, vw b
} }
// ValueMarshalerEncodeValue is the ValueEncoderFunc for ValueMarshaler implementations. // ValueMarshalerEncodeValue is the ValueEncoderFunc for ValueMarshaler implementations.
func (dve DefaultValueEncoders) ValueMarshalerEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { //
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with all default
// value encoders registered.
func (dve DefaultValueEncoders) ValueMarshalerEncodeValue(_ EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {
// Either val or a pointer to val must implement ValueMarshaler // Either val or a pointer to val must implement ValueMarshaler
switch { switch {
case !val.IsValid(): case !val.IsValid():
@ -531,17 +564,22 @@ func (dve DefaultValueEncoders) ValueMarshalerEncodeValue(ec EncodeContext, vw b
return ValueEncoderError{Name: "ValueMarshalerEncodeValue", Types: []reflect.Type{tValueMarshaler}, Received: val} return ValueEncoderError{Name: "ValueMarshalerEncodeValue", Types: []reflect.Type{tValueMarshaler}, Received: val}
} }
fn := val.Convert(tValueMarshaler).MethodByName("MarshalBSONValue") m, ok := val.Interface().(ValueMarshaler)
returns := fn.Call(nil) if !ok {
if !returns[2].IsNil() { return vw.WriteNull()
return returns[2].Interface().(error) }
t, data, err := m.MarshalBSONValue()
if err != nil {
return err
} }
t, data := returns[0].Interface().(bsontype.Type), returns[1].Interface().([]byte)
return bsonrw.Copier{}.CopyValueFromBytes(vw, t, data) return bsonrw.Copier{}.CopyValueFromBytes(vw, t, data)
} }
// MarshalerEncodeValue is the ValueEncoderFunc for Marshaler implementations. // MarshalerEncodeValue is the ValueEncoderFunc for Marshaler implementations.
func (dve DefaultValueEncoders) MarshalerEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { //
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with all default
// value encoders registered.
func (dve DefaultValueEncoders) MarshalerEncodeValue(_ EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {
// Either val or a pointer to val must implement Marshaler // Either val or a pointer to val must implement Marshaler
switch { switch {
case !val.IsValid(): case !val.IsValid():
@ -557,16 +595,21 @@ func (dve DefaultValueEncoders) MarshalerEncodeValue(ec EncodeContext, vw bsonrw
return ValueEncoderError{Name: "MarshalerEncodeValue", Types: []reflect.Type{tMarshaler}, Received: val} return ValueEncoderError{Name: "MarshalerEncodeValue", Types: []reflect.Type{tMarshaler}, Received: val}
} }
fn := val.Convert(tMarshaler).MethodByName("MarshalBSON") m, ok := val.Interface().(Marshaler)
returns := fn.Call(nil) if !ok {
if !returns[1].IsNil() { return vw.WriteNull()
return returns[1].Interface().(error) }
data, err := m.MarshalBSON()
if err != nil {
return err
} }
data := returns[0].Interface().([]byte)
return bsonrw.Copier{}.CopyValueFromBytes(vw, bsontype.EmbeddedDocument, data) return bsonrw.Copier{}.CopyValueFromBytes(vw, bsontype.EmbeddedDocument, data)
} }
// ProxyEncodeValue is the ValueEncoderFunc for Proxy implementations. // ProxyEncodeValue is the ValueEncoderFunc for Proxy implementations.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with all default
// value encoders registered.
func (dve DefaultValueEncoders) ProxyEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { func (dve DefaultValueEncoders) ProxyEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {
// Either val or a pointer to val must implement Proxy // Either val or a pointer to val must implement Proxy
switch { switch {
@ -583,27 +626,38 @@ func (dve DefaultValueEncoders) ProxyEncodeValue(ec EncodeContext, vw bsonrw.Val
return ValueEncoderError{Name: "ProxyEncodeValue", Types: []reflect.Type{tProxy}, Received: val} return ValueEncoderError{Name: "ProxyEncodeValue", Types: []reflect.Type{tProxy}, Received: val}
} }
fn := val.Convert(tProxy).MethodByName("ProxyBSON") m, ok := val.Interface().(Proxy)
returns := fn.Call(nil) if !ok {
if !returns[1].IsNil() { return vw.WriteNull()
return returns[1].Interface().(error)
}
data := returns[0]
var encoder ValueEncoder
var err error
if data.Elem().IsValid() {
encoder, err = ec.LookupEncoder(data.Elem().Type())
} else {
encoder, err = ec.LookupEncoder(nil)
} }
v, err := m.ProxyBSON()
if err != nil { if err != nil {
return err return err
} }
return encoder.EncodeValue(ec, vw, data.Elem()) if v == nil {
encoder, err := ec.LookupEncoder(nil)
if err != nil {
return err
}
return encoder.EncodeValue(ec, vw, reflect.ValueOf(nil))
}
vv := reflect.ValueOf(v)
switch vv.Kind() {
case reflect.Ptr, reflect.Interface:
vv = vv.Elem()
}
encoder, err := ec.LookupEncoder(vv.Type())
if err != nil {
return err
}
return encoder.EncodeValue(ec, vw, vv)
} }
// JavaScriptEncodeValue is the ValueEncoderFunc for the primitive.JavaScript type. // JavaScriptEncodeValue is the ValueEncoderFunc for the primitive.JavaScript type.
func (DefaultValueEncoders) JavaScriptEncodeValue(ectx EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { //
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with all default
// value encoders registered.
func (DefaultValueEncoders) JavaScriptEncodeValue(_ EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {
if !val.IsValid() || val.Type() != tJavaScript { if !val.IsValid() || val.Type() != tJavaScript {
return ValueEncoderError{Name: "JavaScriptEncodeValue", Types: []reflect.Type{tJavaScript}, Received: val} return ValueEncoderError{Name: "JavaScriptEncodeValue", Types: []reflect.Type{tJavaScript}, Received: val}
} }
@ -612,7 +666,10 @@ func (DefaultValueEncoders) JavaScriptEncodeValue(ectx EncodeContext, vw bsonrw.
} }
// SymbolEncodeValue is the ValueEncoderFunc for the primitive.Symbol type. // SymbolEncodeValue is the ValueEncoderFunc for the primitive.Symbol type.
func (DefaultValueEncoders) SymbolEncodeValue(ectx EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { //
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with all default
// value encoders registered.
func (DefaultValueEncoders) SymbolEncodeValue(_ EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {
if !val.IsValid() || val.Type() != tSymbol { if !val.IsValid() || val.Type() != tSymbol {
return ValueEncoderError{Name: "SymbolEncodeValue", Types: []reflect.Type{tSymbol}, Received: val} return ValueEncoderError{Name: "SymbolEncodeValue", Types: []reflect.Type{tSymbol}, Received: val}
} }
@ -621,7 +678,10 @@ func (DefaultValueEncoders) SymbolEncodeValue(ectx EncodeContext, vw bsonrw.Valu
} }
// BinaryEncodeValue is the ValueEncoderFunc for Binary. // BinaryEncodeValue is the ValueEncoderFunc for Binary.
func (DefaultValueEncoders) BinaryEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { //
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with all default
// value encoders registered.
func (DefaultValueEncoders) BinaryEncodeValue(_ EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {
if !val.IsValid() || val.Type() != tBinary { if !val.IsValid() || val.Type() != tBinary {
return ValueEncoderError{Name: "BinaryEncodeValue", Types: []reflect.Type{tBinary}, Received: val} return ValueEncoderError{Name: "BinaryEncodeValue", Types: []reflect.Type{tBinary}, Received: val}
} }
@ -631,7 +691,10 @@ func (DefaultValueEncoders) BinaryEncodeValue(ec EncodeContext, vw bsonrw.ValueW
} }
// UndefinedEncodeValue is the ValueEncoderFunc for Undefined. // UndefinedEncodeValue is the ValueEncoderFunc for Undefined.
func (DefaultValueEncoders) UndefinedEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { //
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with all default
// value encoders registered.
func (DefaultValueEncoders) UndefinedEncodeValue(_ EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {
if !val.IsValid() || val.Type() != tUndefined { if !val.IsValid() || val.Type() != tUndefined {
return ValueEncoderError{Name: "UndefinedEncodeValue", Types: []reflect.Type{tUndefined}, Received: val} return ValueEncoderError{Name: "UndefinedEncodeValue", Types: []reflect.Type{tUndefined}, Received: val}
} }
@ -640,7 +703,10 @@ func (DefaultValueEncoders) UndefinedEncodeValue(ec EncodeContext, vw bsonrw.Val
} }
// DateTimeEncodeValue is the ValueEncoderFunc for DateTime. // DateTimeEncodeValue is the ValueEncoderFunc for DateTime.
func (DefaultValueEncoders) DateTimeEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { //
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with all default
// value encoders registered.
func (DefaultValueEncoders) DateTimeEncodeValue(_ EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {
if !val.IsValid() || val.Type() != tDateTime { if !val.IsValid() || val.Type() != tDateTime {
return ValueEncoderError{Name: "DateTimeEncodeValue", Types: []reflect.Type{tDateTime}, Received: val} return ValueEncoderError{Name: "DateTimeEncodeValue", Types: []reflect.Type{tDateTime}, Received: val}
} }
@ -649,7 +715,10 @@ func (DefaultValueEncoders) DateTimeEncodeValue(ec EncodeContext, vw bsonrw.Valu
} }
// NullEncodeValue is the ValueEncoderFunc for Null. // NullEncodeValue is the ValueEncoderFunc for Null.
func (DefaultValueEncoders) NullEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { //
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with all default
// value encoders registered.
func (DefaultValueEncoders) NullEncodeValue(_ EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {
if !val.IsValid() || val.Type() != tNull { if !val.IsValid() || val.Type() != tNull {
return ValueEncoderError{Name: "NullEncodeValue", Types: []reflect.Type{tNull}, Received: val} return ValueEncoderError{Name: "NullEncodeValue", Types: []reflect.Type{tNull}, Received: val}
} }
@ -658,7 +727,10 @@ func (DefaultValueEncoders) NullEncodeValue(ec EncodeContext, vw bsonrw.ValueWri
} }
// RegexEncodeValue is the ValueEncoderFunc for Regex. // RegexEncodeValue is the ValueEncoderFunc for Regex.
func (DefaultValueEncoders) RegexEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { //
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with all default
// value encoders registered.
func (DefaultValueEncoders) RegexEncodeValue(_ EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {
if !val.IsValid() || val.Type() != tRegex { if !val.IsValid() || val.Type() != tRegex {
return ValueEncoderError{Name: "RegexEncodeValue", Types: []reflect.Type{tRegex}, Received: val} return ValueEncoderError{Name: "RegexEncodeValue", Types: []reflect.Type{tRegex}, Received: val}
} }
@ -669,7 +741,10 @@ func (DefaultValueEncoders) RegexEncodeValue(ec EncodeContext, vw bsonrw.ValueWr
} }
// DBPointerEncodeValue is the ValueEncoderFunc for DBPointer. // DBPointerEncodeValue is the ValueEncoderFunc for DBPointer.
func (DefaultValueEncoders) DBPointerEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { //
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with all default
// value encoders registered.
func (DefaultValueEncoders) DBPointerEncodeValue(_ EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {
if !val.IsValid() || val.Type() != tDBPointer { if !val.IsValid() || val.Type() != tDBPointer {
return ValueEncoderError{Name: "DBPointerEncodeValue", Types: []reflect.Type{tDBPointer}, Received: val} return ValueEncoderError{Name: "DBPointerEncodeValue", Types: []reflect.Type{tDBPointer}, Received: val}
} }
@ -680,7 +755,10 @@ func (DefaultValueEncoders) DBPointerEncodeValue(ec EncodeContext, vw bsonrw.Val
} }
// TimestampEncodeValue is the ValueEncoderFunc for Timestamp. // TimestampEncodeValue is the ValueEncoderFunc for Timestamp.
func (DefaultValueEncoders) TimestampEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { //
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with all default
// value encoders registered.
func (DefaultValueEncoders) TimestampEncodeValue(_ EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {
if !val.IsValid() || val.Type() != tTimestamp { if !val.IsValid() || val.Type() != tTimestamp {
return ValueEncoderError{Name: "TimestampEncodeValue", Types: []reflect.Type{tTimestamp}, Received: val} return ValueEncoderError{Name: "TimestampEncodeValue", Types: []reflect.Type{tTimestamp}, Received: val}
} }
@ -691,7 +769,10 @@ func (DefaultValueEncoders) TimestampEncodeValue(ec EncodeContext, vw bsonrw.Val
} }
// MinKeyEncodeValue is the ValueEncoderFunc for MinKey. // MinKeyEncodeValue is the ValueEncoderFunc for MinKey.
func (DefaultValueEncoders) MinKeyEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { //
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with all default
// value encoders registered.
func (DefaultValueEncoders) MinKeyEncodeValue(_ EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {
if !val.IsValid() || val.Type() != tMinKey { if !val.IsValid() || val.Type() != tMinKey {
return ValueEncoderError{Name: "MinKeyEncodeValue", Types: []reflect.Type{tMinKey}, Received: val} return ValueEncoderError{Name: "MinKeyEncodeValue", Types: []reflect.Type{tMinKey}, Received: val}
} }
@ -700,7 +781,10 @@ func (DefaultValueEncoders) MinKeyEncodeValue(ec EncodeContext, vw bsonrw.ValueW
} }
// MaxKeyEncodeValue is the ValueEncoderFunc for MaxKey. // MaxKeyEncodeValue is the ValueEncoderFunc for MaxKey.
func (DefaultValueEncoders) MaxKeyEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { //
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with all default
// value encoders registered.
func (DefaultValueEncoders) MaxKeyEncodeValue(_ EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {
if !val.IsValid() || val.Type() != tMaxKey { if !val.IsValid() || val.Type() != tMaxKey {
return ValueEncoderError{Name: "MaxKeyEncodeValue", Types: []reflect.Type{tMaxKey}, Received: val} return ValueEncoderError{Name: "MaxKeyEncodeValue", Types: []reflect.Type{tMaxKey}, Received: val}
} }
@ -709,7 +793,10 @@ func (DefaultValueEncoders) MaxKeyEncodeValue(ec EncodeContext, vw bsonrw.ValueW
} }
// CoreDocumentEncodeValue is the ValueEncoderFunc for bsoncore.Document. // CoreDocumentEncodeValue is the ValueEncoderFunc for bsoncore.Document.
func (DefaultValueEncoders) CoreDocumentEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { //
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with all default
// value encoders registered.
func (DefaultValueEncoders) CoreDocumentEncodeValue(_ EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {
if !val.IsValid() || val.Type() != tCoreDocument { if !val.IsValid() || val.Type() != tCoreDocument {
return ValueEncoderError{Name: "CoreDocumentEncodeValue", Types: []reflect.Type{tCoreDocument}, Received: val} return ValueEncoderError{Name: "CoreDocumentEncodeValue", Types: []reflect.Type{tCoreDocument}, Received: val}
} }
@ -720,6 +807,9 @@ func (DefaultValueEncoders) CoreDocumentEncodeValue(ec EncodeContext, vw bsonrw.
} }
// CodeWithScopeEncodeValue is the ValueEncoderFunc for CodeWithScope. // CodeWithScopeEncodeValue is the ValueEncoderFunc for CodeWithScope.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.NewRegistry] to get a registry with all default
// value encoders registered.
func (dve DefaultValueEncoders) CodeWithScopeEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { func (dve DefaultValueEncoders) CodeWithScopeEncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {
if !val.IsValid() || val.Type() != tCodeWithScope { if !val.IsValid() || val.Type() != tCodeWithScope {
return ValueEncoderError{Name: "CodeWithScopeEncodeValue", Types: []reflect.Type{tCodeWithScope}, Received: val} return ValueEncoderError{Name: "CodeWithScopeEncodeValue", Types: []reflect.Type{tCodeWithScope}, Received: val}

View file

@ -31,35 +31,39 @@
// allow the use of a function with the correct signature as a ValueDecoder. A DecodeContext // allow the use of a function with the correct signature as a ValueDecoder. A DecodeContext
// instance is provided and serves similar functionality to the EncodeContext. // instance is provided and serves similar functionality to the EncodeContext.
// //
// # Registry and RegistryBuilder // # Registry
// //
// A Registry is an immutable store for ValueEncoders, ValueDecoders, and a type map. See the Registry type // A Registry is a store for ValueEncoders, ValueDecoders, and a type map. See the Registry type
// documentation for examples of registering various custom encoders and decoders. A Registry can be constructed using a // documentation for examples of registering various custom encoders and decoders. A Registry can
// RegistryBuilder, which handles three main types of codecs: // have three main types of codecs:
// //
// 1. Type encoders/decoders - These can be registered using the RegisterTypeEncoder and RegisterTypeDecoder methods. // 1. Type encoders/decoders - These can be registered using the RegisterTypeEncoder and
// The registered codec will be invoked when encoding/decoding a value whose type matches the registered type exactly. // RegisterTypeDecoder methods. The registered codec will be invoked when encoding/decoding a value
// If the registered type is an interface, the codec will be invoked when encoding or decoding values whose type is the // whose type matches the registered type exactly.
// interface, but not for values with concrete types that implement the interface. // If the registered type is an interface, the codec will be invoked when encoding or decoding
// values whose type is the interface, but not for values with concrete types that implement the
// interface.
// //
// 2. Hook encoders/decoders - These can be registered using the RegisterHookEncoder and RegisterHookDecoder methods. // 2. Hook encoders/decoders - These can be registered using the RegisterHookEncoder and
// These methods only accept interface types and the registered codecs will be invoked when encoding or decoding values // RegisterHookDecoder methods. These methods only accept interface types and the registered codecs
// whose types implement the interface. An example of a hook defined by the driver is bson.Marshaler. The driver will // will be invoked when encoding or decoding values whose types implement the interface. An example
// call the MarshalBSON method for any value whose type implements bson.Marshaler, regardless of the value's concrete // of a hook defined by the driver is bson.Marshaler. The driver will call the MarshalBSON method
// type. // for any value whose type implements bson.Marshaler, regardless of the value's concrete type.
// //
// 3. Type map entries - This can be used to associate a BSON type with a Go type. These type associations are used when // 3. Type map entries - This can be used to associate a BSON type with a Go type. These type
// decoding into a bson.D/bson.M or a struct field of type interface{}. For example, by default, BSON int32 and int64 // associations are used when decoding into a bson.D/bson.M or a struct field of type interface{}.
// values decode as Go int32 and int64 instances, respectively, when decoding into a bson.D. The following code would // For example, by default, BSON int32 and int64 values decode as Go int32 and int64 instances,
// change the behavior so these values decode as Go int instances instead: // respectively, when decoding into a bson.D. The following code would change the behavior so these
// values decode as Go int instances instead:
// //
// intType := reflect.TypeOf(int(0)) // intType := reflect.TypeOf(int(0))
// registryBuilder.RegisterTypeMapEntry(bsontype.Int32, intType).RegisterTypeMapEntry(bsontype.Int64, intType) // registry.RegisterTypeMapEntry(bsontype.Int32, intType).RegisterTypeMapEntry(bsontype.Int64, intType)
// //
// 4. Kind encoder/decoders - These can be registered using the RegisterDefaultEncoder and RegisterDefaultDecoder // 4. Kind encoder/decoders - These can be registered using the RegisterDefaultEncoder and
// methods. The registered codec will be invoked when encoding or decoding values whose reflect.Kind matches the // RegisterDefaultDecoder methods. The registered codec will be invoked when encoding or decoding
// registered reflect.Kind as long as the value's type doesn't match a registered type or hook encoder/decoder first. // values whose reflect.Kind matches the registered reflect.Kind as long as the value's type doesn't
// These methods should be used to change the behavior for all values for a specific kind. // match a registered type or hook encoder/decoder first. These methods should be used to change the
// behavior for all values for a specific kind.
// //
// # Registry Lookup Procedure // # Registry Lookup Procedure
// //
@ -67,17 +71,18 @@
// //
// 1. A type encoder registered for the exact type of the value. // 1. A type encoder registered for the exact type of the value.
// //
// 2. A hook encoder registered for an interface that is implemented by the value or by a pointer to the value. If the // 2. A hook encoder registered for an interface that is implemented by the value or by a pointer to
// value matches multiple hooks (e.g. the type implements bsoncodec.Marshaler and bsoncodec.ValueMarshaler), the first // the value. If the value matches multiple hooks (e.g. the type implements bsoncodec.Marshaler and
// one registered will be selected. Note that registries constructed using bson.NewRegistryBuilder have driver-defined // bsoncodec.ValueMarshaler), the first one registered will be selected. Note that registries
// hooks registered for the bsoncodec.Marshaler, bsoncodec.ValueMarshaler, and bsoncodec.Proxy interfaces, so those // constructed using bson.NewRegistry have driver-defined hooks registered for the
// will take precedence over any new hooks. // bsoncodec.Marshaler, bsoncodec.ValueMarshaler, and bsoncodec.Proxy interfaces, so those will take
// precedence over any new hooks.
// //
// 3. A kind encoder registered for the value's kind. // 3. A kind encoder registered for the value's kind.
// //
// If all of these lookups fail to find an encoder, an error of type ErrNoEncoder is returned. The same precedence // If all of these lookups fail to find an encoder, an error of type ErrNoEncoder is returned. The
// rules apply for decoders, with the exception that an error of type ErrNoDecoder will be returned if no decoder is // same precedence rules apply for decoders, with the exception that an error of type ErrNoDecoder
// found. // will be returned if no decoder is found.
// //
// # DefaultValueEncoders and DefaultValueDecoders // # DefaultValueEncoders and DefaultValueDecoders
// //

View file

@ -16,18 +16,44 @@
) )
// EmptyInterfaceCodec is the Codec used for interface{} values. // EmptyInterfaceCodec is the Codec used for interface{} values.
//
// Deprecated: EmptyInterfaceCodec will not be directly configurable in Go
// Driver 2.0. To configure the empty interface encode and decode behavior, use
// the configuration methods on a [go.mongodb.org/mongo-driver/bson.Encoder] or
// [go.mongodb.org/mongo-driver/bson.Decoder]. To configure the empty interface
// encode and decode behavior for a mongo.Client, use
// [go.mongodb.org/mongo-driver/mongo/options.ClientOptions.SetBSONOptions].
//
// For example, to configure a mongo.Client to unmarshal BSON binary field
// values as a Go byte slice, use:
//
// opt := options.Client().SetBSONOptions(&options.BSONOptions{
// BinaryAsSlice: true,
// })
//
// See the deprecation notice for each field in EmptyInterfaceCodec for the
// corresponding settings.
type EmptyInterfaceCodec struct { type EmptyInterfaceCodec struct {
// DecodeBinaryAsSlice causes DecodeValue to unmarshal BSON binary field values that are the
// "Generic" or "Old" BSON binary subtype as a Go byte slice instead of a primitive.Binary.
//
// Deprecated: Use bson.Decoder.BinaryAsSlice or options.BSONOptions.BinaryAsSlice instead.
DecodeBinaryAsSlice bool DecodeBinaryAsSlice bool
} }
var ( var (
defaultEmptyInterfaceCodec = NewEmptyInterfaceCodec() defaultEmptyInterfaceCodec = NewEmptyInterfaceCodec()
_ ValueCodec = defaultEmptyInterfaceCodec // Assert that defaultEmptyInterfaceCodec satisfies the typeDecoder interface, which allows it
// to be used by collection type decoders (e.g. map, slice, etc) to set individual values in a
// collection.
_ typeDecoder = defaultEmptyInterfaceCodec _ typeDecoder = defaultEmptyInterfaceCodec
) )
// NewEmptyInterfaceCodec returns a EmptyInterfaceCodec with options opts. // NewEmptyInterfaceCodec returns a EmptyInterfaceCodec with options opts.
//
// Deprecated: NewEmptyInterfaceCodec will not be available in Go Driver 2.0. See
// [EmptyInterfaceCodec] for more details.
func NewEmptyInterfaceCodec(opts ...*bsonoptions.EmptyInterfaceCodecOptions) *EmptyInterfaceCodec { func NewEmptyInterfaceCodec(opts ...*bsonoptions.EmptyInterfaceCodecOptions) *EmptyInterfaceCodec {
interfaceOpt := bsonoptions.MergeEmptyInterfaceCodecOptions(opts...) interfaceOpt := bsonoptions.MergeEmptyInterfaceCodecOptions(opts...)
@ -121,7 +147,7 @@ func (eic EmptyInterfaceCodec) decodeType(dc DecodeContext, vr bsonrw.ValueReade
return emptyValue, err return emptyValue, err
} }
if eic.DecodeBinaryAsSlice && rtype == tBinary { if (eic.DecodeBinaryAsSlice || dc.binaryAsSlice) && rtype == tBinary {
binElem := elem.Interface().(primitive.Binary) binElem := elem.Interface().(primitive.Binary)
if binElem.Subtype == bsontype.BinaryGeneric || binElem.Subtype == bsontype.BinaryBinaryOld { if binElem.Subtype == bsontype.BinaryGeneric || binElem.Subtype == bsontype.BinaryBinaryOld {
elem = reflect.ValueOf(binElem.Data) elem = reflect.ValueOf(binElem.Data)

View file

@ -8,6 +8,7 @@
import ( import (
"encoding" "encoding"
"errors"
"fmt" "fmt"
"reflect" "reflect"
"strconv" "strconv"
@ -20,14 +21,44 @@
var defaultMapCodec = NewMapCodec() var defaultMapCodec = NewMapCodec()
// MapCodec is the Codec used for map values. // MapCodec is the Codec used for map values.
//
// Deprecated: MapCodec will not be directly configurable in Go Driver 2.0. To
// configure the map encode and decode behavior, use the configuration methods
// on a [go.mongodb.org/mongo-driver/bson.Encoder] or
// [go.mongodb.org/mongo-driver/bson.Decoder]. To configure the map encode and
// decode behavior for a mongo.Client, use
// [go.mongodb.org/mongo-driver/mongo/options.ClientOptions.SetBSONOptions].
//
// For example, to configure a mongo.Client to marshal nil Go maps as empty BSON
// documents, use:
//
// opt := options.Client().SetBSONOptions(&options.BSONOptions{
// NilMapAsEmpty: true,
// })
//
// See the deprecation notice for each field in MapCodec for the corresponding
// settings.
type MapCodec struct { type MapCodec struct {
DecodeZerosMap bool // DecodeZerosMap causes DecodeValue to delete any existing values from Go maps in the destination
EncodeNilAsEmpty bool // value passed to Decode before unmarshaling BSON documents into them.
//
// Deprecated: Use bson.Decoder.ZeroMaps or options.BSONOptions.ZeroMaps instead.
DecodeZerosMap bool
// EncodeNilAsEmpty causes EncodeValue to marshal nil Go maps as empty BSON documents instead of
// BSON null.
//
// Deprecated: Use bson.Encoder.NilMapAsEmpty or options.BSONOptions.NilMapAsEmpty instead.
EncodeNilAsEmpty bool
// EncodeKeysWithStringer causes the Encoder to convert Go map keys to BSON document field name
// strings using fmt.Sprintf() instead of the default string conversion logic.
//
// Deprecated: Use bson.Encoder.StringifyMapKeysWithFmt or
// options.BSONOptions.StringifyMapKeysWithFmt instead.
EncodeKeysWithStringer bool EncodeKeysWithStringer bool
} }
var _ ValueCodec = &MapCodec{}
// KeyMarshaler is the interface implemented by an object that can marshal itself into a string key. // KeyMarshaler is the interface implemented by an object that can marshal itself into a string key.
// This applies to types used as map keys and is similar to encoding.TextMarshaler. // This applies to types used as map keys and is similar to encoding.TextMarshaler.
type KeyMarshaler interface { type KeyMarshaler interface {
@ -45,6 +76,9 @@ type KeyUnmarshaler interface {
} }
// NewMapCodec returns a MapCodec with options opts. // NewMapCodec returns a MapCodec with options opts.
//
// Deprecated: NewMapCodec will not be available in Go Driver 2.0. See
// [MapCodec] for more details.
func NewMapCodec(opts ...*bsonoptions.MapCodecOptions) *MapCodec { func NewMapCodec(opts ...*bsonoptions.MapCodecOptions) *MapCodec {
mapOpt := bsonoptions.MergeMapCodecOptions(opts...) mapOpt := bsonoptions.MergeMapCodecOptions(opts...)
@ -67,7 +101,7 @@ func (mc *MapCodec) EncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val ref
return ValueEncoderError{Name: "MapEncodeValue", Kinds: []reflect.Kind{reflect.Map}, Received: val} return ValueEncoderError{Name: "MapEncodeValue", Kinds: []reflect.Kind{reflect.Map}, Received: val}
} }
if val.IsNil() && !mc.EncodeNilAsEmpty { if val.IsNil() && !mc.EncodeNilAsEmpty && !ec.nilMapAsEmpty {
// If we have a nil map but we can't WriteNull, that means we're probably trying to encode // If we have a nil map but we can't WriteNull, that means we're probably trying to encode
// to a TopLevel document. We can't currently tell if this is what actually happened, but if // to a TopLevel document. We can't currently tell if this is what actually happened, but if
// there's a deeper underlying problem, the error will also be returned from WriteDocument, // there's a deeper underlying problem, the error will also be returned from WriteDocument,
@ -100,7 +134,7 @@ func (mc *MapCodec) mapEncodeValue(ec EncodeContext, dw bsonrw.DocumentWriter, v
keys := val.MapKeys() keys := val.MapKeys()
for _, key := range keys { for _, key := range keys {
keyStr, err := mc.encodeKey(key) keyStr, err := mc.encodeKey(key, ec.stringifyMapKeysWithFmt)
if err != nil { if err != nil {
return err return err
} }
@ -110,7 +144,7 @@ func (mc *MapCodec) mapEncodeValue(ec EncodeContext, dw bsonrw.DocumentWriter, v
} }
currEncoder, currVal, lookupErr := defaultValueEncoders.lookupElementEncoder(ec, encoder, val.MapIndex(key)) currEncoder, currVal, lookupErr := defaultValueEncoders.lookupElementEncoder(ec, encoder, val.MapIndex(key))
if lookupErr != nil && lookupErr != errInvalidValue { if lookupErr != nil && !errors.Is(lookupErr, errInvalidValue) {
return lookupErr return lookupErr
} }
@ -119,7 +153,7 @@ func (mc *MapCodec) mapEncodeValue(ec EncodeContext, dw bsonrw.DocumentWriter, v
return err return err
} }
if lookupErr == errInvalidValue { if errors.Is(lookupErr, errInvalidValue) {
err = vw.WriteNull() err = vw.WriteNull()
if err != nil { if err != nil {
return err return err
@ -163,7 +197,7 @@ func (mc *MapCodec) DecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val ref
val.Set(reflect.MakeMap(val.Type())) val.Set(reflect.MakeMap(val.Type()))
} }
if val.Len() > 0 && mc.DecodeZerosMap { if val.Len() > 0 && (mc.DecodeZerosMap || dc.zeroMaps) {
clearMap(val) clearMap(val)
} }
@ -182,7 +216,7 @@ func (mc *MapCodec) DecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val ref
for { for {
key, vr, err := dr.ReadElement() key, vr, err := dr.ReadElement()
if err == bsonrw.ErrEOD { if errors.Is(err, bsonrw.ErrEOD) {
break break
} }
if err != nil { if err != nil {
@ -211,8 +245,8 @@ func clearMap(m reflect.Value) {
} }
} }
func (mc *MapCodec) encodeKey(val reflect.Value) (string, error) { func (mc *MapCodec) encodeKey(val reflect.Value, encodeKeysWithStringer bool) (string, error) {
if mc.EncodeKeysWithStringer { if mc.EncodeKeysWithStringer || encodeKeysWithStringer {
return fmt.Sprint(val), nil return fmt.Sprint(val), nil
} }
@ -295,7 +329,7 @@ func (mc *MapCodec) decodeKey(key string, keyType reflect.Type) (reflect.Value,
if mc.EncodeKeysWithStringer { if mc.EncodeKeysWithStringer {
parsed, err := strconv.ParseFloat(key, 64) parsed, err := strconv.ParseFloat(key, 64)
if err != nil { if err != nil {
return keyVal, fmt.Errorf("Map key is defined to be a decimal type (%v) but got error %v", keyType.Kind(), err) return keyVal, fmt.Errorf("Map key is defined to be a decimal type (%v) but got error %w", keyType.Kind(), err)
} }
keyVal = reflect.ValueOf(parsed) keyVal = reflect.ValueOf(parsed)
break break

View file

@ -8,7 +8,6 @@
import ( import (
"reflect" "reflect"
"sync"
"go.mongodb.org/mongo-driver/bson/bsonrw" "go.mongodb.org/mongo-driver/bson/bsonrw"
"go.mongodb.org/mongo-driver/bson/bsontype" "go.mongodb.org/mongo-driver/bson/bsontype"
@ -18,18 +17,28 @@
var _ ValueDecoder = &PointerCodec{} var _ ValueDecoder = &PointerCodec{}
// PointerCodec is the Codec used for pointers. // PointerCodec is the Codec used for pointers.
//
// Deprecated: PointerCodec will not be directly accessible in Go Driver 2.0. To
// override the default pointer encode and decode behavior, create a new registry
// with [go.mongodb.org/mongo-driver/bson.NewRegistry] and register a new
// encoder and decoder for pointers.
//
// For example,
//
// reg := bson.NewRegistry()
// reg.RegisterKindEncoder(reflect.Ptr, myPointerEncoder)
// reg.RegisterKindDecoder(reflect.Ptr, myPointerDecoder)
type PointerCodec struct { type PointerCodec struct {
ecache map[reflect.Type]ValueEncoder ecache typeEncoderCache
dcache map[reflect.Type]ValueDecoder dcache typeDecoderCache
l sync.RWMutex
} }
// NewPointerCodec returns a PointerCodec that has been initialized. // NewPointerCodec returns a PointerCodec that has been initialized.
//
// Deprecated: NewPointerCodec will not be available in Go Driver 2.0. See
// [PointerCodec] for more details.
func NewPointerCodec() *PointerCodec { func NewPointerCodec() *PointerCodec {
return &PointerCodec{ return &PointerCodec{}
ecache: make(map[reflect.Type]ValueEncoder),
dcache: make(map[reflect.Type]ValueDecoder),
}
} }
// EncodeValue handles encoding a pointer by either encoding it to BSON Null if the pointer is nil // EncodeValue handles encoding a pointer by either encoding it to BSON Null if the pointer is nil
@ -46,24 +55,19 @@ func (pc *PointerCodec) EncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val
return vw.WriteNull() return vw.WriteNull()
} }
pc.l.RLock() typ := val.Type()
enc, ok := pc.ecache[val.Type()] if v, ok := pc.ecache.Load(typ); ok {
pc.l.RUnlock() if v == nil {
if ok { return ErrNoEncoder{Type: typ}
if enc == nil {
return ErrNoEncoder{Type: val.Type()}
} }
return enc.EncodeValue(ec, vw, val.Elem()) return v.EncodeValue(ec, vw, val.Elem())
} }
// TODO(charlie): handle concurrent requests for the same type
enc, err := ec.LookupEncoder(val.Type().Elem()) enc, err := ec.LookupEncoder(typ.Elem())
pc.l.Lock() enc = pc.ecache.LoadOrStore(typ, enc)
pc.ecache[val.Type()] = enc
pc.l.Unlock()
if err != nil { if err != nil {
return err return err
} }
return enc.EncodeValue(ec, vw, val.Elem()) return enc.EncodeValue(ec, vw, val.Elem())
} }
@ -74,36 +78,31 @@ func (pc *PointerCodec) DecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val
return ValueDecoderError{Name: "PointerCodec.DecodeValue", Kinds: []reflect.Kind{reflect.Ptr}, Received: val} return ValueDecoderError{Name: "PointerCodec.DecodeValue", Kinds: []reflect.Kind{reflect.Ptr}, Received: val}
} }
typ := val.Type()
if vr.Type() == bsontype.Null { if vr.Type() == bsontype.Null {
val.Set(reflect.Zero(val.Type())) val.Set(reflect.Zero(typ))
return vr.ReadNull() return vr.ReadNull()
} }
if vr.Type() == bsontype.Undefined { if vr.Type() == bsontype.Undefined {
val.Set(reflect.Zero(val.Type())) val.Set(reflect.Zero(typ))
return vr.ReadUndefined() return vr.ReadUndefined()
} }
if val.IsNil() { if val.IsNil() {
val.Set(reflect.New(val.Type().Elem())) val.Set(reflect.New(typ.Elem()))
} }
pc.l.RLock() if v, ok := pc.dcache.Load(typ); ok {
dec, ok := pc.dcache[val.Type()] if v == nil {
pc.l.RUnlock() return ErrNoDecoder{Type: typ}
if ok {
if dec == nil {
return ErrNoDecoder{Type: val.Type()}
} }
return dec.DecodeValue(dc, vr, val.Elem()) return v.DecodeValue(dc, vr, val.Elem())
} }
// TODO(charlie): handle concurrent requests for the same type
dec, err := dc.LookupDecoder(val.Type().Elem()) dec, err := dc.LookupDecoder(typ.Elem())
pc.l.Lock() dec = pc.dcache.LoadOrStore(typ, dec)
pc.dcache[val.Type()] = dec
pc.l.Unlock()
if err != nil { if err != nil {
return err return err
} }
return dec.DecodeValue(dc, vr, val.Elem()) return dec.DecodeValue(dc, vr, val.Elem())
} }

View file

@ -16,12 +16,18 @@
) )
// ErrNilType is returned when nil is passed to either LookupEncoder or LookupDecoder. // ErrNilType is returned when nil is passed to either LookupEncoder or LookupDecoder.
//
// Deprecated: ErrNilType will not be supported in Go Driver 2.0.
var ErrNilType = errors.New("cannot perform a decoder lookup on <nil>") var ErrNilType = errors.New("cannot perform a decoder lookup on <nil>")
// ErrNotPointer is returned when a non-pointer type is provided to LookupDecoder. // ErrNotPointer is returned when a non-pointer type is provided to LookupDecoder.
//
// Deprecated: ErrNotPointer will not be supported in Go Driver 2.0.
var ErrNotPointer = errors.New("non-pointer provided to LookupDecoder") var ErrNotPointer = errors.New("non-pointer provided to LookupDecoder")
// ErrNoEncoder is returned when there wasn't an encoder available for a type. // ErrNoEncoder is returned when there wasn't an encoder available for a type.
//
// Deprecated: ErrNoEncoder will not be supported in Go Driver 2.0.
type ErrNoEncoder struct { type ErrNoEncoder struct {
Type reflect.Type Type reflect.Type
} }
@ -34,6 +40,8 @@ func (ene ErrNoEncoder) Error() string {
} }
// ErrNoDecoder is returned when there wasn't a decoder available for a type. // ErrNoDecoder is returned when there wasn't a decoder available for a type.
//
// Deprecated: ErrNoDecoder will not be supported in Go Driver 2.0.
type ErrNoDecoder struct { type ErrNoDecoder struct {
Type reflect.Type Type reflect.Type
} }
@ -43,6 +51,8 @@ func (end ErrNoDecoder) Error() string {
} }
// ErrNoTypeMapEntry is returned when there wasn't a type available for the provided BSON type. // ErrNoTypeMapEntry is returned when there wasn't a type available for the provided BSON type.
//
// Deprecated: ErrNoTypeMapEntry will not be supported in Go Driver 2.0.
type ErrNoTypeMapEntry struct { type ErrNoTypeMapEntry struct {
Type bsontype.Type Type bsontype.Type
} }
@ -52,63 +62,30 @@ func (entme ErrNoTypeMapEntry) Error() string {
} }
// ErrNotInterface is returned when the provided type is not an interface. // ErrNotInterface is returned when the provided type is not an interface.
//
// Deprecated: ErrNotInterface will not be supported in Go Driver 2.0.
var ErrNotInterface = errors.New("The provided type is not an interface") var ErrNotInterface = errors.New("The provided type is not an interface")
// A RegistryBuilder is used to build a Registry. This type is not goroutine // A RegistryBuilder is used to build a Registry. This type is not goroutine
// safe. // safe.
//
// Deprecated: Use Registry instead.
type RegistryBuilder struct { type RegistryBuilder struct {
typeEncoders map[reflect.Type]ValueEncoder registry *Registry
interfaceEncoders []interfaceValueEncoder
kindEncoders map[reflect.Kind]ValueEncoder
typeDecoders map[reflect.Type]ValueDecoder
interfaceDecoders []interfaceValueDecoder
kindDecoders map[reflect.Kind]ValueDecoder
typeMap map[bsontype.Type]reflect.Type
}
// A Registry is used to store and retrieve codecs for types and interfaces. This type is the main
// typed passed around and Encoders and Decoders are constructed from it.
type Registry struct {
typeEncoders map[reflect.Type]ValueEncoder
typeDecoders map[reflect.Type]ValueDecoder
interfaceEncoders []interfaceValueEncoder
interfaceDecoders []interfaceValueDecoder
kindEncoders map[reflect.Kind]ValueEncoder
kindDecoders map[reflect.Kind]ValueDecoder
typeMap map[bsontype.Type]reflect.Type
mu sync.RWMutex
} }
// NewRegistryBuilder creates a new empty RegistryBuilder. // NewRegistryBuilder creates a new empty RegistryBuilder.
//
// Deprecated: Use NewRegistry instead.
func NewRegistryBuilder() *RegistryBuilder { func NewRegistryBuilder() *RegistryBuilder {
return &RegistryBuilder{ return &RegistryBuilder{
typeEncoders: make(map[reflect.Type]ValueEncoder), registry: NewRegistry(),
typeDecoders: make(map[reflect.Type]ValueDecoder),
interfaceEncoders: make([]interfaceValueEncoder, 0),
interfaceDecoders: make([]interfaceValueDecoder, 0),
kindEncoders: make(map[reflect.Kind]ValueEncoder),
kindDecoders: make(map[reflect.Kind]ValueDecoder),
typeMap: make(map[bsontype.Type]reflect.Type),
} }
} }
func buildDefaultRegistry() *Registry {
rb := NewRegistryBuilder()
defaultValueEncoders.RegisterDefaultEncoders(rb)
defaultValueDecoders.RegisterDefaultDecoders(rb)
return rb.Build()
}
// RegisterCodec will register the provided ValueCodec for the provided type. // RegisterCodec will register the provided ValueCodec for the provided type.
//
// Deprecated: Use Registry.RegisterTypeEncoder and Registry.RegisterTypeDecoder instead.
func (rb *RegistryBuilder) RegisterCodec(t reflect.Type, codec ValueCodec) *RegistryBuilder { func (rb *RegistryBuilder) RegisterCodec(t reflect.Type, codec ValueCodec) *RegistryBuilder {
rb.RegisterTypeEncoder(t, codec) rb.RegisterTypeEncoder(t, codec)
rb.RegisterTypeDecoder(t, codec) rb.RegisterTypeDecoder(t, codec)
@ -120,31 +97,22 @@ func (rb *RegistryBuilder) RegisterCodec(t reflect.Type, codec ValueCodec) *Regi
// The type will be used directly, so an encoder can be registered for a type and a different encoder can be registered // The type will be used directly, so an encoder can be registered for a type and a different encoder can be registered
// for a pointer to that type. // for a pointer to that type.
// //
// If the given type is an interface, the encoder will be called when marshalling a type that is that interface. It // If the given type is an interface, the encoder will be called when marshaling a type that is that interface. It
// will not be called when marshalling a non-interface type that implements the interface. // will not be called when marshaling a non-interface type that implements the interface.
//
// Deprecated: Use Registry.RegisterTypeEncoder instead.
func (rb *RegistryBuilder) RegisterTypeEncoder(t reflect.Type, enc ValueEncoder) *RegistryBuilder { func (rb *RegistryBuilder) RegisterTypeEncoder(t reflect.Type, enc ValueEncoder) *RegistryBuilder {
rb.typeEncoders[t] = enc rb.registry.RegisterTypeEncoder(t, enc)
return rb return rb
} }
// RegisterHookEncoder will register an encoder for the provided interface type t. This encoder will be called when // RegisterHookEncoder will register an encoder for the provided interface type t. This encoder will be called when
// marshalling a type if the type implements t or a pointer to the type implements t. If the provided type is not // marshaling a type if the type implements t or a pointer to the type implements t. If the provided type is not
// an interface (i.e. t.Kind() != reflect.Interface), this method will panic. // an interface (i.e. t.Kind() != reflect.Interface), this method will panic.
//
// Deprecated: Use Registry.RegisterInterfaceEncoder instead.
func (rb *RegistryBuilder) RegisterHookEncoder(t reflect.Type, enc ValueEncoder) *RegistryBuilder { func (rb *RegistryBuilder) RegisterHookEncoder(t reflect.Type, enc ValueEncoder) *RegistryBuilder {
if t.Kind() != reflect.Interface { rb.registry.RegisterInterfaceEncoder(t, enc)
panicStr := fmt.Sprintf("RegisterHookEncoder expects a type with kind reflect.Interface, "+
"got type %s with kind %s", t, t.Kind())
panic(panicStr)
}
for idx, encoder := range rb.interfaceEncoders {
if encoder.i == t {
rb.interfaceEncoders[idx].ve = enc
return rb
}
}
rb.interfaceEncoders = append(rb.interfaceEncoders, interfaceValueEncoder{i: t, ve: enc})
return rb return rb
} }
@ -153,97 +121,78 @@ func (rb *RegistryBuilder) RegisterHookEncoder(t reflect.Type, enc ValueEncoder)
// The type will be used directly, so a decoder can be registered for a type and a different decoder can be registered // The type will be used directly, so a decoder can be registered for a type and a different decoder can be registered
// for a pointer to that type. // for a pointer to that type.
// //
// If the given type is an interface, the decoder will be called when unmarshalling into a type that is that interface. // If the given type is an interface, the decoder will be called when unmarshaling into a type that is that interface.
// It will not be called when unmarshalling into a non-interface type that implements the interface. // It will not be called when unmarshaling into a non-interface type that implements the interface.
//
// Deprecated: Use Registry.RegisterTypeDecoder instead.
func (rb *RegistryBuilder) RegisterTypeDecoder(t reflect.Type, dec ValueDecoder) *RegistryBuilder { func (rb *RegistryBuilder) RegisterTypeDecoder(t reflect.Type, dec ValueDecoder) *RegistryBuilder {
rb.typeDecoders[t] = dec rb.registry.RegisterTypeDecoder(t, dec)
return rb return rb
} }
// RegisterHookDecoder will register an decoder for the provided interface type t. This decoder will be called when // RegisterHookDecoder will register an decoder for the provided interface type t. This decoder will be called when
// unmarshalling into a type if the type implements t or a pointer to the type implements t. If the provided type is not // unmarshaling into a type if the type implements t or a pointer to the type implements t. If the provided type is not
// an interface (i.e. t.Kind() != reflect.Interface), this method will panic. // an interface (i.e. t.Kind() != reflect.Interface), this method will panic.
//
// Deprecated: Use Registry.RegisterInterfaceDecoder instead.
func (rb *RegistryBuilder) RegisterHookDecoder(t reflect.Type, dec ValueDecoder) *RegistryBuilder { func (rb *RegistryBuilder) RegisterHookDecoder(t reflect.Type, dec ValueDecoder) *RegistryBuilder {
if t.Kind() != reflect.Interface { rb.registry.RegisterInterfaceDecoder(t, dec)
panicStr := fmt.Sprintf("RegisterHookDecoder expects a type with kind reflect.Interface, "+
"got type %s with kind %s", t, t.Kind())
panic(panicStr)
}
for idx, decoder := range rb.interfaceDecoders {
if decoder.i == t {
rb.interfaceDecoders[idx].vd = dec
return rb
}
}
rb.interfaceDecoders = append(rb.interfaceDecoders, interfaceValueDecoder{i: t, vd: dec})
return rb return rb
} }
// RegisterEncoder registers the provided type and encoder pair. // RegisterEncoder registers the provided type and encoder pair.
// //
// Deprecated: Use RegisterTypeEncoder or RegisterHookEncoder instead. // Deprecated: Use Registry.RegisterTypeEncoder or Registry.RegisterInterfaceEncoder instead.
func (rb *RegistryBuilder) RegisterEncoder(t reflect.Type, enc ValueEncoder) *RegistryBuilder { func (rb *RegistryBuilder) RegisterEncoder(t reflect.Type, enc ValueEncoder) *RegistryBuilder {
if t == tEmpty { if t == tEmpty {
rb.typeEncoders[t] = enc rb.registry.RegisterTypeEncoder(t, enc)
return rb return rb
} }
switch t.Kind() { switch t.Kind() {
case reflect.Interface: case reflect.Interface:
for idx, ir := range rb.interfaceEncoders { rb.registry.RegisterInterfaceEncoder(t, enc)
if ir.i == t {
rb.interfaceEncoders[idx].ve = enc
return rb
}
}
rb.interfaceEncoders = append(rb.interfaceEncoders, interfaceValueEncoder{i: t, ve: enc})
default: default:
rb.typeEncoders[t] = enc rb.registry.RegisterTypeEncoder(t, enc)
} }
return rb return rb
} }
// RegisterDecoder registers the provided type and decoder pair. // RegisterDecoder registers the provided type and decoder pair.
// //
// Deprecated: Use RegisterTypeDecoder or RegisterHookDecoder instead. // Deprecated: Use Registry.RegisterTypeDecoder or Registry.RegisterInterfaceDecoder instead.
func (rb *RegistryBuilder) RegisterDecoder(t reflect.Type, dec ValueDecoder) *RegistryBuilder { func (rb *RegistryBuilder) RegisterDecoder(t reflect.Type, dec ValueDecoder) *RegistryBuilder {
if t == nil { if t == nil {
rb.typeDecoders[nil] = dec rb.registry.RegisterTypeDecoder(t, dec)
return rb return rb
} }
if t == tEmpty { if t == tEmpty {
rb.typeDecoders[t] = dec rb.registry.RegisterTypeDecoder(t, dec)
return rb return rb
} }
switch t.Kind() { switch t.Kind() {
case reflect.Interface: case reflect.Interface:
for idx, ir := range rb.interfaceDecoders { rb.registry.RegisterInterfaceDecoder(t, dec)
if ir.i == t {
rb.interfaceDecoders[idx].vd = dec
return rb
}
}
rb.interfaceDecoders = append(rb.interfaceDecoders, interfaceValueDecoder{i: t, vd: dec})
default: default:
rb.typeDecoders[t] = dec rb.registry.RegisterTypeDecoder(t, dec)
} }
return rb return rb
} }
// RegisterDefaultEncoder will registr the provided ValueEncoder to the provided // RegisterDefaultEncoder will register the provided ValueEncoder to the provided
// kind. // kind.
//
// Deprecated: Use Registry.RegisterKindEncoder instead.
func (rb *RegistryBuilder) RegisterDefaultEncoder(kind reflect.Kind, enc ValueEncoder) *RegistryBuilder { func (rb *RegistryBuilder) RegisterDefaultEncoder(kind reflect.Kind, enc ValueEncoder) *RegistryBuilder {
rb.kindEncoders[kind] = enc rb.registry.RegisterKindEncoder(kind, enc)
return rb return rb
} }
// RegisterDefaultDecoder will register the provided ValueDecoder to the // RegisterDefaultDecoder will register the provided ValueDecoder to the
// provided kind. // provided kind.
//
// Deprecated: Use Registry.RegisterKindDecoder instead.
func (rb *RegistryBuilder) RegisterDefaultDecoder(kind reflect.Kind, dec ValueDecoder) *RegistryBuilder { func (rb *RegistryBuilder) RegisterDefaultDecoder(kind reflect.Kind, dec ValueDecoder) *RegistryBuilder {
rb.kindDecoders[kind] = dec rb.registry.RegisterKindDecoder(kind, dec)
return rb return rb
} }
@ -256,120 +205,233 @@ func (rb *RegistryBuilder) RegisterDefaultDecoder(kind reflect.Kind, dec ValueDe
// to decode to bson.Raw, use the following code: // to decode to bson.Raw, use the following code:
// //
// rb.RegisterTypeMapEntry(bsontype.EmbeddedDocument, reflect.TypeOf(bson.Raw{})) // rb.RegisterTypeMapEntry(bsontype.EmbeddedDocument, reflect.TypeOf(bson.Raw{}))
//
// Deprecated: Use Registry.RegisterTypeMapEntry instead.
func (rb *RegistryBuilder) RegisterTypeMapEntry(bt bsontype.Type, rt reflect.Type) *RegistryBuilder { func (rb *RegistryBuilder) RegisterTypeMapEntry(bt bsontype.Type, rt reflect.Type) *RegistryBuilder {
rb.typeMap[bt] = rt rb.registry.RegisterTypeMapEntry(bt, rt)
return rb return rb
} }
// Build creates a Registry from the current state of this RegistryBuilder. // Build creates a Registry from the current state of this RegistryBuilder.
//
// Deprecated: Use NewRegistry instead.
func (rb *RegistryBuilder) Build() *Registry { func (rb *RegistryBuilder) Build() *Registry {
registry := new(Registry) r := &Registry{
interfaceEncoders: append([]interfaceValueEncoder(nil), rb.registry.interfaceEncoders...),
registry.typeEncoders = make(map[reflect.Type]ValueEncoder) interfaceDecoders: append([]interfaceValueDecoder(nil), rb.registry.interfaceDecoders...),
for t, enc := range rb.typeEncoders { typeEncoders: rb.registry.typeEncoders.Clone(),
registry.typeEncoders[t] = enc typeDecoders: rb.registry.typeDecoders.Clone(),
kindEncoders: rb.registry.kindEncoders.Clone(),
kindDecoders: rb.registry.kindDecoders.Clone(),
} }
rb.registry.typeMap.Range(func(k, v interface{}) bool {
registry.typeDecoders = make(map[reflect.Type]ValueDecoder) if k != nil && v != nil {
for t, dec := range rb.typeDecoders { r.typeMap.Store(k, v)
registry.typeDecoders[t] = dec }
} return true
})
registry.interfaceEncoders = make([]interfaceValueEncoder, len(rb.interfaceEncoders)) return r
copy(registry.interfaceEncoders, rb.interfaceEncoders)
registry.interfaceDecoders = make([]interfaceValueDecoder, len(rb.interfaceDecoders))
copy(registry.interfaceDecoders, rb.interfaceDecoders)
registry.kindEncoders = make(map[reflect.Kind]ValueEncoder)
for kind, enc := range rb.kindEncoders {
registry.kindEncoders[kind] = enc
}
registry.kindDecoders = make(map[reflect.Kind]ValueDecoder)
for kind, dec := range rb.kindDecoders {
registry.kindDecoders[kind] = dec
}
registry.typeMap = make(map[bsontype.Type]reflect.Type)
for bt, rt := range rb.typeMap {
registry.typeMap[bt] = rt
}
return registry
} }
// LookupEncoder inspects the registry for an encoder for the given type. The lookup precedence works as follows: // A Registry is used to store and retrieve codecs for types and interfaces. This type is the main
// typed passed around and Encoders and Decoders are constructed from it.
type Registry struct {
interfaceEncoders []interfaceValueEncoder
interfaceDecoders []interfaceValueDecoder
typeEncoders *typeEncoderCache
typeDecoders *typeDecoderCache
kindEncoders *kindEncoderCache
kindDecoders *kindDecoderCache
typeMap sync.Map // map[bsontype.Type]reflect.Type
}
// NewRegistry creates a new empty Registry.
func NewRegistry() *Registry {
return &Registry{
typeEncoders: new(typeEncoderCache),
typeDecoders: new(typeDecoderCache),
kindEncoders: new(kindEncoderCache),
kindDecoders: new(kindDecoderCache),
}
}
// RegisterTypeEncoder registers the provided ValueEncoder for the provided type.
// //
// 1. An encoder registered for the exact type. If the given type represents an interface, an encoder registered using // The type will be used as provided, so an encoder can be registered for a type and a different
// RegisterTypeEncoder for the interface will be selected. // encoder can be registered for a pointer to that type.
// //
// 2. An encoder registered using RegisterHookEncoder for an interface implemented by the type or by a pointer to the // If the given type is an interface, the encoder will be called when marshaling a type that is
// type. // that interface. It will not be called when marshaling a non-interface type that implements the
// interface. To get the latter behavior, call RegisterHookEncoder instead.
// //
// 3. An encoder registered for the reflect.Kind of the value. // RegisterTypeEncoder should not be called concurrently with any other Registry method.
func (r *Registry) RegisterTypeEncoder(valueType reflect.Type, enc ValueEncoder) {
r.typeEncoders.Store(valueType, enc)
}
// RegisterTypeDecoder registers the provided ValueDecoder for the provided type.
// //
// If no encoder is found, an error of type ErrNoEncoder is returned. // The type will be used as provided, so a decoder can be registered for a type and a different
func (r *Registry) LookupEncoder(t reflect.Type) (ValueEncoder, error) { // decoder can be registered for a pointer to that type.
encodererr := ErrNoEncoder{Type: t} //
r.mu.RLock() // If the given type is an interface, the decoder will be called when unmarshaling into a type that
enc, found := r.lookupTypeEncoder(t) // is that interface. It will not be called when unmarshaling into a non-interface type that
r.mu.RUnlock() // implements the interface. To get the latter behavior, call RegisterHookDecoder instead.
//
// RegisterTypeDecoder should not be called concurrently with any other Registry method.
func (r *Registry) RegisterTypeDecoder(valueType reflect.Type, dec ValueDecoder) {
r.typeDecoders.Store(valueType, dec)
}
// RegisterKindEncoder registers the provided ValueEncoder for the provided kind.
//
// Use RegisterKindEncoder to register an encoder for any type with the same underlying kind. For
// example, consider the type MyInt defined as
//
// type MyInt int32
//
// To define an encoder for MyInt and int32, use RegisterKindEncoder like
//
// reg.RegisterKindEncoder(reflect.Int32, myEncoder)
//
// RegisterKindEncoder should not be called concurrently with any other Registry method.
func (r *Registry) RegisterKindEncoder(kind reflect.Kind, enc ValueEncoder) {
r.kindEncoders.Store(kind, enc)
}
// RegisterKindDecoder registers the provided ValueDecoder for the provided kind.
//
// Use RegisterKindDecoder to register a decoder for any type with the same underlying kind. For
// example, consider the type MyInt defined as
//
// type MyInt int32
//
// To define an decoder for MyInt and int32, use RegisterKindDecoder like
//
// reg.RegisterKindDecoder(reflect.Int32, myDecoder)
//
// RegisterKindDecoder should not be called concurrently with any other Registry method.
func (r *Registry) RegisterKindDecoder(kind reflect.Kind, dec ValueDecoder) {
r.kindDecoders.Store(kind, dec)
}
// RegisterInterfaceEncoder registers an encoder for the provided interface type iface. This encoder will
// be called when marshaling a type if the type implements iface or a pointer to the type
// implements iface. If the provided type is not an interface
// (i.e. iface.Kind() != reflect.Interface), this method will panic.
//
// RegisterInterfaceEncoder should not be called concurrently with any other Registry method.
func (r *Registry) RegisterInterfaceEncoder(iface reflect.Type, enc ValueEncoder) {
if iface.Kind() != reflect.Interface {
panicStr := fmt.Errorf("RegisterInterfaceEncoder expects a type with kind reflect.Interface, "+
"got type %s with kind %s", iface, iface.Kind())
panic(panicStr)
}
for idx, encoder := range r.interfaceEncoders {
if encoder.i == iface {
r.interfaceEncoders[idx].ve = enc
return
}
}
r.interfaceEncoders = append(r.interfaceEncoders, interfaceValueEncoder{i: iface, ve: enc})
}
// RegisterInterfaceDecoder registers an decoder for the provided interface type iface. This decoder will
// be called when unmarshaling into a type if the type implements iface or a pointer to the type
// implements iface. If the provided type is not an interface (i.e. iface.Kind() != reflect.Interface),
// this method will panic.
//
// RegisterInterfaceDecoder should not be called concurrently with any other Registry method.
func (r *Registry) RegisterInterfaceDecoder(iface reflect.Type, dec ValueDecoder) {
if iface.Kind() != reflect.Interface {
panicStr := fmt.Errorf("RegisterInterfaceDecoder expects a type with kind reflect.Interface, "+
"got type %s with kind %s", iface, iface.Kind())
panic(panicStr)
}
for idx, decoder := range r.interfaceDecoders {
if decoder.i == iface {
r.interfaceDecoders[idx].vd = dec
return
}
}
r.interfaceDecoders = append(r.interfaceDecoders, interfaceValueDecoder{i: iface, vd: dec})
}
// RegisterTypeMapEntry will register the provided type to the BSON type. The primary usage for this
// mapping is decoding situations where an empty interface is used and a default type needs to be
// created and decoded into.
//
// By default, BSON documents will decode into interface{} values as bson.D. To change the default type for BSON
// documents, a type map entry for bsontype.EmbeddedDocument should be registered. For example, to force BSON documents
// to decode to bson.Raw, use the following code:
//
// reg.RegisterTypeMapEntry(bsontype.EmbeddedDocument, reflect.TypeOf(bson.Raw{}))
func (r *Registry) RegisterTypeMapEntry(bt bsontype.Type, rt reflect.Type) {
r.typeMap.Store(bt, rt)
}
// LookupEncoder returns the first matching encoder in the Registry. It uses the following lookup
// order:
//
// 1. An encoder registered for the exact type. If the given type is an interface, an encoder
// registered using RegisterTypeEncoder for that interface will be selected.
//
// 2. An encoder registered using RegisterInterfaceEncoder for an interface implemented by the type
// or by a pointer to the type.
//
// 3. An encoder registered using RegisterKindEncoder for the kind of value.
//
// If no encoder is found, an error of type ErrNoEncoder is returned. LookupEncoder is safe for
// concurrent use by multiple goroutines after all codecs and encoders are registered.
func (r *Registry) LookupEncoder(valueType reflect.Type) (ValueEncoder, error) {
if valueType == nil {
return nil, ErrNoEncoder{Type: valueType}
}
enc, found := r.lookupTypeEncoder(valueType)
if found { if found {
if enc == nil { if enc == nil {
return nil, ErrNoEncoder{Type: t} return nil, ErrNoEncoder{Type: valueType}
} }
return enc, nil return enc, nil
} }
enc, found = r.lookupInterfaceEncoder(t, true) enc, found = r.lookupInterfaceEncoder(valueType, true)
if found { if found {
r.mu.Lock() return r.typeEncoders.LoadOrStore(valueType, enc), nil
r.typeEncoders[t] = enc
r.mu.Unlock()
return enc, nil
} }
if t == nil { if v, ok := r.kindEncoders.Load(valueType.Kind()); ok {
r.mu.Lock() return r.storeTypeEncoder(valueType, v), nil
r.typeEncoders[t] = nil
r.mu.Unlock()
return nil, encodererr
} }
return nil, ErrNoEncoder{Type: valueType}
enc, found = r.kindEncoders[t.Kind()]
if !found {
r.mu.Lock()
r.typeEncoders[t] = nil
r.mu.Unlock()
return nil, encodererr
}
r.mu.Lock()
r.typeEncoders[t] = enc
r.mu.Unlock()
return enc, nil
} }
func (r *Registry) lookupTypeEncoder(t reflect.Type) (ValueEncoder, bool) { func (r *Registry) storeTypeEncoder(rt reflect.Type, enc ValueEncoder) ValueEncoder {
enc, found := r.typeEncoders[t] return r.typeEncoders.LoadOrStore(rt, enc)
return enc, found
} }
func (r *Registry) lookupInterfaceEncoder(t reflect.Type, allowAddr bool) (ValueEncoder, bool) { func (r *Registry) lookupTypeEncoder(rt reflect.Type) (ValueEncoder, bool) {
if t == nil { return r.typeEncoders.Load(rt)
}
func (r *Registry) lookupInterfaceEncoder(valueType reflect.Type, allowAddr bool) (ValueEncoder, bool) {
if valueType == nil {
return nil, false return nil, false
} }
for _, ienc := range r.interfaceEncoders { for _, ienc := range r.interfaceEncoders {
if t.Implements(ienc.i) { if valueType.Implements(ienc.i) {
return ienc.ve, true return ienc.ve, true
} }
if allowAddr && t.Kind() != reflect.Ptr && reflect.PtrTo(t).Implements(ienc.i) { if allowAddr && valueType.Kind() != reflect.Ptr && reflect.PtrTo(valueType).Implements(ienc.i) {
// if *t implements an interface, this will catch if t implements an interface further ahead // if *t implements an interface, this will catch if t implements an interface further
// in interfaceEncoders // ahead in interfaceEncoders
defaultEnc, found := r.lookupInterfaceEncoder(t, false) defaultEnc, found := r.lookupInterfaceEncoder(valueType, false)
if !found { if !found {
defaultEnc = r.kindEncoders[t.Kind()] defaultEnc, _ = r.kindEncoders.Load(valueType.Kind())
} }
return newCondAddrEncoder(ienc.ve, defaultEnc), true return newCondAddrEncoder(ienc.ve, defaultEnc), true
} }
@ -377,70 +439,61 @@ func (r *Registry) lookupInterfaceEncoder(t reflect.Type, allowAddr bool) (Value
return nil, false return nil, false
} }
// LookupDecoder inspects the registry for an decoder for the given type. The lookup precedence works as follows: // LookupDecoder returns the first matching decoder in the Registry. It uses the following lookup
// order:
// //
// 1. A decoder registered for the exact type. If the given type represents an interface, a decoder registered using // 1. A decoder registered for the exact type. If the given type is an interface, a decoder
// RegisterTypeDecoder for the interface will be selected. // registered using RegisterTypeDecoder for that interface will be selected.
// //
// 2. A decoder registered using RegisterHookDecoder for an interface implemented by the type or by a pointer to the // 2. A decoder registered using RegisterInterfaceDecoder for an interface implemented by the type or by
// type. // a pointer to the type.
// //
// 3. A decoder registered for the reflect.Kind of the value. // 3. A decoder registered using RegisterKindDecoder for the kind of value.
// //
// If no decoder is found, an error of type ErrNoDecoder is returned. // If no decoder is found, an error of type ErrNoDecoder is returned. LookupDecoder is safe for
func (r *Registry) LookupDecoder(t reflect.Type) (ValueDecoder, error) { // concurrent use by multiple goroutines after all codecs and decoders are registered.
if t == nil { func (r *Registry) LookupDecoder(valueType reflect.Type) (ValueDecoder, error) {
if valueType == nil {
return nil, ErrNilType return nil, ErrNilType
} }
decodererr := ErrNoDecoder{Type: t} dec, found := r.lookupTypeDecoder(valueType)
r.mu.RLock()
dec, found := r.lookupTypeDecoder(t)
r.mu.RUnlock()
if found { if found {
if dec == nil { if dec == nil {
return nil, ErrNoDecoder{Type: t} return nil, ErrNoDecoder{Type: valueType}
} }
return dec, nil return dec, nil
} }
dec, found = r.lookupInterfaceDecoder(t, true) dec, found = r.lookupInterfaceDecoder(valueType, true)
if found { if found {
r.mu.Lock() return r.storeTypeDecoder(valueType, dec), nil
r.typeDecoders[t] = dec
r.mu.Unlock()
return dec, nil
} }
dec, found = r.kindDecoders[t.Kind()] if v, ok := r.kindDecoders.Load(valueType.Kind()); ok {
if !found { return r.storeTypeDecoder(valueType, v), nil
r.mu.Lock()
r.typeDecoders[t] = nil
r.mu.Unlock()
return nil, decodererr
} }
return nil, ErrNoDecoder{Type: valueType}
r.mu.Lock()
r.typeDecoders[t] = dec
r.mu.Unlock()
return dec, nil
} }
func (r *Registry) lookupTypeDecoder(t reflect.Type) (ValueDecoder, bool) { func (r *Registry) lookupTypeDecoder(valueType reflect.Type) (ValueDecoder, bool) {
dec, found := r.typeDecoders[t] return r.typeDecoders.Load(valueType)
return dec, found
} }
func (r *Registry) lookupInterfaceDecoder(t reflect.Type, allowAddr bool) (ValueDecoder, bool) { func (r *Registry) storeTypeDecoder(typ reflect.Type, dec ValueDecoder) ValueDecoder {
return r.typeDecoders.LoadOrStore(typ, dec)
}
func (r *Registry) lookupInterfaceDecoder(valueType reflect.Type, allowAddr bool) (ValueDecoder, bool) {
for _, idec := range r.interfaceDecoders { for _, idec := range r.interfaceDecoders {
if t.Implements(idec.i) { if valueType.Implements(idec.i) {
return idec.vd, true return idec.vd, true
} }
if allowAddr && t.Kind() != reflect.Ptr && reflect.PtrTo(t).Implements(idec.i) { if allowAddr && valueType.Kind() != reflect.Ptr && reflect.PtrTo(valueType).Implements(idec.i) {
// if *t implements an interface, this will catch if t implements an interface further ahead // if *t implements an interface, this will catch if t implements an interface further
// in interfaceDecoders // ahead in interfaceDecoders
defaultDec, found := r.lookupInterfaceDecoder(t, false) defaultDec, found := r.lookupInterfaceDecoder(valueType, false)
if !found { if !found {
defaultDec = r.kindDecoders[t.Kind()] defaultDec, _ = r.kindDecoders.Load(valueType.Kind())
} }
return newCondAddrDecoder(idec.vd, defaultDec), true return newCondAddrDecoder(idec.vd, defaultDec), true
} }
@ -450,12 +503,14 @@ func (r *Registry) lookupInterfaceDecoder(t reflect.Type, allowAddr bool) (Value
// LookupTypeMapEntry inspects the registry's type map for a Go type for the corresponding BSON // LookupTypeMapEntry inspects the registry's type map for a Go type for the corresponding BSON
// type. If no type is found, ErrNoTypeMapEntry is returned. // type. If no type is found, ErrNoTypeMapEntry is returned.
//
// LookupTypeMapEntry should not be called concurrently with any other Registry method.
func (r *Registry) LookupTypeMapEntry(bt bsontype.Type) (reflect.Type, error) { func (r *Registry) LookupTypeMapEntry(bt bsontype.Type) (reflect.Type, error) {
t, ok := r.typeMap[bt] v, ok := r.typeMap.Load(bt)
if !ok || t == nil { if v == nil || !ok {
return nil, ErrNoTypeMapEntry{Type: bt} return nil, ErrNoTypeMapEntry{Type: bt}
} }
return t, nil return v.(reflect.Type), nil
} }
type interfaceValueEncoder struct { type interfaceValueEncoder struct {

View file

@ -7,6 +7,7 @@
package bsoncodec package bsoncodec
import ( import (
"errors"
"fmt" "fmt"
"reflect" "reflect"
@ -19,13 +20,35 @@
var defaultSliceCodec = NewSliceCodec() var defaultSliceCodec = NewSliceCodec()
// SliceCodec is the Codec used for slice values. // SliceCodec is the Codec used for slice values.
//
// Deprecated: SliceCodec will not be directly configurable in Go Driver 2.0. To
// configure the slice encode and decode behavior, use the configuration methods
// on a [go.mongodb.org/mongo-driver/bson.Encoder] or
// [go.mongodb.org/mongo-driver/bson.Decoder]. To configure the slice encode and
// decode behavior for a mongo.Client, use
// [go.mongodb.org/mongo-driver/mongo/options.ClientOptions.SetBSONOptions].
//
// For example, to configure a mongo.Client to marshal nil Go slices as empty
// BSON arrays, use:
//
// opt := options.Client().SetBSONOptions(&options.BSONOptions{
// NilSliceAsEmpty: true,
// })
//
// See the deprecation notice for each field in SliceCodec for the corresponding
// settings.
type SliceCodec struct { type SliceCodec struct {
// EncodeNilAsEmpty causes EncodeValue to marshal nil Go slices as empty BSON arrays instead of
// BSON null.
//
// Deprecated: Use bson.Encoder.NilSliceAsEmpty instead.
EncodeNilAsEmpty bool EncodeNilAsEmpty bool
} }
var _ ValueCodec = &MapCodec{}
// NewSliceCodec returns a MapCodec with options opts. // NewSliceCodec returns a MapCodec with options opts.
//
// Deprecated: NewSliceCodec will not be available in Go Driver 2.0. See
// [SliceCodec] for more details.
func NewSliceCodec(opts ...*bsonoptions.SliceCodecOptions) *SliceCodec { func NewSliceCodec(opts ...*bsonoptions.SliceCodecOptions) *SliceCodec {
sliceOpt := bsonoptions.MergeSliceCodecOptions(opts...) sliceOpt := bsonoptions.MergeSliceCodecOptions(opts...)
@ -42,21 +65,19 @@ func (sc SliceCodec) EncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val re
return ValueEncoderError{Name: "SliceEncodeValue", Kinds: []reflect.Kind{reflect.Slice}, Received: val} return ValueEncoderError{Name: "SliceEncodeValue", Kinds: []reflect.Kind{reflect.Slice}, Received: val}
} }
if val.IsNil() && !sc.EncodeNilAsEmpty { if val.IsNil() && !sc.EncodeNilAsEmpty && !ec.nilSliceAsEmpty {
return vw.WriteNull() return vw.WriteNull()
} }
// If we have a []byte we want to treat it as a binary instead of as an array. // If we have a []byte we want to treat it as a binary instead of as an array.
if val.Type().Elem() == tByte { if val.Type().Elem() == tByte {
var byteSlice []byte byteSlice := make([]byte, val.Len())
for idx := 0; idx < val.Len(); idx++ { reflect.Copy(reflect.ValueOf(byteSlice), val)
byteSlice = append(byteSlice, val.Index(idx).Interface().(byte))
}
return vw.WriteBinary(byteSlice) return vw.WriteBinary(byteSlice)
} }
// If we have a []primitive.E we want to treat it as a document instead of as an array. // If we have a []primitive.E we want to treat it as a document instead of as an array.
if val.Type().ConvertibleTo(tD) { if val.Type() == tD || val.Type().ConvertibleTo(tD) {
d := val.Convert(tD).Interface().(primitive.D) d := val.Convert(tD).Interface().(primitive.D)
dw, err := vw.WriteDocument() dw, err := vw.WriteDocument()
@ -87,7 +108,7 @@ func (sc SliceCodec) EncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val re
for idx := 0; idx < val.Len(); idx++ { for idx := 0; idx < val.Len(); idx++ {
currEncoder, currVal, lookupErr := defaultValueEncoders.lookupElementEncoder(ec, encoder, val.Index(idx)) currEncoder, currVal, lookupErr := defaultValueEncoders.lookupElementEncoder(ec, encoder, val.Index(idx))
if lookupErr != nil && lookupErr != errInvalidValue { if lookupErr != nil && !errors.Is(lookupErr, errInvalidValue) {
return lookupErr return lookupErr
} }
@ -96,7 +117,7 @@ func (sc SliceCodec) EncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val re
return err return err
} }
if lookupErr == errInvalidValue { if errors.Is(lookupErr, errInvalidValue) {
err = vw.WriteNull() err = vw.WriteNull()
if err != nil { if err != nil {
return err return err
@ -145,11 +166,8 @@ func (sc *SliceCodec) DecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val r
if val.IsNil() { if val.IsNil() {
val.Set(reflect.MakeSlice(val.Type(), 0, len(data))) val.Set(reflect.MakeSlice(val.Type(), 0, len(data)))
} }
val.SetLen(0) val.SetLen(0)
for _, elem := range data { val.Set(reflect.AppendSlice(val, reflect.ValueOf(data)))
val.Set(reflect.Append(val, reflect.ValueOf(elem)))
}
return nil return nil
case bsontype.String: case bsontype.String:
if sliceType := val.Type().Elem(); sliceType != tByte { if sliceType := val.Type().Elem(); sliceType != tByte {
@ -164,11 +182,8 @@ func (sc *SliceCodec) DecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val r
if val.IsNil() { if val.IsNil() {
val.Set(reflect.MakeSlice(val.Type(), 0, len(byteStr))) val.Set(reflect.MakeSlice(val.Type(), 0, len(byteStr)))
} }
val.SetLen(0) val.SetLen(0)
for _, elem := range byteStr { val.Set(reflect.AppendSlice(val, reflect.ValueOf(byteStr)))
val.Set(reflect.Append(val, reflect.ValueOf(elem)))
}
return nil return nil
default: default:
return fmt.Errorf("cannot decode %v into a slice", vrType) return fmt.Errorf("cannot decode %v into a slice", vrType)

View file

@ -15,26 +15,46 @@
"go.mongodb.org/mongo-driver/bson/bsontype" "go.mongodb.org/mongo-driver/bson/bsontype"
) )
// StringCodec is the Codec used for struct values. // StringCodec is the Codec used for string values.
//
// Deprecated: StringCodec will not be directly accessible in Go Driver 2.0. To
// override the default string encode and decode behavior, create a new registry
// with [go.mongodb.org/mongo-driver/bson.NewRegistry] and register a new
// encoder and decoder for strings.
//
// For example,
//
// reg := bson.NewRegistry()
// reg.RegisterKindEncoder(reflect.String, myStringEncoder)
// reg.RegisterKindDecoder(reflect.String, myStringDecoder)
type StringCodec struct { type StringCodec struct {
// DecodeObjectIDAsHex specifies if object IDs should be decoded as their hex representation.
// If false, a string made from the raw object ID bytes will be used. Defaults to true.
//
// Deprecated: Decoding object IDs as raw bytes will not be supported in Go Driver 2.0.
DecodeObjectIDAsHex bool DecodeObjectIDAsHex bool
} }
var ( var (
defaultStringCodec = NewStringCodec() defaultStringCodec = NewStringCodec()
_ ValueCodec = defaultStringCodec // Assert that defaultStringCodec satisfies the typeDecoder interface, which allows it to be
// used by collection type decoders (e.g. map, slice, etc) to set individual values in a
// collection.
_ typeDecoder = defaultStringCodec _ typeDecoder = defaultStringCodec
) )
// NewStringCodec returns a StringCodec with options opts. // NewStringCodec returns a StringCodec with options opts.
//
// Deprecated: NewStringCodec will not be available in Go Driver 2.0. See
// [StringCodec] for more details.
func NewStringCodec(opts ...*bsonoptions.StringCodecOptions) *StringCodec { func NewStringCodec(opts ...*bsonoptions.StringCodecOptions) *StringCodec {
stringOpt := bsonoptions.MergeStringCodecOptions(opts...) stringOpt := bsonoptions.MergeStringCodecOptions(opts...)
return &StringCodec{*stringOpt.DecodeObjectIDAsHex} return &StringCodec{*stringOpt.DecodeObjectIDAsHex}
} }
// EncodeValue is the ValueEncoder for string types. // EncodeValue is the ValueEncoder for string types.
func (sc *StringCodec) EncodeValue(ectx EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { func (sc *StringCodec) EncodeValue(_ EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {
if val.Kind() != reflect.String { if val.Kind() != reflect.String {
return ValueEncoderError{ return ValueEncoderError{
Name: "StringEncodeValue", Name: "StringEncodeValue",
@ -46,7 +66,7 @@ func (sc *StringCodec) EncodeValue(ectx EncodeContext, vw bsonrw.ValueWriter, va
return vw.WriteString(val.String()) return vw.WriteString(val.String())
} }
func (sc *StringCodec) decodeType(dc DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) { func (sc *StringCodec) decodeType(_ DecodeContext, vr bsonrw.ValueReader, t reflect.Type) (reflect.Value, error) {
if t.Kind() != reflect.String { if t.Kind() != reflect.String {
return emptyValue, ValueDecoderError{ return emptyValue, ValueDecoderError{
Name: "StringDecodeValue", Name: "StringDecodeValue",
@ -71,6 +91,7 @@ func (sc *StringCodec) decodeType(dc DecodeContext, vr bsonrw.ValueReader, t ref
if sc.DecodeObjectIDAsHex { if sc.DecodeObjectIDAsHex {
str = oid.Hex() str = oid.Hex()
} else { } else {
// TODO(GODRIVER-2796): Return an error here instead of decoding to a garbled string.
byteArray := [12]byte(oid) byteArray := [12]byte(oid)
str = string(byteArray[:]) str = string(byteArray[:])
} }

View file

@ -59,14 +59,58 @@ type Zeroer interface {
} }
// StructCodec is the Codec used for struct values. // StructCodec is the Codec used for struct values.
//
// Deprecated: StructCodec will not be directly configurable in Go Driver 2.0.
// To configure the struct encode and decode behavior, use the configuration
// methods on a [go.mongodb.org/mongo-driver/bson.Encoder] or
// [go.mongodb.org/mongo-driver/bson.Decoder]. To configure the struct encode
// and decode behavior for a mongo.Client, use
// [go.mongodb.org/mongo-driver/mongo/options.ClientOptions.SetBSONOptions].
//
// For example, to configure a mongo.Client to omit zero-value structs when
// using the "omitempty" struct tag, use:
//
// opt := options.Client().SetBSONOptions(&options.BSONOptions{
// OmitZeroStruct: true,
// })
//
// See the deprecation notice for each field in StructCodec for the corresponding
// settings.
type StructCodec struct { type StructCodec struct {
cache map[reflect.Type]*structDescription cache sync.Map // map[reflect.Type]*structDescription
l sync.RWMutex parser StructTagParser
parser StructTagParser
DecodeZeroStruct bool // DecodeZeroStruct causes DecodeValue to delete any existing values from Go structs in the
DecodeDeepZeroInline bool // destination value passed to Decode before unmarshaling BSON documents into them.
EncodeOmitDefaultStruct bool //
AllowUnexportedFields bool // Deprecated: Use bson.Decoder.ZeroStructs or options.BSONOptions.ZeroStructs instead.
DecodeZeroStruct bool
// DecodeDeepZeroInline causes DecodeValue to delete any existing values from Go structs in the
// destination value passed to Decode before unmarshaling BSON documents into them.
//
// Deprecated: DecodeDeepZeroInline will not be supported in Go Driver 2.0.
DecodeDeepZeroInline bool
// EncodeOmitDefaultStruct causes the Encoder to consider the zero value for a struct (e.g.
// MyStruct{}) as empty and omit it from the marshaled BSON when the "omitempty" struct tag
// option is set.
//
// Deprecated: Use bson.Encoder.OmitZeroStruct or options.BSONOptions.OmitZeroStruct instead.
EncodeOmitDefaultStruct bool
// AllowUnexportedFields allows encoding and decoding values from un-exported struct fields.
//
// Deprecated: AllowUnexportedFields does not work on recent versions of Go and will not be
// supported in Go Driver 2.0.
AllowUnexportedFields bool
// OverwriteDuplicatedInlinedFields, if false, causes EncodeValue to return an error if there is
// a duplicate field in the marshaled BSON when the "inline" struct tag option is set. The
// default value is true.
//
// Deprecated: Use bson.Encoder.ErrorOnInlineDuplicates or
// options.BSONOptions.ErrorOnInlineDuplicates instead.
OverwriteDuplicatedInlinedFields bool OverwriteDuplicatedInlinedFields bool
} }
@ -74,6 +118,9 @@ type StructCodec struct {
var _ ValueDecoder = &StructCodec{} var _ ValueDecoder = &StructCodec{}
// NewStructCodec returns a StructCodec that uses p for struct tag parsing. // NewStructCodec returns a StructCodec that uses p for struct tag parsing.
//
// Deprecated: NewStructCodec will not be available in Go Driver 2.0. See
// [StructCodec] for more details.
func NewStructCodec(p StructTagParser, opts ...*bsonoptions.StructCodecOptions) (*StructCodec, error) { func NewStructCodec(p StructTagParser, opts ...*bsonoptions.StructCodecOptions) (*StructCodec, error) {
if p == nil { if p == nil {
return nil, errors.New("a StructTagParser must be provided to NewStructCodec") return nil, errors.New("a StructTagParser must be provided to NewStructCodec")
@ -82,7 +129,6 @@ func NewStructCodec(p StructTagParser, opts ...*bsonoptions.StructCodecOptions)
structOpt := bsonoptions.MergeStructCodecOptions(opts...) structOpt := bsonoptions.MergeStructCodecOptions(opts...)
codec := &StructCodec{ codec := &StructCodec{
cache: make(map[reflect.Type]*structDescription),
parser: p, parser: p,
} }
@ -106,12 +152,12 @@ func NewStructCodec(p StructTagParser, opts ...*bsonoptions.StructCodecOptions)
} }
// EncodeValue handles encoding generic struct types. // EncodeValue handles encoding generic struct types.
func (sc *StructCodec) EncodeValue(r EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { func (sc *StructCodec) EncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {
if !val.IsValid() || val.Kind() != reflect.Struct { if !val.IsValid() || val.Kind() != reflect.Struct {
return ValueEncoderError{Name: "StructCodec.EncodeValue", Kinds: []reflect.Kind{reflect.Struct}, Received: val} return ValueEncoderError{Name: "StructCodec.EncodeValue", Kinds: []reflect.Kind{reflect.Struct}, Received: val}
} }
sd, err := sc.describeStruct(r.Registry, val.Type()) sd, err := sc.describeStruct(ec.Registry, val.Type(), ec.useJSONStructTags, ec.errorOnInlineDuplicates)
if err != nil { if err != nil {
return err return err
} }
@ -131,13 +177,13 @@ func (sc *StructCodec) EncodeValue(r EncodeContext, vw bsonrw.ValueWriter, val r
} }
} }
desc.encoder, rv, err = defaultValueEncoders.lookupElementEncoder(r, desc.encoder, rv) desc.encoder, rv, err = defaultValueEncoders.lookupElementEncoder(ec, desc.encoder, rv)
if err != nil && err != errInvalidValue { if err != nil && !errors.Is(err, errInvalidValue) {
return err return err
} }
if err == errInvalidValue { if errors.Is(err, errInvalidValue) {
if desc.omitEmpty { if desc.omitEmpty {
continue continue
} }
@ -158,17 +204,17 @@ func (sc *StructCodec) EncodeValue(r EncodeContext, vw bsonrw.ValueWriter, val r
encoder := desc.encoder encoder := desc.encoder
var isZero bool var empty bool
rvInterface := rv.Interface()
if cz, ok := encoder.(CodecZeroer); ok { if cz, ok := encoder.(CodecZeroer); ok {
isZero = cz.IsTypeZero(rvInterface) empty = cz.IsTypeZero(rv.Interface())
} else if rv.Kind() == reflect.Interface { } else if rv.Kind() == reflect.Interface {
// sc.isZero will not treat an interface rv as an interface, so we need to check for the zero interface separately. // isEmpty will not treat an interface rv as an interface, so we need to check for the
isZero = rv.IsNil() // nil interface separately.
empty = rv.IsNil()
} else { } else {
isZero = sc.isZero(rvInterface) empty = isEmpty(rv, sc.EncodeOmitDefaultStruct || ec.omitZeroStruct)
} }
if desc.omitEmpty && isZero { if desc.omitEmpty && empty {
continue continue
} }
@ -177,7 +223,17 @@ func (sc *StructCodec) EncodeValue(r EncodeContext, vw bsonrw.ValueWriter, val r
return err return err
} }
ectx := EncodeContext{Registry: r.Registry, MinSize: desc.minSize} ectx := EncodeContext{
Registry: ec.Registry,
MinSize: desc.minSize || ec.MinSize,
errorOnInlineDuplicates: ec.errorOnInlineDuplicates,
stringifyMapKeysWithFmt: ec.stringifyMapKeysWithFmt,
nilMapAsEmpty: ec.nilMapAsEmpty,
nilSliceAsEmpty: ec.nilSliceAsEmpty,
nilByteSliceAsEmpty: ec.nilByteSliceAsEmpty,
omitZeroStruct: ec.omitZeroStruct,
useJSONStructTags: ec.useJSONStructTags,
}
err = encoder.EncodeValue(ectx, vw2, rv) err = encoder.EncodeValue(ectx, vw2, rv)
if err != nil { if err != nil {
return err return err
@ -191,15 +247,15 @@ func (sc *StructCodec) EncodeValue(r EncodeContext, vw bsonrw.ValueWriter, val r
return exists return exists
} }
return defaultMapCodec.mapEncodeValue(r, dw, rv, collisionFn) return defaultMapCodec.mapEncodeValue(ec, dw, rv, collisionFn)
} }
return dw.WriteDocumentEnd() return dw.WriteDocumentEnd()
} }
func newDecodeError(key string, original error) error { func newDecodeError(key string, original error) error {
de, ok := original.(*DecodeError) var de *DecodeError
if !ok { if !errors.As(original, &de) {
return &DecodeError{ return &DecodeError{
keys: []string{key}, keys: []string{key},
wrapped: original, wrapped: original,
@ -213,7 +269,7 @@ func newDecodeError(key string, original error) error {
// DecodeValue implements the Codec interface. // DecodeValue implements the Codec interface.
// By default, map types in val will not be cleared. If a map has existing key/value pairs, it will be extended with the new ones from vr. // By default, map types in val will not be cleared. If a map has existing key/value pairs, it will be extended with the new ones from vr.
// For slices, the decoder will set the length of the slice to zero and append all elements. The underlying array will not be cleared. // For slices, the decoder will set the length of the slice to zero and append all elements. The underlying array will not be cleared.
func (sc *StructCodec) DecodeValue(r DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { func (sc *StructCodec) DecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
if !val.CanSet() || val.Kind() != reflect.Struct { if !val.CanSet() || val.Kind() != reflect.Struct {
return ValueDecoderError{Name: "StructCodec.DecodeValue", Kinds: []reflect.Kind{reflect.Struct}, Received: val} return ValueDecoderError{Name: "StructCodec.DecodeValue", Kinds: []reflect.Kind{reflect.Struct}, Received: val}
} }
@ -238,12 +294,12 @@ func (sc *StructCodec) DecodeValue(r DecodeContext, vr bsonrw.ValueReader, val r
return fmt.Errorf("cannot decode %v into a %s", vrType, val.Type()) return fmt.Errorf("cannot decode %v into a %s", vrType, val.Type())
} }
sd, err := sc.describeStruct(r.Registry, val.Type()) sd, err := sc.describeStruct(dc.Registry, val.Type(), dc.useJSONStructTags, false)
if err != nil { if err != nil {
return err return err
} }
if sc.DecodeZeroStruct { if sc.DecodeZeroStruct || dc.zeroStructs {
val.Set(reflect.Zero(val.Type())) val.Set(reflect.Zero(val.Type()))
} }
if sc.DecodeDeepZeroInline && sd.inline { if sc.DecodeDeepZeroInline && sd.inline {
@ -254,7 +310,7 @@ func (sc *StructCodec) DecodeValue(r DecodeContext, vr bsonrw.ValueReader, val r
var inlineMap reflect.Value var inlineMap reflect.Value
if sd.inlineMap >= 0 { if sd.inlineMap >= 0 {
inlineMap = val.Field(sd.inlineMap) inlineMap = val.Field(sd.inlineMap)
decoder, err = r.LookupDecoder(inlineMap.Type().Elem()) decoder, err = dc.LookupDecoder(inlineMap.Type().Elem())
if err != nil { if err != nil {
return err return err
} }
@ -267,7 +323,7 @@ func (sc *StructCodec) DecodeValue(r DecodeContext, vr bsonrw.ValueReader, val r
for { for {
name, vr, err := dr.ReadElement() name, vr, err := dr.ReadElement()
if err == bsonrw.ErrEOD { if errors.Is(err, bsonrw.ErrEOD) {
break break
} }
if err != nil { if err != nil {
@ -298,8 +354,8 @@ func (sc *StructCodec) DecodeValue(r DecodeContext, vr bsonrw.ValueReader, val r
} }
elem := reflect.New(inlineMap.Type().Elem()).Elem() elem := reflect.New(inlineMap.Type().Elem()).Elem()
r.Ancestor = inlineMap.Type() dc.Ancestor = inlineMap.Type()
err = decoder.DecodeValue(r, vr, elem) err = decoder.DecodeValue(dc, vr, elem)
if err != nil { if err != nil {
return err return err
} }
@ -326,7 +382,17 @@ func (sc *StructCodec) DecodeValue(r DecodeContext, vr bsonrw.ValueReader, val r
} }
field = field.Addr() field = field.Addr()
dctx := DecodeContext{Registry: r.Registry, Truncate: fd.truncate || r.Truncate} dctx := DecodeContext{
Registry: dc.Registry,
Truncate: fd.truncate || dc.Truncate,
defaultDocumentType: dc.defaultDocumentType,
binaryAsSlice: dc.binaryAsSlice,
useJSONStructTags: dc.useJSONStructTags,
useLocalTimeZone: dc.useLocalTimeZone,
zeroMaps: dc.zeroMaps,
zeroStructs: dc.zeroStructs,
}
if fd.decoder == nil { if fd.decoder == nil {
return newDecodeError(fd.name, ErrNoDecoder{Type: field.Elem().Type()}) return newDecodeError(fd.name, ErrNoDecoder{Type: field.Elem().Type()})
} }
@ -340,51 +406,35 @@ func (sc *StructCodec) DecodeValue(r DecodeContext, vr bsonrw.ValueReader, val r
return nil return nil
} }
func (sc *StructCodec) isZero(i interface{}) bool { func isEmpty(v reflect.Value, omitZeroStruct bool) bool {
v := reflect.ValueOf(i) kind := v.Kind()
if (kind != reflect.Ptr || !v.IsNil()) && v.Type().Implements(tZeroer) {
// check the value validity return v.Interface().(Zeroer).IsZero()
if !v.IsValid() {
return true
} }
switch kind {
if z, ok := v.Interface().(Zeroer); ok && (v.Kind() != reflect.Ptr || !v.IsNil()) {
return z.IsZero()
}
switch v.Kind() {
case reflect.Array, reflect.Map, reflect.Slice, reflect.String: case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
return v.Len() == 0 return v.Len() == 0
case reflect.Bool:
return !v.Bool()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return v.Int() == 0
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return v.Uint() == 0
case reflect.Float32, reflect.Float64:
return v.Float() == 0
case reflect.Interface, reflect.Ptr:
return v.IsNil()
case reflect.Struct: case reflect.Struct:
if sc.EncodeOmitDefaultStruct { if !omitZeroStruct {
vt := v.Type() return false
if vt == tTime {
return v.Interface().(time.Time).IsZero()
}
for i := 0; i < v.NumField(); i++ {
if vt.Field(i).PkgPath != "" && !vt.Field(i).Anonymous {
continue // Private field
}
fld := v.Field(i)
if !sc.isZero(fld.Interface()) {
return false
}
}
return true
} }
vt := v.Type()
if vt == tTime {
return v.Interface().(time.Time).IsZero()
}
numField := vt.NumField()
for i := 0; i < numField; i++ {
ff := vt.Field(i)
if ff.PkgPath != "" && !ff.Anonymous {
continue // Private field
}
if !isEmpty(v.Field(i), omitZeroStruct) {
return false
}
}
return true
} }
return !v.IsValid() || v.IsZero()
return false
} }
type structDescription struct { type structDescription struct {
@ -435,16 +485,35 @@ func (bi byIndex) Less(i, j int) bool {
return len(bi[i].inline) < len(bi[j].inline) return len(bi[i].inline) < len(bi[j].inline)
} }
func (sc *StructCodec) describeStruct(r *Registry, t reflect.Type) (*structDescription, error) { func (sc *StructCodec) describeStruct(
r *Registry,
t reflect.Type,
useJSONStructTags bool,
errorOnDuplicates bool,
) (*structDescription, error) {
// We need to analyze the struct, including getting the tags, collecting // We need to analyze the struct, including getting the tags, collecting
// information about inlining, and create a map of the field name to the field. // information about inlining, and create a map of the field name to the field.
sc.l.RLock() if v, ok := sc.cache.Load(t); ok {
ds, exists := sc.cache[t] return v.(*structDescription), nil
sc.l.RUnlock()
if exists {
return ds, nil
} }
// TODO(charlie): Only describe the struct once when called
// concurrently with the same type.
ds, err := sc.describeStructSlow(r, t, useJSONStructTags, errorOnDuplicates)
if err != nil {
return nil, err
}
if v, loaded := sc.cache.LoadOrStore(t, ds); loaded {
ds = v.(*structDescription)
}
return ds, nil
}
func (sc *StructCodec) describeStructSlow(
r *Registry,
t reflect.Type,
useJSONStructTags bool,
errorOnDuplicates bool,
) (*structDescription, error) {
numFields := t.NumField() numFields := t.NumField()
sd := &structDescription{ sd := &structDescription{
fm: make(map[string]fieldDescription, numFields), fm: make(map[string]fieldDescription, numFields),
@ -477,7 +546,14 @@ func (sc *StructCodec) describeStruct(r *Registry, t reflect.Type) (*structDescr
decoder: decoder, decoder: decoder,
} }
stags, err := sc.parser.ParseStructTags(sf) var stags StructTags
// If the caller requested that we use JSON struct tags, use the JSONFallbackStructTagParser
// instead of the parser defined on the codec.
if useJSONStructTags {
stags, err = JSONFallbackStructTagParser.ParseStructTags(sf)
} else {
stags, err = sc.parser.ParseStructTags(sf)
}
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -507,7 +583,7 @@ func (sc *StructCodec) describeStruct(r *Registry, t reflect.Type) (*structDescr
} }
fallthrough fallthrough
case reflect.Struct: case reflect.Struct:
inlinesf, err := sc.describeStruct(r, sfType) inlinesf, err := sc.describeStruct(r, sfType, useJSONStructTags, errorOnDuplicates)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -559,7 +635,7 @@ func (sc *StructCodec) describeStruct(r *Registry, t reflect.Type) (*structDescr
continue continue
} }
dominant, ok := dominantField(fields[i : i+advance]) dominant, ok := dominantField(fields[i : i+advance])
if !ok || !sc.OverwriteDuplicatedInlinedFields { if !ok || !sc.OverwriteDuplicatedInlinedFields || errorOnDuplicates {
return nil, fmt.Errorf("struct %s has duplicated key %s", t.String(), name) return nil, fmt.Errorf("struct %s has duplicated key %s", t.String(), name)
} }
sd.fl = append(sd.fl, dominant) sd.fl = append(sd.fl, dominant)
@ -568,10 +644,6 @@ func (sc *StructCodec) describeStruct(r *Registry, t reflect.Type) (*structDescr
sort.Sort(byIndex(sd.fl)) sort.Sort(byIndex(sd.fl))
sc.l.Lock()
sc.cache[t] = sd
sc.l.Unlock()
return sd, nil return sd, nil
} }
@ -629,21 +701,21 @@ func getInlineField(val reflect.Value, index []int) (reflect.Value, error) {
// DeepZero returns recursive zero object // DeepZero returns recursive zero object
func deepZero(st reflect.Type) (result reflect.Value) { func deepZero(st reflect.Type) (result reflect.Value) {
result = reflect.Indirect(reflect.New(st)) if st.Kind() == reflect.Struct {
numField := st.NumField()
if result.Kind() == reflect.Struct { for i := 0; i < numField; i++ {
for i := 0; i < result.NumField(); i++ { if result == emptyValue {
if f := result.Field(i); f.Kind() == reflect.Ptr { result = reflect.Indirect(reflect.New(st))
if f.CanInterface() { }
if ft := reflect.TypeOf(f.Interface()); ft.Elem().Kind() == reflect.Struct { f := result.Field(i)
result.Field(i).Set(recursivePointerTo(deepZero(ft.Elem()))) if f.CanInterface() {
} if f.Type().Kind() == reflect.Struct {
result.Field(i).Set(recursivePointerTo(deepZero(f.Type().Elem())))
} }
} }
} }
} }
return result
return
} }
// recursivePointerTo calls reflect.New(v.Type) but recursively for its fields inside // recursivePointerTo calls reflect.New(v.Type) but recursively for its fields inside

View file

@ -12,12 +12,16 @@
) )
// StructTagParser returns the struct tags for a given struct field. // StructTagParser returns the struct tags for a given struct field.
//
// Deprecated: Defining custom BSON struct tag parsers will not be supported in Go Driver 2.0.
type StructTagParser interface { type StructTagParser interface {
ParseStructTags(reflect.StructField) (StructTags, error) ParseStructTags(reflect.StructField) (StructTags, error)
} }
// StructTagParserFunc is an adapter that allows a generic function to be used // StructTagParserFunc is an adapter that allows a generic function to be used
// as a StructTagParser. // as a StructTagParser.
//
// Deprecated: Defining custom BSON struct tag parsers will not be supported in Go Driver 2.0.
type StructTagParserFunc func(reflect.StructField) (StructTags, error) type StructTagParserFunc func(reflect.StructField) (StructTags, error)
// ParseStructTags implements the StructTagParser interface. // ParseStructTags implements the StructTagParser interface.
@ -50,7 +54,7 @@ func (stpf StructTagParserFunc) ParseStructTags(sf reflect.StructField) (StructT
// Skip This struct field should be skipped. This is usually denoted by parsing a "-" // Skip This struct field should be skipped. This is usually denoted by parsing a "-"
// for the name. // for the name.
// //
// TODO(skriptble): Add tags for undefined as nil and for null as nil. // Deprecated: Defining custom BSON struct tag parsers will not be supported in Go Driver 2.0.
type StructTags struct { type StructTags struct {
Name string Name string
OmitEmpty bool OmitEmpty bool
@ -85,6 +89,8 @@ type StructTags struct {
// A struct tag either consisting entirely of '-' or with a bson key with a // A struct tag either consisting entirely of '-' or with a bson key with a
// value consisting entirely of '-' will return a StructTags with Skip true and // value consisting entirely of '-' will return a StructTags with Skip true and
// the remaining fields will be their default values. // the remaining fields will be their default values.
//
// Deprecated: DefaultStructTagParser will be removed in Go Driver 2.0.
var DefaultStructTagParser StructTagParserFunc = func(sf reflect.StructField) (StructTags, error) { var DefaultStructTagParser StructTagParserFunc = func(sf reflect.StructField) (StructTags, error) {
key := strings.ToLower(sf.Name) key := strings.ToLower(sf.Name)
tag, ok := sf.Tag.Lookup("bson") tag, ok := sf.Tag.Lookup("bson")
@ -125,6 +131,9 @@ func parseTags(key string, tag string) (StructTags, error) {
// JSONFallbackStructTagParser has the same behavior as DefaultStructTagParser // JSONFallbackStructTagParser has the same behavior as DefaultStructTagParser
// but will also fallback to parsing the json tag instead on a field where the // but will also fallback to parsing the json tag instead on a field where the
// bson tag isn't available. // bson tag isn't available.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.Encoder.UseJSONStructTags] and
// [go.mongodb.org/mongo-driver/bson.Decoder.UseJSONStructTags] instead.
var JSONFallbackStructTagParser StructTagParserFunc = func(sf reflect.StructField) (StructTags, error) { var JSONFallbackStructTagParser StructTagParserFunc = func(sf reflect.StructField) (StructTags, error) {
key := strings.ToLower(sf.Name) key := strings.ToLower(sf.Name)
tag, ok := sf.Tag.Lookup("bson") tag, ok := sf.Tag.Lookup("bson")

View file

@ -22,18 +22,42 @@
) )
// TimeCodec is the Codec used for time.Time values. // TimeCodec is the Codec used for time.Time values.
//
// Deprecated: TimeCodec will not be directly configurable in Go Driver 2.0.
// To configure the time.Time encode and decode behavior, use the configuration
// methods on a [go.mongodb.org/mongo-driver/bson.Encoder] or
// [go.mongodb.org/mongo-driver/bson.Decoder]. To configure the time.Time encode
// and decode behavior for a mongo.Client, use
// [go.mongodb.org/mongo-driver/mongo/options.ClientOptions.SetBSONOptions].
//
// For example, to configure a mongo.Client to ..., use:
//
// opt := options.Client().SetBSONOptions(&options.BSONOptions{
// UseLocalTimeZone: true,
// })
//
// See the deprecation notice for each field in TimeCodec for the corresponding
// settings.
type TimeCodec struct { type TimeCodec struct {
// UseLocalTimeZone specifies if we should decode into the local time zone. Defaults to false.
//
// Deprecated: Use bson.Decoder.UseLocalTimeZone or options.BSONOptions.UseLocalTimeZone
// instead.
UseLocalTimeZone bool UseLocalTimeZone bool
} }
var ( var (
defaultTimeCodec = NewTimeCodec() defaultTimeCodec = NewTimeCodec()
_ ValueCodec = defaultTimeCodec // Assert that defaultTimeCodec satisfies the typeDecoder interface, which allows it to be used
// by collection type decoders (e.g. map, slice, etc) to set individual values in a collection.
_ typeDecoder = defaultTimeCodec _ typeDecoder = defaultTimeCodec
) )
// NewTimeCodec returns a TimeCodec with options opts. // NewTimeCodec returns a TimeCodec with options opts.
//
// Deprecated: NewTimeCodec will not be available in Go Driver 2.0. See
// [TimeCodec] for more details.
func NewTimeCodec(opts ...*bsonoptions.TimeCodecOptions) *TimeCodec { func NewTimeCodec(opts ...*bsonoptions.TimeCodecOptions) *TimeCodec {
timeOpt := bsonoptions.MergeTimeCodecOptions(opts...) timeOpt := bsonoptions.MergeTimeCodecOptions(opts...)
@ -95,7 +119,7 @@ func (tc *TimeCodec) decodeType(dc DecodeContext, vr bsonrw.ValueReader, t refle
return emptyValue, fmt.Errorf("cannot decode %v into a time.Time", vrType) return emptyValue, fmt.Errorf("cannot decode %v into a time.Time", vrType)
} }
if !tc.UseLocalTimeZone { if !tc.UseLocalTimeZone && !dc.useLocalTimeZone {
timeVal = timeVal.UTC() timeVal = timeVal.UTC()
} }
return reflect.ValueOf(timeVal), nil return reflect.ValueOf(timeVal), nil
@ -117,7 +141,7 @@ func (tc *TimeCodec) DecodeValue(dc DecodeContext, vr bsonrw.ValueReader, val re
} }
// EncodeValue is the ValueEncoderFunc for time.TIme. // EncodeValue is the ValueEncoderFunc for time.TIme.
func (tc *TimeCodec) EncodeValue(ec EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { func (tc *TimeCodec) EncodeValue(_ EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {
if !val.IsValid() || val.Type() != tTime { if !val.IsValid() || val.Type() != tTime {
return ValueEncoderError{Name: "TimeEncodeValue", Types: []reflect.Type{tTime}, Received: val} return ValueEncoderError{Name: "TimeEncodeValue", Types: []reflect.Type{tTime}, Received: val}
} }

View file

@ -34,6 +34,7 @@
var tMarshaler = reflect.TypeOf((*Marshaler)(nil)).Elem() var tMarshaler = reflect.TypeOf((*Marshaler)(nil)).Elem()
var tUnmarshaler = reflect.TypeOf((*Unmarshaler)(nil)).Elem() var tUnmarshaler = reflect.TypeOf((*Unmarshaler)(nil)).Elem()
var tProxy = reflect.TypeOf((*Proxy)(nil)).Elem() var tProxy = reflect.TypeOf((*Proxy)(nil)).Elem()
var tZeroer = reflect.TypeOf((*Zeroer)(nil)).Elem()
var tBinary = reflect.TypeOf(primitive.Binary{}) var tBinary = reflect.TypeOf(primitive.Binary{})
var tUndefined = reflect.TypeOf(primitive.Undefined{}) var tUndefined = reflect.TypeOf(primitive.Undefined{})

View file

@ -17,18 +17,43 @@
) )
// UIntCodec is the Codec used for uint values. // UIntCodec is the Codec used for uint values.
//
// Deprecated: UIntCodec will not be directly configurable in Go Driver 2.0. To
// configure the uint encode and decode behavior, use the configuration methods
// on a [go.mongodb.org/mongo-driver/bson.Encoder] or
// [go.mongodb.org/mongo-driver/bson.Decoder]. To configure the uint encode and
// decode behavior for a mongo.Client, use
// [go.mongodb.org/mongo-driver/mongo/options.ClientOptions.SetBSONOptions].
//
// For example, to configure a mongo.Client to marshal Go uint values as the
// minimum BSON int size that can represent the value, use:
//
// opt := options.Client().SetBSONOptions(&options.BSONOptions{
// IntMinSize: true,
// })
//
// See the deprecation notice for each field in UIntCodec for the corresponding
// settings.
type UIntCodec struct { type UIntCodec struct {
// EncodeToMinSize causes EncodeValue to marshal Go uint values (excluding uint64) as the
// minimum BSON int size (either 32-bit or 64-bit) that can represent the integer value.
//
// Deprecated: Use bson.Encoder.IntMinSize or options.BSONOptions.IntMinSize instead.
EncodeToMinSize bool EncodeToMinSize bool
} }
var ( var (
defaultUIntCodec = NewUIntCodec() defaultUIntCodec = NewUIntCodec()
_ ValueCodec = defaultUIntCodec // Assert that defaultUIntCodec satisfies the typeDecoder interface, which allows it to be used
// by collection type decoders (e.g. map, slice, etc) to set individual values in a collection.
_ typeDecoder = defaultUIntCodec _ typeDecoder = defaultUIntCodec
) )
// NewUIntCodec returns a UIntCodec with options opts. // NewUIntCodec returns a UIntCodec with options opts.
//
// Deprecated: NewUIntCodec will not be available in Go Driver 2.0. See
// [UIntCodec] for more details.
func NewUIntCodec(opts ...*bsonoptions.UIntCodecOptions) *UIntCodec { func NewUIntCodec(opts ...*bsonoptions.UIntCodecOptions) *UIntCodec {
uintOpt := bsonoptions.MergeUIntCodecOptions(opts...) uintOpt := bsonoptions.MergeUIntCodecOptions(opts...)

View file

@ -7,22 +7,33 @@
package bsonoptions package bsonoptions
// ByteSliceCodecOptions represents all possible options for byte slice encoding and decoding. // ByteSliceCodecOptions represents all possible options for byte slice encoding and decoding.
//
// Deprecated: Use the bson.Encoder and bson.Decoder configuration methods to set the desired BSON marshal
// and unmarshal behavior instead.
type ByteSliceCodecOptions struct { type ByteSliceCodecOptions struct {
EncodeNilAsEmpty *bool // Specifies if a nil byte slice should encode as an empty binary instead of null. Defaults to false. EncodeNilAsEmpty *bool // Specifies if a nil byte slice should encode as an empty binary instead of null. Defaults to false.
} }
// ByteSliceCodec creates a new *ByteSliceCodecOptions // ByteSliceCodec creates a new *ByteSliceCodecOptions
//
// Deprecated: Use the bson.Encoder and bson.Decoder configuration methods to set the desired BSON marshal
// and unmarshal behavior instead.
func ByteSliceCodec() *ByteSliceCodecOptions { func ByteSliceCodec() *ByteSliceCodecOptions {
return &ByteSliceCodecOptions{} return &ByteSliceCodecOptions{}
} }
// SetEncodeNilAsEmpty specifies if a nil byte slice should encode as an empty binary instead of null. Defaults to false. // SetEncodeNilAsEmpty specifies if a nil byte slice should encode as an empty binary instead of null. Defaults to false.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.Encoder.NilByteSliceAsEmpty] instead.
func (bs *ByteSliceCodecOptions) SetEncodeNilAsEmpty(b bool) *ByteSliceCodecOptions { func (bs *ByteSliceCodecOptions) SetEncodeNilAsEmpty(b bool) *ByteSliceCodecOptions {
bs.EncodeNilAsEmpty = &b bs.EncodeNilAsEmpty = &b
return bs return bs
} }
// MergeByteSliceCodecOptions combines the given *ByteSliceCodecOptions into a single *ByteSliceCodecOptions in a last one wins fashion. // MergeByteSliceCodecOptions combines the given *ByteSliceCodecOptions into a single *ByteSliceCodecOptions in a last one wins fashion.
//
// Deprecated: Merging options structs will not be supported in Go Driver 2.0. Users should create a
// single options struct instead.
func MergeByteSliceCodecOptions(opts ...*ByteSliceCodecOptions) *ByteSliceCodecOptions { func MergeByteSliceCodecOptions(opts ...*ByteSliceCodecOptions) *ByteSliceCodecOptions {
bs := ByteSliceCodec() bs := ByteSliceCodec()
for _, opt := range opts { for _, opt := range opts {

View file

@ -7,22 +7,33 @@
package bsonoptions package bsonoptions
// EmptyInterfaceCodecOptions represents all possible options for interface{} encoding and decoding. // EmptyInterfaceCodecOptions represents all possible options for interface{} encoding and decoding.
//
// Deprecated: Use the bson.Encoder and bson.Decoder configuration methods to set the desired BSON marshal
// and unmarshal behavior instead.
type EmptyInterfaceCodecOptions struct { type EmptyInterfaceCodecOptions struct {
DecodeBinaryAsSlice *bool // Specifies if Old and Generic type binarys should default to []slice instead of primitive.Binary. Defaults to false. DecodeBinaryAsSlice *bool // Specifies if Old and Generic type binarys should default to []slice instead of primitive.Binary. Defaults to false.
} }
// EmptyInterfaceCodec creates a new *EmptyInterfaceCodecOptions // EmptyInterfaceCodec creates a new *EmptyInterfaceCodecOptions
//
// Deprecated: Use the bson.Encoder and bson.Decoder configuration methods to set the desired BSON marshal
// and unmarshal behavior instead.
func EmptyInterfaceCodec() *EmptyInterfaceCodecOptions { func EmptyInterfaceCodec() *EmptyInterfaceCodecOptions {
return &EmptyInterfaceCodecOptions{} return &EmptyInterfaceCodecOptions{}
} }
// SetDecodeBinaryAsSlice specifies if Old and Generic type binarys should default to []slice instead of primitive.Binary. Defaults to false. // SetDecodeBinaryAsSlice specifies if Old and Generic type binarys should default to []slice instead of primitive.Binary. Defaults to false.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.Decoder.BinaryAsSlice] instead.
func (e *EmptyInterfaceCodecOptions) SetDecodeBinaryAsSlice(b bool) *EmptyInterfaceCodecOptions { func (e *EmptyInterfaceCodecOptions) SetDecodeBinaryAsSlice(b bool) *EmptyInterfaceCodecOptions {
e.DecodeBinaryAsSlice = &b e.DecodeBinaryAsSlice = &b
return e return e
} }
// MergeEmptyInterfaceCodecOptions combines the given *EmptyInterfaceCodecOptions into a single *EmptyInterfaceCodecOptions in a last one wins fashion. // MergeEmptyInterfaceCodecOptions combines the given *EmptyInterfaceCodecOptions into a single *EmptyInterfaceCodecOptions in a last one wins fashion.
//
// Deprecated: Merging options structs will not be supported in Go Driver 2.0. Users should create a
// single options struct instead.
func MergeEmptyInterfaceCodecOptions(opts ...*EmptyInterfaceCodecOptions) *EmptyInterfaceCodecOptions { func MergeEmptyInterfaceCodecOptions(opts ...*EmptyInterfaceCodecOptions) *EmptyInterfaceCodecOptions {
e := EmptyInterfaceCodec() e := EmptyInterfaceCodec()
for _, opt := range opts { for _, opt := range opts {

View file

@ -7,6 +7,9 @@
package bsonoptions package bsonoptions
// MapCodecOptions represents all possible options for map encoding and decoding. // MapCodecOptions represents all possible options for map encoding and decoding.
//
// Deprecated: Use the bson.Encoder and bson.Decoder configuration methods to set the desired BSON marshal
// and unmarshal behavior instead.
type MapCodecOptions struct { type MapCodecOptions struct {
DecodeZerosMap *bool // Specifies if the map should be zeroed before decoding into it. Defaults to false. DecodeZerosMap *bool // Specifies if the map should be zeroed before decoding into it. Defaults to false.
EncodeNilAsEmpty *bool // Specifies if a nil map should encode as an empty document instead of null. Defaults to false. EncodeNilAsEmpty *bool // Specifies if a nil map should encode as an empty document instead of null. Defaults to false.
@ -19,17 +22,24 @@ type MapCodecOptions struct {
} }
// MapCodec creates a new *MapCodecOptions // MapCodec creates a new *MapCodecOptions
//
// Deprecated: Use the bson.Encoder and bson.Decoder configuration methods to set the desired BSON marshal
// and unmarshal behavior instead.
func MapCodec() *MapCodecOptions { func MapCodec() *MapCodecOptions {
return &MapCodecOptions{} return &MapCodecOptions{}
} }
// SetDecodeZerosMap specifies if the map should be zeroed before decoding into it. Defaults to false. // SetDecodeZerosMap specifies if the map should be zeroed before decoding into it. Defaults to false.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.Decoder.ZeroMaps] instead.
func (t *MapCodecOptions) SetDecodeZerosMap(b bool) *MapCodecOptions { func (t *MapCodecOptions) SetDecodeZerosMap(b bool) *MapCodecOptions {
t.DecodeZerosMap = &b t.DecodeZerosMap = &b
return t return t
} }
// SetEncodeNilAsEmpty specifies if a nil map should encode as an empty document instead of null. Defaults to false. // SetEncodeNilAsEmpty specifies if a nil map should encode as an empty document instead of null. Defaults to false.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.Encoder.NilMapAsEmpty] instead.
func (t *MapCodecOptions) SetEncodeNilAsEmpty(b bool) *MapCodecOptions { func (t *MapCodecOptions) SetEncodeNilAsEmpty(b bool) *MapCodecOptions {
t.EncodeNilAsEmpty = &b t.EncodeNilAsEmpty = &b
return t return t
@ -40,12 +50,17 @@ func (t *MapCodecOptions) SetEncodeNilAsEmpty(b bool) *MapCodecOptions {
// type must either be a string, an integer type, or implement bsoncodec.KeyUnmarshaler. If true, keys are encoded with // type must either be a string, an integer type, or implement bsoncodec.KeyUnmarshaler. If true, keys are encoded with
// fmt.Sprint() and the encoding key type must be a string, an integer type, or a float. If true, the use of Stringer // fmt.Sprint() and the encoding key type must be a string, an integer type, or a float. If true, the use of Stringer
// will override TextMarshaler/TextUnmarshaler. Defaults to false. // will override TextMarshaler/TextUnmarshaler. Defaults to false.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.Encoder.StringifyMapKeysWithFmt] instead.
func (t *MapCodecOptions) SetEncodeKeysWithStringer(b bool) *MapCodecOptions { func (t *MapCodecOptions) SetEncodeKeysWithStringer(b bool) *MapCodecOptions {
t.EncodeKeysWithStringer = &b t.EncodeKeysWithStringer = &b
return t return t
} }
// MergeMapCodecOptions combines the given *MapCodecOptions into a single *MapCodecOptions in a last one wins fashion. // MergeMapCodecOptions combines the given *MapCodecOptions into a single *MapCodecOptions in a last one wins fashion.
//
// Deprecated: Merging options structs will not be supported in Go Driver 2.0. Users should create a
// single options struct instead.
func MergeMapCodecOptions(opts ...*MapCodecOptions) *MapCodecOptions { func MergeMapCodecOptions(opts ...*MapCodecOptions) *MapCodecOptions {
s := MapCodec() s := MapCodec()
for _, opt := range opts { for _, opt := range opts {

View file

@ -7,22 +7,33 @@
package bsonoptions package bsonoptions
// SliceCodecOptions represents all possible options for slice encoding and decoding. // SliceCodecOptions represents all possible options for slice encoding and decoding.
//
// Deprecated: Use the bson.Encoder and bson.Decoder configuration methods to set the desired BSON marshal
// and unmarshal behavior instead.
type SliceCodecOptions struct { type SliceCodecOptions struct {
EncodeNilAsEmpty *bool // Specifies if a nil slice should encode as an empty array instead of null. Defaults to false. EncodeNilAsEmpty *bool // Specifies if a nil slice should encode as an empty array instead of null. Defaults to false.
} }
// SliceCodec creates a new *SliceCodecOptions // SliceCodec creates a new *SliceCodecOptions
//
// Deprecated: Use the bson.Encoder and bson.Decoder configuration methods to set the desired BSON marshal
// and unmarshal behavior instead.
func SliceCodec() *SliceCodecOptions { func SliceCodec() *SliceCodecOptions {
return &SliceCodecOptions{} return &SliceCodecOptions{}
} }
// SetEncodeNilAsEmpty specifies if a nil slice should encode as an empty array instead of null. Defaults to false. // SetEncodeNilAsEmpty specifies if a nil slice should encode as an empty array instead of null. Defaults to false.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.Encoder.NilSliceAsEmpty] instead.
func (s *SliceCodecOptions) SetEncodeNilAsEmpty(b bool) *SliceCodecOptions { func (s *SliceCodecOptions) SetEncodeNilAsEmpty(b bool) *SliceCodecOptions {
s.EncodeNilAsEmpty = &b s.EncodeNilAsEmpty = &b
return s return s
} }
// MergeSliceCodecOptions combines the given *SliceCodecOptions into a single *SliceCodecOptions in a last one wins fashion. // MergeSliceCodecOptions combines the given *SliceCodecOptions into a single *SliceCodecOptions in a last one wins fashion.
//
// Deprecated: Merging options structs will not be supported in Go Driver 2.0. Users should create a
// single options struct instead.
func MergeSliceCodecOptions(opts ...*SliceCodecOptions) *SliceCodecOptions { func MergeSliceCodecOptions(opts ...*SliceCodecOptions) *SliceCodecOptions {
s := SliceCodec() s := SliceCodec()
for _, opt := range opts { for _, opt := range opts {

View file

@ -9,23 +9,34 @@
var defaultDecodeOIDAsHex = true var defaultDecodeOIDAsHex = true
// StringCodecOptions represents all possible options for string encoding and decoding. // StringCodecOptions represents all possible options for string encoding and decoding.
//
// Deprecated: Use the bson.Encoder and bson.Decoder configuration methods to set the desired BSON marshal
// and unmarshal behavior instead.
type StringCodecOptions struct { type StringCodecOptions struct {
DecodeObjectIDAsHex *bool // Specifies if we should decode ObjectID as the hex value. Defaults to true. DecodeObjectIDAsHex *bool // Specifies if we should decode ObjectID as the hex value. Defaults to true.
} }
// StringCodec creates a new *StringCodecOptions // StringCodec creates a new *StringCodecOptions
//
// Deprecated: Use the bson.Encoder and bson.Decoder configuration methods to set the desired BSON marshal
// and unmarshal behavior instead.
func StringCodec() *StringCodecOptions { func StringCodec() *StringCodecOptions {
return &StringCodecOptions{} return &StringCodecOptions{}
} }
// SetDecodeObjectIDAsHex specifies if object IDs should be decoded as their hex representation. If false, a string made // SetDecodeObjectIDAsHex specifies if object IDs should be decoded as their hex representation. If false, a string made
// from the raw object ID bytes will be used. Defaults to true. // from the raw object ID bytes will be used. Defaults to true.
//
// Deprecated: Decoding object IDs as raw bytes will not be supported in Go Driver 2.0.
func (t *StringCodecOptions) SetDecodeObjectIDAsHex(b bool) *StringCodecOptions { func (t *StringCodecOptions) SetDecodeObjectIDAsHex(b bool) *StringCodecOptions {
t.DecodeObjectIDAsHex = &b t.DecodeObjectIDAsHex = &b
return t return t
} }
// MergeStringCodecOptions combines the given *StringCodecOptions into a single *StringCodecOptions in a last one wins fashion. // MergeStringCodecOptions combines the given *StringCodecOptions into a single *StringCodecOptions in a last one wins fashion.
//
// Deprecated: Merging options structs will not be supported in Go Driver 2.0. Users should create a
// single options struct instead.
func MergeStringCodecOptions(opts ...*StringCodecOptions) *StringCodecOptions { func MergeStringCodecOptions(opts ...*StringCodecOptions) *StringCodecOptions {
s := &StringCodecOptions{&defaultDecodeOIDAsHex} s := &StringCodecOptions{&defaultDecodeOIDAsHex}
for _, opt := range opts { for _, opt := range opts {

View file

@ -9,6 +9,9 @@
var defaultOverwriteDuplicatedInlinedFields = true var defaultOverwriteDuplicatedInlinedFields = true
// StructCodecOptions represents all possible options for struct encoding and decoding. // StructCodecOptions represents all possible options for struct encoding and decoding.
//
// Deprecated: Use the bson.Encoder and bson.Decoder configuration methods to set the desired BSON marshal
// and unmarshal behavior instead.
type StructCodecOptions struct { type StructCodecOptions struct {
DecodeZeroStruct *bool // Specifies if structs should be zeroed before decoding into them. Defaults to false. DecodeZeroStruct *bool // Specifies if structs should be zeroed before decoding into them. Defaults to false.
DecodeDeepZeroInline *bool // Specifies if structs should be recursively zeroed when a inline value is decoded. Defaults to false. DecodeDeepZeroInline *bool // Specifies if structs should be recursively zeroed when a inline value is decoded. Defaults to false.
@ -18,17 +21,24 @@ type StructCodecOptions struct {
} }
// StructCodec creates a new *StructCodecOptions // StructCodec creates a new *StructCodecOptions
//
// Deprecated: Use the bson.Encoder and bson.Decoder configuration methods to set the desired BSON marshal
// and unmarshal behavior instead.
func StructCodec() *StructCodecOptions { func StructCodec() *StructCodecOptions {
return &StructCodecOptions{} return &StructCodecOptions{}
} }
// SetDecodeZeroStruct specifies if structs should be zeroed before decoding into them. Defaults to false. // SetDecodeZeroStruct specifies if structs should be zeroed before decoding into them. Defaults to false.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.Decoder.ZeroStructs] instead.
func (t *StructCodecOptions) SetDecodeZeroStruct(b bool) *StructCodecOptions { func (t *StructCodecOptions) SetDecodeZeroStruct(b bool) *StructCodecOptions {
t.DecodeZeroStruct = &b t.DecodeZeroStruct = &b
return t return t
} }
// SetDecodeDeepZeroInline specifies if structs should be zeroed before decoding into them. Defaults to false. // SetDecodeDeepZeroInline specifies if structs should be zeroed before decoding into them. Defaults to false.
//
// Deprecated: DecodeDeepZeroInline will not be supported in Go Driver 2.0.
func (t *StructCodecOptions) SetDecodeDeepZeroInline(b bool) *StructCodecOptions { func (t *StructCodecOptions) SetDecodeDeepZeroInline(b bool) *StructCodecOptions {
t.DecodeDeepZeroInline = &b t.DecodeDeepZeroInline = &b
return t return t
@ -36,6 +46,8 @@ func (t *StructCodecOptions) SetDecodeDeepZeroInline(b bool) *StructCodecOptions
// SetEncodeOmitDefaultStruct specifies if default structs should be considered empty by omitempty. A default struct has all // SetEncodeOmitDefaultStruct specifies if default structs should be considered empty by omitempty. A default struct has all
// its values set to their default value. Defaults to false. // its values set to their default value. Defaults to false.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.Encoder.OmitZeroStruct] instead.
func (t *StructCodecOptions) SetEncodeOmitDefaultStruct(b bool) *StructCodecOptions { func (t *StructCodecOptions) SetEncodeOmitDefaultStruct(b bool) *StructCodecOptions {
t.EncodeOmitDefaultStruct = &b t.EncodeOmitDefaultStruct = &b
return t return t
@ -45,18 +57,26 @@ func (t *StructCodecOptions) SetEncodeOmitDefaultStruct(b bool) *StructCodecOpti
// same bson key. When true and decoding, values will be written to the outermost struct with a matching key, and when // same bson key. When true and decoding, values will be written to the outermost struct with a matching key, and when
// encoding, keys will have the value of the top-most matching field. When false, decoding and encoding will error if // encoding, keys will have the value of the top-most matching field. When false, decoding and encoding will error if
// there are duplicate keys after the struct is inlined. Defaults to true. // there are duplicate keys after the struct is inlined. Defaults to true.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.Encoder.ErrorOnInlineDuplicates] instead.
func (t *StructCodecOptions) SetOverwriteDuplicatedInlinedFields(b bool) *StructCodecOptions { func (t *StructCodecOptions) SetOverwriteDuplicatedInlinedFields(b bool) *StructCodecOptions {
t.OverwriteDuplicatedInlinedFields = &b t.OverwriteDuplicatedInlinedFields = &b
return t return t
} }
// SetAllowUnexportedFields specifies if unexported fields should be marshaled/unmarshaled. Defaults to false. // SetAllowUnexportedFields specifies if unexported fields should be marshaled/unmarshaled. Defaults to false.
//
// Deprecated: AllowUnexportedFields does not work on recent versions of Go and will not be
// supported in Go Driver 2.0.
func (t *StructCodecOptions) SetAllowUnexportedFields(b bool) *StructCodecOptions { func (t *StructCodecOptions) SetAllowUnexportedFields(b bool) *StructCodecOptions {
t.AllowUnexportedFields = &b t.AllowUnexportedFields = &b
return t return t
} }
// MergeStructCodecOptions combines the given *StructCodecOptions into a single *StructCodecOptions in a last one wins fashion. // MergeStructCodecOptions combines the given *StructCodecOptions into a single *StructCodecOptions in a last one wins fashion.
//
// Deprecated: Merging options structs will not be supported in Go Driver 2.0. Users should create a
// single options struct instead.
func MergeStructCodecOptions(opts ...*StructCodecOptions) *StructCodecOptions { func MergeStructCodecOptions(opts ...*StructCodecOptions) *StructCodecOptions {
s := &StructCodecOptions{ s := &StructCodecOptions{
OverwriteDuplicatedInlinedFields: &defaultOverwriteDuplicatedInlinedFields, OverwriteDuplicatedInlinedFields: &defaultOverwriteDuplicatedInlinedFields,

View file

@ -7,22 +7,33 @@
package bsonoptions package bsonoptions
// TimeCodecOptions represents all possible options for time.Time encoding and decoding. // TimeCodecOptions represents all possible options for time.Time encoding and decoding.
//
// Deprecated: Use the bson.Encoder and bson.Decoder configuration methods to set the desired BSON marshal
// and unmarshal behavior instead.
type TimeCodecOptions struct { type TimeCodecOptions struct {
UseLocalTimeZone *bool // Specifies if we should decode into the local time zone. Defaults to false. UseLocalTimeZone *bool // Specifies if we should decode into the local time zone. Defaults to false.
} }
// TimeCodec creates a new *TimeCodecOptions // TimeCodec creates a new *TimeCodecOptions
//
// Deprecated: Use the bson.Encoder and bson.Decoder configuration methods to set the desired BSON marshal
// and unmarshal behavior instead.
func TimeCodec() *TimeCodecOptions { func TimeCodec() *TimeCodecOptions {
return &TimeCodecOptions{} return &TimeCodecOptions{}
} }
// SetUseLocalTimeZone specifies if we should decode into the local time zone. Defaults to false. // SetUseLocalTimeZone specifies if we should decode into the local time zone. Defaults to false.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.Decoder.UseLocalTimeZone] instead.
func (t *TimeCodecOptions) SetUseLocalTimeZone(b bool) *TimeCodecOptions { func (t *TimeCodecOptions) SetUseLocalTimeZone(b bool) *TimeCodecOptions {
t.UseLocalTimeZone = &b t.UseLocalTimeZone = &b
return t return t
} }
// MergeTimeCodecOptions combines the given *TimeCodecOptions into a single *TimeCodecOptions in a last one wins fashion. // MergeTimeCodecOptions combines the given *TimeCodecOptions into a single *TimeCodecOptions in a last one wins fashion.
//
// Deprecated: Merging options structs will not be supported in Go Driver 2.0. Users should create a
// single options struct instead.
func MergeTimeCodecOptions(opts ...*TimeCodecOptions) *TimeCodecOptions { func MergeTimeCodecOptions(opts ...*TimeCodecOptions) *TimeCodecOptions {
t := TimeCodec() t := TimeCodec()
for _, opt := range opts { for _, opt := range opts {

View file

@ -7,22 +7,33 @@
package bsonoptions package bsonoptions
// UIntCodecOptions represents all possible options for uint encoding and decoding. // UIntCodecOptions represents all possible options for uint encoding and decoding.
//
// Deprecated: Use the bson.Encoder and bson.Decoder configuration methods to set the desired BSON marshal
// and unmarshal behavior instead.
type UIntCodecOptions struct { type UIntCodecOptions struct {
EncodeToMinSize *bool // Specifies if all uints except uint64 should be decoded to minimum size bsontype. Defaults to false. EncodeToMinSize *bool // Specifies if all uints except uint64 should be decoded to minimum size bsontype. Defaults to false.
} }
// UIntCodec creates a new *UIntCodecOptions // UIntCodec creates a new *UIntCodecOptions
//
// Deprecated: Use the bson.Encoder and bson.Decoder configuration methods to set the desired BSON marshal
// and unmarshal behavior instead.
func UIntCodec() *UIntCodecOptions { func UIntCodec() *UIntCodecOptions {
return &UIntCodecOptions{} return &UIntCodecOptions{}
} }
// SetEncodeToMinSize specifies if all uints except uint64 should be decoded to minimum size bsontype. Defaults to false. // SetEncodeToMinSize specifies if all uints except uint64 should be decoded to minimum size bsontype. Defaults to false.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.Encoder.IntMinSize] instead.
func (u *UIntCodecOptions) SetEncodeToMinSize(b bool) *UIntCodecOptions { func (u *UIntCodecOptions) SetEncodeToMinSize(b bool) *UIntCodecOptions {
u.EncodeToMinSize = &b u.EncodeToMinSize = &b
return u return u
} }
// MergeUIntCodecOptions combines the given *UIntCodecOptions into a single *UIntCodecOptions in a last one wins fashion. // MergeUIntCodecOptions combines the given *UIntCodecOptions into a single *UIntCodecOptions in a last one wins fashion.
//
// Deprecated: Merging options structs will not be supported in Go Driver 2.0. Users should create a
// single options struct instead.
func MergeUIntCodecOptions(opts ...*UIntCodecOptions) *UIntCodecOptions { func MergeUIntCodecOptions(opts ...*UIntCodecOptions) *UIntCodecOptions {
u := UIntCodec() u := UIntCodec()
for _, opt := range opts { for _, opt := range opts {

View file

@ -7,6 +7,7 @@
package bsonrw package bsonrw
import ( import (
"errors"
"fmt" "fmt"
"io" "io"
@ -17,20 +18,32 @@
// Copier is a type that allows copying between ValueReaders, ValueWriters, and // Copier is a type that allows copying between ValueReaders, ValueWriters, and
// []byte values. // []byte values.
//
// Deprecated: Copying BSON documents using the ValueWriter and ValueReader interfaces will not be
// supported in Go Driver 2.0.
type Copier struct{} type Copier struct{}
// NewCopier creates a new copier with the given registry. If a nil registry is provided // NewCopier creates a new copier with the given registry. If a nil registry is provided
// a default registry is used. // a default registry is used.
//
// Deprecated: Copying BSON documents using the ValueWriter and ValueReader interfaces will not be
// supported in Go Driver 2.0.
func NewCopier() Copier { func NewCopier() Copier {
return Copier{} return Copier{}
} }
// CopyDocument handles copying a document from src to dst. // CopyDocument handles copying a document from src to dst.
//
// Deprecated: Copying BSON documents using the ValueWriter and ValueReader interfaces will not be
// supported in Go Driver 2.0.
func CopyDocument(dst ValueWriter, src ValueReader) error { func CopyDocument(dst ValueWriter, src ValueReader) error {
return Copier{}.CopyDocument(dst, src) return Copier{}.CopyDocument(dst, src)
} }
// CopyDocument handles copying one document from the src to the dst. // CopyDocument handles copying one document from the src to the dst.
//
// Deprecated: Copying BSON documents using the ValueWriter and ValueReader interfaces will not be
// supported in Go Driver 2.0.
func (c Copier) CopyDocument(dst ValueWriter, src ValueReader) error { func (c Copier) CopyDocument(dst ValueWriter, src ValueReader) error {
dr, err := src.ReadDocument() dr, err := src.ReadDocument()
if err != nil { if err != nil {
@ -47,6 +60,9 @@ func (c Copier) CopyDocument(dst ValueWriter, src ValueReader) error {
// CopyArrayFromBytes copies the values from a BSON array represented as a // CopyArrayFromBytes copies the values from a BSON array represented as a
// []byte to a ValueWriter. // []byte to a ValueWriter.
//
// Deprecated: Copying BSON arrays using the ValueWriter and ValueReader interfaces will not be
// supported in Go Driver 2.0.
func (c Copier) CopyArrayFromBytes(dst ValueWriter, src []byte) error { func (c Copier) CopyArrayFromBytes(dst ValueWriter, src []byte) error {
aw, err := dst.WriteArray() aw, err := dst.WriteArray()
if err != nil { if err != nil {
@ -63,6 +79,9 @@ func (c Copier) CopyArrayFromBytes(dst ValueWriter, src []byte) error {
// CopyDocumentFromBytes copies the values from a BSON document represented as a // CopyDocumentFromBytes copies the values from a BSON document represented as a
// []byte to a ValueWriter. // []byte to a ValueWriter.
//
// Deprecated: Copying BSON documents using the ValueWriter and ValueReader interfaces will not be
// supported in Go Driver 2.0.
func (c Copier) CopyDocumentFromBytes(dst ValueWriter, src []byte) error { func (c Copier) CopyDocumentFromBytes(dst ValueWriter, src []byte) error {
dw, err := dst.WriteDocument() dw, err := dst.WriteDocument()
if err != nil { if err != nil {
@ -81,6 +100,9 @@ func (c Copier) CopyDocumentFromBytes(dst ValueWriter, src []byte) error {
// CopyBytesToArrayWriter copies the values from a BSON Array represented as a []byte to an // CopyBytesToArrayWriter copies the values from a BSON Array represented as a []byte to an
// ArrayWriter. // ArrayWriter.
//
// Deprecated: Copying BSON arrays using the ArrayWriter interface will not be supported in Go
// Driver 2.0.
func (c Copier) CopyBytesToArrayWriter(dst ArrayWriter, src []byte) error { func (c Copier) CopyBytesToArrayWriter(dst ArrayWriter, src []byte) error {
wef := func(_ string) (ValueWriter, error) { wef := func(_ string) (ValueWriter, error) {
return dst.WriteArrayElement() return dst.WriteArrayElement()
@ -91,6 +113,9 @@ func (c Copier) CopyBytesToArrayWriter(dst ArrayWriter, src []byte) error {
// CopyBytesToDocumentWriter copies the values from a BSON document represented as a []byte to a // CopyBytesToDocumentWriter copies the values from a BSON document represented as a []byte to a
// DocumentWriter. // DocumentWriter.
//
// Deprecated: Copying BSON documents using the ValueWriter and ValueReader interfaces will not be
// supported in Go Driver 2.0.
func (c Copier) CopyBytesToDocumentWriter(dst DocumentWriter, src []byte) error { func (c Copier) CopyBytesToDocumentWriter(dst DocumentWriter, src []byte) error {
wef := func(key string) (ValueWriter, error) { wef := func(key string) (ValueWriter, error) {
return dst.WriteDocumentElement(key) return dst.WriteDocumentElement(key)
@ -100,7 +125,7 @@ func (c Copier) CopyBytesToDocumentWriter(dst DocumentWriter, src []byte) error
} }
func (c Copier) copyBytesToValueWriter(src []byte, wef writeElementFn) error { func (c Copier) copyBytesToValueWriter(src []byte, wef writeElementFn) error {
// TODO(skriptble): Create errors types here. Anything thats a tag should be a property. // TODO(skriptble): Create errors types here. Anything that is a tag should be a property.
length, rem, ok := bsoncore.ReadLength(src) length, rem, ok := bsoncore.ReadLength(src)
if !ok { if !ok {
return fmt.Errorf("couldn't read length from src, not enough bytes. length=%d", len(src)) return fmt.Errorf("couldn't read length from src, not enough bytes. length=%d", len(src))
@ -150,12 +175,18 @@ func (c Copier) copyBytesToValueWriter(src []byte, wef writeElementFn) error {
// CopyDocumentToBytes copies an entire document from the ValueReader and // CopyDocumentToBytes copies an entire document from the ValueReader and
// returns it as bytes. // returns it as bytes.
//
// Deprecated: Copying BSON documents using the ValueWriter and ValueReader interfaces will not be
// supported in Go Driver 2.0.
func (c Copier) CopyDocumentToBytes(src ValueReader) ([]byte, error) { func (c Copier) CopyDocumentToBytes(src ValueReader) ([]byte, error) {
return c.AppendDocumentBytes(nil, src) return c.AppendDocumentBytes(nil, src)
} }
// AppendDocumentBytes functions the same as CopyDocumentToBytes, but will // AppendDocumentBytes functions the same as CopyDocumentToBytes, but will
// append the result to dst. // append the result to dst.
//
// Deprecated: Copying BSON documents using the ValueWriter and ValueReader interfaces will not be
// supported in Go Driver 2.0.
func (c Copier) AppendDocumentBytes(dst []byte, src ValueReader) ([]byte, error) { func (c Copier) AppendDocumentBytes(dst []byte, src ValueReader) ([]byte, error) {
if br, ok := src.(BytesReader); ok { if br, ok := src.(BytesReader); ok {
_, dst, err := br.ReadValueBytes(dst) _, dst, err := br.ReadValueBytes(dst)
@ -163,7 +194,7 @@ func (c Copier) AppendDocumentBytes(dst []byte, src ValueReader) ([]byte, error)
} }
vw := vwPool.Get().(*valueWriter) vw := vwPool.Get().(*valueWriter)
defer vwPool.Put(vw) defer putValueWriter(vw)
vw.reset(dst) vw.reset(dst)
@ -173,6 +204,9 @@ func (c Copier) AppendDocumentBytes(dst []byte, src ValueReader) ([]byte, error)
} }
// AppendArrayBytes copies an array from the ValueReader to dst. // AppendArrayBytes copies an array from the ValueReader to dst.
//
// Deprecated: Copying BSON arrays using the ValueWriter and ValueReader interfaces will not be
// supported in Go Driver 2.0.
func (c Copier) AppendArrayBytes(dst []byte, src ValueReader) ([]byte, error) { func (c Copier) AppendArrayBytes(dst []byte, src ValueReader) ([]byte, error) {
if br, ok := src.(BytesReader); ok { if br, ok := src.(BytesReader); ok {
_, dst, err := br.ReadValueBytes(dst) _, dst, err := br.ReadValueBytes(dst)
@ -180,7 +214,7 @@ func (c Copier) AppendArrayBytes(dst []byte, src ValueReader) ([]byte, error) {
} }
vw := vwPool.Get().(*valueWriter) vw := vwPool.Get().(*valueWriter)
defer vwPool.Put(vw) defer putValueWriter(vw)
vw.reset(dst) vw.reset(dst)
@ -190,6 +224,8 @@ func (c Copier) AppendArrayBytes(dst []byte, src ValueReader) ([]byte, error) {
} }
// CopyValueFromBytes will write the value represtend by t and src to dst. // CopyValueFromBytes will write the value represtend by t and src to dst.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.UnmarshalValue] instead.
func (c Copier) CopyValueFromBytes(dst ValueWriter, t bsontype.Type, src []byte) error { func (c Copier) CopyValueFromBytes(dst ValueWriter, t bsontype.Type, src []byte) error {
if wvb, ok := dst.(BytesWriter); ok { if wvb, ok := dst.(BytesWriter); ok {
return wvb.WriteValueBytes(t, src) return wvb.WriteValueBytes(t, src)
@ -206,19 +242,24 @@ func (c Copier) CopyValueFromBytes(dst ValueWriter, t bsontype.Type, src []byte)
// CopyValueToBytes copies a value from src and returns it as a bsontype.Type and a // CopyValueToBytes copies a value from src and returns it as a bsontype.Type and a
// []byte. // []byte.
//
// Deprecated: Use [go.mongodb.org/mongo-driver/bson.MarshalValue] instead.
func (c Copier) CopyValueToBytes(src ValueReader) (bsontype.Type, []byte, error) { func (c Copier) CopyValueToBytes(src ValueReader) (bsontype.Type, []byte, error) {
return c.AppendValueBytes(nil, src) return c.AppendValueBytes(nil, src)
} }
// AppendValueBytes functions the same as CopyValueToBytes, but will append the // AppendValueBytes functions the same as CopyValueToBytes, but will append the
// result to dst. // result to dst.
//
// Deprecated: Appending individual BSON elements to an existing slice will not be supported in Go
// Driver 2.0.
func (c Copier) AppendValueBytes(dst []byte, src ValueReader) (bsontype.Type, []byte, error) { func (c Copier) AppendValueBytes(dst []byte, src ValueReader) (bsontype.Type, []byte, error) {
if br, ok := src.(BytesReader); ok { if br, ok := src.(BytesReader); ok {
return br.ReadValueBytes(dst) return br.ReadValueBytes(dst)
} }
vw := vwPool.Get().(*valueWriter) vw := vwPool.Get().(*valueWriter)
defer vwPool.Put(vw) defer putValueWriter(vw)
start := len(dst) start := len(dst)
@ -234,6 +275,9 @@ func (c Copier) AppendValueBytes(dst []byte, src ValueReader) (bsontype.Type, []
} }
// CopyValue will copy a single value from src to dst. // CopyValue will copy a single value from src to dst.
//
// Deprecated: Copying BSON values using the ValueWriter and ValueReader interfaces will not be
// supported in Go Driver 2.0.
func (c Copier) CopyValue(dst ValueWriter, src ValueReader) error { func (c Copier) CopyValue(dst ValueWriter, src ValueReader) error {
var err error var err error
switch src.Type() { switch src.Type() {
@ -399,7 +443,7 @@ func (c Copier) copyArray(dst ValueWriter, src ValueReader) error {
for { for {
vr, err := ar.ReadValue() vr, err := ar.ReadValue()
if err == ErrEOA { if errors.Is(err, ErrEOA) {
break break
} }
if err != nil { if err != nil {
@ -423,7 +467,7 @@ func (c Copier) copyArray(dst ValueWriter, src ValueReader) error {
func (c Copier) copyDocumentCore(dw DocumentWriter, dr DocumentReader) error { func (c Copier) copyDocumentCore(dw DocumentWriter, dr DocumentReader) error {
for { for {
key, vr, err := dr.ReadElement() key, vr, err := dr.ReadElement()
if err == ErrEOD { if errors.Is(err, ErrEOD) {
break break
} }
if err != nil { if err != nil {

View file

@ -313,7 +313,7 @@ func (ejp *extJSONParser) readValue(t bsontype.Type) (*extJSONValue, error) {
// convert hex to bytes // convert hex to bytes
bytes, err := hex.DecodeString(uuidNoHyphens) bytes, err := hex.DecodeString(uuidNoHyphens)
if err != nil { if err != nil {
return nil, fmt.Errorf("$uuid value does not follow RFC 4122 format regarding hex bytes: %v", err) return nil, fmt.Errorf("$uuid value does not follow RFC 4122 format regarding hex bytes: %w", err)
} }
ejp.advanceState() ejp.advanceState()

View file

@ -7,6 +7,7 @@
package bsonrw package bsonrw
import ( import (
"errors"
"fmt" "fmt"
"io" "io"
"sync" "sync"
@ -16,11 +17,15 @@
) )
// ExtJSONValueReaderPool is a pool for ValueReaders that read ExtJSON. // ExtJSONValueReaderPool is a pool for ValueReaders that read ExtJSON.
//
// Deprecated: ExtJSONValueReaderPool will not be supported in Go Driver 2.0.
type ExtJSONValueReaderPool struct { type ExtJSONValueReaderPool struct {
pool sync.Pool pool sync.Pool
} }
// NewExtJSONValueReaderPool instantiates a new ExtJSONValueReaderPool. // NewExtJSONValueReaderPool instantiates a new ExtJSONValueReaderPool.
//
// Deprecated: ExtJSONValueReaderPool will not be supported in Go Driver 2.0.
func NewExtJSONValueReaderPool() *ExtJSONValueReaderPool { func NewExtJSONValueReaderPool() *ExtJSONValueReaderPool {
return &ExtJSONValueReaderPool{ return &ExtJSONValueReaderPool{
pool: sync.Pool{ pool: sync.Pool{
@ -32,6 +37,8 @@ func NewExtJSONValueReaderPool() *ExtJSONValueReaderPool {
} }
// Get retrieves a ValueReader from the pool and uses src as the underlying ExtJSON. // Get retrieves a ValueReader from the pool and uses src as the underlying ExtJSON.
//
// Deprecated: ExtJSONValueReaderPool will not be supported in Go Driver 2.0.
func (bvrp *ExtJSONValueReaderPool) Get(r io.Reader, canonical bool) (ValueReader, error) { func (bvrp *ExtJSONValueReaderPool) Get(r io.Reader, canonical bool) (ValueReader, error) {
vr := bvrp.pool.Get().(*extJSONValueReader) vr := bvrp.pool.Get().(*extJSONValueReader)
return vr.reset(r, canonical) return vr.reset(r, canonical)
@ -39,6 +46,8 @@ func (bvrp *ExtJSONValueReaderPool) Get(r io.Reader, canonical bool) (ValueReade
// Put inserts a ValueReader into the pool. If the ValueReader is not a ExtJSON ValueReader nothing // Put inserts a ValueReader into the pool. If the ValueReader is not a ExtJSON ValueReader nothing
// is inserted into the pool and ok will be false. // is inserted into the pool and ok will be false.
//
// Deprecated: ExtJSONValueReaderPool will not be supported in Go Driver 2.0.
func (bvrp *ExtJSONValueReaderPool) Put(vr ValueReader) (ok bool) { func (bvrp *ExtJSONValueReaderPool) Put(vr ValueReader) (ok bool) {
bvr, ok := vr.(*extJSONValueReader) bvr, ok := vr.(*extJSONValueReader)
if !ok { if !ok {
@ -605,7 +614,7 @@ func (ejvr *extJSONValueReader) ReadElement() (string, ValueReader, error) {
name, t, err := ejvr.p.readKey() name, t, err := ejvr.p.readKey()
if err != nil { if err != nil {
if err == ErrEOD { if errors.Is(err, ErrEOD) {
if ejvr.stack[ejvr.frame].mode == mCodeWithScope { if ejvr.stack[ejvr.frame].mode == mCodeWithScope {
_, err := ejvr.p.peekType() _, err := ejvr.p.peekType()
if err != nil { if err != nil {
@ -632,7 +641,7 @@ func (ejvr *extJSONValueReader) ReadValue() (ValueReader, error) {
t, err := ejvr.p.peekType() t, err := ejvr.p.peekType()
if err != nil { if err != nil {
if err == ErrEOA { if errors.Is(err, ErrEOA) {
ejvr.pop() ejvr.pop()
} }

View file

@ -23,11 +23,15 @@
) )
// ExtJSONValueWriterPool is a pool for ExtJSON ValueWriters. // ExtJSONValueWriterPool is a pool for ExtJSON ValueWriters.
//
// Deprecated: ExtJSONValueWriterPool will not be supported in Go Driver 2.0.
type ExtJSONValueWriterPool struct { type ExtJSONValueWriterPool struct {
pool sync.Pool pool sync.Pool
} }
// NewExtJSONValueWriterPool creates a new pool for ValueWriter instances that write to ExtJSON. // NewExtJSONValueWriterPool creates a new pool for ValueWriter instances that write to ExtJSON.
//
// Deprecated: ExtJSONValueWriterPool will not be supported in Go Driver 2.0.
func NewExtJSONValueWriterPool() *ExtJSONValueWriterPool { func NewExtJSONValueWriterPool() *ExtJSONValueWriterPool {
return &ExtJSONValueWriterPool{ return &ExtJSONValueWriterPool{
pool: sync.Pool{ pool: sync.Pool{
@ -39,6 +43,8 @@ func NewExtJSONValueWriterPool() *ExtJSONValueWriterPool {
} }
// Get retrieves a ExtJSON ValueWriter from the pool and resets it to use w as the destination. // Get retrieves a ExtJSON ValueWriter from the pool and resets it to use w as the destination.
//
// Deprecated: ExtJSONValueWriterPool will not be supported in Go Driver 2.0.
func (bvwp *ExtJSONValueWriterPool) Get(w io.Writer, canonical, escapeHTML bool) ValueWriter { func (bvwp *ExtJSONValueWriterPool) Get(w io.Writer, canonical, escapeHTML bool) ValueWriter {
vw := bvwp.pool.Get().(*extJSONValueWriter) vw := bvwp.pool.Get().(*extJSONValueWriter)
if writer, ok := w.(*SliceWriter); ok { if writer, ok := w.(*SliceWriter); ok {
@ -53,6 +59,8 @@ func (bvwp *ExtJSONValueWriterPool) Get(w io.Writer, canonical, escapeHTML bool)
// Put inserts a ValueWriter into the pool. If the ValueWriter is not a ExtJSON ValueWriter, nothing // Put inserts a ValueWriter into the pool. If the ValueWriter is not a ExtJSON ValueWriter, nothing
// happens and ok will be false. // happens and ok will be false.
//
// Deprecated: ExtJSONValueWriterPool will not be supported in Go Driver 2.0.
func (bvwp *ExtJSONValueWriterPool) Put(vw ValueWriter) (ok bool) { func (bvwp *ExtJSONValueWriterPool) Put(vw ValueWriter) (ok bool) {
bvw, ok := vw.(*extJSONValueWriter) bvw, ok := vw.(*extJSONValueWriter)
if !ok { if !ok {
@ -80,6 +88,7 @@ type extJSONValueWriter struct {
frame int64 frame int64
canonical bool canonical bool
escapeHTML bool escapeHTML bool
newlines bool
} }
// NewExtJSONValueWriter creates a ValueWriter that writes Extended JSON to w. // NewExtJSONValueWriter creates a ValueWriter that writes Extended JSON to w.
@ -88,10 +97,13 @@ func NewExtJSONValueWriter(w io.Writer, canonical, escapeHTML bool) (ValueWriter
return nil, errNilWriter return nil, errNilWriter
} }
return newExtJSONWriter(w, canonical, escapeHTML), nil // Enable newlines for all Extended JSON value writers created by NewExtJSONValueWriter. We
// expect these value writers to be used with an Encoder, which should add newlines after
// encoded Extended JSON documents.
return newExtJSONWriter(w, canonical, escapeHTML, true), nil
} }
func newExtJSONWriter(w io.Writer, canonical, escapeHTML bool) *extJSONValueWriter { func newExtJSONWriter(w io.Writer, canonical, escapeHTML, newlines bool) *extJSONValueWriter {
stack := make([]ejvwState, 1, 5) stack := make([]ejvwState, 1, 5)
stack[0] = ejvwState{mode: mTopLevel} stack[0] = ejvwState{mode: mTopLevel}
@ -101,6 +113,7 @@ func newExtJSONWriter(w io.Writer, canonical, escapeHTML bool) *extJSONValueWrit
stack: stack, stack: stack,
canonical: canonical, canonical: canonical,
escapeHTML: escapeHTML, escapeHTML: escapeHTML,
newlines: newlines,
} }
} }
@ -564,6 +577,12 @@ func (ejvw *extJSONValueWriter) WriteDocumentEnd() error {
case mDocument: case mDocument:
ejvw.buf = append(ejvw.buf, ',') ejvw.buf = append(ejvw.buf, ',')
case mTopLevel: case mTopLevel:
// If the value writer has newlines enabled, end top-level documents with a newline so that
// multiple documents encoded to the same writer are separated by newlines. That matches the
// Go json.Encoder behavior and also works with bsonrw.NewExtJSONValueReader.
if ejvw.newlines {
ejvw.buf = append(ejvw.buf, '\n')
}
if ejvw.w != nil { if ejvw.w != nil {
if _, err := ejvw.w.Write(ejvw.buf); err != nil { if _, err := ejvw.w.Write(ejvw.buf); err != nil {
return err return err

View file

@ -58,7 +58,7 @@ func (js *jsonScanner) nextToken() (*jsonToken, error) {
c, err = js.readNextByte() c, err = js.readNextByte()
} }
if err == io.EOF { if errors.Is(err, io.EOF) {
return &jsonToken{t: jttEOF}, nil return &jsonToken{t: jttEOF}, nil
} else if err != nil { } else if err != nil {
return nil, err return nil, err
@ -198,7 +198,7 @@ func (js *jsonScanner) scanString() (*jsonToken, error) {
for { for {
c, err = js.readNextByte() c, err = js.readNextByte()
if err != nil { if err != nil {
if err == io.EOF { if errors.Is(err, io.EOF) {
return nil, errors.New("end of input in JSON string") return nil, errors.New("end of input in JSON string")
} }
return nil, err return nil, err
@ -209,7 +209,7 @@ func (js *jsonScanner) scanString() (*jsonToken, error) {
case '\\': case '\\':
c, err = js.readNextByte() c, err = js.readNextByte()
if err != nil { if err != nil {
if err == io.EOF { if errors.Is(err, io.EOF) {
return nil, errors.New("end of input in JSON string") return nil, errors.New("end of input in JSON string")
} }
return nil, err return nil, err
@ -248,7 +248,7 @@ func (js *jsonScanner) scanString() (*jsonToken, error) {
if utf16.IsSurrogate(rn) { if utf16.IsSurrogate(rn) {
c, err = js.readNextByte() c, err = js.readNextByte()
if err != nil { if err != nil {
if err == io.EOF { if errors.Is(err, io.EOF) {
return nil, errors.New("end of input in JSON string") return nil, errors.New("end of input in JSON string")
} }
return nil, err return nil, err
@ -264,7 +264,7 @@ func (js *jsonScanner) scanString() (*jsonToken, error) {
c, err = js.readNextByte() c, err = js.readNextByte()
if err != nil { if err != nil {
if err == io.EOF { if errors.Is(err, io.EOF) {
return nil, errors.New("end of input in JSON string") return nil, errors.New("end of input in JSON string")
} }
return nil, err return nil, err
@ -325,17 +325,17 @@ func (js *jsonScanner) scanLiteral(first byte) (*jsonToken, error) {
c5, err := js.readNextByte() c5, err := js.readNextByte()
if bytes.Equal([]byte("true"), lit) && (isValueTerminator(c5) || err == io.EOF) { if bytes.Equal([]byte("true"), lit) && (isValueTerminator(c5) || errors.Is(err, io.EOF)) {
js.pos = int(math.Max(0, float64(js.pos-1))) js.pos = int(math.Max(0, float64(js.pos-1)))
return &jsonToken{t: jttBool, v: true, p: p}, nil return &jsonToken{t: jttBool, v: true, p: p}, nil
} else if bytes.Equal([]byte("null"), lit) && (isValueTerminator(c5) || err == io.EOF) { } else if bytes.Equal([]byte("null"), lit) && (isValueTerminator(c5) || errors.Is(err, io.EOF)) {
js.pos = int(math.Max(0, float64(js.pos-1))) js.pos = int(math.Max(0, float64(js.pos-1)))
return &jsonToken{t: jttNull, v: nil, p: p}, nil return &jsonToken{t: jttNull, v: nil, p: p}, nil
} else if bytes.Equal([]byte("fals"), lit) { } else if bytes.Equal([]byte("fals"), lit) {
if c5 == 'e' { if c5 == 'e' {
c5, err = js.readNextByte() c5, err = js.readNextByte()
if isValueTerminator(c5) || err == io.EOF { if isValueTerminator(c5) || errors.Is(err, io.EOF) {
js.pos = int(math.Max(0, float64(js.pos-1))) js.pos = int(math.Max(0, float64(js.pos-1)))
return &jsonToken{t: jttBool, v: false, p: p}, nil return &jsonToken{t: jttBool, v: false, p: p}, nil
} }
@ -384,7 +384,7 @@ func (js *jsonScanner) scanNumber(first byte) (*jsonToken, error) {
for { for {
c, err = js.readNextByte() c, err = js.readNextByte()
if err != nil && err != io.EOF { if err != nil && !errors.Is(err, io.EOF) {
return nil, err return nil, err
} }
@ -413,7 +413,7 @@ func (js *jsonScanner) scanNumber(first byte) (*jsonToken, error) {
case '}', ']', ',': case '}', ']', ',':
s = nssDone s = nssDone
default: default:
if isWhiteSpace(c) || err == io.EOF { if isWhiteSpace(c) || errors.Is(err, io.EOF) {
s = nssDone s = nssDone
} else { } else {
s = nssInvalid s = nssInvalid
@ -430,7 +430,7 @@ func (js *jsonScanner) scanNumber(first byte) (*jsonToken, error) {
case '}', ']', ',': case '}', ']', ',':
s = nssDone s = nssDone
default: default:
if isWhiteSpace(c) || err == io.EOF { if isWhiteSpace(c) || errors.Is(err, io.EOF) {
s = nssDone s = nssDone
} else if isDigit(c) { } else if isDigit(c) {
s = nssSawIntegerDigits s = nssSawIntegerDigits
@ -455,7 +455,7 @@ func (js *jsonScanner) scanNumber(first byte) (*jsonToken, error) {
case '}', ']', ',': case '}', ']', ',':
s = nssDone s = nssDone
default: default:
if isWhiteSpace(c) || err == io.EOF { if isWhiteSpace(c) || errors.Is(err, io.EOF) {
s = nssDone s = nssDone
} else if isDigit(c) { } else if isDigit(c) {
s = nssSawFractionDigits s = nssSawFractionDigits
@ -490,7 +490,7 @@ func (js *jsonScanner) scanNumber(first byte) (*jsonToken, error) {
case '}', ']', ',': case '}', ']', ',':
s = nssDone s = nssDone
default: default:
if isWhiteSpace(c) || err == io.EOF { if isWhiteSpace(c) || errors.Is(err, io.EOF) {
s = nssDone s = nssDone
} else if isDigit(c) { } else if isDigit(c) {
s = nssSawExponentDigits s = nssSawExponentDigits

View file

@ -58,6 +58,8 @@ type ValueReader interface {
// types that implement ValueReader may also implement this interface. // types that implement ValueReader may also implement this interface.
// //
// The bytes of the value will be appended to dst. // The bytes of the value will be appended to dst.
//
// Deprecated: BytesReader will not be supported in Go Driver 2.0.
type BytesReader interface { type BytesReader interface {
ReadValueBytes(dst []byte) (bsontype.Type, []byte, error) ReadValueBytes(dst []byte) (bsontype.Type, []byte, error)
} }

View file

@ -28,11 +28,15 @@
} }
// BSONValueReaderPool is a pool for ValueReaders that read BSON. // BSONValueReaderPool is a pool for ValueReaders that read BSON.
//
// Deprecated: BSONValueReaderPool will not be supported in Go Driver 2.0.
type BSONValueReaderPool struct { type BSONValueReaderPool struct {
pool sync.Pool pool sync.Pool
} }
// NewBSONValueReaderPool instantiates a new BSONValueReaderPool. // NewBSONValueReaderPool instantiates a new BSONValueReaderPool.
//
// Deprecated: BSONValueReaderPool will not be supported in Go Driver 2.0.
func NewBSONValueReaderPool() *BSONValueReaderPool { func NewBSONValueReaderPool() *BSONValueReaderPool {
return &BSONValueReaderPool{ return &BSONValueReaderPool{
pool: sync.Pool{ pool: sync.Pool{
@ -44,6 +48,8 @@ func NewBSONValueReaderPool() *BSONValueReaderPool {
} }
// Get retrieves a ValueReader from the pool and uses src as the underlying BSON. // Get retrieves a ValueReader from the pool and uses src as the underlying BSON.
//
// Deprecated: BSONValueReaderPool will not be supported in Go Driver 2.0.
func (bvrp *BSONValueReaderPool) Get(src []byte) ValueReader { func (bvrp *BSONValueReaderPool) Get(src []byte) ValueReader {
vr := bvrp.pool.Get().(*valueReader) vr := bvrp.pool.Get().(*valueReader)
vr.reset(src) vr.reset(src)
@ -52,6 +58,8 @@ func (bvrp *BSONValueReaderPool) Get(src []byte) ValueReader {
// Put inserts a ValueReader into the pool. If the ValueReader is not a BSON ValueReader nothing // Put inserts a ValueReader into the pool. If the ValueReader is not a BSON ValueReader nothing
// is inserted into the pool and ok will be false. // is inserted into the pool and ok will be false.
//
// Deprecated: BSONValueReaderPool will not be supported in Go Driver 2.0.
func (bvrp *BSONValueReaderPool) Put(vr ValueReader) (ok bool) { func (bvrp *BSONValueReaderPool) Put(vr ValueReader) (ok bool) {
bvr, ok := vr.(*valueReader) bvr, ok := vr.(*valueReader)
if !ok { if !ok {
@ -731,8 +739,7 @@ func (vr *valueReader) ReadValue() (ValueReader, error) {
return nil, ErrEOA return nil, ErrEOA
} }
_, err = vr.readCString() if err := vr.skipCString(); err != nil {
if err != nil {
return nil, err return nil, err
} }
@ -786,6 +793,15 @@ func (vr *valueReader) readByte() (byte, error) {
return vr.d[vr.offset-1], nil return vr.d[vr.offset-1], nil
} }
func (vr *valueReader) skipCString() error {
idx := bytes.IndexByte(vr.d[vr.offset:], 0x00)
if idx < 0 {
return io.EOF
}
vr.offset += int64(idx) + 1
return nil
}
func (vr *valueReader) readCString() (string, error) { func (vr *valueReader) readCString() (string, error) {
idx := bytes.IndexByte(vr.d[vr.offset:], 0x00) idx := bytes.IndexByte(vr.d[vr.offset:], 0x00)
if idx < 0 { if idx < 0 {

View file

@ -28,12 +28,23 @@
}, },
} }
func putValueWriter(vw *valueWriter) {
if vw != nil {
vw.w = nil // don't leak the writer
vwPool.Put(vw)
}
}
// BSONValueWriterPool is a pool for BSON ValueWriters. // BSONValueWriterPool is a pool for BSON ValueWriters.
//
// Deprecated: BSONValueWriterPool will not be supported in Go Driver 2.0.
type BSONValueWriterPool struct { type BSONValueWriterPool struct {
pool sync.Pool pool sync.Pool
} }
// NewBSONValueWriterPool creates a new pool for ValueWriter instances that write to BSON. // NewBSONValueWriterPool creates a new pool for ValueWriter instances that write to BSON.
//
// Deprecated: BSONValueWriterPool will not be supported in Go Driver 2.0.
func NewBSONValueWriterPool() *BSONValueWriterPool { func NewBSONValueWriterPool() *BSONValueWriterPool {
return &BSONValueWriterPool{ return &BSONValueWriterPool{
pool: sync.Pool{ pool: sync.Pool{
@ -45,6 +56,8 @@ func NewBSONValueWriterPool() *BSONValueWriterPool {
} }
// Get retrieves a BSON ValueWriter from the pool and resets it to use w as the destination. // Get retrieves a BSON ValueWriter from the pool and resets it to use w as the destination.
//
// Deprecated: BSONValueWriterPool will not be supported in Go Driver 2.0.
func (bvwp *BSONValueWriterPool) Get(w io.Writer) ValueWriter { func (bvwp *BSONValueWriterPool) Get(w io.Writer) ValueWriter {
vw := bvwp.pool.Get().(*valueWriter) vw := bvwp.pool.Get().(*valueWriter)
@ -56,6 +69,8 @@ func (bvwp *BSONValueWriterPool) Get(w io.Writer) ValueWriter {
} }
// GetAtModeElement retrieves a ValueWriterFlusher from the pool and resets it to use w as the destination. // GetAtModeElement retrieves a ValueWriterFlusher from the pool and resets it to use w as the destination.
//
// Deprecated: BSONValueWriterPool will not be supported in Go Driver 2.0.
func (bvwp *BSONValueWriterPool) GetAtModeElement(w io.Writer) ValueWriterFlusher { func (bvwp *BSONValueWriterPool) GetAtModeElement(w io.Writer) ValueWriterFlusher {
vw := bvwp.Get(w).(*valueWriter) vw := bvwp.Get(w).(*valueWriter)
vw.push(mElement) vw.push(mElement)
@ -64,6 +79,8 @@ func (bvwp *BSONValueWriterPool) GetAtModeElement(w io.Writer) ValueWriterFlushe
// Put inserts a ValueWriter into the pool. If the ValueWriter is not a BSON ValueWriter, nothing // Put inserts a ValueWriter into the pool. If the ValueWriter is not a BSON ValueWriter, nothing
// happens and ok will be false. // happens and ok will be false.
//
// Deprecated: BSONValueWriterPool will not be supported in Go Driver 2.0.
func (bvwp *BSONValueWriterPool) Put(vw ValueWriter) (ok bool) { func (bvwp *BSONValueWriterPool) Put(vw ValueWriter) (ok bool) {
bvw, ok := vw.(*valueWriter) bvw, ok := vw.(*valueWriter)
if !ok { if !ok {
@ -139,32 +156,21 @@ type valueWriter struct {
} }
func (vw *valueWriter) advanceFrame() { func (vw *valueWriter) advanceFrame() {
if vw.frame+1 >= int64(len(vw.stack)) { // We need to grow the stack
length := len(vw.stack)
if length+1 >= cap(vw.stack) {
// double it
buf := make([]vwState, 2*cap(vw.stack)+1)
copy(buf, vw.stack)
vw.stack = buf
}
vw.stack = vw.stack[:length+1]
}
vw.frame++ vw.frame++
if vw.frame >= int64(len(vw.stack)) {
vw.stack = append(vw.stack, vwState{})
}
} }
func (vw *valueWriter) push(m mode) { func (vw *valueWriter) push(m mode) {
vw.advanceFrame() vw.advanceFrame()
// Clean the stack // Clean the stack
vw.stack[vw.frame].mode = m vw.stack[vw.frame] = vwState{mode: m}
vw.stack[vw.frame].key = ""
vw.stack[vw.frame].arrkey = 0
vw.stack[vw.frame].start = 0
vw.stack[vw.frame].mode = m
switch m { switch m {
case mDocument, mArray, mCodeWithScope: case mDocument, mArray, mCodeWithScope:
vw.reserveLength() vw.reserveLength() // WARN: this is not needed
} }
} }
@ -203,6 +209,7 @@ func newValueWriter(w io.Writer) *valueWriter {
return vw return vw
} }
// TODO: only used in tests
func newValueWriterFromSlice(buf []byte) *valueWriter { func newValueWriterFromSlice(buf []byte) *valueWriter {
vw := new(valueWriter) vw := new(valueWriter)
stack := make([]vwState, 1, 5) stack := make([]vwState, 1, 5)
@ -239,17 +246,16 @@ func (vw *valueWriter) invalidTransitionError(destination mode, name string, mod
} }
func (vw *valueWriter) writeElementHeader(t bsontype.Type, destination mode, callerName string, addmodes ...mode) error { func (vw *valueWriter) writeElementHeader(t bsontype.Type, destination mode, callerName string, addmodes ...mode) error {
switch vw.stack[vw.frame].mode { frame := &vw.stack[vw.frame]
switch frame.mode {
case mElement: case mElement:
key := vw.stack[vw.frame].key key := frame.key
if !isValidCString(key) { if !isValidCString(key) {
return errors.New("BSON element key cannot contain null bytes") return errors.New("BSON element key cannot contain null bytes")
} }
vw.appendHeader(t, key)
vw.buf = bsoncore.AppendHeader(vw.buf, t, key)
case mValue: case mValue:
// TODO: Do this with a cache of the first 1000 or so array keys. vw.appendIntHeader(t, frame.arrkey)
vw.buf = bsoncore.AppendHeader(vw.buf, t, strconv.Itoa(vw.stack[vw.frame].arrkey))
default: default:
modes := []mode{mElement, mValue} modes := []mode{mElement, mValue}
if addmodes != nil { if addmodes != nil {
@ -591,9 +597,11 @@ func (vw *valueWriter) writeLength() error {
if length > maxSize { if length > maxSize {
return errMaxDocumentSizeExceeded{size: int64(len(vw.buf))} return errMaxDocumentSizeExceeded{size: int64(len(vw.buf))}
} }
length = length - int(vw.stack[vw.frame].start) frame := &vw.stack[vw.frame]
start := vw.stack[vw.frame].start length = length - int(frame.start)
start := frame.start
_ = vw.buf[start+3] // BCE
vw.buf[start+0] = byte(length) vw.buf[start+0] = byte(length)
vw.buf[start+1] = byte(length >> 8) vw.buf[start+1] = byte(length >> 8)
vw.buf[start+2] = byte(length >> 16) vw.buf[start+2] = byte(length >> 16)
@ -602,5 +610,31 @@ func (vw *valueWriter) writeLength() error {
} }
func isValidCString(cs string) bool { func isValidCString(cs string) bool {
return !strings.ContainsRune(cs, '\x00') // Disallow the zero byte in a cstring because the zero byte is used as the
// terminating character.
//
// It's safe to check bytes instead of runes because all multibyte UTF-8
// code points start with (binary) 11xxxxxx or 10xxxxxx, so 00000000 (i.e.
// 0) will never be part of a multibyte UTF-8 code point. This logic is the
// same as the "r < utf8.RuneSelf" case in strings.IndexRune but can be
// inlined.
//
// https://cs.opensource.google/go/go/+/refs/tags/go1.21.1:src/strings/strings.go;l=127
return strings.IndexByte(cs, 0) == -1
}
// appendHeader is the same as bsoncore.AppendHeader but does not check if the
// key is a valid C string since the caller has already checked for that.
//
// The caller of this function must check if key is a valid C string.
func (vw *valueWriter) appendHeader(t bsontype.Type, key string) {
vw.buf = bsoncore.AppendType(vw.buf, t)
vw.buf = append(vw.buf, key...)
vw.buf = append(vw.buf, 0x00)
}
func (vw *valueWriter) appendIntHeader(t bsontype.Type, key int) {
vw.buf = bsoncore.AppendType(vw.buf, t)
vw.buf = strconv.AppendInt(vw.buf, int64(key), 10)
vw.buf = append(vw.buf, 0x00)
} }

View file

@ -56,6 +56,8 @@ type ValueWriter interface {
} }
// ValueWriterFlusher is a superset of ValueWriter that exposes functionality to flush to the underlying buffer. // ValueWriterFlusher is a superset of ValueWriter that exposes functionality to flush to the underlying buffer.
//
// Deprecated: ValueWriterFlusher will not be supported in Go Driver 2.0.
type ValueWriterFlusher interface { type ValueWriterFlusher interface {
ValueWriter ValueWriter
Flush() error Flush() error
@ -64,13 +66,20 @@ type ValueWriterFlusher interface {
// BytesWriter is the interface used to write BSON bytes to a ValueWriter. // BytesWriter is the interface used to write BSON bytes to a ValueWriter.
// This interface is meant to be a superset of ValueWriter, so that types that // This interface is meant to be a superset of ValueWriter, so that types that
// implement ValueWriter may also implement this interface. // implement ValueWriter may also implement this interface.
//
// Deprecated: BytesWriter will not be supported in Go Driver 2.0.
type BytesWriter interface { type BytesWriter interface {
WriteValueBytes(t bsontype.Type, b []byte) error WriteValueBytes(t bsontype.Type, b []byte) error
} }
// SliceWriter allows a pointer to a slice of bytes to be used as an io.Writer. // SliceWriter allows a pointer to a slice of bytes to be used as an io.Writer.
//
// Deprecated: SliceWriter will not be supported in Go Driver 2.0.
type SliceWriter []byte type SliceWriter []byte
// Write writes the bytes to the underlying slice.
//
// Deprecated: SliceWriter will not be supported in Go Driver 2.0.
func (sw *SliceWriter) Write(p []byte) (int, error) { func (sw *SliceWriter) Write(p []byte) (int, error) {
written := len(p) written := len(p)
*sw = append(*sw, p...) *sw = append(*sw, p...)

View file

@ -8,7 +8,9 @@
// a stringifier for the Type to enable easier debugging when working with BSON. // a stringifier for the Type to enable easier debugging when working with BSON.
package bsontype // import "go.mongodb.org/mongo-driver/bson/bsontype" package bsontype // import "go.mongodb.org/mongo-driver/bson/bsontype"
// These constants uniquely refer to each BSON type. // BSON element types as described in https://bsonspec.org/spec.html.
//
// Deprecated: Use bson.Type* constants instead.
const ( const (
Double Type = 0x01 Double Type = 0x01
String Type = 0x02 String Type = 0x02
@ -31,7 +33,12 @@
Decimal128 Type = 0x13 Decimal128 Type = 0x13
MinKey Type = 0xFF MinKey Type = 0xFF
MaxKey Type = 0x7F MaxKey Type = 0x7F
)
// BSON binary element subtypes as described in https://bsonspec.org/spec.html.
//
// Deprecated: Use the bson.TypeBinary* constants instead.
const (
BinaryGeneric byte = 0x00 BinaryGeneric byte = 0x00
BinaryFunction byte = 0x01 BinaryFunction byte = 0x01
BinaryBinaryOld byte = 0x02 BinaryBinaryOld byte = 0x02
@ -40,6 +47,7 @@
BinaryMD5 byte = 0x05 BinaryMD5 byte = 0x05
BinaryEncrypted byte = 0x06 BinaryEncrypted byte = 0x06
BinaryColumn byte = 0x07 BinaryColumn byte = 0x07
BinarySensitive byte = 0x08
BinaryUserDefined byte = 0x80 BinaryUserDefined byte = 0x80
) )
@ -95,3 +103,14 @@ func (bt Type) String() string {
return "invalid" return "invalid"
} }
} }
// IsValid will return true if the Type is valid.
func (bt Type) IsValid() bool {
switch bt {
case Double, String, EmbeddedDocument, Array, Binary, Undefined, ObjectID, Boolean, DateTime, Null, Regex,
DBPointer, JavaScript, Symbol, CodeWithScope, Int32, Timestamp, Int64, Decimal128, MinKey, MaxKey:
return true
default:
return false
}
}

View file

@ -38,6 +38,12 @@ type Decoder struct {
// (*Decoder).SetContext. // (*Decoder).SetContext.
defaultDocumentM bool defaultDocumentM bool
defaultDocumentD bool defaultDocumentD bool
binaryAsSlice bool
useJSONStructTags bool
useLocalTimeZone bool
zeroMaps bool
zeroStructs bool
} }
// NewDecoder returns a new decoder that uses the DefaultRegistry to read from vr. // NewDecoder returns a new decoder that uses the DefaultRegistry to read from vr.
@ -53,6 +59,9 @@ func NewDecoder(vr bsonrw.ValueReader) (*Decoder, error) {
} }
// NewDecoderWithContext returns a new decoder that uses DecodeContext dc to read from vr. // NewDecoderWithContext returns a new decoder that uses DecodeContext dc to read from vr.
//
// Deprecated: Use [NewDecoder] and use the Decoder configuration methods set the desired unmarshal
// behavior instead.
func NewDecoderWithContext(dc bsoncodec.DecodeContext, vr bsonrw.ValueReader) (*Decoder, error) { func NewDecoderWithContext(dc bsoncodec.DecodeContext, vr bsonrw.ValueReader) (*Decoder, error) {
if dc.Registry == nil { if dc.Registry == nil {
dc.Registry = DefaultRegistry dc.Registry = DefaultRegistry
@ -70,8 +79,7 @@ func NewDecoderWithContext(dc bsoncodec.DecodeContext, vr bsonrw.ValueReader) (*
// Decode reads the next BSON document from the stream and decodes it into the // Decode reads the next BSON document from the stream and decodes it into the
// value pointed to by val. // value pointed to by val.
// //
// The documentation for Unmarshal contains details about of BSON into a Go // See [Unmarshal] for details about BSON unmarshaling behavior.
// value.
func (d *Decoder) Decode(val interface{}) error { func (d *Decoder) Decode(val interface{}) error {
if unmarshaler, ok := val.(Unmarshaler); ok { if unmarshaler, ok := val.(Unmarshaler); ok {
// TODO(skriptble): Reuse a []byte here and use the AppendDocumentBytes method. // TODO(skriptble): Reuse a []byte here and use the AppendDocumentBytes method.
@ -100,42 +108,101 @@ func (d *Decoder) Decode(val interface{}) error {
if err != nil { if err != nil {
return err return err
} }
if d.defaultDocumentM { if d.defaultDocumentM {
d.dc.DefaultDocumentM() d.dc.DefaultDocumentM()
} }
if d.defaultDocumentD { if d.defaultDocumentD {
d.dc.DefaultDocumentD() d.dc.DefaultDocumentD()
} }
if d.binaryAsSlice {
d.dc.BinaryAsSlice()
}
if d.useJSONStructTags {
d.dc.UseJSONStructTags()
}
if d.useLocalTimeZone {
d.dc.UseLocalTimeZone()
}
if d.zeroMaps {
d.dc.ZeroMaps()
}
if d.zeroStructs {
d.dc.ZeroStructs()
}
return decoder.DecodeValue(d.dc, d.vr, rval) return decoder.DecodeValue(d.dc, d.vr, rval)
} }
// Reset will reset the state of the decoder, using the same *DecodeContext used in // Reset will reset the state of the decoder, using the same *DecodeContext used in
// the original construction but using vr for reading. // the original construction but using vr for reading.
func (d *Decoder) Reset(vr bsonrw.ValueReader) error { func (d *Decoder) Reset(vr bsonrw.ValueReader) error {
// TODO:(GODRIVER-2719): Remove error return value.
d.vr = vr d.vr = vr
return nil return nil
} }
// SetRegistry replaces the current registry of the decoder with r. // SetRegistry replaces the current registry of the decoder with r.
func (d *Decoder) SetRegistry(r *bsoncodec.Registry) error { func (d *Decoder) SetRegistry(r *bsoncodec.Registry) error {
// TODO:(GODRIVER-2719): Remove error return value.
d.dc.Registry = r d.dc.Registry = r
return nil return nil
} }
// SetContext replaces the current registry of the decoder with dc. // SetContext replaces the current registry of the decoder with dc.
//
// Deprecated: Use the Decoder configuration methods to set the desired unmarshal behavior instead.
func (d *Decoder) SetContext(dc bsoncodec.DecodeContext) error { func (d *Decoder) SetContext(dc bsoncodec.DecodeContext) error {
// TODO:(GODRIVER-2719): Remove error return value.
d.dc = dc d.dc = dc
return nil return nil
} }
// DefaultDocumentM will decode empty documents using the primitive.M type. This behavior is restricted to data typed as // DefaultDocumentM causes the Decoder to always unmarshal documents into the primitive.M type. This
// "interface{}" or "map[string]interface{}". // behavior is restricted to data typed as "interface{}" or "map[string]interface{}".
func (d *Decoder) DefaultDocumentM() { func (d *Decoder) DefaultDocumentM() {
d.defaultDocumentM = true d.defaultDocumentM = true
} }
// DefaultDocumentD will decode empty documents using the primitive.D type. This behavior is restricted to data typed as // DefaultDocumentD causes the Decoder to always unmarshal documents into the primitive.D type. This
// "interface{}" or "map[string]interface{}". // behavior is restricted to data typed as "interface{}" or "map[string]interface{}".
func (d *Decoder) DefaultDocumentD() { func (d *Decoder) DefaultDocumentD() {
d.defaultDocumentD = true d.defaultDocumentD = true
} }
// AllowTruncatingDoubles causes the Decoder to truncate the fractional part of BSON "double" values
// when attempting to unmarshal them into a Go integer (int, int8, int16, int32, or int64) struct
// field. The truncation logic does not apply to BSON "decimal128" values.
func (d *Decoder) AllowTruncatingDoubles() {
d.dc.Truncate = true
}
// BinaryAsSlice causes the Decoder to unmarshal BSON binary field values that are the "Generic" or
// "Old" BSON binary subtype as a Go byte slice instead of a primitive.Binary.
func (d *Decoder) BinaryAsSlice() {
d.binaryAsSlice = true
}
// UseJSONStructTags causes the Decoder to fall back to using the "json" struct tag if a "bson"
// struct tag is not specified.
func (d *Decoder) UseJSONStructTags() {
d.useJSONStructTags = true
}
// UseLocalTimeZone causes the Decoder to unmarshal time.Time values in the local timezone instead
// of the UTC timezone.
func (d *Decoder) UseLocalTimeZone() {
d.useLocalTimeZone = true
}
// ZeroMaps causes the Decoder to delete any existing values from Go maps in the destination value
// passed to Decode before unmarshaling BSON documents into them.
func (d *Decoder) ZeroMaps() {
d.zeroMaps = true
}
// ZeroStructs causes the Decoder to delete any existing values from Go structs in the destination
// value passed to Decode before unmarshaling BSON documents into them.
func (d *Decoder) ZeroStructs() {
d.zeroStructs = true
}

View file

@ -6,8 +6,9 @@
// Package bson is a library for reading, writing, and manipulating BSON. BSON is a binary serialization format used to // Package bson is a library for reading, writing, and manipulating BSON. BSON is a binary serialization format used to
// store documents and make remote procedure calls in MongoDB. The BSON specification is located at https://bsonspec.org. // store documents and make remote procedure calls in MongoDB. The BSON specification is located at https://bsonspec.org.
// The BSON library handles marshalling and unmarshalling of values through a configurable codec system. For a description // The BSON library handles marshaling and unmarshaling of values through a configurable codec system. For a description
// of the codec system and examples of registering custom codecs, see the bsoncodec package. // of the codec system and examples of registering custom codecs, see the bsoncodec package. For additional information
// and usage examples, check out the [Work with BSON] page in the Go Driver docs site.
// //
// # Raw BSON // # Raw BSON
// //
@ -37,7 +38,7 @@
// bson.D{{"foo", "bar"}, {"hello", "world"}, {"pi", 3.14159}} // bson.D{{"foo", "bar"}, {"hello", "world"}, {"pi", 3.14159}}
// bson.M{"foo": "bar", "hello": "world", "pi": 3.14159} // bson.M{"foo": "bar", "hello": "world", "pi": 3.14159}
// //
// When decoding BSON to a D or M, the following type mappings apply when unmarshalling: // When decoding BSON to a D or M, the following type mappings apply when unmarshaling:
// //
// 1. BSON int32 unmarshals to an int32. // 1. BSON int32 unmarshals to an int32.
// 2. BSON int64 unmarshals to an int64. // 2. BSON int64 unmarshals to an int64.
@ -61,81 +62,78 @@
// 20. BSON DBPointer unmarshals to a primitive.DBPointer. // 20. BSON DBPointer unmarshals to a primitive.DBPointer.
// 21. BSON symbol unmarshals to a primitive.Symbol. // 21. BSON symbol unmarshals to a primitive.Symbol.
// //
// The above mappings also apply when marshalling a D or M to BSON. Some other useful marshalling mappings are: // The above mappings also apply when marshaling a D or M to BSON. Some other useful marshaling mappings are:
// //
// 1. time.Time marshals to a BSON datetime. // 1. time.Time marshals to a BSON datetime.
// 2. int8, int16, and int32 marshal to a BSON int32. // 2. int8, int16, and int32 marshal to a BSON int32.
// 3. int marshals to a BSON int32 if the value is between math.MinInt32 and math.MaxInt32, inclusive, and a BSON int64 // 3. int marshals to a BSON int32 if the value is between math.MinInt32 and math.MaxInt32, inclusive, and a BSON int64
// otherwise. // otherwise.
// 4. int64 marshals to BSON int64. // 4. int64 marshals to BSON int64 (unless [Encoder.IntMinSize] is set).
// 5. uint8 and uint16 marshal to a BSON int32. // 5. uint8 and uint16 marshal to a BSON int32.
// 6. uint, uint32, and uint64 marshal to a BSON int32 if the value is between math.MinInt32 and math.MaxInt32, // 6. uint, uint32, and uint64 marshal to a BSON int64 (unless [Encoder.IntMinSize] is set).
// inclusive, and BSON int64 otherwise. // 7. BSON null and undefined values will unmarshal into the zero value of a field (e.g. unmarshaling a BSON null or
// 7. BSON null and undefined values will unmarshal into the zero value of a field (e.g. unmarshalling a BSON null or
// undefined value into a string will yield the empty string.). // undefined value into a string will yield the empty string.).
// //
// # Structs // # Structs
// //
// Structs can be marshalled/unmarshalled to/from BSON or Extended JSON. When transforming structs to/from BSON or Extended // Structs can be marshaled/unmarshaled to/from BSON or Extended JSON. When transforming structs to/from BSON or Extended
// JSON, the following rules apply: // JSON, the following rules apply:
// //
// 1. Only exported fields in structs will be marshalled or unmarshalled. // 1. Only exported fields in structs will be marshaled or unmarshaled.
// //
// 2. When marshalling a struct, each field will be lowercased to generate the key for the corresponding BSON element. // 2. When marshaling a struct, each field will be lowercased to generate the key for the corresponding BSON element.
// For example, a struct field named "Foo" will generate key "foo". This can be overridden via a struct tag (e.g. // For example, a struct field named "Foo" will generate key "foo". This can be overridden via a struct tag (e.g.
// `bson:"fooField"` to generate key "fooField" instead). // `bson:"fooField"` to generate key "fooField" instead).
// //
// 3. An embedded struct field is marshalled as a subdocument. The key will be the lowercased name of the field's type. // 3. An embedded struct field is marshaled as a subdocument. The key will be the lowercased name of the field's type.
// //
// 4. A pointer field is marshalled as the underlying type if the pointer is non-nil. If the pointer is nil, it is // 4. A pointer field is marshaled as the underlying type if the pointer is non-nil. If the pointer is nil, it is
// marshalled as a BSON null value. // marshaled as a BSON null value.
// //
// 5. When unmarshalling, a field of type interface{} will follow the D/M type mappings listed above. BSON documents // 5. When unmarshaling, a field of type interface{} will follow the D/M type mappings listed above. BSON documents
// unmarshalled into an interface{} field will be unmarshalled as a D. // unmarshaled into an interface{} field will be unmarshaled as a D.
// //
// The encoding of each struct field can be customized by the "bson" struct tag. // The encoding of each struct field can be customized by the "bson" struct tag.
// //
// This tag behavior is configurable, and different struct tag behavior can be configured by initializing a new // This tag behavior is configurable, and different struct tag behavior can be configured by initializing a new
// bsoncodec.StructCodec with the desired tag parser and registering that StructCodec onto the Registry. By default, JSON tags // bsoncodec.StructCodec with the desired tag parser and registering that StructCodec onto the Registry. By default, JSON
// are not honored, but that can be enabled by creating a StructCodec with JSONFallbackStructTagParser, like below: // tags are not honored, but that can be enabled by creating a StructCodec with JSONFallbackStructTagParser, like below:
// //
// Example: // Example:
// //
// structcodec, _ := bsoncodec.NewStructCodec(bsoncodec.JSONFallbackStructTagParser) // structcodec, _ := bsoncodec.NewStructCodec(bsoncodec.JSONFallbackStructTagParser)
// //
// The bson tag gives the name of the field, possibly followed by a comma-separated list of options. // The bson tag gives the name of the field, possibly followed by a comma-separated list of options.
// The name may be empty in order to specify options without overriding the default field name. The following options can be used // The name may be empty in order to specify options without overriding the default field name. The following options can
// to configure behavior: // be used to configure behavior:
// //
// 1. omitempty: If the omitempty struct tag is specified on a field, the field will not be marshalled if it is set to // 1. omitempty: If the omitempty struct tag is specified on a field, the field will be omitted from the marshaling if
// the zero value. Fields with language primitive types such as integers, booleans, and strings are considered empty if // the field has an empty value, defined as false, 0, a nil pointer, a nil interface value, and any empty array,
// their value is equal to the zero value for the type (i.e. 0 for integers, false for booleans, and "" for strings). // slice, map, or string.
// Slices, maps, and arrays are considered empty if they are of length zero. Interfaces and pointers are considered
// empty if their value is nil. By default, structs are only considered empty if the struct type implements the
// bsoncodec.Zeroer interface and the IsZero method returns true. Struct fields whose types do not implement Zeroer are
// never considered empty and will be marshalled as embedded documents.
// NOTE: It is recommended that this tag be used for all slice and map fields. // NOTE: It is recommended that this tag be used for all slice and map fields.
// //
// 2. minsize: If the minsize struct tag is specified on a field of type int64, uint, uint32, or uint64 and the value of // 2. minsize: If the minsize struct tag is specified on a field of type int64, uint, uint32, or uint64 and the value of
// the field can fit in a signed int32, the field will be serialized as a BSON int32 rather than a BSON int64. For other // the field can fit in a signed int32, the field will be serialized as a BSON int32 rather than a BSON int64. For
// types, this tag is ignored. // other types, this tag is ignored.
// //
// 3. truncate: If the truncate struct tag is specified on a field with a non-float numeric type, BSON doubles unmarshalled // 3. truncate: If the truncate struct tag is specified on a field with a non-float numeric type, BSON doubles
// into that field will be truncated at the decimal point. For example, if 3.14 is unmarshalled into a field of type int, // unmarshaled into that field will be truncated at the decimal point. For example, if 3.14 is unmarshaled into a
// it will be unmarshalled as 3. If this tag is not specified, the decoder will throw an error if the value cannot be // field of type int, it will be unmarshaled as 3. If this tag is not specified, the decoder will throw an error if
// decoded without losing precision. For float64 or non-numeric types, this tag is ignored. // the value cannot be decoded without losing precision. For float64 or non-numeric types, this tag is ignored.
// //
// 4. inline: If the inline struct tag is specified for a struct or map field, the field will be "flattened" when // 4. inline: If the inline struct tag is specified for a struct or map field, the field will be "flattened" when
// marshalling and "un-flattened" when unmarshalling. This means that all of the fields in that struct/map will be // marshaling and "un-flattened" when unmarshaling. This means that all of the fields in that struct/map will be
// pulled up one level and will become top-level fields rather than being fields in a nested document. For example, if a // pulled up one level and will become top-level fields rather than being fields in a nested document. For example,
// map field named "Map" with value map[string]interface{}{"foo": "bar"} is inlined, the resulting document will be // if a map field named "Map" with value map[string]interface{}{"foo": "bar"} is inlined, the resulting document will
// {"foo": "bar"} instead of {"map": {"foo": "bar"}}. There can only be one inlined map field in a struct. If there are // be {"foo": "bar"} instead of {"map": {"foo": "bar"}}. There can only be one inlined map field in a struct. If
// duplicated fields in the resulting document when an inlined struct is marshalled, the inlined field will be overwritten. // there are duplicated fields in the resulting document when an inlined struct is marshaled, the inlined field will
// If there are duplicated fields in the resulting document when an inlined map is marshalled, an error will be returned. // be overwritten. If there are duplicated fields in the resulting document when an inlined map is marshaled, an
// This tag can be used with fields that are pointers to structs. If an inlined pointer field is nil, it will not be // error will be returned. This tag can be used with fields that are pointers to structs. If an inlined pointer field
// marshalled. For fields that are not maps or structs, this tag is ignored. // is nil, it will not be marshaled. For fields that are not maps or structs, this tag is ignored.
// //
// # Marshalling and Unmarshalling // # Marshaling and Unmarshaling
// //
// Manually marshalling and unmarshalling can be done with the Marshal and Unmarshal family of functions. // Manually marshaling and unmarshaling can be done with the Marshal and Unmarshal family of functions.
//
// [Work with BSON]: https://www.mongodb.com/docs/drivers/go/current/fundamentals/bson/
package bson package bson

View file

@ -29,10 +29,20 @@
type Encoder struct { type Encoder struct {
ec bsoncodec.EncodeContext ec bsoncodec.EncodeContext
vw bsonrw.ValueWriter vw bsonrw.ValueWriter
errorOnInlineDuplicates bool
intMinSize bool
stringifyMapKeysWithFmt bool
nilMapAsEmpty bool
nilSliceAsEmpty bool
nilByteSliceAsEmpty bool
omitZeroStruct bool
useJSONStructTags bool
} }
// NewEncoder returns a new encoder that uses the DefaultRegistry to write to vw. // NewEncoder returns a new encoder that uses the DefaultRegistry to write to vw.
func NewEncoder(vw bsonrw.ValueWriter) (*Encoder, error) { func NewEncoder(vw bsonrw.ValueWriter) (*Encoder, error) {
// TODO:(GODRIVER-2719): Remove error return value.
if vw == nil { if vw == nil {
return nil, errors.New("cannot create a new Encoder with a nil ValueWriter") return nil, errors.New("cannot create a new Encoder with a nil ValueWriter")
} }
@ -44,6 +54,9 @@ func NewEncoder(vw bsonrw.ValueWriter) (*Encoder, error) {
} }
// NewEncoderWithContext returns a new encoder that uses EncodeContext ec to write to vw. // NewEncoderWithContext returns a new encoder that uses EncodeContext ec to write to vw.
//
// Deprecated: Use [NewEncoder] and use the Encoder configuration methods to set the desired marshal
// behavior instead.
func NewEncoderWithContext(ec bsoncodec.EncodeContext, vw bsonrw.ValueWriter) (*Encoder, error) { func NewEncoderWithContext(ec bsoncodec.EncodeContext, vw bsonrw.ValueWriter) (*Encoder, error) {
if ec.Registry == nil { if ec.Registry == nil {
ec = bsoncodec.EncodeContext{Registry: DefaultRegistry} ec = bsoncodec.EncodeContext{Registry: DefaultRegistry}
@ -60,8 +73,7 @@ func NewEncoderWithContext(ec bsoncodec.EncodeContext, vw bsonrw.ValueWriter) (*
// Encode writes the BSON encoding of val to the stream. // Encode writes the BSON encoding of val to the stream.
// //
// The documentation for Marshal contains details about the conversion of Go // See [Marshal] for details about BSON marshaling behavior.
// values to BSON.
func (e *Encoder) Encode(val interface{}) error { func (e *Encoder) Encode(val interface{}) error {
if marshaler, ok := val.(Marshaler); ok { if marshaler, ok := val.(Marshaler); ok {
// TODO(skriptble): Should we have a MarshalAppender interface so that we can have []byte reuse? // TODO(skriptble): Should we have a MarshalAppender interface so that we can have []byte reuse?
@ -76,24 +88,112 @@ func (e *Encoder) Encode(val interface{}) error {
if err != nil { if err != nil {
return err return err
} }
// Copy the configurations applied to the Encoder over to the EncodeContext, which actually
// communicates those configurations to the default ValueEncoders.
if e.errorOnInlineDuplicates {
e.ec.ErrorOnInlineDuplicates()
}
if e.intMinSize {
e.ec.MinSize = true
}
if e.stringifyMapKeysWithFmt {
e.ec.StringifyMapKeysWithFmt()
}
if e.nilMapAsEmpty {
e.ec.NilMapAsEmpty()
}
if e.nilSliceAsEmpty {
e.ec.NilSliceAsEmpty()
}
if e.nilByteSliceAsEmpty {
e.ec.NilByteSliceAsEmpty()
}
if e.omitZeroStruct {
e.ec.OmitZeroStruct()
}
if e.useJSONStructTags {
e.ec.UseJSONStructTags()
}
return encoder.EncodeValue(e.ec, e.vw, reflect.ValueOf(val)) return encoder.EncodeValue(e.ec, e.vw, reflect.ValueOf(val))
} }
// Reset will reset the state of the encoder, using the same *EncodeContext used in // Reset will reset the state of the Encoder, using the same *EncodeContext used in
// the original construction but using vw. // the original construction but using vw.
func (e *Encoder) Reset(vw bsonrw.ValueWriter) error { func (e *Encoder) Reset(vw bsonrw.ValueWriter) error {
// TODO:(GODRIVER-2719): Remove error return value.
e.vw = vw e.vw = vw
return nil return nil
} }
// SetRegistry replaces the current registry of the encoder with r. // SetRegistry replaces the current registry of the Encoder with r.
func (e *Encoder) SetRegistry(r *bsoncodec.Registry) error { func (e *Encoder) SetRegistry(r *bsoncodec.Registry) error {
// TODO:(GODRIVER-2719): Remove error return value.
e.ec.Registry = r e.ec.Registry = r
return nil return nil
} }
// SetContext replaces the current EncodeContext of the encoder with er. // SetContext replaces the current EncodeContext of the encoder with ec.
//
// Deprecated: Use the Encoder configuration methods set the desired marshal behavior instead.
func (e *Encoder) SetContext(ec bsoncodec.EncodeContext) error { func (e *Encoder) SetContext(ec bsoncodec.EncodeContext) error {
// TODO:(GODRIVER-2719): Remove error return value.
e.ec = ec e.ec = ec
return nil return nil
} }
// ErrorOnInlineDuplicates causes the Encoder to return an error if there is a duplicate field in
// the marshaled BSON when the "inline" struct tag option is set.
func (e *Encoder) ErrorOnInlineDuplicates() {
e.errorOnInlineDuplicates = true
}
// IntMinSize causes the Encoder to marshal Go integer values (int, int8, int16, int32, int64, uint,
// uint8, uint16, uint32, or uint64) as the minimum BSON int size (either 32 or 64 bits) that can
// represent the integer value.
func (e *Encoder) IntMinSize() {
e.intMinSize = true
}
// StringifyMapKeysWithFmt causes the Encoder to convert Go map keys to BSON document field name
// strings using fmt.Sprint instead of the default string conversion logic.
func (e *Encoder) StringifyMapKeysWithFmt() {
e.stringifyMapKeysWithFmt = true
}
// NilMapAsEmpty causes the Encoder to marshal nil Go maps as empty BSON documents instead of BSON
// null.
func (e *Encoder) NilMapAsEmpty() {
e.nilMapAsEmpty = true
}
// NilSliceAsEmpty causes the Encoder to marshal nil Go slices as empty BSON arrays instead of BSON
// null.
func (e *Encoder) NilSliceAsEmpty() {
e.nilSliceAsEmpty = true
}
// NilByteSliceAsEmpty causes the Encoder to marshal nil Go byte slices as empty BSON binary values
// instead of BSON null.
func (e *Encoder) NilByteSliceAsEmpty() {
e.nilByteSliceAsEmpty = true
}
// TODO(GODRIVER-2820): Update the description to remove the note about only examining exported
// TODO struct fields once the logic is updated to also inspect private struct fields.
// OmitZeroStruct causes the Encoder to consider the zero value for a struct (e.g. MyStruct{})
// as empty and omit it from the marshaled BSON when the "omitempty" struct tag option is set.
//
// Note that the Encoder only examines exported struct fields when determining if a struct is the
// zero value. It considers pointers to a zero struct value (e.g. &MyStruct{}) not empty.
func (e *Encoder) OmitZeroStruct() {
e.omitZeroStruct = true
}
// UseJSONStructTags causes the Encoder to fall back to using the "json" struct tag if a "bson"
// struct tag is not specified.
func (e *Encoder) UseJSONStructTags() {
e.useJSONStructTags = true
}

View file

@ -9,6 +9,7 @@
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"sync"
"go.mongodb.org/mongo-driver/bson/bsoncodec" "go.mongodb.org/mongo-driver/bson/bsoncodec"
"go.mongodb.org/mongo-driver/bson/bsonrw" "go.mongodb.org/mongo-driver/bson/bsonrw"
@ -20,17 +21,23 @@
var bvwPool = bsonrw.NewBSONValueWriterPool() var bvwPool = bsonrw.NewBSONValueWriterPool()
var extjPool = bsonrw.NewExtJSONValueWriterPool() var extjPool = bsonrw.NewExtJSONValueWriterPool()
// Marshaler is an interface implemented by types that can marshal themselves // Marshaler is the interface implemented by types that can marshal themselves
// into a BSON document represented as bytes. The bytes returned must be a valid // into a valid BSON document.
// BSON document if the error is nil. //
// Implementations of Marshaler must return a full BSON document. To create
// custom BSON marshaling behavior for individual values in a BSON document,
// implement the ValueMarshaler interface instead.
type Marshaler interface { type Marshaler interface {
MarshalBSON() ([]byte, error) MarshalBSON() ([]byte, error)
} }
// ValueMarshaler is an interface implemented by types that can marshal // ValueMarshaler is the interface implemented by types that can marshal
// themselves into a BSON value as bytes. The type must be the valid type for // themselves into a valid BSON value. The format of the returned bytes must
// the bytes returned. The bytes and byte type together must be valid if the // match the returned type.
// error is nil. //
// Implementations of ValueMarshaler must return an individual BSON value. To
// create custom BSON marshaling behavior for an entire BSON document, implement
// the Marshaler interface instead.
type ValueMarshaler interface { type ValueMarshaler interface {
MarshalBSONValue() (bsontype.Type, []byte, error) MarshalBSONValue() (bsontype.Type, []byte, error)
} }
@ -48,12 +55,42 @@ func Marshal(val interface{}) ([]byte, error) {
// MarshalAppend will encode val as a BSON document and append the bytes to dst. If dst is not large enough to hold the // MarshalAppend will encode val as a BSON document and append the bytes to dst. If dst is not large enough to hold the
// bytes, it will be grown. If val is not a type that can be transformed into a document, MarshalValueAppend should be // bytes, it will be grown. If val is not a type that can be transformed into a document, MarshalValueAppend should be
// used instead. // used instead.
//
// Deprecated: Use [NewEncoder] and pass the dst byte slice (wrapped by a bytes.Buffer) into
// [bsonrw.NewBSONValueWriter]:
//
// buf := bytes.NewBuffer(dst)
// vw, err := bsonrw.NewBSONValueWriter(buf)
// if err != nil {
// panic(err)
// }
// enc, err := bson.NewEncoder(vw)
// if err != nil {
// panic(err)
// }
//
// See [Encoder] for more examples.
func MarshalAppend(dst []byte, val interface{}) ([]byte, error) { func MarshalAppend(dst []byte, val interface{}) ([]byte, error) {
return MarshalAppendWithRegistry(DefaultRegistry, dst, val) return MarshalAppendWithRegistry(DefaultRegistry, dst, val)
} }
// MarshalWithRegistry returns the BSON encoding of val as a BSON document. If val is not a type that can be transformed // MarshalWithRegistry returns the BSON encoding of val as a BSON document. If val is not a type that can be transformed
// into a document, MarshalValueWithRegistry should be used instead. // into a document, MarshalValueWithRegistry should be used instead.
//
// Deprecated: Use [NewEncoder] and specify the Registry by calling [Encoder.SetRegistry] instead:
//
// buf := new(bytes.Buffer)
// vw, err := bsonrw.NewBSONValueWriter(buf)
// if err != nil {
// panic(err)
// }
// enc, err := bson.NewEncoder(vw)
// if err != nil {
// panic(err)
// }
// enc.SetRegistry(reg)
//
// See [Encoder] for more examples.
func MarshalWithRegistry(r *bsoncodec.Registry, val interface{}) ([]byte, error) { func MarshalWithRegistry(r *bsoncodec.Registry, val interface{}) ([]byte, error) {
dst := make([]byte, 0) dst := make([]byte, 0)
return MarshalAppendWithRegistry(r, dst, val) return MarshalAppendWithRegistry(r, dst, val)
@ -61,6 +98,22 @@ func MarshalWithRegistry(r *bsoncodec.Registry, val interface{}) ([]byte, error)
// MarshalWithContext returns the BSON encoding of val as a BSON document using EncodeContext ec. If val is not a type // MarshalWithContext returns the BSON encoding of val as a BSON document using EncodeContext ec. If val is not a type
// that can be transformed into a document, MarshalValueWithContext should be used instead. // that can be transformed into a document, MarshalValueWithContext should be used instead.
//
// Deprecated: Use [NewEncoder] and use the Encoder configuration methods to set the desired marshal
// behavior instead:
//
// buf := bytes.NewBuffer(dst)
// vw, err := bsonrw.NewBSONValueWriter(buf)
// if err != nil {
// panic(err)
// }
// enc, err := bson.NewEncoder(vw)
// if err != nil {
// panic(err)
// }
// enc.IntMinSize()
//
// See [Encoder] for more examples.
func MarshalWithContext(ec bsoncodec.EncodeContext, val interface{}) ([]byte, error) { func MarshalWithContext(ec bsoncodec.EncodeContext, val interface{}) ([]byte, error) {
dst := make([]byte, 0) dst := make([]byte, 0)
return MarshalAppendWithContext(ec, dst, val) return MarshalAppendWithContext(ec, dst, val)
@ -69,16 +122,74 @@ func MarshalWithContext(ec bsoncodec.EncodeContext, val interface{}) ([]byte, er
// MarshalAppendWithRegistry will encode val as a BSON document using Registry r and append the bytes to dst. If dst is // MarshalAppendWithRegistry will encode val as a BSON document using Registry r and append the bytes to dst. If dst is
// not large enough to hold the bytes, it will be grown. If val is not a type that can be transformed into a document, // not large enough to hold the bytes, it will be grown. If val is not a type that can be transformed into a document,
// MarshalValueAppendWithRegistry should be used instead. // MarshalValueAppendWithRegistry should be used instead.
//
// Deprecated: Use [NewEncoder], and pass the dst byte slice (wrapped by a bytes.Buffer) into
// [bsonrw.NewBSONValueWriter], and specify the Registry by calling [Encoder.SetRegistry] instead:
//
// buf := bytes.NewBuffer(dst)
// vw, err := bsonrw.NewBSONValueWriter(buf)
// if err != nil {
// panic(err)
// }
// enc, err := bson.NewEncoder(vw)
// if err != nil {
// panic(err)
// }
// enc.SetRegistry(reg)
//
// See [Encoder] for more examples.
func MarshalAppendWithRegistry(r *bsoncodec.Registry, dst []byte, val interface{}) ([]byte, error) { func MarshalAppendWithRegistry(r *bsoncodec.Registry, dst []byte, val interface{}) ([]byte, error) {
return MarshalAppendWithContext(bsoncodec.EncodeContext{Registry: r}, dst, val) return MarshalAppendWithContext(bsoncodec.EncodeContext{Registry: r}, dst, val)
} }
// Pool of buffers for marshalling BSON.
var bufPool = sync.Pool{
New: func() interface{} {
return new(bytes.Buffer)
},
}
// MarshalAppendWithContext will encode val as a BSON document using Registry r and EncodeContext ec and append the // MarshalAppendWithContext will encode val as a BSON document using Registry r and EncodeContext ec and append the
// bytes to dst. If dst is not large enough to hold the bytes, it will be grown. If val is not a type that can be // bytes to dst. If dst is not large enough to hold the bytes, it will be grown. If val is not a type that can be
// transformed into a document, MarshalValueAppendWithContext should be used instead. // transformed into a document, MarshalValueAppendWithContext should be used instead.
//
// Deprecated: Use [NewEncoder], pass the dst byte slice (wrapped by a bytes.Buffer) into
// [bsonrw.NewBSONValueWriter], and use the Encoder configuration methods to set the desired marshal
// behavior instead:
//
// buf := bytes.NewBuffer(dst)
// vw, err := bsonrw.NewBSONValueWriter(buf)
// if err != nil {
// panic(err)
// }
// enc, err := bson.NewEncoder(vw)
// if err != nil {
// panic(err)
// }
// enc.IntMinSize()
//
// See [Encoder] for more examples.
func MarshalAppendWithContext(ec bsoncodec.EncodeContext, dst []byte, val interface{}) ([]byte, error) { func MarshalAppendWithContext(ec bsoncodec.EncodeContext, dst []byte, val interface{}) ([]byte, error) {
sw := new(bsonrw.SliceWriter) sw := bufPool.Get().(*bytes.Buffer)
*sw = dst defer func() {
// Proper usage of a sync.Pool requires each entry to have approximately
// the same memory cost. To obtain this property when the stored type
// contains a variably-sized buffer, we add a hard limit on the maximum
// buffer to place back in the pool. We limit the size to 16MiB because
// that's the maximum wire message size supported by any current MongoDB
// server.
//
// Comment based on
// https://cs.opensource.google/go/go/+/refs/tags/go1.19:src/fmt/print.go;l=147
//
// Recycle byte slices that are smaller than 16MiB and at least half
// occupied.
if sw.Cap() < 16*1024*1024 && sw.Cap()/2 < sw.Len() {
bufPool.Put(sw)
}
}()
sw.Reset()
vw := bvwPool.Get(sw) vw := bvwPool.Get(sw)
defer bvwPool.Put(vw) defer bvwPool.Put(vw)
@ -99,7 +210,7 @@ func MarshalAppendWithContext(ec bsoncodec.EncodeContext, dst []byte, val interf
return nil, err return nil, err
} }
return *sw, nil return append(dst, sw.Bytes()...), nil
} }
// MarshalValue returns the BSON encoding of val. // MarshalValue returns the BSON encoding of val.
@ -112,17 +223,26 @@ func MarshalValue(val interface{}) (bsontype.Type, []byte, error) {
// MarshalValueAppend will append the BSON encoding of val to dst. If dst is not large enough to hold the BSON encoding // MarshalValueAppend will append the BSON encoding of val to dst. If dst is not large enough to hold the BSON encoding
// of val, dst will be grown. // of val, dst will be grown.
//
// Deprecated: Appending individual BSON elements to an existing slice will not be supported in Go
// Driver 2.0.
func MarshalValueAppend(dst []byte, val interface{}) (bsontype.Type, []byte, error) { func MarshalValueAppend(dst []byte, val interface{}) (bsontype.Type, []byte, error) {
return MarshalValueAppendWithRegistry(DefaultRegistry, dst, val) return MarshalValueAppendWithRegistry(DefaultRegistry, dst, val)
} }
// MarshalValueWithRegistry returns the BSON encoding of val using Registry r. // MarshalValueWithRegistry returns the BSON encoding of val using Registry r.
//
// Deprecated: Using a custom registry to marshal individual BSON values will not be supported in Go
// Driver 2.0.
func MarshalValueWithRegistry(r *bsoncodec.Registry, val interface{}) (bsontype.Type, []byte, error) { func MarshalValueWithRegistry(r *bsoncodec.Registry, val interface{}) (bsontype.Type, []byte, error) {
dst := make([]byte, 0) dst := make([]byte, 0)
return MarshalValueAppendWithRegistry(r, dst, val) return MarshalValueAppendWithRegistry(r, dst, val)
} }
// MarshalValueWithContext returns the BSON encoding of val using EncodeContext ec. // MarshalValueWithContext returns the BSON encoding of val using EncodeContext ec.
//
// Deprecated: Using a custom EncodeContext to marshal individual BSON elements will not be
// supported in Go Driver 2.0.
func MarshalValueWithContext(ec bsoncodec.EncodeContext, val interface{}) (bsontype.Type, []byte, error) { func MarshalValueWithContext(ec bsoncodec.EncodeContext, val interface{}) (bsontype.Type, []byte, error) {
dst := make([]byte, 0) dst := make([]byte, 0)
return MarshalValueAppendWithContext(ec, dst, val) return MarshalValueAppendWithContext(ec, dst, val)
@ -130,12 +250,18 @@ func MarshalValueWithContext(ec bsoncodec.EncodeContext, val interface{}) (bsont
// MarshalValueAppendWithRegistry will append the BSON encoding of val to dst using Registry r. If dst is not large // MarshalValueAppendWithRegistry will append the BSON encoding of val to dst using Registry r. If dst is not large
// enough to hold the BSON encoding of val, dst will be grown. // enough to hold the BSON encoding of val, dst will be grown.
//
// Deprecated: Appending individual BSON elements to an existing slice will not be supported in Go
// Driver 2.0.
func MarshalValueAppendWithRegistry(r *bsoncodec.Registry, dst []byte, val interface{}) (bsontype.Type, []byte, error) { func MarshalValueAppendWithRegistry(r *bsoncodec.Registry, dst []byte, val interface{}) (bsontype.Type, []byte, error) {
return MarshalValueAppendWithContext(bsoncodec.EncodeContext{Registry: r}, dst, val) return MarshalValueAppendWithContext(bsoncodec.EncodeContext{Registry: r}, dst, val)
} }
// MarshalValueAppendWithContext will append the BSON encoding of val to dst using EncodeContext ec. If dst is not large // MarshalValueAppendWithContext will append the BSON encoding of val to dst using EncodeContext ec. If dst is not large
// enough to hold the BSON encoding of val, dst will be grown. // enough to hold the BSON encoding of val, dst will be grown.
//
// Deprecated: Appending individual BSON elements to an existing slice will not be supported in Go
// Driver 2.0.
func MarshalValueAppendWithContext(ec bsoncodec.EncodeContext, dst []byte, val interface{}) (bsontype.Type, []byte, error) { func MarshalValueAppendWithContext(ec bsoncodec.EncodeContext, dst []byte, val interface{}) (bsontype.Type, []byte, error) {
// get a ValueWriter configured to write to dst // get a ValueWriter configured to write to dst
sw := new(bsonrw.SliceWriter) sw := new(bsonrw.SliceWriter)
@ -173,17 +299,63 @@ func MarshalExtJSON(val interface{}, canonical, escapeHTML bool) ([]byte, error)
// MarshalExtJSONAppend will append the extended JSON encoding of val to dst. // MarshalExtJSONAppend will append the extended JSON encoding of val to dst.
// If dst is not large enough to hold the extended JSON encoding of val, dst // If dst is not large enough to hold the extended JSON encoding of val, dst
// will be grown. // will be grown.
//
// Deprecated: Use [NewEncoder] and pass the dst byte slice (wrapped by a bytes.Buffer) into
// [bsonrw.NewExtJSONValueWriter] instead:
//
// buf := bytes.NewBuffer(dst)
// vw, err := bsonrw.NewExtJSONValueWriter(buf, true, false)
// if err != nil {
// panic(err)
// }
// enc, err := bson.NewEncoder(vw)
// if err != nil {
// panic(err)
// }
//
// See [Encoder] for more examples.
func MarshalExtJSONAppend(dst []byte, val interface{}, canonical, escapeHTML bool) ([]byte, error) { func MarshalExtJSONAppend(dst []byte, val interface{}, canonical, escapeHTML bool) ([]byte, error) {
return MarshalExtJSONAppendWithRegistry(DefaultRegistry, dst, val, canonical, escapeHTML) return MarshalExtJSONAppendWithRegistry(DefaultRegistry, dst, val, canonical, escapeHTML)
} }
// MarshalExtJSONWithRegistry returns the extended JSON encoding of val using Registry r. // MarshalExtJSONWithRegistry returns the extended JSON encoding of val using Registry r.
//
// Deprecated: Use [NewEncoder] and specify the Registry by calling [Encoder.SetRegistry] instead:
//
// buf := new(bytes.Buffer)
// vw, err := bsonrw.NewBSONValueWriter(buf)
// if err != nil {
// panic(err)
// }
// enc, err := bson.NewEncoder(vw)
// if err != nil {
// panic(err)
// }
// enc.SetRegistry(reg)
//
// See [Encoder] for more examples.
func MarshalExtJSONWithRegistry(r *bsoncodec.Registry, val interface{}, canonical, escapeHTML bool) ([]byte, error) { func MarshalExtJSONWithRegistry(r *bsoncodec.Registry, val interface{}, canonical, escapeHTML bool) ([]byte, error) {
dst := make([]byte, 0, defaultDstCap) dst := make([]byte, 0, defaultDstCap)
return MarshalExtJSONAppendWithContext(bsoncodec.EncodeContext{Registry: r}, dst, val, canonical, escapeHTML) return MarshalExtJSONAppendWithContext(bsoncodec.EncodeContext{Registry: r}, dst, val, canonical, escapeHTML)
} }
// MarshalExtJSONWithContext returns the extended JSON encoding of val using Registry r. // MarshalExtJSONWithContext returns the extended JSON encoding of val using Registry r.
//
// Deprecated: Use [NewEncoder] and use the Encoder configuration methods to set the desired marshal
// behavior instead:
//
// buf := new(bytes.Buffer)
// vw, err := bsonrw.NewBSONValueWriter(buf)
// if err != nil {
// panic(err)
// }
// enc, err := bson.NewEncoder(vw)
// if err != nil {
// panic(err)
// }
// enc.IntMinSize()
//
// See [Encoder] for more examples.
func MarshalExtJSONWithContext(ec bsoncodec.EncodeContext, val interface{}, canonical, escapeHTML bool) ([]byte, error) { func MarshalExtJSONWithContext(ec bsoncodec.EncodeContext, val interface{}, canonical, escapeHTML bool) ([]byte, error) {
dst := make([]byte, 0, defaultDstCap) dst := make([]byte, 0, defaultDstCap)
return MarshalExtJSONAppendWithContext(ec, dst, val, canonical, escapeHTML) return MarshalExtJSONAppendWithContext(ec, dst, val, canonical, escapeHTML)
@ -192,6 +364,22 @@ func MarshalExtJSONWithContext(ec bsoncodec.EncodeContext, val interface{}, cano
// MarshalExtJSONAppendWithRegistry will append the extended JSON encoding of // MarshalExtJSONAppendWithRegistry will append the extended JSON encoding of
// val to dst using Registry r. If dst is not large enough to hold the BSON // val to dst using Registry r. If dst is not large enough to hold the BSON
// encoding of val, dst will be grown. // encoding of val, dst will be grown.
//
// Deprecated: Use [NewEncoder], pass the dst byte slice (wrapped by a bytes.Buffer) into
// [bsonrw.NewExtJSONValueWriter], and specify the Registry by calling [Encoder.SetRegistry]
// instead:
//
// buf := bytes.NewBuffer(dst)
// vw, err := bsonrw.NewExtJSONValueWriter(buf, true, false)
// if err != nil {
// panic(err)
// }
// enc, err := bson.NewEncoder(vw)
// if err != nil {
// panic(err)
// }
//
// See [Encoder] for more examples.
func MarshalExtJSONAppendWithRegistry(r *bsoncodec.Registry, dst []byte, val interface{}, canonical, escapeHTML bool) ([]byte, error) { func MarshalExtJSONAppendWithRegistry(r *bsoncodec.Registry, dst []byte, val interface{}, canonical, escapeHTML bool) ([]byte, error) {
return MarshalExtJSONAppendWithContext(bsoncodec.EncodeContext{Registry: r}, dst, val, canonical, escapeHTML) return MarshalExtJSONAppendWithContext(bsoncodec.EncodeContext{Registry: r}, dst, val, canonical, escapeHTML)
} }
@ -199,6 +387,23 @@ func MarshalExtJSONAppendWithRegistry(r *bsoncodec.Registry, dst []byte, val int
// MarshalExtJSONAppendWithContext will append the extended JSON encoding of // MarshalExtJSONAppendWithContext will append the extended JSON encoding of
// val to dst using Registry r. If dst is not large enough to hold the BSON // val to dst using Registry r. If dst is not large enough to hold the BSON
// encoding of val, dst will be grown. // encoding of val, dst will be grown.
//
// Deprecated: Use [NewEncoder], pass the dst byte slice (wrapped by a bytes.Buffer) into
// [bsonrw.NewExtJSONValueWriter], and use the Encoder configuration methods to set the desired marshal
// behavior instead:
//
// buf := bytes.NewBuffer(dst)
// vw, err := bsonrw.NewExtJSONValueWriter(buf, true, false)
// if err != nil {
// panic(err)
// }
// enc, err := bson.NewEncoder(vw)
// if err != nil {
// panic(err)
// }
// enc.IntMinSize()
//
// See [Encoder] for more examples.
func MarshalExtJSONAppendWithContext(ec bsoncodec.EncodeContext, dst []byte, val interface{}, canonical, escapeHTML bool) ([]byte, error) { func MarshalExtJSONAppendWithContext(ec bsoncodec.EncodeContext, dst []byte, val interface{}, canonical, escapeHTML bool) ([]byte, error) {
sw := new(bsonrw.SliceWriter) sw := new(bsonrw.SliceWriter)
*sw = dst *sw = dst

View file

@ -164,9 +164,6 @@ func (d Decimal128) BigInt() (*big.Int, int, error) {
// Would be handled by the logic below, but that's trivial and common. // Would be handled by the logic below, but that's trivial and common.
if high == 0 && low == 0 && exp == 0 { if high == 0 && low == 0 && exp == 0 {
if posSign {
return new(big.Int), 0, nil
}
return new(big.Int), 0, nil return new(big.Int), 0, nil
} }
@ -328,6 +325,7 @@ func ParseDecimal128(s string) (Decimal128, error) {
return dErr(s) return dErr(s)
} }
// Parse the significand (i.e. the non-exponent part) as a big.Int.
bi, ok := new(big.Int).SetString(intPart+decPart, 10) bi, ok := new(big.Int).SetString(intPart+decPart, 10)
if !ok { if !ok {
return dErr(s) return dErr(s)
@ -360,6 +358,19 @@ func ParseDecimal128FromBigInt(bi *big.Int, exp int) (Decimal128, bool) {
q := new(big.Int) q := new(big.Int)
r := new(big.Int) r := new(big.Int)
// If the significand is zero, the logical value will always be zero, independent of the
// exponent. However, the loops for handling out-of-range exponent values below may be extremely
// slow for zero values because the significand never changes. Limit the exponent value to the
// supported range here to prevent entering the loops below.
if bi.Cmp(zero) == 0 {
if exp > MaxDecimal128Exp {
exp = MaxDecimal128Exp
}
if exp < MinDecimal128Exp {
exp = MinDecimal128Exp
}
}
for bigIntCmpAbs(bi, maxS) == 1 { for bigIntCmpAbs(bi, maxS) == 1 {
bi, _ = q.QuoRem(bi, ten, r) bi, _ = q.QuoRem(bi, ten, r)
if r.Cmp(zero) != 0 { if r.Cmp(zero) != 0 {

View file

@ -82,18 +82,18 @@ func ObjectIDFromHex(s string) (ObjectID, error) {
return NilObjectID, ErrInvalidHex return NilObjectID, ErrInvalidHex
} }
b, err := hex.DecodeString(s) var oid [12]byte
_, err := hex.Decode(oid[:], []byte(s))
if err != nil { if err != nil {
return NilObjectID, err return NilObjectID, err
} }
var oid [12]byte
copy(oid[:], b)
return oid, nil return oid, nil
} }
// IsValidObjectID returns true if the provided hex string represents a valid ObjectID and false if not. // IsValidObjectID returns true if the provided hex string represents a valid ObjectID and false if not.
//
// Deprecated: Use ObjectIDFromHex and check the error instead.
func IsValidObjectID(s string) bool { func IsValidObjectID(s string) bool {
_, err := ObjectIDFromHex(s) _, err := ObjectIDFromHex(s)
return err == nil return err == nil
@ -183,7 +183,7 @@ func processUniqueBytes() [5]byte {
var b [5]byte var b [5]byte
_, err := io.ReadFull(rand.Reader, b[:]) _, err := io.ReadFull(rand.Reader, b[:])
if err != nil { if err != nil {
panic(fmt.Errorf("cannot initialize objectid package with crypto.rand.Reader: %v", err)) panic(fmt.Errorf("cannot initialize objectid package with crypto.rand.Reader: %w", err))
} }
return b return b
@ -193,7 +193,7 @@ func readRandomUint32() uint32 {
var b [4]byte var b [4]byte
_, err := io.ReadFull(rand.Reader, b[:]) _, err := io.ReadFull(rand.Reader, b[:])
if err != nil { if err != nil {
panic(fmt.Errorf("cannot initialize objectid package with crypto.rand.Reader: %v", err)) panic(fmt.Errorf("cannot initialize objectid package with crypto.rand.Reader: %w", err))
} }
return (uint32(b[0]) << 0) | (uint32(b[1]) << 8) | (uint32(b[2]) << 16) | (uint32(b[3]) << 24) return (uint32(b[0]) << 0) | (uint32(b[1]) << 8) | (uint32(b[2]) << 16) | (uint32(b[3]) << 24)

View file

@ -45,7 +45,7 @@ type Undefined struct{
// MarshalJSON marshal to time type. // MarshalJSON marshal to time type.
func (d DateTime) MarshalJSON() ([]byte, error) { func (d DateTime) MarshalJSON() ([]byte, error) {
return json.Marshal(d.Time()) return json.Marshal(d.Time().UTC())
} }
// UnmarshalJSON creates a primitive.DateTime from a JSON string. // UnmarshalJSON creates a primitive.DateTime from a JSON string.
@ -141,6 +141,16 @@ type Timestamp struct {
I uint32 I uint32
} }
// After reports whether the time instant tp is after tp2.
func (tp Timestamp) After(tp2 Timestamp) bool {
return tp.T > tp2.T || (tp.T == tp2.T && tp.I > tp2.I)
}
// Before reports whether the time instant tp is before tp2.
func (tp Timestamp) Before(tp2 Timestamp) bool {
return tp.T < tp2.T || (tp.T == tp2.T && tp.I < tp2.I)
}
// Equal compares tp to tp2 and returns true if they are equal. // Equal compares tp to tp2 and returns true if they are equal.
func (tp Timestamp) Equal(tp2 Timestamp) bool { func (tp Timestamp) Equal(tp2 Timestamp) bool {
return tp.T == tp2.T && tp.I == tp2.I return tp.T == tp2.T && tp.I == tp2.I
@ -151,24 +161,25 @@ func (tp Timestamp) IsZero() bool {
return tp.T == 0 && tp.I == 0 return tp.T == 0 && tp.I == 0
} }
// CompareTimestamp returns an integer comparing two Timestamps, where T is compared first, followed by I. // Compare compares the time instant tp with tp2. If tp is before tp2, it returns -1; if tp is after
// Returns 0 if tp = tp2, 1 if tp > tp2, -1 if tp < tp2. // tp2, it returns +1; if they're the same, it returns 0.
func CompareTimestamp(tp, tp2 Timestamp) int { func (tp Timestamp) Compare(tp2 Timestamp) int {
if tp.Equal(tp2) { switch {
case tp.Equal(tp2):
return 0 return 0
} case tp.Before(tp2):
if tp.T > tp2.T {
return 1
}
if tp.T < tp2.T {
return -1 return -1
default:
return +1
} }
// Compare I values because T values are equal }
if tp.I > tp2.I {
return 1 // CompareTimestamp compares the time instant tp with tp2. If tp is before tp2, it returns -1; if tp is after
} // tp2, it returns +1; if they're the same, it returns 0.
return -1 //
// Deprecated: Use Timestamp.Compare instead.
func CompareTimestamp(tp, tp2 Timestamp) int {
return tp.Compare(tp2)
} }
// MinKey represents the BSON minkey value. // MinKey represents the BSON minkey value.
@ -186,6 +197,9 @@ type MaxKey struct{
type D []E type D []E
// Map creates a map from the elements of the D. // Map creates a map from the elements of the D.
//
// Deprecated: Converting directly from a D to an M will not be supported in Go Driver 2.0. Instead,
// users should marshal the D to BSON using bson.Marshal and unmarshal it to M using bson.Unmarshal.
func (d D) Map() M { func (d D) Map() M {
m := make(M, len(d)) m := make(M, len(d))
for _, e := range d { for _, e := range d {

View file

@ -8,6 +8,7 @@
import ( import (
"errors" "errors"
"fmt"
"reflect" "reflect"
"go.mongodb.org/mongo-driver/bson/bsoncodec" "go.mongodb.org/mongo-driver/bson/bsoncodec"
@ -21,10 +22,16 @@
// PrimitiveCodecs is a namespace for all of the default bsoncodec.Codecs for the primitive types // PrimitiveCodecs is a namespace for all of the default bsoncodec.Codecs for the primitive types
// defined in this package. // defined in this package.
//
// Deprecated: Use bson.NewRegistry to get a registry with all primitive encoders and decoders
// registered.
type PrimitiveCodecs struct{} type PrimitiveCodecs struct{}
// RegisterPrimitiveCodecs will register the encode and decode methods attached to PrimitiveCodecs // RegisterPrimitiveCodecs will register the encode and decode methods attached to PrimitiveCodecs
// with the provided RegistryBuilder. if rb is nil, a new empty RegistryBuilder will be created. // with the provided RegistryBuilder. if rb is nil, a new empty RegistryBuilder will be created.
//
// Deprecated: Use bson.NewRegistry to get a registry with all primitive encoders and decoders
// registered.
func (pc PrimitiveCodecs) RegisterPrimitiveCodecs(rb *bsoncodec.RegistryBuilder) { func (pc PrimitiveCodecs) RegisterPrimitiveCodecs(rb *bsoncodec.RegistryBuilder) {
if rb == nil { if rb == nil {
panic(errors.New("argument to RegisterPrimitiveCodecs must not be nil")) panic(errors.New("argument to RegisterPrimitiveCodecs must not be nil"))
@ -38,18 +45,35 @@ func (pc PrimitiveCodecs) RegisterPrimitiveCodecs(rb *bsoncodec.RegistryBuilder)
} }
// RawValueEncodeValue is the ValueEncoderFunc for RawValue. // RawValueEncodeValue is the ValueEncoderFunc for RawValue.
func (PrimitiveCodecs) RawValueEncodeValue(ec bsoncodec.EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { //
// If the RawValue's Type is "invalid" and the RawValue's Value is not empty or
// nil, then this method will return an error.
//
// Deprecated: Use bson.NewRegistry to get a registry with all primitive
// encoders and decoders registered.
func (PrimitiveCodecs) RawValueEncodeValue(_ bsoncodec.EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {
if !val.IsValid() || val.Type() != tRawValue { if !val.IsValid() || val.Type() != tRawValue {
return bsoncodec.ValueEncoderError{Name: "RawValueEncodeValue", Types: []reflect.Type{tRawValue}, Received: val} return bsoncodec.ValueEncoderError{
Name: "RawValueEncodeValue",
Types: []reflect.Type{tRawValue},
Received: val,
}
} }
rawvalue := val.Interface().(RawValue) rawvalue := val.Interface().(RawValue)
if !rawvalue.Type.IsValid() {
return fmt.Errorf("the RawValue Type specifies an invalid BSON type: %#x", byte(rawvalue.Type))
}
return bsonrw.Copier{}.CopyValueFromBytes(vw, rawvalue.Type, rawvalue.Value) return bsonrw.Copier{}.CopyValueFromBytes(vw, rawvalue.Type, rawvalue.Value)
} }
// RawValueDecodeValue is the ValueDecoderFunc for RawValue. // RawValueDecodeValue is the ValueDecoderFunc for RawValue.
func (PrimitiveCodecs) RawValueDecodeValue(dc bsoncodec.DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { //
// Deprecated: Use bson.NewRegistry to get a registry with all primitive encoders and decoders
// registered.
func (PrimitiveCodecs) RawValueDecodeValue(_ bsoncodec.DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
if !val.CanSet() || val.Type() != tRawValue { if !val.CanSet() || val.Type() != tRawValue {
return bsoncodec.ValueDecoderError{Name: "RawValueDecodeValue", Types: []reflect.Type{tRawValue}, Received: val} return bsoncodec.ValueDecoderError{Name: "RawValueDecodeValue", Types: []reflect.Type{tRawValue}, Received: val}
} }
@ -64,7 +88,10 @@ func (PrimitiveCodecs) RawValueDecodeValue(dc bsoncodec.DecodeContext, vr bsonrw
} }
// RawEncodeValue is the ValueEncoderFunc for Reader. // RawEncodeValue is the ValueEncoderFunc for Reader.
func (PrimitiveCodecs) RawEncodeValue(ec bsoncodec.EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error { //
// Deprecated: Use bson.NewRegistry to get a registry with all primitive encoders and decoders
// registered.
func (PrimitiveCodecs) RawEncodeValue(_ bsoncodec.EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {
if !val.IsValid() || val.Type() != tRaw { if !val.IsValid() || val.Type() != tRaw {
return bsoncodec.ValueEncoderError{Name: "RawEncodeValue", Types: []reflect.Type{tRaw}, Received: val} return bsoncodec.ValueEncoderError{Name: "RawEncodeValue", Types: []reflect.Type{tRaw}, Received: val}
} }
@ -75,7 +102,10 @@ func (PrimitiveCodecs) RawEncodeValue(ec bsoncodec.EncodeContext, vw bsonrw.Valu
} }
// RawDecodeValue is the ValueDecoderFunc for Reader. // RawDecodeValue is the ValueDecoderFunc for Reader.
func (PrimitiveCodecs) RawDecodeValue(dc bsoncodec.DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { //
// Deprecated: Use bson.NewRegistry to get a registry with all primitive encoders and decoders
// registered.
func (PrimitiveCodecs) RawDecodeValue(_ bsoncodec.DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
if !val.CanSet() || val.Type() != tRaw { if !val.CanSet() || val.Type() != tRaw {
return bsoncodec.ValueDecoderError{Name: "RawDecodeValue", Types: []reflect.Type{tRaw}, Received: val} return bsoncodec.ValueDecoderError{Name: "RawDecodeValue", Types: []reflect.Type{tRaw}, Received: val}
} }

View file

@ -16,18 +16,27 @@
// ErrNilReader indicates that an operation was attempted on a nil bson.Reader. // ErrNilReader indicates that an operation was attempted on a nil bson.Reader.
var ErrNilReader = errors.New("nil reader") var ErrNilReader = errors.New("nil reader")
// Raw is a wrapper around a byte slice. It will interpret the slice as a // Raw is a raw encoded BSON document. It can be used to delay BSON document decoding or precompute
// BSON document. This type is a wrapper around a bsoncore.Document. Errors returned from the // a BSON encoded document.
// methods on this type and associated types come from the bsoncore package. //
// A Raw must be a full BSON document. Use the RawValue type for individual BSON values.
type Raw []byte type Raw []byte
// NewFromIOReader reads in a document from the given io.Reader and constructs a Raw from // ReadDocument reads a BSON document from the io.Reader and returns it as a bson.Raw. If the
// it. // reader contains multiple BSON documents, only the first document is read.
func NewFromIOReader(r io.Reader) (Raw, error) { func ReadDocument(r io.Reader) (Raw, error) {
doc, err := bsoncore.NewDocumentFromReader(r) doc, err := bsoncore.NewDocumentFromReader(r)
return Raw(doc), err return Raw(doc), err
} }
// NewFromIOReader reads a BSON document from the io.Reader and returns it as a bson.Raw. If the
// reader contains multiple BSON documents, only the first document is read.
//
// Deprecated: Use ReadDocument instead.
func NewFromIOReader(r io.Reader) (Raw, error) {
return ReadDocument(r)
}
// Validate validates the document. This method only validates the first document in // Validate validates the document. This method only validates the first document in
// the slice, to validate other documents, the slice must be resliced. // the slice, to validate other documents, the slice must be resliced.
func (r Raw) Validate() (err error) { return bsoncore.Document(r).Validate() } func (r Raw) Validate() (err error) { return bsoncore.Document(r).Validate() }
@ -51,12 +60,19 @@ func (r Raw) LookupErr(key ...string) (RawValue, error) {
// elements. If the document is not valid, the elements up to the invalid point will be returned // elements. If the document is not valid, the elements up to the invalid point will be returned
// along with an error. // along with an error.
func (r Raw) Elements() ([]RawElement, error) { func (r Raw) Elements() ([]RawElement, error) {
elems, err := bsoncore.Document(r).Elements() doc := bsoncore.Document(r)
if len(doc) == 0 {
return nil, nil
}
elems, err := doc.Elements()
if err != nil {
return nil, err
}
relems := make([]RawElement, 0, len(elems)) relems := make([]RawElement, 0, len(elems))
for _, elem := range elems { for _, elem := range elems {
relems = append(relems, RawElement(elem)) relems = append(relems, RawElement(elem))
} }
return relems, err return relems, nil
} }
// Values returns this document as a slice of values. The returned slice will contain valid values. // Values returns this document as a slice of values. The returned slice will contain valid values.
@ -81,5 +97,5 @@ func (r Raw) IndexErr(index uint) (RawElement, error) {
return RawElement(elem), err return RawElement(elem), err
} }
// String implements the fmt.Stringer interface. // String returns the BSON document encoded as Extended JSON.
func (r Raw) String() string { return bsoncore.Document(r).String() } func (r Raw) String() string { return bsoncore.Document(r).String() }

View file

@ -10,10 +10,7 @@
"go.mongodb.org/mongo-driver/x/bsonx/bsoncore" "go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
) )
// RawElement represents a BSON element in byte form. This type provides a simple way to // RawElement is a raw encoded BSON document or array element.
// transform a slice of bytes into a BSON element and extract information from it.
//
// RawElement is a thin wrapper around a bsoncore.Element.
type RawElement []byte type RawElement []byte
// Key returns the key for this element. If the element is not valid, this method returns an empty // Key returns the key for this element. If the element is not valid, this method returns an empty
@ -36,7 +33,7 @@ func (re RawElement) ValueErr() (RawValue, error) {
// Validate ensures re is a valid BSON element. // Validate ensures re is a valid BSON element.
func (re RawElement) Validate() error { return bsoncore.Element(re).Validate() } func (re RawElement) Validate() error { return bsoncore.Element(re).Validate() }
// String implements the fmt.Stringer interface. The output will be in extended JSON format. // String returns the BSON element encoded as Extended JSON.
func (re RawElement) String() string { func (re RawElement) String() string {
doc := bsoncore.BuildDocument(nil, re) doc := bsoncore.BuildDocument(nil, re)
j, err := MarshalExtJSON(Raw(doc), true, false) j, err := MarshalExtJSON(Raw(doc), true, false)

View file

@ -26,11 +26,10 @@
// ErrNilRegistry is returned when the provided registry is nil. // ErrNilRegistry is returned when the provided registry is nil.
var ErrNilRegistry = errors.New("Registry cannot be nil") var ErrNilRegistry = errors.New("Registry cannot be nil")
// RawValue represents a BSON value in byte form. It can be used to hold unprocessed BSON or to // RawValue is a raw encoded BSON value. It can be used to delay BSON value decoding or precompute
// defer processing of BSON. Type is the BSON type of the value and Value are the raw bytes that // BSON encoded value. Type is the BSON type of the value and Value is the raw encoded BSON value.
// represent the element.
// //
// This type wraps bsoncore.Value for most of it's functionality. // A RawValue must be an individual BSON value. Use the Raw type for full BSON documents.
type RawValue struct { type RawValue struct {
Type bsontype.Type Type bsontype.Type
Value []byte Value []byte
@ -38,6 +37,12 @@ type RawValue struct {
r *bsoncodec.Registry r *bsoncodec.Registry
} }
// IsZero reports whether the RawValue is zero, i.e. no data is present on
// the RawValue. It returns true if Type is 0 and Value is empty or nil.
func (rv RawValue) IsZero() bool {
return rv.Type == 0x00 && len(rv.Value) == 0
}
// Unmarshal deserializes BSON into the provided val. If RawValue cannot be unmarshaled into val, an // Unmarshal deserializes BSON into the provided val. If RawValue cannot be unmarshaled into val, an
// error is returned. This method will use the registry used to create the RawValue, if the RawValue // error is returned. This method will use the registry used to create the RawValue, if the RawValue
// was created from partial BSON processing, or it will use the default registry. Users wishing to // was created from partial BSON processing, or it will use the default registry. Users wishing to
@ -268,10 +273,16 @@ func (rv RawValue) Int32OK() (int32, bool) { return convertToCoreValue(rv).Int32
// AsInt32 returns a BSON number as an int32. If the BSON type is not a numeric one, this method // AsInt32 returns a BSON number as an int32. If the BSON type is not a numeric one, this method
// will panic. // will panic.
//
// Deprecated: Use AsInt64 instead. If an int32 is required, convert the returned value to an int32
// and perform any required overflow/underflow checking.
func (rv RawValue) AsInt32() int32 { return convertToCoreValue(rv).AsInt32() } func (rv RawValue) AsInt32() int32 { return convertToCoreValue(rv).AsInt32() }
// AsInt32OK is the same as AsInt32, except that it returns a boolean instead of // AsInt32OK is the same as AsInt32, except that it returns a boolean instead of
// panicking. // panicking.
//
// Deprecated: Use AsInt64OK instead. If an int32 is required, convert the returned value to an
// int32 and perform any required overflow/underflow checking.
func (rv RawValue) AsInt32OK() (int32, bool) { return convertToCoreValue(rv).AsInt32OK() } func (rv RawValue) AsInt32OK() (int32, bool) { return convertToCoreValue(rv).AsInt32OK() }
// Timestamp returns the BSON timestamp value the Value represents. It panics if the value is a // Timestamp returns the BSON timestamp value the Value represents. It panics if the value is a

View file

@ -6,15 +6,19 @@
package bson package bson
import "go.mongodb.org/mongo-driver/bson/bsoncodec" import (
"go.mongodb.org/mongo-driver/bson/bsoncodec"
)
// DefaultRegistry is the default bsoncodec.Registry. It contains the default codecs and the // DefaultRegistry is the default bsoncodec.Registry. It contains the default codecs and the
// primitive codecs. // primitive codecs.
var DefaultRegistry = NewRegistryBuilder().Build() var DefaultRegistry = NewRegistry()
// NewRegistryBuilder creates a new RegistryBuilder configured with the default encoders and // NewRegistryBuilder creates a new RegistryBuilder configured with the default encoders and
// decoders from the bsoncodec.DefaultValueEncoders and bsoncodec.DefaultValueDecoders types and the // decoders from the bsoncodec.DefaultValueEncoders and bsoncodec.DefaultValueDecoders types and the
// PrimitiveCodecs type in this package. // PrimitiveCodecs type in this package.
//
// Deprecated: Use NewRegistry instead.
func NewRegistryBuilder() *bsoncodec.RegistryBuilder { func NewRegistryBuilder() *bsoncodec.RegistryBuilder {
rb := bsoncodec.NewRegistryBuilder() rb := bsoncodec.NewRegistryBuilder()
bsoncodec.DefaultValueEncoders{}.RegisterDefaultEncoders(rb) bsoncodec.DefaultValueEncoders{}.RegisterDefaultEncoders(rb)
@ -22,3 +26,10 @@ func NewRegistryBuilder() *bsoncodec.RegistryBuilder {
primitiveCodecs.RegisterPrimitiveCodecs(rb) primitiveCodecs.RegisterPrimitiveCodecs(rb)
return rb return rb
} }
// NewRegistry creates a new Registry configured with the default encoders and decoders from the
// bsoncodec.DefaultValueEncoders and bsoncodec.DefaultValueDecoders types and the PrimitiveCodecs
// type in this package.
func NewRegistry() *bsoncodec.Registry {
return NewRegistryBuilder().Build()
}

View file

@ -10,7 +10,7 @@
"go.mongodb.org/mongo-driver/bson/bsontype" "go.mongodb.org/mongo-driver/bson/bsontype"
) )
// These constants uniquely refer to each BSON type. // BSON element types as described in https://bsonspec.org/spec.html.
const ( const (
TypeDouble = bsontype.Double TypeDouble = bsontype.Double
TypeString = bsontype.String TypeString = bsontype.String
@ -34,3 +34,17 @@
TypeMinKey = bsontype.MinKey TypeMinKey = bsontype.MinKey
TypeMaxKey = bsontype.MaxKey TypeMaxKey = bsontype.MaxKey
) )
// BSON binary element subtypes as described in https://bsonspec.org/spec.html.
const (
TypeBinaryGeneric = bsontype.BinaryGeneric
TypeBinaryFunction = bsontype.BinaryFunction
TypeBinaryBinaryOld = bsontype.BinaryBinaryOld
TypeBinaryUUIDOld = bsontype.BinaryUUIDOld
TypeBinaryUUID = bsontype.BinaryUUID
TypeBinaryMD5 = bsontype.BinaryMD5
TypeBinaryEncrypted = bsontype.BinaryEncrypted
TypeBinaryColumn = bsontype.BinaryColumn
TypeBinarySensitive = bsontype.BinarySensitive
TypeBinaryUserDefined = bsontype.BinaryUserDefined
)

View file

@ -14,18 +14,26 @@
"go.mongodb.org/mongo-driver/bson/bsontype" "go.mongodb.org/mongo-driver/bson/bsontype"
) )
// Unmarshaler is an interface implemented by types that can unmarshal a BSON // Unmarshaler is the interface implemented by types that can unmarshal a BSON
// document representation of themselves. The BSON bytes can be assumed to be // document representation of themselves. The input can be assumed to be a valid
// valid. UnmarshalBSON must copy the BSON bytes if it wishes to retain the data // encoding of a BSON document. UnmarshalBSON must copy the JSON data if it
// after returning. // wishes to retain the data after returning.
//
// Unmarshaler is only used to unmarshal full BSON documents. To create custom
// BSON unmarshaling behavior for individual values in a BSON document,
// implement the ValueUnmarshaler interface instead.
type Unmarshaler interface { type Unmarshaler interface {
UnmarshalBSON([]byte) error UnmarshalBSON([]byte) error
} }
// ValueUnmarshaler is an interface implemented by types that can unmarshal a // ValueUnmarshaler is the interface implemented by types that can unmarshal a
// BSON value representation of themselves. The BSON bytes and type can be // BSON value representation of themselves. The input can be assumed to be a
// assumed to be valid. UnmarshalBSONValue must copy the BSON value bytes if it // valid encoding of a BSON value. UnmarshalBSONValue must copy the BSON value
// wishes to retain the data after returning. // bytes if it wishes to retain the data after returning.
//
// ValueUnmarshaler is only used to unmarshal individual values in a BSON
// document. To create custom BSON unmarshaling behavior for an entire BSON
// document, implement the Unmarshaler interface instead.
type ValueUnmarshaler interface { type ValueUnmarshaler interface {
UnmarshalBSONValue(bsontype.Type, []byte) error UnmarshalBSONValue(bsontype.Type, []byte) error
} }
@ -40,6 +48,16 @@ func Unmarshal(data []byte, val interface{}) error {
// UnmarshalWithRegistry parses the BSON-encoded data using Registry r and // UnmarshalWithRegistry parses the BSON-encoded data using Registry r and
// stores the result in the value pointed to by val. If val is nil or not // stores the result in the value pointed to by val. If val is nil or not
// a pointer, UnmarshalWithRegistry returns InvalidUnmarshalError. // a pointer, UnmarshalWithRegistry returns InvalidUnmarshalError.
//
// Deprecated: Use [NewDecoder] and specify the Registry by calling [Decoder.SetRegistry] instead:
//
// dec, err := bson.NewDecoder(bsonrw.NewBSONDocumentReader(data))
// if err != nil {
// panic(err)
// }
// dec.SetRegistry(reg)
//
// See [Decoder] for more examples.
func UnmarshalWithRegistry(r *bsoncodec.Registry, data []byte, val interface{}) error { func UnmarshalWithRegistry(r *bsoncodec.Registry, data []byte, val interface{}) error {
vr := bsonrw.NewBSONDocumentReader(data) vr := bsonrw.NewBSONDocumentReader(data)
return unmarshalFromReader(bsoncodec.DecodeContext{Registry: r}, vr, val) return unmarshalFromReader(bsoncodec.DecodeContext{Registry: r}, vr, val)
@ -48,11 +66,40 @@ func UnmarshalWithRegistry(r *bsoncodec.Registry, data []byte, val interface{})
// UnmarshalWithContext parses the BSON-encoded data using DecodeContext dc and // UnmarshalWithContext parses the BSON-encoded data using DecodeContext dc and
// stores the result in the value pointed to by val. If val is nil or not // stores the result in the value pointed to by val. If val is nil or not
// a pointer, UnmarshalWithRegistry returns InvalidUnmarshalError. // a pointer, UnmarshalWithRegistry returns InvalidUnmarshalError.
//
// Deprecated: Use [NewDecoder] and use the Decoder configuration methods to set the desired unmarshal
// behavior instead:
//
// dec, err := bson.NewDecoder(bsonrw.NewBSONDocumentReader(data))
// if err != nil {
// panic(err)
// }
// dec.DefaultDocumentM()
//
// See [Decoder] for more examples.
func UnmarshalWithContext(dc bsoncodec.DecodeContext, data []byte, val interface{}) error { func UnmarshalWithContext(dc bsoncodec.DecodeContext, data []byte, val interface{}) error {
vr := bsonrw.NewBSONDocumentReader(data) vr := bsonrw.NewBSONDocumentReader(data)
return unmarshalFromReader(dc, vr, val) return unmarshalFromReader(dc, vr, val)
} }
// UnmarshalValue parses the BSON value of type t with bson.DefaultRegistry and
// stores the result in the value pointed to by val. If val is nil or not a pointer,
// UnmarshalValue returns an error.
func UnmarshalValue(t bsontype.Type, data []byte, val interface{}) error {
return UnmarshalValueWithRegistry(DefaultRegistry, t, data, val)
}
// UnmarshalValueWithRegistry parses the BSON value of type t with registry r and
// stores the result in the value pointed to by val. If val is nil or not a pointer,
// UnmarshalValue returns an error.
//
// Deprecated: Using a custom registry to unmarshal individual BSON values will not be supported in
// Go Driver 2.0.
func UnmarshalValueWithRegistry(r *bsoncodec.Registry, t bsontype.Type, data []byte, val interface{}) error {
vr := bsonrw.NewBSONValueReader(t, data)
return unmarshalFromReader(bsoncodec.DecodeContext{Registry: r}, vr, val)
}
// UnmarshalExtJSON parses the extended JSON-encoded data and stores the result // UnmarshalExtJSON parses the extended JSON-encoded data and stores the result
// in the value pointed to by val. If val is nil or not a pointer, Unmarshal // in the value pointed to by val. If val is nil or not a pointer, Unmarshal
// returns InvalidUnmarshalError. // returns InvalidUnmarshalError.
@ -63,6 +110,20 @@ func UnmarshalExtJSON(data []byte, canonical bool, val interface{}) error {
// UnmarshalExtJSONWithRegistry parses the extended JSON-encoded data using // UnmarshalExtJSONWithRegistry parses the extended JSON-encoded data using
// Registry r and stores the result in the value pointed to by val. If val is // Registry r and stores the result in the value pointed to by val. If val is
// nil or not a pointer, UnmarshalWithRegistry returns InvalidUnmarshalError. // nil or not a pointer, UnmarshalWithRegistry returns InvalidUnmarshalError.
//
// Deprecated: Use [NewDecoder] and specify the Registry by calling [Decoder.SetRegistry] instead:
//
// vr, err := bsonrw.NewExtJSONValueReader(bytes.NewReader(data), true)
// if err != nil {
// panic(err)
// }
// dec, err := bson.NewDecoder(vr)
// if err != nil {
// panic(err)
// }
// dec.SetRegistry(reg)
//
// See [Decoder] for more examples.
func UnmarshalExtJSONWithRegistry(r *bsoncodec.Registry, data []byte, canonical bool, val interface{}) error { func UnmarshalExtJSONWithRegistry(r *bsoncodec.Registry, data []byte, canonical bool, val interface{}) error {
ejvr, err := bsonrw.NewExtJSONValueReader(bytes.NewReader(data), canonical) ejvr, err := bsonrw.NewExtJSONValueReader(bytes.NewReader(data), canonical)
if err != nil { if err != nil {
@ -75,6 +136,21 @@ func UnmarshalExtJSONWithRegistry(r *bsoncodec.Registry, data []byte, canonical
// UnmarshalExtJSONWithContext parses the extended JSON-encoded data using // UnmarshalExtJSONWithContext parses the extended JSON-encoded data using
// DecodeContext dc and stores the result in the value pointed to by val. If val is // DecodeContext dc and stores the result in the value pointed to by val. If val is
// nil or not a pointer, UnmarshalWithRegistry returns InvalidUnmarshalError. // nil or not a pointer, UnmarshalWithRegistry returns InvalidUnmarshalError.
//
// Deprecated: Use [NewDecoder] and use the Decoder configuration methods to set the desired unmarshal
// behavior instead:
//
// vr, err := bsonrw.NewExtJSONValueReader(bytes.NewReader(data), true)
// if err != nil {
// panic(err)
// }
// dec, err := bson.NewDecoder(vr)
// if err != nil {
// panic(err)
// }
// dec.DefaultDocumentM()
//
// See [Decoder] for more examples.
func UnmarshalExtJSONWithContext(dc bsoncodec.DecodeContext, data []byte, canonical bool, val interface{}) error { func UnmarshalExtJSONWithContext(dc bsoncodec.DecodeContext, data []byte, canonical bool, val interface{}) error {
ejvr, err := bsonrw.NewExtJSONValueReader(bytes.NewReader(data), canonical) ejvr, err := bsonrw.NewExtJSONValueReader(bytes.NewReader(data), canonical)
if err != nil { if err != nil {

View file

@ -7,10 +7,10 @@
package bsoncore package bsoncore
import ( import (
"bytes"
"fmt" "fmt"
"io" "io"
"strconv" "strconv"
"strings"
) )
// NewArrayLengthError creates and returns an error for when the length of an array exceeds the // NewArrayLengthError creates and returns an error for when the length of an array exceeds the
@ -53,7 +53,7 @@ func (a Array) DebugString() string {
if len(a) < 5 { if len(a) < 5 {
return "<malformed>" return "<malformed>"
} }
var buf bytes.Buffer var buf strings.Builder
buf.WriteString("Array") buf.WriteString("Array")
length, rem, _ := ReadLength(a) // We know we have enough bytes to read the length length, rem, _ := ReadLength(a) // We know we have enough bytes to read the length
buf.WriteByte('(') buf.WriteByte('(')
@ -69,7 +69,7 @@ func (a Array) DebugString() string {
buf.WriteString(fmt.Sprintf("<malformed (%d)>", length)) buf.WriteString(fmt.Sprintf("<malformed (%d)>", length))
break break
} }
fmt.Fprintf(&buf, "%s", elem.Value().DebugString()) buf.WriteString(elem.Value().DebugString())
if length != 1 { if length != 1 {
buf.WriteByte(',') buf.WriteByte(',')
} }
@ -85,7 +85,7 @@ func (a Array) String() string {
if len(a) < 5 { if len(a) < 5 {
return "" return ""
} }
var buf bytes.Buffer var buf strings.Builder
buf.WriteByte('[') buf.WriteByte('[')
length, rem, _ := ReadLength(a) // We know we have enough bytes to read the length length, rem, _ := ReadLength(a) // We know we have enough bytes to read the length
@ -100,7 +100,7 @@ func (a Array) String() string {
if !ok { if !ok {
return "" return ""
} }
fmt.Fprintf(&buf, "%s", elem.Value().String()) buf.WriteString(elem.Value().String())
if length > 1 { if length > 1 {
buf.WriteByte(',') buf.WriteByte(',')
} }

View file

@ -4,25 +4,6 @@
// not use this file except in compliance with the License. You may obtain // not use this file except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 // a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
// Package bsoncore contains functions that can be used to encode and decode BSON
// elements and values to or from a slice of bytes. These functions are aimed at
// allowing low level manipulation of BSON and can be used to build a higher
// level BSON library.
//
// The Read* functions within this package return the values of the element and
// a boolean indicating if the values are valid. A boolean was used instead of
// an error because any error that would be returned would be the same: not
// enough bytes. This library attempts to do no validation, it will only return
// false if there are not enough bytes for an item to be read. For example, the
// ReadDocument function checks the length, if that length is larger than the
// number of bytes available, it will return false, if there are enough bytes, it
// will return those bytes and true. It is the consumers responsibility to
// validate those bytes.
//
// The Append* functions within this package will append the type value to the
// given dst slice. If the slice has enough capacity, it will not grow the
// slice. The Append*Element functions within this package operate in the same
// way, but additionally append the BSON type and the key before the value.
package bsoncore // import "go.mongodb.org/mongo-driver/x/bsonx/bsoncore" package bsoncore // import "go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
import ( import (
@ -254,7 +235,7 @@ func BuildDocumentValue(elems ...[]byte) Value {
return Value{Type: bsontype.EmbeddedDocument, Data: BuildDocument(nil, elems...)} return Value{Type: bsontype.EmbeddedDocument, Data: BuildDocument(nil, elems...)}
} }
// BuildDocumentElement will append a BSON embedded document elemnt using key and the provided // BuildDocumentElement will append a BSON embedded document element using key and the provided
// elements and return the extended buffer. // elements and return the extended buffer.
func BuildDocumentElement(dst []byte, key string, elems ...[]byte) []byte { func BuildDocumentElement(dst []byte, key string, elems ...[]byte) []byte {
return BuildDocument(AppendHeader(dst, bsontype.EmbeddedDocument, key), elems...) return BuildDocument(AppendHeader(dst, bsontype.EmbeddedDocument, key), elems...)
@ -844,6 +825,9 @@ func readLengthBytes(src []byte) ([]byte, []byte, bool) {
if !ok { if !ok {
return nil, src, false return nil, src, false
} }
if l < 4 {
return nil, src, false
}
if len(src) < int(l) { if len(src) < int(l) {
return nil, src, false return nil, src, false
} }

View file

@ -0,0 +1,29 @@
// Copyright (C) MongoDB, Inc. 2022-present.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
// Package bsoncore contains functions that can be used to encode and decode BSON
// elements and values to or from a slice of bytes. These functions are aimed at
// allowing low level manipulation of BSON and can be used to build a higher
// level BSON library.
//
// The Read* functions within this package return the values of the element and
// a boolean indicating if the values are valid. A boolean was used instead of
// an error because any error that would be returned would be the same: not
// enough bytes. This library attempts to do no validation, it will only return
// false if there are not enough bytes for an item to be read. For example, the
// ReadDocument function checks the length, if that length is larger than the
// number of bytes available, it will return false, if there are enough bytes, it
// will return those bytes and true. It is the consumers responsibility to
// validate those bytes.
//
// The Append* functions within this package will append the type value to the
// given dst slice. If the slice has enough capacity, it will not grow the
// slice. The Append*Element functions within this package operate in the same
// way, but additionally append the BSON type and the key before the value.
//
// Warning: Package bsoncore is unstable and there is no backward compatibility
// guarantee. It is experimental and subject to change.
package bsoncore

View file

@ -7,11 +7,11 @@
package bsoncore package bsoncore
import ( import (
"bytes"
"errors" "errors"
"fmt" "fmt"
"io" "io"
"strconv" "strconv"
"strings"
"go.mongodb.org/mongo-driver/bson/bsontype" "go.mongodb.org/mongo-driver/bson/bsontype"
) )
@ -237,7 +237,7 @@ func (d Document) DebugString() string {
if len(d) < 5 { if len(d) < 5 {
return "<malformed>" return "<malformed>"
} }
var buf bytes.Buffer var buf strings.Builder
buf.WriteString("Document") buf.WriteString("Document")
length, rem, _ := ReadLength(d) // We know we have enough bytes to read the length length, rem, _ := ReadLength(d) // We know we have enough bytes to read the length
buf.WriteByte('(') buf.WriteByte('(')
@ -253,7 +253,7 @@ func (d Document) DebugString() string {
buf.WriteString(fmt.Sprintf("<malformed (%d)>", length)) buf.WriteString(fmt.Sprintf("<malformed (%d)>", length))
break break
} }
fmt.Fprintf(&buf, "%s ", elem.DebugString()) buf.WriteString(elem.DebugString())
} }
buf.WriteByte('}') buf.WriteByte('}')
@ -266,7 +266,7 @@ func (d Document) String() string {
if len(d) < 5 { if len(d) < 5 {
return "" return ""
} }
var buf bytes.Buffer var buf strings.Builder
buf.WriteByte('{') buf.WriteByte('{')
length, rem, _ := ReadLength(d) // We know we have enough bytes to read the length length, rem, _ := ReadLength(d) // We know we have enough bytes to read the length
@ -285,7 +285,7 @@ func (d Document) String() string {
if !ok { if !ok {
return "" return ""
} }
fmt.Fprintf(&buf, "%s", elem.String()) buf.WriteString(elem.String())
first = false first = false
} }
buf.WriteByte('}') buf.WriteByte('}')

View file

@ -129,7 +129,7 @@ func (e Element) String() string {
if !valid { if !valid {
return "" return ""
} }
return fmt.Sprintf(`"%s": %v`, key, val) return "\"" + string(key) + "\": " + val.String()
} }
// DebugString outputs a human readable version of RawElement. It will attempt to stringify the // DebugString outputs a human readable version of RawElement. It will attempt to stringify the

View file

@ -59,8 +59,6 @@ func (v Value) IsNumber() bool {
// AsInt32 returns a BSON number as an int32. If the BSON type is not a numeric one, this method // AsInt32 returns a BSON number as an int32. If the BSON type is not a numeric one, this method
// will panic. // will panic.
//
// TODO(skriptble): Add support for Decimal128.
func (v Value) AsInt32() int32 { func (v Value) AsInt32() int32 {
if !v.IsNumber() { if !v.IsNumber() {
panic(ElementTypeError{"bsoncore.Value.AsInt32", v.Type}) panic(ElementTypeError{"bsoncore.Value.AsInt32", v.Type})
@ -93,8 +91,6 @@ func (v Value) AsInt32() int32 {
// AsInt32OK functions the same as AsInt32 but returns a boolean instead of panicking. False // AsInt32OK functions the same as AsInt32 but returns a boolean instead of panicking. False
// indicates an error. // indicates an error.
//
// TODO(skriptble): Add support for Decimal128.
func (v Value) AsInt32OK() (int32, bool) { func (v Value) AsInt32OK() (int32, bool) {
if !v.IsNumber() { if !v.IsNumber() {
return 0, false return 0, false
@ -127,8 +123,6 @@ func (v Value) AsInt32OK() (int32, bool) {
// AsInt64 returns a BSON number as an int64. If the BSON type is not a numeric one, this method // AsInt64 returns a BSON number as an int64. If the BSON type is not a numeric one, this method
// will panic. // will panic.
//
// TODO(skriptble): Add support for Decimal128.
func (v Value) AsInt64() int64 { func (v Value) AsInt64() int64 {
if !v.IsNumber() { if !v.IsNumber() {
panic(ElementTypeError{"bsoncore.Value.AsInt64", v.Type}) panic(ElementTypeError{"bsoncore.Value.AsInt64", v.Type})
@ -162,8 +156,6 @@ func (v Value) AsInt64() int64 {
// AsInt64OK functions the same as AsInt64 but returns a boolean instead of panicking. False // AsInt64OK functions the same as AsInt64 but returns a boolean instead of panicking. False
// indicates an error. // indicates an error.
//
// TODO(skriptble): Add support for Decimal128.
func (v Value) AsInt64OK() (int64, bool) { func (v Value) AsInt64OK() (int64, bool) {
if !v.IsNumber() { if !v.IsNumber() {
return 0, false return 0, false
@ -198,21 +190,14 @@ func (v Value) AsInt64OK() (int64, bool) {
// AsFloat64 returns a BSON number as an float64. If the BSON type is not a numeric one, this method // AsFloat64 returns a BSON number as an float64. If the BSON type is not a numeric one, this method
// will panic. // will panic.
// //
// TODO(skriptble): Add support for Decimal128. // TODO(GODRIVER-2751): Implement AsFloat64.
func (v Value) AsFloat64() float64 { return 0 } // func (v Value) AsFloat64() float64
// AsFloat64OK functions the same as AsFloat64 but returns a boolean instead of panicking. False // AsFloat64OK functions the same as AsFloat64 but returns a boolean instead of panicking. False
// indicates an error. // indicates an error.
// //
// TODO(skriptble): Add support for Decimal128. // TODO(GODRIVER-2751): Implement AsFloat64OK.
func (v Value) AsFloat64OK() (float64, bool) { return 0, false } // func (v Value) AsFloat64OK() (float64, bool)
// Add will add this value to another. This is currently only implemented for strings and numbers.
// If either value is a string, the other type is coerced into a string and added to the other.
//
// This method will alter v and will attempt to reuse the []byte of v. If the []byte is too small,
// it will be expanded.
func (v *Value) Add(v2 Value) error { return nil }
// Equal compaes v to v2 and returns true if they are equal. // Equal compaes v to v2 and returns true if they are equal.
func (v Value) Equal(v2 Value) bool { func (v Value) Equal(v2 Value) bool {

22
vendor/modules.txt vendored
View file

@ -207,7 +207,7 @@ github.com/gin-contrib/cors
# github.com/gin-contrib/gzip v1.0.0 # github.com/gin-contrib/gzip v1.0.0
## explicit; go 1.18 ## explicit; go 1.18
github.com/gin-contrib/gzip github.com/gin-contrib/gzip
# github.com/gin-contrib/sessions v0.0.5 # github.com/gin-contrib/sessions v1.0.0
## explicit; go 1.18 ## explicit; go 1.18
github.com/gin-contrib/sessions github.com/gin-contrib/sessions
github.com/gin-contrib/sessions/memstore github.com/gin-contrib/sessions/memstore
@ -347,8 +347,8 @@ github.com/golang/protobuf/ptypes/timestamp
# github.com/google/uuid v1.6.0 # github.com/google/uuid v1.6.0
## explicit ## explicit
github.com/google/uuid github.com/google/uuid
# github.com/gorilla/context v1.1.1 # github.com/gorilla/context v1.1.2
## explicit ## explicit; go 1.20
github.com/gorilla/context github.com/gorilla/context
# github.com/gorilla/css v1.0.0 # github.com/gorilla/css v1.0.0
## explicit ## explicit
@ -359,11 +359,11 @@ github.com/gorilla/feeds
# github.com/gorilla/handlers v1.5.1 # github.com/gorilla/handlers v1.5.1
## explicit; go 1.14 ## explicit; go 1.14
github.com/gorilla/handlers github.com/gorilla/handlers
# github.com/gorilla/securecookie v1.1.1 # github.com/gorilla/securecookie v1.1.2
## explicit ## explicit; go 1.20
github.com/gorilla/securecookie github.com/gorilla/securecookie
# github.com/gorilla/sessions v1.2.1 # github.com/gorilla/sessions v1.2.2
## explicit ## explicit; go 1.20
github.com/gorilla/sessions github.com/gorilla/sessions
# github.com/gorilla/websocket v1.5.1 # github.com/gorilla/websocket v1.5.1
## explicit; go 1.20 ## explicit; go 1.20
@ -442,8 +442,8 @@ github.com/josharian/intern
# github.com/json-iterator/go v1.1.12 # github.com/json-iterator/go v1.1.12
## explicit; go 1.12 ## explicit; go 1.12
github.com/json-iterator/go github.com/json-iterator/go
# github.com/klauspost/compress v1.17.6 # github.com/klauspost/compress v1.17.7
## explicit; go 1.19 ## explicit; go 1.20
github.com/klauspost/compress/flate github.com/klauspost/compress/flate
github.com/klauspost/compress/gzip github.com/klauspost/compress/gzip
github.com/klauspost/compress/internal/race github.com/klauspost/compress/internal/race
@ -907,8 +907,8 @@ github.com/yuin/goldmark/util
# github.com/zeebo/xxh3 v1.0.2 # github.com/zeebo/xxh3 v1.0.2
## explicit; go 1.17 ## explicit; go 1.17
github.com/zeebo/xxh3 github.com/zeebo/xxh3
# go.mongodb.org/mongo-driver v1.11.3 # go.mongodb.org/mongo-driver v1.14.0
## explicit; go 1.13 ## explicit; go 1.18
go.mongodb.org/mongo-driver/bson go.mongodb.org/mongo-driver/bson
go.mongodb.org/mongo-driver/bson/bsoncodec go.mongodb.org/mongo-driver/bson/bsoncodec
go.mongodb.org/mongo-driver/bson/bsonoptions go.mongodb.org/mongo-driver/bson/bsonoptions