Repository: valkey-io/valkey
File: src/geo.c (C)

Code before:
int decodeGeohash(double bits, double *xy) {
    GeoHashBits hash = {.bits = (uint64_t)bits, .step = GEO_STEP_MAX};
    return geohashDecodeToLongLatWGS84(hash, xy);
}

/* Input Argument Helper */
/* Take a pointer to the latitude arg then use the next arg for longitude.
 * On parse error C_ERR is returned, otherwise C_OK. */
int extractLongLatOrReply(client *c, robj **argv, double *xy) {
    int i;
    for (i = 0; i < 2; i++) {
        if (getDoubleFromObjectOrReply(c, argv[i], xy + i, NULL) != C_OK) {
            return C_ERR;
        }
    }
    if (xy[0] < GEO_LONG_MIN || xy[0] > GEO_LONG_MAX || xy[1] < GEO_LAT_MIN || xy[1] > GEO_LAT_MAX) {
        addReplyErrorFormat(c, "-ERR invalid longitude,latitude pair %f,%f\r\n", xy[0], xy[1]);
        return C_ERR;
    }
    return C_OK;
}

/* Input Argument Helper */
/* Decode lat/long from a zset member's score.
 * Returns C_OK on successful decoding, otherwise C_ERR is returned. */
int longLatFromMember(robj *zobj, robj *member, double *xy, sds* err) {
    double score = 0;

    if (zsetScore(zobj, member->ptr, &score) == C_ERR){
        *err = sdsnew("member des not exist");
        return C_ERR;
    } 
    if (!decodeGeohash(score, xy)) {
        *err = sdsnew("failed to decode");
        return C_ERR;
    }
    return C_OK;
}

/* Check that the unit argument matches one of the known units, and returns
 * the conversion factor to meters (you need to divide meters by the conversion
 * factor to convert to the right unit).
 *
 * If the unit is not valid, an error is reported to the client, and a value
 * less than zero is returned. */
double extractUnitOrReply(client *c, robj *unit) {
    char *u = unit->ptr;

    if (!strcasecmp(u, "m")) {
        return 1;
    } else if (!strcasecmp(u, "km")) {

Review comment (suggestion):
```suggestion
int longLatFromMemberOrReply(client *c, robj *zobj, robj *member, double *xy) {
```
A more common pattern we use is "validate" or reply. This makes it so we don't have to pass a buncch of stack allocated objects back and forth. If we pass in the client object, we can do all the logic and then also put the replies on the client object here. The replying code becomes centralized as well. 

Code after:
int decodeGeohash(double bits, double *xy) {
    GeoHashBits hash = {.bits = (uint64_t)bits, .step = GEO_STEP_MAX};
    return geohashDecodeToLongLatWGS84(hash, xy);
}

/* Input Argument Helper */
/* Take a pointer to the latitude arg then use the next arg for longitude.
 * On parse error C_ERR is returned, otherwise C_OK. */
int extractLongLatOrReply(client *c, robj **argv, double *xy) {
    int i;
    for (i = 0; i < 2; i++) {
        if (getDoubleFromObjectOrReply(c, argv[i], xy + i, NULL) != C_OK) {
            return C_ERR;
        }
    }
    if (xy[0] < GEO_LONG_MIN || xy[0] > GEO_LONG_MAX || xy[1] < GEO_LAT_MIN || xy[1] > GEO_LAT_MAX) {
        addReplyErrorFormat(c, "-ERR invalid longitude,latitude pair %f,%f\r\n", xy[0], xy[1]);
        return C_ERR;
    }
    return C_OK;
}

/* Input Argument Helper */
/* Decode lat/long from a zset member's score.
 * Returns C_OK on successful decoding, otherwise C_ERR is returned. */
int longLatFromMemberOrReply(client *c, robj *zobj, robj *member, double *xy) {
    double score = 0;

    if (zsetScore(zobj, member->ptr, &score) == C_ERR) {
        addReplyErrorFormat(c, "member %s does not exist", (char *)member->ptr);
        return C_ERR;
    }
    if (!decodeGeohash(score, xy)) {
        addReplyErrorFormat(c, "failed to decode, member %s is not a valid geohash", (char *)member->ptr);
        return C_ERR;
    }
    return C_OK;
}

/* Check that the unit argument matches one of the known units, and returns
 * the conversion factor to meters (you need to divide meters by the conversion
 * factor to convert to the right unit).
 *
 * If the unit is not valid, an error is reported to the client, and a value
 * less than zero is returned. */
double extractUnitOrReply(client *c, robj *unit) {
    char *u = unit->ptr;

    if (!strcasecmp(u, "m")) {
        return 1;
    } else if (!strcasecmp(u, "km")) {