1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to you under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  * https://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
14  * implied.  See the License for the specific language governing
15  * permissions and limitations under the License.
16  */
17 
18 #include "avro_private.h"
19 #include <string.h>
20 #include "datum.h"
21 
22 static int
array_equal(struct avro_array_datum_t * a,struct avro_array_datum_t * b)23 array_equal(struct avro_array_datum_t *a, struct avro_array_datum_t *b)
24 {
25 	if (!avro_schema_equal(a->schema, b->schema)) {
26 		return 0;
27 	}
28 
29 	long i;
30 
31 	if (a->els->num_entries != b->els->num_entries) {
32 		return 0;
33 	}
34 	for (i = 0; i < a->els->num_entries; i++) {
35 		union {
36 			st_data_t data;
37 			avro_datum_t datum;
38 		} ael, bel;
39 		st_lookup(a->els, i, &ael.data);
40 		st_lookup(b->els, i, &bel.data);
41 		if (!avro_datum_equal(ael.datum, bel.datum)) {
42 			return 0;
43 		}
44 	}
45 	return 1;
46 }
47 
48 struct st_equal_args {
49 	int rval;
50 	st_table *st;
51 };
52 
53 static int
st_equal_foreach(char * key,avro_datum_t datum,struct st_equal_args * args)54 st_equal_foreach(char *key, avro_datum_t datum, struct st_equal_args *args)
55 {
56 	union {
57 		avro_datum_t datum_other;
58 		st_data_t data;
59 	} val;
60 	if (!st_lookup(args->st, (st_data_t) key, &(val.data))) {
61 		args->rval = 0;
62 		return ST_STOP;
63 	}
64 	if (!avro_datum_equal(datum, val.datum_other)) {
65 		args->rval = 0;
66 		return ST_STOP;
67 	}
68 	return ST_CONTINUE;
69 }
70 
map_equal(struct avro_map_datum_t * a,struct avro_map_datum_t * b)71 static int map_equal(struct avro_map_datum_t *a, struct avro_map_datum_t *b)
72 {
73 	if (!avro_schema_equal(a->schema, b->schema)) {
74 		return 0;
75 	}
76 
77 	struct st_equal_args args = { 1, b->map };
78 	if (a->map->num_entries != b->map->num_entries) {
79 		return 0;
80 	}
81 	st_foreach(a->map, HASH_FUNCTION_CAST st_equal_foreach, (st_data_t) & args);
82 	return args.rval;
83 }
84 
record_equal(struct avro_record_datum_t * a,struct avro_record_datum_t * b)85 static int record_equal(struct avro_record_datum_t *a,
86 			struct avro_record_datum_t *b)
87 {
88 	if (!avro_schema_equal(a->schema, b->schema)) {
89 		return 0;
90 	}
91 
92 	struct st_equal_args args = { 1, b->fields_byname };
93 	if (a->fields_byname->num_entries != b->fields_byname->num_entries) {
94 		return 0;
95 	}
96 	st_foreach(a->fields_byname, HASH_FUNCTION_CAST st_equal_foreach, (st_data_t) & args);
97 	return args.rval;
98 }
99 
enum_equal(struct avro_enum_datum_t * a,struct avro_enum_datum_t * b)100 static int enum_equal(struct avro_enum_datum_t *a, struct avro_enum_datum_t *b)
101 {
102 	return avro_schema_equal(a->schema, b->schema) && a->value == b->value;
103 }
104 
fixed_equal(struct avro_fixed_datum_t * a,struct avro_fixed_datum_t * b)105 static int fixed_equal(struct avro_fixed_datum_t *a,
106 		       struct avro_fixed_datum_t *b)
107 {
108 	if (!avro_schema_equal(a->schema, b->schema)) {
109 		return 0;
110 	}
111 
112 	return a->size == b->size && memcmp(a->bytes, b->bytes, a->size) == 0;
113 }
114 
union_equal(struct avro_union_datum_t * a,struct avro_union_datum_t * b)115 static int union_equal(struct avro_union_datum_t *a,
116 		       struct avro_union_datum_t *b)
117 {
118 	if (!avro_schema_equal(a->schema, b->schema)) {
119 		return 0;
120 	}
121 
122 	return a->discriminant == b->discriminant && avro_datum_equal(a->value, b->value);
123 }
124 
avro_datum_equal(const avro_datum_t a,const avro_datum_t b)125 int avro_datum_equal(const avro_datum_t a, const avro_datum_t b)
126 {
127 	if (!(is_avro_datum(a) && is_avro_datum(b))) {
128 		return 0;
129 	}
130 	if (avro_typeof(a) != avro_typeof(b)) {
131 		return 0;
132 	}
133 	switch (avro_typeof(a)) {
134 	case AVRO_STRING:
135 		return strcmp(avro_datum_to_string(a)->s,
136 			      avro_datum_to_string(b)->s) == 0;
137 	case AVRO_BYTES:
138 		return (avro_datum_to_bytes(a)->size ==
139 			avro_datum_to_bytes(b)->size)
140 		    && memcmp(avro_datum_to_bytes(a)->bytes,
141 			      avro_datum_to_bytes(b)->bytes,
142 			      avro_datum_to_bytes(a)->size) == 0;
143 	case AVRO_INT32:
144 		return avro_datum_to_int32(a)->i32 ==
145 		    avro_datum_to_int32(b)->i32;
146 	case AVRO_INT64:
147 		return avro_datum_to_int64(a)->i64 ==
148 		    avro_datum_to_int64(b)->i64;
149 	case AVRO_FLOAT:
150 		return avro_datum_to_float(a)->f == avro_datum_to_float(b)->f;
151 	case AVRO_DOUBLE:
152 		return avro_datum_to_double(a)->d == avro_datum_to_double(b)->d;
153 	case AVRO_BOOLEAN:
154 		return avro_datum_to_boolean(a)->i ==
155 		    avro_datum_to_boolean(b)->i;
156 	case AVRO_NULL:
157 		return 1;
158 	case AVRO_ARRAY:
159 		return array_equal(avro_datum_to_array(a),
160 				   avro_datum_to_array(b));
161 	case AVRO_MAP:
162 		return map_equal(avro_datum_to_map(a), avro_datum_to_map(b));
163 
164 	case AVRO_RECORD:
165 		return record_equal(avro_datum_to_record(a),
166 				    avro_datum_to_record(b));
167 
168 	case AVRO_ENUM:
169 		return enum_equal(avro_datum_to_enum(a), avro_datum_to_enum(b));
170 
171 	case AVRO_FIXED:
172 		return fixed_equal(avro_datum_to_fixed(a),
173 				   avro_datum_to_fixed(b));
174 
175 	case AVRO_UNION:
176 		return union_equal(avro_datum_to_union(a),
177 				   avro_datum_to_union(b));
178 
179 	case AVRO_LINK:
180 		/*
181 		 * TODO
182 		 */
183 		return 0;
184 	}
185 	return 0;
186 }
187